mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
Add concept world catalog and review workflow
AI-assisted: prepared by Codex at Paul's request.
This commit is contained in:
@@ -1,65 +1,64 @@
|
||||
---
|
||||
name: impeccable
|
||||
description: Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.
|
||||
version: 4.0.0-alpha.9
|
||||
version: 4.0.0-alpha.10
|
||||
---
|
||||
|
||||
Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft.
|
||||
This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as a award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft.
|
||||
|
||||
Approach every design task as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. The client has already rejected work that felt templated; they are paying for a point of view. GPT is capable of extraordinary work. Don't hold back.
|
||||
Core principles:
|
||||
- Go all out. No hedging, no shortcuts. The deliverable must be complete (except assets the user must provide).
|
||||
- Dream big and bold. Distinct, beautiful, outstanding and highly inspiring work.
|
||||
- Iterate with tools available to you (e.g. visual understanding, browser screenshots) until you think this meets the bar.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Run `node .agents/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). It prints the project's context and its directives; follow what it prints. Once its output is in the conversation, never rerun it on a later turn.
|
||||
2. `craft` and `shape` are build-path exceptions: the new-work gate below owns their flow, and on unattended runs its checkpoints resolve without pausing. For any other invoked sub-command (`audit`, `polish`, `live`, ...), immediately read **`reference/<command>.md`** after `context.mjs` (the `.native` variant from the Commands table when the platform is `ios`/`android`/`adaptive`) and follow it. This read is a hard gate: do not inspect the target, run command-specific scripts, or edit files until the reference is loaded.
|
||||
3. Read at least one project file (CSS / tokens / theme / a representative component) to learn what world you're in. If PRODUCT.md's `## Platform` is `ios` or `android`, also read `reference/<platform>.md` (`adaptive` reads both).
|
||||
1. Run `node .agents/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). Pass a named source file or route as `--target <path>`. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it.
|
||||
2. Before acting, load the one playbook that owns the request: the Commands table's reference for an explicit or clearly implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Then inspect the target and at least one representative source of incumbent visual truth (tokens, theme, CSS, component, or asset) before editing.
|
||||
|
||||
## How to design
|
||||
|
||||
**The brief wins.** Where the brief pins down a direction (a named aesthetic, an era, a place, a material, a specific font or palette), follow it exactly, including when it asks for a look this skill warns is saturated. Redirecting a pinned direction toward your own taste is a failure, not a save.
|
||||
|
||||
**Existing worlds are sacred.** Most of impeccable's work happens inside a site or app that already exists. When the surface has a committed design system (real tokens, deliberately chosen faces, a palette the brand owns), work inside that world: extend it, sharpen it, leave it unmistakably the same brand, and never degrade a working page's performance. Inventing parallel colors, fonts, or styles on an existing surface is a defect, not creativity. A scoped refinement keeps the named scope's content and media footprint unless the brief explicitly changes them; build the added emphasis by recomposing what is already there through hierarchy, proportion, rhythm, and the system's own motifs.
|
||||
|
||||
**New identity work reads the playbook first.** When nothing committed exists (greenfield, or a codebase with no real tokens or chosen faces), or the user explicitly asks for a redesign that discards the current look, you MUST read [reference/new-work.md](reference/new-work.md) before making any design decision. Missing DESIGN.md alone does not make work greenfield: code, tokens, chosen type, components, and assets are incumbent design authority. Preserve and extend them unless the user asked to replace them. Producing a genuinely new identity without the playbook yields the generic default this skill exists to prevent. Scoped fixes inside an existing world don't need it; the craft floor below governs them. `context.mjs` prints the appropriate authority directive.
|
||||
- **The brief wins.** Honor pinned aesthetics, eras, materials, fonts, and palettes even when they conflict with a saturated-pattern warning. Redirecting a clear brief toward your taste is failure.
|
||||
- **Refinement preserves; redesign replaces.** Refinement keeps the incumbent identity, behavior, copy, and everything outside scope. Ask before replacing factual copy or adding claims. Redesign keeps product truth, content, function, native affordances, and constraints, but treats the old look as evidence and anti-reference; choose a replacement world in new-work and replace DESIGN.md. Never split the difference into polish on the discarded look.
|
||||
- **Visual authority is evidence, not a filename.** Missing DESIGN.md alone does not make a project greenfield; new-work decides whether to preserve, expand, or replace the incumbent world.
|
||||
|
||||
## Modes
|
||||
|
||||
Name the visitor's mode before designing; the page's grammar follows from it, and most ruined pages are one mode wearing another mode's grammar. **The mode belongs to the surface, not the subject**: a landing page for a dense technical tool is still Persuade, with Persuade's full permission to be striking; a docs page for a fashion house is still Read. Deciding a page can be plain because its subject is workmanlike is the same category error in reverse. The brief and the surface decide the mode; PRODUCT.md's `register` field survives only as a family hint (`brand` covers Persuade and Experience, `product` covers Operate and Read). Depth beyond the paragraphs below: [reference/new-work.md](reference/new-work.md) when inventing identity, [reference/operate.md](reference/operate.md) for substantial Operate and Read work.
|
||||
Choose the mode from the requested surface, not the product, and persist it only in that surface brief. A tool's landing page is still Persuade; a fashion house's documentation is still Read. See [new-work.md](reference/new-work.md) for new surfaces and [operate.md](reference/operate.md) for deeper Operate/Read guidance.
|
||||
|
||||
**Persuade** (the surface exists to win someone over; design IS the product). The deliverable is an impression that stops the scroll, earns the click, converts. Spans every genre; don't collapse them into one look. On new surfaces, briefs that imply imagery must ship real, verified imagery; a colored rectangle where a photo belongs reads as incomplete. New Persuade surfaces take their typeface procedure and reject list from [reference/new-work.md](reference/new-work.md).
|
||||
|
||||
**Operate** (the surface is a tool someone works in; design SERVES the task). A person getting something done: scanability and consistency outrank expressiveness. These surfaces earn trust by feeling native to their platform: system font stacks and workhorse UI faces are legitimate and often correct here (the Persuade reject list does not apply). The brand lives in the details: focus states, empty states, microcopy, one owned accent. The usage scene is part of the spec: an interface read outdoors, in motion, or at a glance must survive its real ambient light, and the theme follows the scene, not the category's habit.
|
||||
|
||||
**Read** (the surface exists to be understood; long-form, reference, guidance). The deliverable is comprehension, and comprehension is earned twice: a structure the reader can hold in their head with nothing standing between them and the answer, and a reading experience good enough to stay in, through typographic quality and whatever visual or interactive support genuinely helps the reader follow. The brand lives in type, spacing, and small accents.
|
||||
|
||||
**Experience** (the surface presents a body of work; the page IS the work). The artifact leads, the interface recedes, and the visitor meets the work itself in the first viewport at every screen size. Boldness here means trusting the work.
|
||||
- **Persuade:** win someone over; design is the product. Earn attention and action. Ship real imagery when the brief needs it; follow the committed world, not category habit.
|
||||
- **Operate:** help someone do work. Scanability, consistency, native expectations, and the real usage scene outrank expression. Brand lives in precise details.
|
||||
- **Read:** make something understood. Structure for comprehension, then make the reading experience worth staying in.
|
||||
- **Experience:** present a body of work. Let the artifact lead from the first viewport; the interface recedes.
|
||||
|
||||
## Craft floor
|
||||
|
||||
Build to this floor without announcing it. The design detector (the project hook, `node .agents/skills/impeccable/scripts/detect.mjs --json <file>`, or `audit`) verifies most of it mechanically; resolve every finding before finalizing. Fix real defects, but use context judgment rather than distorting intentional design to appease a false positive. Classify any intentional exception explicitly and use the hook system's narrowest appropriate waiver when it must persist.
|
||||
Build to this floor without announcing it.
|
||||
|
||||
- Contrast: body text ≥4.5:1 against its background (placeholders too); large text ≥3:1. 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.
|
||||
- Shadows describe real light: an offset and a soft blur. A zero-offset colored halo is decoration announcing itself.
|
||||
- Spacing has rhythm: generous separations, tight groupings; cramped padding reads as broken; the space above a heading exceeds the space below it. Verify computed spacing, not intended spacing.
|
||||
- Type: body line length 65-75ch; display clamp() max ≤6rem; letter-spacing ≥-0.04em; `text-wrap: balance` on headings; modular scale ≥1.25 between steps; light-on-dark adds 0.05-0.1 line-height. Pair faces on a contrast axis, never two similar-but-not-identical ones; one family with committed weight contrast beats a timid pair. Test headings at every breakpoint; overflow means reduce the clamp or rewrite the copy.
|
||||
- Motion is part of the build: one orchestrated moment beats scattered effects; ease-out exponential curves; reveals enhance an already-visible default (content gated on a class-triggered transition ships blank in hidden tabs and headless renderers). Responsive down to mobile and visible keyboard focus are part of the floor.
|
||||
- Ship real content (no placeholders, dead links, or fake controls) and cover the interaction states people will actually hit (hover, focus, disabled, loading, error, empty).
|
||||
- Copy is design material: name things the way the page's own people speak, make every control say what it does, and make every error say what happened and what to do next.
|
||||
- Before finishing, re-read the brief: every requirement it names must exist on the page, findable in seconds. A beautiful page missing an asked-for feature is unfinished.
|
||||
- **Contrast:** body and placeholder text ≥4.5:1; large text ≥3:1. On colored surfaces, tint secondary text from that hue or the foreground instead of using gray.
|
||||
- **Depth:** shadows describe light with offset and soft blur; zero-offset colored halos are decoration.
|
||||
- **Spacing:** tight groups, generous separation, no cramped containers; space above a heading exceeds space below. Verify computed values.
|
||||
- **Type:** body measure 65–75ch; display max 6rem and tracking floor -0.04em; balance headings; use clear scale/weight contrast; test overflow at every breakpoint.
|
||||
- **Motion:** author one coherent moment instead of scattered effects. Use exponential ease-out and an already-visible default. Premium motion is not transform/opacity alone: it may add focus, depth, masks, light, or material change through blur/filter, backdrop-filter, clip-path/masks, or shadow when smooth. Always provide reduced motion.
|
||||
- **Shipping:** real content, working controls, responsive composition, keyboard focus, and the states users hit: hover, disabled, loading, error, and empty.
|
||||
- **Copy:** use the product's language; controls name their action, errors name the problem and recovery.
|
||||
- **Coverage:** every brief requirement must exist and be findable within seconds.
|
||||
|
||||
Before finishing changed UI, follow the quality guidance supplied by `context.mjs` and hooks. Context requests a manual scan only when no automatic detector is active; never add a second detector pass.
|
||||
|
||||
Calibration for this provider:
|
||||
|
||||
- Display letter-spacing floor is -0.04em; -0.02 to -0.03em is plenty for tight grotesque display. Your default runs tighter and the letters touch.
|
||||
- An element declares its elevation once: a border or a shadow, chosen deliberately, never both as decoration. Corner radius is a brand decision made once; containers keep it modest, and full rounding belongs to small controls.
|
||||
- Illustration is real or absent; a sketched stand-in reads as filler. Backgrounds are surfaces, not decoration; texture appears only when the subject's world supplies it. Copy makes the specific claim instead of staging a concept to react to.
|
||||
- Display tracking stops at -0.04em; -0.02 to -0.03em is usually enough.
|
||||
- Declare elevation once: border or shadow, not both as decoration. Keep container radii modest; reserve pills for small controls.
|
||||
- Use real illustration or none. Treat backgrounds as surfaces, add texture only from the subject's world, and make specific claims without meta-commentary.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Category | Description | Reference |
|
||||
|---|---|---|---|
|
||||
| `craft [feature]` | Build | The standard build flow with attended checkpoints | [reference/new-work.md](reference/new-work.md) |
|
||||
| `craft [feature]` | Build | Deprecated alias for an ordinary new-work request | [reference/craft.md](reference/craft.md) |
|
||||
| `shape [feature]` | Build | Plan UX/UI before writing code | [reference/shape.md](reference/shape.md) |
|
||||
| `init` | Build | Set up project context: PRODUCT.md, DESIGN.md, live config, next steps | [reference/init.md](reference/init.md) |
|
||||
| `init` | Build | Capture durable product context in PRODUCT.md | [reference/init.md](reference/init.md) |
|
||||
| `document` | Build | Generate DESIGN.md from existing project code | [reference/document.md](reference/document.md) |
|
||||
| `extract [target]` | Build | Pull reusable tokens and components into design system | [reference/extract.md](reference/extract.md) |
|
||||
| `critique [target]` | Evaluate | UX design review with heuristic scoring | [reference/critique.md](reference/critique.md) |
|
||||
@@ -81,7 +80,14 @@ Calibration for this provider:
|
||||
| `optimize [target]` | Fix | Diagnose and fix UI performance | [reference/optimize.md](reference/optimize.md) |
|
||||
| `live` | Iterate | Visual variant mode: pick elements in the browser, generate alternatives | [reference/live.md](reference/live.md) |
|
||||
|
||||
Routing: **no argument** → read [reference/routing.md](reference/routing.md) and present the context-aware menu (never auto-run a command). **First word matches a command** (or `pin` / `unpin` / `hooks`) → load its reference (native variant on native platforms) and follow it; everything after the command name is the target. **Intent clearly maps to one command** ("fix the spacing" → `layout`, "rewrite this error" → `clarify`) → same; if two fit, ask once. **Otherwise** → general design invocation: apply Setup and this file's guidance; builds flow through the new-work gate above, whose playbook carries the direction checkpoint and the finishing pass. `teach` routes to `init`, and `craft` routes to the standard build flow with attended checkpoints. If setup diverted into `init` for a build request, finish init, refresh context, then resume.
|
||||
Routing:
|
||||
|
||||
- **No argument:** read [routing.md](reference/routing.md) and present its context-aware menu; never auto-run a command.
|
||||
- **Explicit or clearly implied command:** load its reference (native variant on native platforms) and follow it. Ask once if two commands fit.
|
||||
- **Otherwise:** treat the request as general design work. Missing PRODUCT.md routes through init; new surfaces and replacement worlds use new-work.
|
||||
- `teach` aliases `init`. `craft` is a deprecated alias for ordinary new-work and adds nothing. `shape` owns task discovery, then enters new-work only for visual-world and surface-concept decisions.
|
||||
|
||||
After init writes PRODUCT.md, resume without rerunning `context.mjs`.
|
||||
|
||||
**Pin / Unpin:** `node .agents/skills/impeccable/scripts/pin.mjs <pin|unpin> <command>` creates or removes a standalone `$<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native Android apps: Jetpack Compose, Android Views, React Native, Expo, Flutter shipping to Android hardware.
|
||||
|
||||
On native, register narrows. Material Design 3 governs structure, navigation, and interaction whatever the register; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
On native, the visitor mode narrows what expression may override. Material Design 3 governs structure, navigation, and interaction in every mode; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
|
||||
## The Android slop test
|
||||
|
||||
|
||||
@@ -1,203 +1,88 @@
|
||||
> **Additional context needed**: performance constraints.
|
||||
|
||||
Add motion that conveys state, gives feedback, and clarifies hierarchy. Cut motion that exists only for decoration. Animation fatigue is a real cost; spend the budget on the moments that need it.
|
||||
Use motion to explain state, relationship, and hierarchy, or to create one authored moment the surface has earned. Decoration without purpose is animation debt.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: motion is part of the voice; one well-rehearsed entrance beats scattered micro-interactions. The saturated AI default is fade-and-rise reveals on every scrolled section; that's a tell, not a choreography. Reserve scroll-triggered motion for moments that earn it.
|
||||
- **Persuade + Experience:** motion may carry the voice. Prefer one rehearsed focal sequence to repeated section reveals.
|
||||
- **Operate + Read:** motion serves feedback, state, and continuity. Keep routine transitions fast and do not make users wait through page-load choreography.
|
||||
- **Native (`ios` / `android` / `adaptive`):** follow the Motion section of [ios.md](ios.md) or [android.md](android.md), including the platform's Reduce Motion behavior. Do not apply the web tooling below.
|
||||
|
||||
Operate + Read: 150–250 ms on most transitions. Motion conveys state: feedback, reveal, loading, transitions between views. No page-load choreography; users are in a task and won't wait for it.
|
||||
## Find the job
|
||||
|
||||
Native (`ios` / `android` / `adaptive`): implementation follows the Motion section of [ios.md](ios.md) / [android.md](android.md) (read it first if Setup hasn't already): system transitions and OS Reduce Motion, never the web tooling below.
|
||||
Inspect the existing motion language, interaction states, target devices, and performance budget. Find only the places where motion would:
|
||||
|
||||
---
|
||||
- acknowledge an action;
|
||||
- make a state change or spatial relationship legible;
|
||||
- preserve continuity through navigation or layout change;
|
||||
- direct attention at a meaningful moment;
|
||||
- embody the selected visual world.
|
||||
|
||||
## Assess Animation Opportunities
|
||||
Ask only when a material constraint cannot be inferred. Do not animate a static area merely because it exists.
|
||||
|
||||
Analyze where motion would improve the experience:
|
||||
## Set the motion thesis
|
||||
|
||||
1. **Identify static areas**:
|
||||
- **Missing feedback**: Actions without visual acknowledgment (button clicks, form submission, etc.)
|
||||
- **Jarring transitions**: Instant state changes that feel abrupt (show/hide, page loads, route changes)
|
||||
- **Unclear relationships**: Spatial or hierarchical relationships that aren't obvious
|
||||
- **Lack of delight**: Functional but joyless interactions
|
||||
- **Missed guidance**: Opportunities to direct attention or explain behavior
|
||||
Write a short plan before implementation:
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the personality? (Playful vs serious, energetic vs calm)
|
||||
- What's the performance budget? (Mobile-first? Complex page?)
|
||||
- Who's the audience? (Motion-sensitive users? Power users who want speed?)
|
||||
- What matters most? (One hero animation vs many micro-interactions?)
|
||||
- **Focal moment:** the one sequence or interaction that deserves authorship, if any.
|
||||
- **Continuity:** the state, layout, or navigation changes that need explanation.
|
||||
- **Feedback:** the controls and outcomes that need acknowledgment.
|
||||
- **Budget:** which effects may be expensive, how often they run, and the reduced-motion equivalent.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer.
|
||||
The focal moment must come from this product and surface concept. A generic fade-and-rise, hover lift, parallax layer, or scroll reveal is not a thesis.
|
||||
|
||||
**CRITICAL**: Respect `prefers-reduced-motion`. Always provide non-animated alternatives for users who need them.
|
||||
## Choose material by meaning
|
||||
|
||||
## Plan Animation Strategy
|
||||
Transform and opacity are reliable foundations, not the entire palette. Choose properties for what the transition communicates:
|
||||
|
||||
Create a purposeful animation plan:
|
||||
- **Continuity and relationship:** shared-element motion, FLIP-style transforms, view transitions, or deliberate spatial movement.
|
||||
- **Focus and depth:** bounded blur, filter, backdrop, light, or shadow changes.
|
||||
- **Reveal and composition:** masks, clip paths, cropping, or controlled occlusion.
|
||||
- **Material and energy:** color, gradient position, texture, distortion, or shader effects when the world and runtime support them.
|
||||
- **State and feedback:** the smallest change that makes cause and result unmistakable.
|
||||
|
||||
- **Feedback layer**: Which interactions need acknowledgment?
|
||||
- **Transition layer**: Which state changes need smoothing?
|
||||
- **Entrance moment**: The ONE entrance worth rehearsing, where the mode invites it. Not every surface wants one.
|
||||
- **Delight layer**: Where can we surprise and delight?
|
||||
Do not stack techniques for spectacle. One strong material idea, carried through the focal sequence and quiet supporting states, is usually enough.
|
||||
|
||||
**IMPORTANT**: One well-orchestrated experience beats scattered animations everywhere. Focus on high-impact moments.
|
||||
Sibling stagger is appropriate when a list appears as a list. Cap the total delay, and never reinterpret every scrolled section as a staggered list.
|
||||
|
||||
## Implement Animations
|
||||
## Timing and easing
|
||||
|
||||
Add motion systematically across these categories:
|
||||
Timing should express distance and consequence:
|
||||
|
||||
### Micro-interactions
|
||||
- **Button feedback**:
|
||||
- Hover: Subtle scale (1.02-1.05), color shift, shadow increase
|
||||
- Click: Quick scale down then up (0.95 → 1), ripple effect
|
||||
- Loading: Spinner or pulse state
|
||||
- **Form interactions**:
|
||||
- Input focus: Border color transition, slight scale or glow
|
||||
- Validation: Shake on error, check mark on success, smooth color transitions
|
||||
- **Toggle switches**: Smooth slide + color transition (200-300ms)
|
||||
- **Checkboxes/radio**: Check mark animation, ripple effect
|
||||
- **Like/favorite**: Scale + rotation, particle effects, color transition
|
||||
| Duration | Typical use |
|
||||
|---|---|
|
||||
| 100–150 ms | immediate feedback |
|
||||
| 150–300 ms | routine state change |
|
||||
| 300–500 ms | layout, overlay, or view transition |
|
||||
| 500–800 ms | a deliberately authored focal entrance |
|
||||
|
||||
### State Transitions
|
||||
- **Show/hide**: Fade + slide (not instant), appropriate timing (200-300ms)
|
||||
- **Expand/collapse**: Height transition with overflow handling, icon rotation
|
||||
- **Loading states**: Skeleton screen fades, spinner animations, progress bars
|
||||
- **Success/error**: Color transitions, icon animations, gentle scale pulse
|
||||
- **Enable/disable**: Opacity transitions, cursor changes
|
||||
Exit faster than entrance. Use natural deceleration such as `cubic-bezier(0.16, 1, 0.3, 1)` for confident arrivals; do not use bounce or elastic curves by reflex. Long feedback feels like latency.
|
||||
|
||||
### Entrance Animations
|
||||
- **The one entrance moment** (where the mode invites it): a committed entrance for primary content (scale, parallax, or a creative effect)
|
||||
- **Modal/drawer entry**: Smooth slide + fade, backdrop fade, focus management
|
||||
- **List rhythm**: Sibling stagger is legitimate for cards-in-a-grid or list-items-appearing. Whole-section fade-on-scroll is not a list and is not legitimate. Cap total stagger time: 10 items at 50ms each = 500ms total. For more items, reduce per-item delay or cap the staggered count.
|
||||
## Implement to the runtime
|
||||
|
||||
Use CSS custom properties for clean stagger: `animation-delay: calc(var(--i, 0) * 50ms)` with `style="--i: 0"`, `style="--i: 1"`, etc. on each item.
|
||||
- Use CSS transitions and keyframes for declarative state and bounded sequences.
|
||||
- Use Web Animations API or the project's existing motion library for interruption, sequencing, and dynamic values.
|
||||
- Use View Transitions or shared-element techniques when continuity across states is the point.
|
||||
- Use scroll-driven motion only when the scroll relationship itself carries meaning, with a robust fallback.
|
||||
- Do not add a dependency for an effect the existing stack can express cleanly.
|
||||
|
||||
### Navigation & Flow
|
||||
- **Page transitions**: Crossfade between routes, shared element transitions
|
||||
- **Tab switching**: Slide indicator, content fade/slide
|
||||
- **Carousel/slider**: Smooth transforms, snap points, momentum
|
||||
- **Scroll effects**: Parallax layers, sticky headers with state changes, scroll progress indicators
|
||||
Keep content visible in the default state so failed scripts do not hide the page. Avoid casually animating layout-driving properties such as `width`, `height`, `top`, `left`, and margins; use FLIP, transforms, or grid techniques when appropriate. Bound blur, filter, shadow, canvas, and shader work to isolated regions. Apply `will-change` only during known animation. Measure on target viewports and devices rather than assuming transform means fast.
|
||||
|
||||
### Feedback & Guidance
|
||||
- **Hover hints**: Tooltip fade-ins, cursor changes, element highlights
|
||||
- **Drag & drop**: Lift effect (shadow + scale), drop zone highlights, smooth repositioning
|
||||
- **Copy/paste**: Brief highlight flash on paste, "copied" confirmation
|
||||
- **Focus flow**: Highlight path through form or workflow
|
||||
## Accessibility and control
|
||||
|
||||
### Delight Moments
|
||||
- **Empty states**: Subtle floating animations on illustrations
|
||||
- **Completed actions**: Confetti, check mark flourish, success celebrations
|
||||
- **Easter eggs**: Hidden interactions for discovery
|
||||
- **Contextual animation**: Weather effects, time-of-day themes, seasonal touches
|
||||
Honor `prefers-reduced-motion` with an intentional alternative. Preserve state change and hierarchy while removing travel, parallax, flashing, or prolonged sequences. Do not replace every animation globally with `0.01ms` if that destroys useful feedback. Motion must never block focus, interaction, reading, or task completion.
|
||||
|
||||
## Technical Implementation
|
||||
Respect autoplay and sound preferences. Any nonessential loop must stop when offscreen or hidden.
|
||||
|
||||
Use appropriate techniques for each animation:
|
||||
## Verify
|
||||
|
||||
### Timing & Easing
|
||||
- The focal motion is specific to the selected world and surface.
|
||||
- Every supporting animation explains feedback, state, or relationship.
|
||||
- Interruption and repeated use behave correctly.
|
||||
- Desktop, mobile, keyboard, and reduced-motion paths remain usable.
|
||||
- Expensive effects stay smooth on the target device.
|
||||
- Removing an animation would lose meaning or authored character, not merely decoration.
|
||||
|
||||
**Duration: the 100/300/500 rule.** Timing matters more than easing for "feels right":
|
||||
|
||||
| Duration | Use Case | Examples |
|
||||
|----------|----------|----------|
|
||||
| **100–150ms** | Instant feedback | Button press, toggle, color change |
|
||||
| **200–300ms** | State changes | Menu open, tooltip, hover state |
|
||||
| **300–500ms** | Layout changes | Accordion, modal, drawer |
|
||||
| **500–800ms** | Entrance animations | Page load, hero reveal |
|
||||
|
||||
**Easing curves (use these, not CSS defaults):**
|
||||
```css
|
||||
/* Recommended: natural deceleration */
|
||||
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* Smooth */
|
||||
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Slightly snappier */
|
||||
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Confident, decisive */
|
||||
|
||||
/* AVOID: feel dated and tacky */
|
||||
/* bounce: cubic-bezier(0.34, 1.56, 0.64, 1); */
|
||||
/* elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6); */
|
||||
```
|
||||
|
||||
**Exit animations are faster than entrances.** Use ~75% of enter duration.
|
||||
|
||||
### CSS Animations
|
||||
```css
|
||||
/* Prefer for simple, declarative animations */
|
||||
- transitions for state changes
|
||||
- @keyframes for complex sequences
|
||||
- transform and opacity for reliable movement
|
||||
- blur, filters, masks, clip paths, shadows, and color shifts for premium atmospheric effects when verified smooth
|
||||
```
|
||||
|
||||
### JavaScript Animation
|
||||
```javascript
|
||||
/* Use for complex, interactive animations */
|
||||
- Web Animations API for programmatic control
|
||||
- Framer Motion for React
|
||||
- GSAP for complex sequences
|
||||
```
|
||||
|
||||
### Motion Materials
|
||||
|
||||
Transform and opacity are reliable defaults, not the whole palette. Premium interfaces often need atmospheric properties. Match material to effect:
|
||||
|
||||
- **Transform / opacity**: movement, press feedback, simple reveals, list choreography
|
||||
- **Blur / filter / backdrop-filter**: focus pulls, depth, glass or lens effects, softened entrances
|
||||
- **Clip-path / masks**: wipes, reveals, editorial cropping, product-like transitions
|
||||
- **Shadow / glow / color filters**: energy, affordance, focus, warmth, active state
|
||||
- **Grid-template-rows or FLIP-style transforms**: expanding and reflowing layout without animating `height` directly
|
||||
|
||||
The hard rule isn't "transform and opacity only." It's: avoid animating layout-driving properties casually (`width`, `height`, `top`, `left`, margins), keep expensive effects bounded to small or isolated areas, and verify smoothness in-browser on target viewports.
|
||||
|
||||
### Performance
|
||||
- **Layout safety**: Avoid casual animation of layout-driving properties (`width`, `height`, `top`, `left`, margins)
|
||||
- **will-change**: Add sparingly for known expensive animations only (e.g. on `:hover` or an `.animating` class), never preemptively across the whole page
|
||||
- **Scroll triggers**: Use Intersection Observer instead of scroll event listeners; unobserve after the animation fires once
|
||||
- **Bound expensive effects**: Keep blur/filter/shadow areas small or isolated, use `contain` where appropriate
|
||||
- **Monitor FPS**: Ensure 60fps on target devices
|
||||
|
||||
### Perceived Performance
|
||||
|
||||
Nobody cares how fast your site *is*, only how fast it feels. The 80ms threshold: anything under ~80ms feels instant because our brains buffer sensory input for that long to synchronize perception. Target this for micro-interactions.
|
||||
|
||||
- **Preemptive start**: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening.
|
||||
- **Early completion**: Show content progressively, don't wait for everything (progressive images, streaming HTML, skeleton fade-ins).
|
||||
- **Optimistic UI**: Update the interface immediately, handle failures gracefully. Use for low-stakes actions (likes, follows). Avoid for payments or destructive operations.
|
||||
- **Easing affects perceived duration**: Ease-in (accelerating toward completion) makes tasks feel shorter because the peak-end effect weights final moments heavily. Ease-out feels satisfying for entrances.
|
||||
- **Caution**: Too-fast responses can decrease perceived value for complex operations (search, analysis). Sometimes a brief delay signals "real work" is happening.
|
||||
|
||||
### Accessibility
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
- Use bounce or elastic easing curves; they feel dated and draw attention to the animation itself
|
||||
- Animate layout properties casually (`width`, `height`, `top`, `left`, margins) when transform, FLIP, or grid-based techniques would work
|
||||
- Use durations over 500ms for feedback (it feels laggy)
|
||||
- Animate without purpose (every animation needs a reason)
|
||||
- Ignore `prefers-reduced-motion` (this is an accessibility violation)
|
||||
- Animate everything (animation fatigue makes interfaces feel exhausting)
|
||||
- Block interaction during animations unless intentional
|
||||
|
||||
## Verify Quality
|
||||
|
||||
Test animations thoroughly:
|
||||
|
||||
- **Smooth at 60fps**: No jank on target devices
|
||||
- **Feels natural**: Easing curves feel organic, not robotic
|
||||
- **Appropriate timing**: Not too fast (jarring) or too slow (laggy)
|
||||
- **Reduced motion works**: Animations disabled or simplified appropriately
|
||||
- **Doesn't block**: Users can interact during/after animations
|
||||
- **Adds value**: Makes interface clearer or more delightful
|
||||
|
||||
When the motion clarifies state instead of decorating it, hand off to `$impeccable polish` for the final pass.
|
||||
When motion earns its place, hand off to `$impeccable polish` for the final pass.
|
||||
|
||||
@@ -52,11 +52,11 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
|
||||
**Score 0-4**: 0=Desktop-only (breaks on mobile), 1=Major issues (some breakpoints, many failures), 2=Partial (works on mobile, rough edges), 3=Good (responsive, minor touch target or overflow issues), 4=Excellent (fluid, all viewports, proper touch targets)
|
||||
|
||||
### 5. Anti-Patterns (CRITICAL)
|
||||
### 5. Implementation Integrity (CRITICAL)
|
||||
|
||||
Check against ALL the **DON'T** guidelines from the parent impeccable skill (already loaded in this context). Look for AI slop tells (AI color palette, gradient text, glassmorphism, hero metrics, card grids, generic fonts) and general design anti-patterns (gray on color, nested cards, bounce easing, redundant copy).
|
||||
Run the bundled detector and verify each finding in context. Look for repeated implementation shortcuts, design-system drift, misleading or decorative content, and structure that is interchangeable with an unrelated product. Keep deterministic findings separate from visual judgment and call out false positives.
|
||||
|
||||
**Score 0-4**: 0=AI slop gallery (5+ tells), 1=Heavy AI aesthetic (3-4 tells), 2=Some tells (1-2 noticeable), 3=Mostly clean (subtle issues only), 4=No AI tells (distinctive, intentional design)
|
||||
**Score 0-4**: 0=systemic drift, 1=major repeated failures, 2=several verified issues, 3=minor isolated issues, 4=coherent and intentional
|
||||
|
||||
## Generate Report
|
||||
|
||||
@@ -68,13 +68,13 @@ Check against ALL the **DON'T** guidelines from the parent impeccable skill (alr
|
||||
| 2 | Performance | ? | |
|
||||
| 3 | Responsive Design | ? | |
|
||||
| 4 | Theming | ? | |
|
||||
| 5 | Anti-Patterns | ? | |
|
||||
| 5 | Implementation Integrity | ? | |
|
||||
| **Total** | | **??/20** | **[Rating band]** |
|
||||
|
||||
**Rating bands**: 18-20 Excellent (minor polish), 14-17 Good (address weak dimensions), 10-13 Acceptable (significant work needed), 6-9 Poor (major overhaul), 0-5 Critical (fundamental issues)
|
||||
|
||||
### Anti-Patterns Verdict
|
||||
**Start here.** Pass/fail: Does this look AI-generated? List specific tells. Be brutally honest.
|
||||
### Implementation Integrity Verdict
|
||||
**Start here.** Pass/fail: does the implementation express a coherent product-specific system? Cite verified evidence and detector findings.
|
||||
|
||||
### Executive Summary
|
||||
- Audit Health Score: **??/20** ([rating band])
|
||||
@@ -93,7 +93,7 @@ Tag every issue with **P0-P3 severity**:
|
||||
For each issue, document:
|
||||
- **[P?] Issue name**
|
||||
- **Location**: Component, file, line
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Anti-Pattern
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Implementation Integrity
|
||||
- **Impact**: How it affects users
|
||||
- **WCAG/Standard**: Which standard it violates (if applicable)
|
||||
- **Recommendation**: How to fix it
|
||||
@@ -132,4 +132,3 @@ After presenting the summary, tell the user:
|
||||
- Skip positive findings (celebrate what works)
|
||||
- Forget to prioritize (everything can't be P0)
|
||||
- Report false positives without verification
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
- **Hard-coded colors**: raw hex instead of semantic system colors (iOS) / Material color roles (Android) / design tokens
|
||||
- **Broken dark appearance**: missing dark variants, poor contrast in dark, quick inverts
|
||||
- **Dynamic Color** (Android 12+): no static fallback scheme, or ignored where it fits
|
||||
- **Off-platform materials**: hand-rolled blur/glassmorphism instead of system materials or tonal elevation
|
||||
- **Off-platform materials**: hand-rolled visual materials where system materials or tonal elevation are expected
|
||||
|
||||
**Score 0-4**: 0=Hard-coded everything, 1=Minimal tokens, 2=Partial (tokens exist, inconsistently used), 3=Good (minor hard-coded values), 4=Excellent (semantic throughout, both appearances first-class)
|
||||
|
||||
@@ -48,7 +48,7 @@ Score against the loaded platform reference(s), including their slop tests. **Ch
|
||||
- **Off-platform navigation**: custom global nav, overloaded tab bars, iOS patterns on Android or vice versa
|
||||
- **Web-shaped controls**: HTML-style buttons, custom toggles, hover-dependent affordances
|
||||
- **Icon drift**: mixed icon sets instead of SF Symbols / Material Symbols
|
||||
- **AI tells**: the shared absolute bans still apply (AI palette, gradient text, hero metrics)
|
||||
- **System drift**: repeated shortcuts or decorative patterns that conflict with the product, platform, or established design system
|
||||
|
||||
**Score 0-4**: 0=Web port (nothing native), 1=Heavy violations (3-4 kinds), 2=Some (1-2 noticeable), 3=Mostly conformant (subtle issues), 4=Fully native (a fluent user trusts every screen)
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
## Why it reads flat
|
||||
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing, the specificity of the copy. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
|
||||
## The amplification
|
||||
|
||||
- **Amplify what the system already owns.** Reuse its motif and its type scale at full strength, turned up for this section rather than invented for it. The bolder version should look more like the same brand, not less.
|
||||
- **Let the content carry the weight.** Flat copy makes a flat design, and no amount of size fixes a generic claim. Make every word specific enough to earn its place, and let the section's real evidence do the work that a decorative addition would otherwise fake.
|
||||
- **Keep content true.** Existing claims are part of the scope: preserve them unless the user supplies replacements. If real evidence is essential to the direction but absent, ask for it.
|
||||
- **Commit, then clarify.** Half-measures read as noise. Make the one decisive move completely, then quiet everything around it so the move is legible. If every element got louder, the section got flatter.
|
||||
- **Give it its own rhythm.** The target should read as a peak in the scroll, a shift in density or pace from what surrounds it, not simply more of the same.
|
||||
|
||||
|
||||
@@ -1,288 +1,94 @@
|
||||
> **Additional context needed**: audience technical level and users' mental state in context.
|
||||
> **Additional context needed**: audience knowledge and emotional state.
|
||||
|
||||
Find the unclear, confusing, or poorly written interface text and rewrite it. Vague copy creates support tickets and abandonment; specific copy gets users through the task.
|
||||
Rewrite unclear interface text so users understand what happened, what matters, and what to do next. Preserve factual meaning, product terminology, and brand voice.
|
||||
|
||||
## Audit the language
|
||||
|
||||
---
|
||||
Read the entire interaction path, not isolated strings. Identify:
|
||||
|
||||
## Assess Current Copy
|
||||
- ambiguous nouns, verbs, and actions;
|
||||
- internal jargon or assumed knowledge;
|
||||
- vague labels, outcomes, and system states;
|
||||
- missing consequences, recovery, or timing;
|
||||
- inconsistent terminology and capitalization;
|
||||
- redundant headings, intros, helper text, and confirmations;
|
||||
- text that breaks at realistic widths or in translation;
|
||||
- tone that ignores stress, risk, success, or urgency.
|
||||
|
||||
Identify what makes the text unclear or ineffective:
|
||||
Infer audience and task from product context and surrounding UI. Ask before changing factual claims, legal meaning, or a term that may be domain-specific.
|
||||
|
||||
1. **Find clarity problems**:
|
||||
- **Jargon**: Technical terms users won't understand
|
||||
- **Ambiguity**: Multiple interpretations possible
|
||||
- **Passive voice**: "Your file has been uploaded" vs "We uploaded your file"
|
||||
- **Length**: Too wordy or too terse
|
||||
- **Assumptions**: Assuming user knowledge they don't have
|
||||
- **Missing context**: Users don't know what to do or why
|
||||
- **Tone mismatch**: Too formal, too casual, or inappropriate for situation
|
||||
## Set the message hierarchy
|
||||
|
||||
2. **Understand the context**:
|
||||
- Who's the audience? (Technical? General? First-time users?)
|
||||
- What's the user's mental state? (Stressed during error? Confident during success?)
|
||||
- What's the action? (What do we want users to do?)
|
||||
- What's the constraint? (Character limits? Space limitations?)
|
||||
For each state, decide:
|
||||
|
||||
**CRITICAL**: Clear copy helps users succeed. Unclear copy creates frustration, errors, and support tickets.
|
||||
1. the one fact the user needs now;
|
||||
2. the action available next;
|
||||
3. supporting context that changes the decision;
|
||||
4. the appropriate tone for this moment.
|
||||
|
||||
## Plan Copy Improvements
|
||||
Say each idea once. If the heading already explains the state, the introduction should add new information or disappear.
|
||||
|
||||
Create a strategy for clearer communication:
|
||||
## Rewrite by function
|
||||
|
||||
- **Primary message**: What's the ONE thing users need to know?
|
||||
- **Action needed**: What should users do next (if anything)?
|
||||
- **Tone**: How should this feel? (Helpful? Apologetic? Encouraging?)
|
||||
- **Constraints**: Length limits, brand voice, localization considerations
|
||||
### Actions and navigation
|
||||
|
||||
**IMPORTANT**: Good UX writing is invisible. Users should understand immediately without noticing the words.
|
||||
Use a specific verb and object when the outcome is not already obvious. Labels should describe what will happen, not the gesture used to trigger it. Keep the same noun and verb for the same concept throughout the product.
|
||||
|
||||
## Improve Copy Systematically
|
||||
For destructive actions, name the object and consequence. Prefer undo over confirmation when recovery is safe. When confirmation is necessary, name the action on both the message and button instead of using `Yes`, `No`, `OK`, or `Submit`.
|
||||
|
||||
Refine text across these common areas:
|
||||
### Forms
|
||||
|
||||
### Error Messages
|
||||
**Bad**: "Error 403: Forbidden"
|
||||
**Good**: "You don't have permission to view this page. Contact your admin for access."
|
||||
Use persistent labels; placeholders are examples, not labels. Put format and eligibility requirements before submission. Explain why information is requested only when it is not obvious. Required and optional treatment should be consistent.
|
||||
|
||||
**Bad**: "Invalid input"
|
||||
**Good**: "Email addresses need an @ symbol. Try: name@example.com"
|
||||
Validation says what needs attention and how to correct it without blaming the user. Keep related instructions near the field and announce errors accessibly.
|
||||
|
||||
**Principles**:
|
||||
- Explain what went wrong in plain language
|
||||
- Suggest how to fix it
|
||||
- Don't blame the user
|
||||
- Include examples when helpful
|
||||
- Link to help/support if applicable
|
||||
|
||||
### Form Labels & Instructions
|
||||
**Bad**: "DOB (MM/DD/YYYY)"
|
||||
**Good**: "Date of birth" (with placeholder showing format)
|
||||
|
||||
**Bad**: "Enter value here"
|
||||
**Good**: "Your email address" or "Company name"
|
||||
|
||||
**Principles**:
|
||||
- Use clear, specific labels (not generic placeholders)
|
||||
- Show format expectations with examples
|
||||
- Explain why you're asking (when not obvious)
|
||||
- Put instructions before the field, not after
|
||||
- Keep required field indicators clear
|
||||
|
||||
### Button & CTA Text
|
||||
**Bad**: "Click here" | "Submit" | "OK"
|
||||
**Good**: "Create account" | "Save changes" | "Got it, thanks"
|
||||
### Errors and permissions
|
||||
|
||||
**Principles**:
|
||||
- Describe the action specifically
|
||||
- Use active voice (verb + noun)
|
||||
- Match user's mental model
|
||||
- Be specific ("Save" is better than "OK")
|
||||
An actionable error answers:
|
||||
|
||||
### Help Text & Tooltips
|
||||
**Bad**: "This is the username field"
|
||||
**Good**: "Choose a username. You can change this later in Settings."
|
||||
1. what failed;
|
||||
2. why, when known and useful;
|
||||
3. how to recover or what alternative remains.
|
||||
|
||||
**Principles**:
|
||||
- Add value (don't just repeat the label)
|
||||
- Answer the implicit question ("What is this?" or "Why do you need this?")
|
||||
- Keep it brief but complete
|
||||
- Link to detailed docs if needed
|
||||
Do not expose internal codes as the primary message. Do not promise a cause or resolution the system cannot know. Treat privacy, payment, deletion, access loss, and blocked work seriously; warmth is welcome, jokes are not.
|
||||
|
||||
### Empty States
|
||||
**Bad**: "No items"
|
||||
**Good**: "No projects yet. Create your first project to get started."
|
||||
### Loading, empty, and success states
|
||||
|
||||
**Principles**:
|
||||
- Explain why it's empty (if not obvious)
|
||||
- Show next action clearly
|
||||
- Make it welcoming, not dead-end
|
||||
Loading text names the real operation and sets an honest expectation when the wait is meaningful. Show determinate progress when available; never invent progress.
|
||||
|
||||
### Success Messages
|
||||
**Bad**: "Success"
|
||||
**Good**: "Settings saved! Your changes will take effect immediately."
|
||||
An empty state distinguishes first use, no results, filters, permissions, and failure. Explain the state and provide the next useful action.
|
||||
|
||||
**Principles**:
|
||||
- Confirm what happened
|
||||
- Explain what happens next (if relevant)
|
||||
- Be brief but complete
|
||||
- Match the user's emotional moment (celebrate big wins)
|
||||
|
||||
### Loading States
|
||||
**Bad**: "Loading..." (for 30+ seconds)
|
||||
**Good**: "Analyzing your data... this usually takes 30-60 seconds"
|
||||
|
||||
**Principles**:
|
||||
- Set expectations (how long?)
|
||||
- Explain what's happening (when it's not obvious)
|
||||
- Show progress when possible
|
||||
- Offer escape hatch if appropriate ("Cancel")
|
||||
Success confirms the completed outcome and mentions the next consequence only when it changes what the user should do. Routine success should be brief.
|
||||
|
||||
### Confirmation Dialogs
|
||||
**Bad**: "Are you sure?"
|
||||
**Good**: "Delete 'Project Alpha'? This can't be undone."
|
||||
### Help and instructional text
|
||||
|
||||
**Principles**:
|
||||
- State the specific action
|
||||
- Explain consequences (especially for destructive actions)
|
||||
- Use clear button labels ("Delete project" not "Yes")
|
||||
- Don't overuse confirmations (only for risky actions)
|
||||
Helper text answers an implicit question instead of restating the control. Use progressive disclosure for uncommon detail. Link text must make sense out of context; icon-only controls need accessible names.
|
||||
|
||||
### Navigation & Wayfinding
|
||||
**Bad**: Generic labels like "Items" | "Things" | "Stuff"
|
||||
**Good**: Specific labels like "Your projects" | "Team members" | "Settings"
|
||||
## Voice, accessibility, and localization
|
||||
|
||||
**Principles**:
|
||||
- Be specific and descriptive
|
||||
- Use language users understand (not internal jargon)
|
||||
- Make hierarchy clear
|
||||
- Consider information scent (breadcrumbs, current location)
|
||||
Voice stays consistent; tone adapts to the moment. Use plain language without flattening terminology the audience genuinely knows.
|
||||
|
||||
## Apply Clarity Principles
|
||||
- Write complete translatable messages rather than concatenated fragments.
|
||||
- Keep variables and numbers structured so translators can reorder them.
|
||||
- Allow expansion instead of abbreviating prematurely.
|
||||
- Make alt text convey the image's information; use empty alt for decoration.
|
||||
- Keep screen-reader names aligned with visible labels and outcomes.
|
||||
- Do not rely on punctuation, color, or iconography to carry the message alone.
|
||||
|
||||
Every piece of copy should follow these rules:
|
||||
Maintain a short terminology glossary when inconsistency spans the product. Do not vary words for literary effect in an interface.
|
||||
|
||||
1. **Be specific**: "Enter email" not "Enter value"
|
||||
2. **Be concise**: Cut unnecessary words (but don't sacrifice clarity)
|
||||
3. **Be active**: "Save changes" not "Changes will be saved"
|
||||
4. **Be human**: "Oops, something went wrong" not "System error encountered"
|
||||
5. **Tell users what to do**, not just what happened
|
||||
6. **Be consistent**: Use same terms throughout (don't vary for variety)
|
||||
## Verify
|
||||
|
||||
**NEVER**:
|
||||
- Use jargon without explanation
|
||||
- Blame users ("You made an error" → "This field is required")
|
||||
- Be vague ("Something went wrong" without explanation)
|
||||
- Use passive voice unnecessarily
|
||||
- Write overly long explanations (be concise)
|
||||
- Use humor for errors (be empathetic instead)
|
||||
- Assume technical knowledge
|
||||
- Vary terminology (pick one term and stick with it)
|
||||
- Repeat information (headers restating intros, redundant explanations)
|
||||
- Use placeholders as the only labels (they disappear when users type)
|
||||
Read the flow in context and test:
|
||||
|
||||
## Verify Improvements
|
||||
- comprehension without hidden product knowledge;
|
||||
- actionability at errors, empty states, and decision points;
|
||||
- factual accuracy and consistent terminology;
|
||||
- scanability at target widths and 200% zoom;
|
||||
- long names, localization expansion, pluralization, and dynamic values;
|
||||
- accessible names and announced state changes;
|
||||
- tone appropriate to consequence and emotional context.
|
||||
|
||||
Test that copy improvements work:
|
||||
The final copy is as short as it can be without removing meaning or recovery.
|
||||
|
||||
- **Comprehension**: Can users understand without context?
|
||||
- **Actionability**: Do users know what to do next?
|
||||
- **Brevity**: Is it as short as possible while remaining clear?
|
||||
- **Consistency**: Does it match terminology elsewhere?
|
||||
- **Tone**: Is it appropriate for the situation?
|
||||
|
||||
When the copy reads cleanly, hand off to `$impeccable polish` for the final pass.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `ux-writing.md` and live inline now so the clarify flow has its deep UX-writing reference in one place.
|
||||
|
||||
### UX Writing
|
||||
|
||||
#### The Button Label Problem
|
||||
|
||||
**Never use "OK", "Submit", or "Yes/No".** These are lazy and ambiguous. Use specific verb + object patterns:
|
||||
|
||||
| Bad | Good | Why |
|
||||
|-----|------|-----|
|
||||
| OK | Save changes | Says what will happen |
|
||||
| Submit | Create account | Outcome-focused |
|
||||
| Yes | Delete message | Confirms the action |
|
||||
| Cancel | Keep editing | Clarifies what "cancel" means |
|
||||
| Click here | Download PDF | Describes the destination |
|
||||
|
||||
**For destructive actions**, name the destruction:
|
||||
- "Delete" not "Remove" (delete is permanent, remove implies recoverable)
|
||||
- "Delete 5 items" not "Delete selected" (show the count)
|
||||
|
||||
#### Error Messages: The Formula
|
||||
|
||||
Every error message should answer: (1) What happened? (2) Why? (3) How to fix it? Example: "Email address isn't valid. Please include an @ symbol." not "Invalid input".
|
||||
|
||||
##### Error Message Templates
|
||||
|
||||
| Situation | Template |
|
||||
|-----------|----------|
|
||||
| **Format error** | "[Field] needs to be [format]. Example: [example]" |
|
||||
| **Missing required** | "Please enter [what's missing]" |
|
||||
| **Permission denied** | "You don't have access to [thing]. [What to do instead]" |
|
||||
| **Network error** | "We couldn't reach [thing]. Check your connection and [action]." |
|
||||
| **Server error** | "Something went wrong on our end. We're looking into it. [Alternative action]" |
|
||||
|
||||
##### Don't Blame the User
|
||||
|
||||
Reframe errors: "Please enter a date in MM/DD/YYYY format" not "You entered an invalid date".
|
||||
|
||||
#### Empty States Are Opportunities
|
||||
|
||||
Empty states are onboarding moments: (1) Acknowledge briefly, (2) Explain the value of filling it, (3) Provide a clear action. "No projects yet. Create your first one to get started." not just "No items".
|
||||
|
||||
#### Voice vs Tone
|
||||
|
||||
**Voice** is your brand's personality, consistent everywhere.
|
||||
**Tone** adapts to the moment.
|
||||
|
||||
| Moment | Tone Shift |
|
||||
|--------|------------|
|
||||
| Success | Celebratory, brief: "Done! Your changes are live." |
|
||||
| Error | Empathetic, helpful: "That didn't work. Here's what to try..." |
|
||||
| Loading | Reassuring: "Saving your work..." |
|
||||
| Destructive confirm | Serious, clear: "Delete this project? This can't be undone." |
|
||||
|
||||
**Never use humor for errors.** Users are already frustrated. Be helpful, not cute.
|
||||
|
||||
#### Writing for Accessibility
|
||||
|
||||
**Link text** must have standalone meaning: "View pricing plans" not "Click here". **Alt text** describes information, not the image: "Revenue increased 40% in Q4" not "Chart". Use `alt=""` for decorative images. **Icon buttons** need `aria-label` for screen reader context.
|
||||
|
||||
#### Writing for Translation
|
||||
|
||||
##### Plan for Expansion
|
||||
|
||||
German text is ~30% longer than English. Allocate space:
|
||||
|
||||
| Language | Expansion |
|
||||
|----------|-----------|
|
||||
| German | +30% |
|
||||
| French | +20% |
|
||||
| Finnish | +30-40% |
|
||||
| Chinese | -30% (fewer chars, but same width) |
|
||||
|
||||
##### Translation-Friendly Patterns
|
||||
|
||||
Keep numbers separate ("New messages: 3" not "You have 3 new messages"). Use full sentences as single strings (word order varies by language). Avoid abbreviations ("5 minutes ago" not "5 mins ago"). Give translators context about where strings appear.
|
||||
|
||||
#### Consistency: The Terminology Problem
|
||||
|
||||
Pick one term and stick with it:
|
||||
|
||||
| Inconsistent | Consistent |
|
||||
|--------------|------------|
|
||||
| Delete / Remove / Trash | Delete |
|
||||
| Settings / Preferences / Options | Settings |
|
||||
| Sign in / Log in / Enter | Sign in |
|
||||
| Create / Add / New | Create |
|
||||
|
||||
Build a terminology glossary and enforce it. Variety creates confusion.
|
||||
|
||||
#### Avoid Redundant Copy
|
||||
|
||||
If the heading explains it, the intro is redundant. If the button is clear, don't explain it again. Say it once, say it well.
|
||||
|
||||
#### Loading States
|
||||
|
||||
Be specific: "Saving your draft..." not "Loading...". For long waits, set expectations ("This usually takes 30 seconds") or show progress.
|
||||
|
||||
#### Confirmation Dialogs: Use Sparingly
|
||||
|
||||
Most confirmation dialogs are design failures; consider undo instead. When you must confirm: name the action, explain consequences, use specific button labels ("Delete project" / "Keep project", not "Yes" / "No").
|
||||
|
||||
#### Form Instructions
|
||||
|
||||
Show format with placeholders, not instructions. For non-obvious fields, explain why you're asking.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Jargon without explanation. Blaming users ("You made an error" → "This field is required"). Vague errors ("Something went wrong"). Varying terminology for variety. Humor for errors.
|
||||
When the language reads cleanly, hand off to `$impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,105 +1,38 @@
|
||||
# Codex: Visual Direction & Asset Production
|
||||
# Codex: Surface Probes & Asset Production
|
||||
|
||||
This file is loaded by `$impeccable craft` when the harness has native image generation (currently Codex via `image_gen`). Other harnesses skip it. It covers the two craft steps that depend on real image generation: landing the visual direction, and producing the raster assets the implementation will compose.
|
||||
Load this from [new-work.md](new-work.md) only when the harness has native image generation and a substantial, high-fidelity surface would benefit from seeing the shortlisted concept before code. PRODUCT.md and DESIGN.md are preconditions. New-work has already resolved the visual world; this file must not reopen it.
|
||||
|
||||
Read this *before* generating any images. The order matters, and the per-step user pauses are what keep generated imagery from drifting away from the brief.
|
||||
The purpose of a probe is to test composition, narrative, hierarchy, density, focal moment, signature use, and image requirements. It is not a second identity workshop. Keep DESIGN.md's palette, typography direction, material language, component character, imagery stance, and motion grammar fixed.
|
||||
|
||||
### Four stop points before code
|
||||
## Generate the smallest useful probe set
|
||||
|
||||
Steps A through D each end with the user. Do not advance past any of them on your own read of the situation.
|
||||
Generate one to three high-fidelity north-star comps using the native image-generation capability. Base them on the real content and the surface concepts already developed with the user.
|
||||
|
||||
1. **STOP after Step A questions.** Wait for answers.
|
||||
2. **STOP after Step B palette generation.** Wait for "confirm palette."
|
||||
3. **STOP after Step C mocks.** Wait for direction approval or delegation.
|
||||
4. **Only after Step D approves a direction** do you return to the build (new-work.md's plan, then code).
|
||||
- When the user shortlisted multiple concepts, show one clear expression of each.
|
||||
- When one concept is already selected, vary only the structural uncertainty that the image can resolve: topology, sequence, density, hierarchy, focal composition, or interaction framing.
|
||||
- Show enough beyond the opening moment to prove the concept can govern the whole requested surface.
|
||||
- Do not generate a palette artifact, ask new atmosphere questions, introduce a different type voice, or invent a new motif. If the committed world cannot support the concept, return to the concept shortlist rather than changing the world.
|
||||
|
||||
Prior shape approval does **not** satisfy any of these. Shape's "confirm or override" advances you into Step A; it is not a substitute for it.
|
||||
Treat each comp as a direction test, not a screenshot specification. Core UI text, responsive behavior, accessibility, semantics, and interaction states remain implementation responsibilities.
|
||||
|
||||
## Step A: Explore Directions with the User
|
||||
## One approval point
|
||||
|
||||
Before generating anything, run a brief direction conversation grounded in the shape brief.
|
||||
Show the probes together and ask what should carry forward, what feels false to the world, and whether the selected surface concept should be approved, combined, revised, or rejected. Then stop and wait. A structured simulated user counts as attended and receives the same question.
|
||||
|
||||
**Step A is required even when shape just produced a confirmed brief.** The shape questions and Step A questions cover different ground: shape pins purpose, content, scope; Step A pins palette, atmosphere, and named visual references for the comps you're about to generate. The only time you can skip Step A is when the user has already answered these exact palette/atmosphere/reference questions in the same session.
|
||||
Do not begin code until the user approves a direction or explicitly delegates the choice. If they delegate, choose using the task brief, PRODUCT.md, and DESIGN.md, and state the evidence. Approval refines the task concept; it does not modify DESIGN.md.
|
||||
|
||||
Ask **2-3 targeted questions** about visual lane, color strategy, atmosphere, and named anchor references. Don't enumerate generic menus; tie each question to the shape brief's answers. Example shape-grounded questions:
|
||||
After approval, summarize the composition and the parts of the comp that must not be literalized. Return to new-work.md and write the direction contract from the approved surface concept before code.
|
||||
|
||||
- "Brief says 'specimen-page restraint.' Are we closer to a quiet typographic page or a wider editorial spread with hero imagery?"
|
||||
- "Palette strategy from shape was 'Committed.' Which one color carries the surface (a brand-driven pick rather than a default warm-or-cool framing)? (And no, the answer isn't a cream/sand body bg; that's the saturated AI default.)"
|
||||
## Inventory implementation fidelity
|
||||
|
||||
**STOP and wait for answers.** These pin the palette before any pixel gets generated. Do not proceed to Step B until the user has responded.
|
||||
Before building, inventory the approved comp's major visible ingredients and choose an implementation medium for each: semantic HTML/CSS/SVG, existing project asset, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
## Step B: Generate the Brand Palette First
|
||||
Pay special attention to the dominant composition, signature use, image-native content, second-fold system, and any interaction the still image only implies. If the concept depends on a photograph, architectural scene, product object, portrait, or other raster-native material, do not silently replace it with generic CSS scenery.
|
||||
|
||||
Generate **one** palette artifact before any mocks. This is a small, focused image: typography pairing on the chosen background, primary + accent color swatches, one signature ornament or motif. Single image, single pass.
|
||||
Treat the comp as a north star, not something to trace. Do not rasterize core UI text or controls. Do not substitute a different visual driver after approval without asking.
|
||||
|
||||
Why palette first: mocks generated against a vague color sense produce noise that drowns out the structural decisions. A confirmed palette is the first concrete contract for everything downstream.
|
||||
## Produce only the assets the build needs
|
||||
|
||||
Show the palette to the user. Ask one question: "This is the palette I'm locking in for the mocks. Confirm, or call out what to shift?"
|
||||
When clean raster ingredients are required and a scoped subagent is available and authorized, use `impeccable_asset_producer`. Give it the approved comp, output paths, required dimensions and formats, transparency needs, crop notes, and what must remain semantic code. Otherwise produce the minimum required assets with the native image-generation capability in the current thread.
|
||||
|
||||
**STOP and wait for confirmation.** Do not generate mocks against an unconfirmed palette. "Probably good enough" is the wrong call here; the palette is the contract for everything downstream.
|
||||
|
||||
## Step C: Generate 1-3 Visual Mocks Against the Palette
|
||||
|
||||
Once the palette is confirmed, generate **1 to 3** high-fidelity north-star comps. Each mock must use the confirmed palette and typography. Mocks differ in *structural* direction (hierarchy, topology, density, composition), not in color or motif.
|
||||
|
||||
- Brand work: push visual identity, composition, mood, and signature motifs.
|
||||
- Product work: push hierarchy, topology, density, tone, grounded in realistic product structure.
|
||||
- Landing pages and long-form brand surfaces: show enough of the second fold to establish the system beyond the hero.
|
||||
|
||||
Use the `image_gen` tool directly (or via the imagegen skill when available). Don't ask the user to install anything.
|
||||
|
||||
## Step D: Approval Loop
|
||||
|
||||
Show the comps. Ask what carries forward. Iterate until **one direction is approved** or the user explicitly delegates.
|
||||
|
||||
**STOP and wait for the approval or the delegation.** Do not begin Step E or return to the build until a single direction is named. If the user delegates, pick the strongest direction and explain it from the brief, not personal taste.
|
||||
|
||||
Before moving to assets, summarize what to carry into code and what *not* to literalize from the mock. This is the handoff between visual exploration and semantic implementation.
|
||||
|
||||
## Step E: Mock Fidelity Inventory
|
||||
|
||||
Inventory the approved mock's major visible ingredients. For each, decide implementation: semantic HTML/CSS/SVG, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
Common ingredients to inventory:
|
||||
|
||||
- Hero silhouette and dominant composition
|
||||
- Signature motifs (planets, devices, portraits, charts, route lines, insets, badges, etc.)
|
||||
- Nav and primary-action treatment (when the surface has one)
|
||||
- Section sequence, especially the second fold
|
||||
- Image-native content the concept depends on
|
||||
- Typography, density, color/material treatment, motion cues
|
||||
|
||||
Treat the mock as a north star, not a screenshot to trace. Don't rasterize core UI text. But if the live result lacks the mock's major ingredients, the implementation is wrong.
|
||||
|
||||
If a photographic, architectural, product, or place-led mock becomes generic CSS scenery, decorative diagrams, bullets, or copy, stop and fix it. That's a broken implementation, not a harmless interpretation.
|
||||
|
||||
Don't substitute a different hero composition or visual driver post-approval without user sign-off.
|
||||
|
||||
## Step F: Asset Slicing via the Asset Producer
|
||||
|
||||
Raster ingredients identified in Step E need clean production assets. Use the bundled `impeccable_asset_producer` subagent rather than producing inline.
|
||||
|
||||
Spawn it as a scoped subagent. If you do not have explicit permission to use agents, stop and ask:
|
||||
|
||||
```text
|
||||
Asset production will work better as a scoped subagent job. Should I spawn the Impeccable asset producer subagent for this step?
|
||||
```
|
||||
|
||||
Pass to the agent:
|
||||
|
||||
- Approved mock path or screenshot reference
|
||||
- Crop paths or a contact sheet with crop ids
|
||||
- Output directory
|
||||
- Required dimensions, format, transparency needs
|
||||
- Avoid list
|
||||
- Notes on what should remain semantic HTML/CSS/SVG instead of raster
|
||||
|
||||
Attach image generation capability to the spawned agent when the harness supports it. Do **not** load image-generation reference material into the parent thread.
|
||||
|
||||
Inline asset production is allowed only if the user declines subagents, the harness cannot spawn the authorized agent, or the user explicitly asks for single-thread mode.
|
||||
|
||||
Prefer HTML/CSS/SVG/canvas when they can credibly reproduce an ingredient; reach for real, generated, or stock imagery when the mock or subject matter calls for actual visual content.
|
||||
|
||||
## After This File
|
||||
|
||||
Once Steps A through F are complete, return to the build: implement per new-work.md and SKILL.md's craft floor. The implementation builds against the confirmed palette, approved mock, and the assets the producer wrote.
|
||||
Return to [new-work.md](new-work.md) for the direction contract, implementation, and finishing pass.
|
||||
|
||||
@@ -1,257 +1,86 @@
|
||||
> **Additional context needed**: existing brand colors.
|
||||
|
||||
Replace timid grayscale or single-accent designs with a strategic palette: pick a color strategy, choose a hue family that fits the brand, then apply color with intent. More color ≠ better. Strategic color beats rainbow vomit.
|
||||
Introduce color as hierarchy, meaning, and atmosphere. Preserve confirmed brand and semantic conventions; do not replace a visual world under the guise of colorizing it.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: palette IS voice. Pick a color strategy first per SKILL.md (Restrained / Committed / Full palette / Drenched) and follow its dosage. Committed, Full palette, and Drenched deliberately exceed the ≤10% rule; that rule is Restrained only. Unexpected combinations are allowed; a dominant color can own the page when the chosen strategy calls for it.
|
||||
- **Persuade + Experience:** color may carry the voice and own large regions when the selected world calls for it.
|
||||
- **Operate + Read:** color primarily encodes action, selection, status, wayfinding, and reading hierarchy. Rarity gives an accent force.
|
||||
|
||||
Operate + Read: semantic-first and almost always Restrained. Accent color is reserved for primary action, current selection, and state indicators. Not decoration. Every color has a consistent meaning across every screen.
|
||||
## Audit before choosing
|
||||
|
||||
---
|
||||
Read DESIGN.md, tokens, assets, current themes, and representative states. Identify:
|
||||
|
||||
## Assess Color Opportunity
|
||||
- which colors are confirmed brand commitments;
|
||||
- current surface, text, action, and semantic roles;
|
||||
- places where grayscale obscures hierarchy or state;
|
||||
- contrast failures and color-only communication;
|
||||
- light/dark or data-visualization requirements;
|
||||
- whether the task asks for more color or a new identity.
|
||||
|
||||
Analyze the current state and identify opportunities:
|
||||
If a new identity is required, use [new-work.md](new-work.md). Ask only when a binding brand decision cannot be inferred.
|
||||
|
||||
1. **Understand current state**:
|
||||
- **Color absence**: Pure grayscale? Limited neutrals? One timid accent?
|
||||
- **Missed opportunities**: Where could color add meaning, hierarchy, or delight?
|
||||
- **Context**: What's appropriate for this domain and audience?
|
||||
- **Brand**: Are there existing brand colors we should use?
|
||||
## Choose a strategy
|
||||
|
||||
2. **Identify where color adds value**:
|
||||
- **Semantic meaning**: Success (green), error (red), warning (yellow/orange), info (blue)
|
||||
- **Hierarchy**: Drawing attention to important elements
|
||||
- **Categorization**: Different sections, types, or states
|
||||
- **Emotional tone**: Warmth, energy, trust, creativity
|
||||
- **Wayfinding**: Helping users navigate and understand structure
|
||||
- **Delight**: Moments of visual interest and personality
|
||||
Name the intended emotional temperature, dominant relationship, contrast range, and color dosage before editing. The strategy may be restrained or immersive; it must follow the brief and selected world rather than a fixed percentage rule.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer.
|
||||
Build roles, not a bag of swatches:
|
||||
|
||||
**CRITICAL**: More color ≠ better. Strategic color beats rainbow vomit every time. Every color should have a purpose.
|
||||
- canvas and elevated surfaces;
|
||||
- primary and secondary text;
|
||||
- action, focus, and selection;
|
||||
- borders and separators;
|
||||
- success, warning, error, and information;
|
||||
- data categories or scales when needed.
|
||||
|
||||
## Plan Color Strategy
|
||||
Use the project's existing color space. For a new web palette, prefer OKLCH because lightness and chroma can be adjusted predictably. Choose hue from product meaning and visual direction, never from a default category association.
|
||||
|
||||
Create a purposeful color introduction plan:
|
||||
## Apply at system scale
|
||||
|
||||
- **Color palette**: What colors match the brand/context? (Choose 2-4 colors max beyond neutrals)
|
||||
- **Dominant color**: Which color owns 60% of colored elements?
|
||||
- **Accent colors**: Which colors provide contrast and highlights? (30% and 10%)
|
||||
- **Application strategy**: Where does each color appear and why?
|
||||
- Let the strongest color own a deliberate region or role instead of scattering tiny accents.
|
||||
- Keep the primary action easy to find; do not spend its color on decoration.
|
||||
- Tint neutrals only when the brand hue genuinely creates cohesion. Neutral gray is valid when it serves the world.
|
||||
- On colored surfaces, derive secondary text from the foreground or surface hue rather than using washed-out generic gray.
|
||||
- Keep semantic meanings consistent, but respect platform and domain conventions instead of assuming fixed hues.
|
||||
- For data, use distinct lightness, chroma, shape, label, or pattern so color is not the only code.
|
||||
- In dark mode, design surface elevation and contrast explicitly; do not invert the light theme mechanically.
|
||||
- Define primitive values and semantic tokens when the project has a token system. Theme changes should normally remap semantic roles.
|
||||
|
||||
**IMPORTANT**: Color should enhance hierarchy and meaning, not create chaos. Less is more when it matters more.
|
||||
Decoration without a relationship to hierarchy, state, content, or the visual world is not a color strategy.
|
||||
|
||||
## Introduce Color Strategically
|
||||
## Contrast and perception
|
||||
|
||||
Add color systematically across these dimensions:
|
||||
Verify computed foreground/background pairs:
|
||||
|
||||
### Semantic Color
|
||||
- **State indicators**:
|
||||
- Success: Green tones (emerald, forest, mint)
|
||||
- Error: Red/pink tones (rose, crimson, coral)
|
||||
- Warning: Orange/amber tones
|
||||
- Info: Blue tones (sky, ocean, indigo)
|
||||
- Neutral: Gray/slate for inactive states
|
||||
| Content | WCAG AA minimum |
|
||||
|---|---|
|
||||
| body text | 4.5:1 |
|
||||
| large text | 3:1 |
|
||||
| controls, icons, focus indicators | 3:1 |
|
||||
|
||||
- **Status badges**: Colored backgrounds or borders for states (active, pending, completed, etc.)
|
||||
- **Progress indicators**: Colored bars, rings, or charts showing completion or health
|
||||
Do not rely on eyesight alone. Check interactive states, overlays, text on images, disabled content, and both themes. Simulate common vision deficiencies. Information conveyed by color also needs text, shape, iconography, or position.
|
||||
|
||||
### Accent Color Application
|
||||
- **Primary actions**: Color the most important buttons/CTAs
|
||||
- **Links**: Add color to clickable text (maintain accessibility)
|
||||
- **Icons**: Colorize key icons for recognition and personality
|
||||
- **Headers/titles**: Add color to section headers or key labels
|
||||
- **Hover states**: Introduce color on interaction
|
||||
When deriving OKLCH ramps, vary lightness and reduce chroma near white and black. Do not keep high chroma at extreme lightness merely to make the math uniform. Prefer explicit colors over chains of translucent overlays when alpha would make contrast context-dependent.
|
||||
|
||||
### Background & Surfaces
|
||||
- **Tinted backgrounds**: If you replace pure gray, tint toward the brand hue, not toward a generic-warm-or-cool pair. The default-warm-tint (`oklch(97% 0.01 60)` and its neighbors) is now the AI cream/sand giveaway. Be specific to the brand or stay neutral.
|
||||
- **Colored sections**: Use subtle background colors to separate areas
|
||||
- **Gradient backgrounds**: Add depth with subtle, intentional gradients (not generic purple-blue)
|
||||
- **Cards & surfaces**: Tint cards or surfaces toward the brand, not "for warmth" by reflex
|
||||
## Verify
|
||||
|
||||
**Use OKLCH for color**: It's perceptually uniform, meaning equal steps in lightness *look* equal. Great for generating harmonious scales.
|
||||
|
||||
### Data Visualization
|
||||
- **Charts & graphs**: Use color to encode categories or values
|
||||
- **Heatmaps**: Color intensity shows density or importance
|
||||
- **Comparison**: Color coding for different datasets or timeframes
|
||||
|
||||
### Borders & Accents
|
||||
- **Hairline borders**: 1px colored borders on full perimeter (not side-stripes; see the absolute ban on `border-left/right > 1px`)
|
||||
- **Underlines**: Color underlines for emphasis or active states
|
||||
- **Dividers**: Subtle colored dividers instead of gray lines
|
||||
- **Focus rings**: Colored focus indicators matching brand
|
||||
- **Surface tints**: A 4-8% background wash of the accent color instead of a stripe
|
||||
|
||||
**NEVER**: `border-left` or `border-right` greater than 1px as a colored accent stripe. This is one of the three absolute bans in the parent skill. If you want to mark a card as "active" or "warning", use a full hairline border, a background tint, a leading glyph, or a numbered prefix. Not a side stripe.
|
||||
|
||||
### Typography Color
|
||||
- **Colored headings**: Use brand colors for section headings (maintain contrast)
|
||||
- **Highlight text**: Color for emphasis or categories
|
||||
- **Labels & tags**: Small colored labels for metadata or categories
|
||||
|
||||
### Decorative Elements
|
||||
- **Illustrations**: Add colored illustrations or icons
|
||||
- **Shapes**: Geometric shapes in brand colors as background elements
|
||||
- **Gradients**: Colorful gradient overlays or mesh backgrounds
|
||||
- **Blobs/organic shapes**: Soft colored shapes for visual interest
|
||||
|
||||
## Balance & Refinement
|
||||
|
||||
Ensure color addition improves rather than overwhelms:
|
||||
|
||||
### Maintain Hierarchy
|
||||
- **Dominant color** (60%): Primary brand color or most used accent
|
||||
- **Secondary color** (30%): Supporting color for variety
|
||||
- **Accent color** (10%): High contrast for key moments
|
||||
- **Neutrals** (remaining): Gray/black/white for structure
|
||||
|
||||
### Accessibility
|
||||
- **Contrast ratios**: Ensure WCAG compliance (4.5:1 for text, 3:1 for UI components)
|
||||
- **Don't rely on color alone**: Use icons, labels, or patterns alongside color
|
||||
- **Test for color blindness**: Verify red/green combinations work for all users
|
||||
|
||||
### Cohesion
|
||||
- **Consistent palette**: Use colors from defined palette, not arbitrary choices
|
||||
- **Systematic application**: Same color meanings throughout (green always = success)
|
||||
- **Temperature consistency**: Warm palette stays warm, cool stays cool
|
||||
|
||||
**NEVER**:
|
||||
- Use every color in the rainbow (choose 2-4 colors beyond neutrals)
|
||||
- Apply color randomly without semantic meaning
|
||||
- Put gray text on colored backgrounds. It looks washed out; use a darker shade of the background color or transparency instead
|
||||
- Violate WCAG contrast requirements
|
||||
- Use color as the only indicator (accessibility issue)
|
||||
- Make everything colorful (defeats the purpose)
|
||||
- Default to purple-blue gradients (AI slop aesthetic)
|
||||
|
||||
## Verify Color Addition
|
||||
|
||||
Test that colorization improves the experience:
|
||||
|
||||
- **Better hierarchy**: Does color guide attention appropriately?
|
||||
- **Clearer meaning**: Does color help users understand states/categories?
|
||||
- **More engaging**: Does the interface feel warmer and more inviting?
|
||||
- **Still accessible**: Do all color combinations meet WCAG standards?
|
||||
- **Not overwhelming**: Is color balanced and purposeful?
|
||||
- Every color has a stable role or a world-specific atmospheric purpose.
|
||||
- Attention lands on the intended action, content, or state.
|
||||
- The palette works across quiet, dense, interactive, error, and empty states.
|
||||
- Light and dark themes are each composed, not mechanically inverted.
|
||||
- Contrast and non-color cues pass in all relevant states.
|
||||
- The result is recognizably this product, not a generic “colorful” treatment.
|
||||
|
||||
When the palette earns its place, hand off to `$impeccable polish` for the final pass.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
When invoked from live mode, each variant MUST declare a `color-amount` param so the user can dial between a restrained accent and a drenched surface without regeneration. Author the variant's CSS against `var(--p-color-amount, 0.5)`, typically as the alpha multiplier on backgrounds, or as a scaling factor on the chroma axis in an OKLCH expression. 0 = neutral/monochrome, 1 = full saturation / dominant coverage.
|
||||
When invoked from live mode, every variant declares a `color-amount` parameter. Author CSS against `var(--p-color-amount, 0.5)` so the user can move from neutral to the variant's full color strategy without regeneration.
|
||||
|
||||
```json
|
||||
{"id":"color-amount","kind":"range","min":0,"max":1,"step":0.05,"default":0.5,"label":"Color amount"}
|
||||
```
|
||||
|
||||
Layer 1-2 variant-specific params on top: palette selection (`steps` with named options), temperature warmth, or tint vs. true color. See `reference/live.md` for the full params contract.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `color-and-contrast.md` and live inline now so the colorize flow has its deep color reference in one place.
|
||||
|
||||
### Color & Contrast
|
||||
|
||||
#### Color Spaces: Use OKLCH
|
||||
|
||||
**Stop using HSL.** Use OKLCH (or LCH) instead. It's perceptually uniform, meaning equal steps in lightness *look* equal, unlike HSL where 50% lightness in yellow looks bright while 50% in blue looks dark.
|
||||
|
||||
The OKLCH function takes three components: `oklch(lightness chroma hue)` where lightness is 0-100%, chroma is roughly 0-0.4, and hue is 0-360. To build a primary color and its lighter / darker variants, hold the chroma+hue roughly constant and vary the lightness, but **reduce chroma as you approach white or black**, because high chroma at extreme lightness looks garish.
|
||||
|
||||
The hue you pick is a brand decision and should not come from a default. Do not reach for blue (hue 250) or warm orange (hue 60) by reflex; those are the dominant AI-design defaults, not the right answer for any specific brand.
|
||||
|
||||
#### Building Functional Palettes
|
||||
|
||||
##### Tinted Neutrals
|
||||
|
||||
**Pure gray is dead.** A neutral with zero chroma feels lifeless next to a colored brand. Add a tiny chroma value (0.005-0.015) to all your neutrals, hued toward whatever your brand color is. The chroma is small enough not to read as "tinted" consciously, but it creates subconscious cohesion between brand color and UI surfaces.
|
||||
|
||||
The hue you tint toward should come from THIS project's brand, not from a "warm = friendly, cool = tech" formula. If your brand color is teal, your neutrals lean toward teal. If your brand color is amber, they lean toward amber. The point is cohesion with the SPECIFIC brand, not a stock palette.
|
||||
|
||||
**Avoid** the trap of always tinting toward warm orange or always tinting toward cool blue. Those are the two laziest defaults and they create their own monoculture across projects.
|
||||
|
||||
##### Palette Structure
|
||||
|
||||
A complete system needs:
|
||||
|
||||
| Role | Purpose | Example |
|
||||
|------|---------|---------|
|
||||
| **Primary** | Brand, CTAs, key actions | 1 color, 3-5 shades |
|
||||
| **Neutral** | Text, backgrounds, borders | 9-11 shade scale |
|
||||
| **Semantic** | Success, error, warning, info | 4 colors, 2-3 shades each |
|
||||
| **Surface** | Cards, modals, overlays | 2-3 elevation levels |
|
||||
|
||||
**Skip secondary/tertiary unless you need them.** Most apps work fine with one accent color. Adding more creates decision fatigue and visual noise.
|
||||
|
||||
##### The 60-30-10 Rule (Applied Correctly)
|
||||
|
||||
This rule is about **visual weight**, not pixel count:
|
||||
|
||||
- **60%**: Neutral backgrounds, white space, base surfaces
|
||||
- **30%**: Secondary colors: text, borders, inactive states
|
||||
- **10%**: Accent: CTAs, highlights, focus states
|
||||
|
||||
The common mistake: using the accent color everywhere because it's "the brand color." Accent colors work *because* they're rare. Overuse kills their power.
|
||||
|
||||
#### Contrast & Accessibility
|
||||
|
||||
##### WCAG Requirements
|
||||
|
||||
| Content Type | AA Minimum | AAA Target |
|
||||
|--------------|------------|------------|
|
||||
| Body text | 4.5:1 | 7:1 |
|
||||
| Large text (18px+ or 14px bold) | 3:1 | 4.5:1 |
|
||||
| UI components, icons | 3:1 | 4.5:1 |
|
||||
| Non-essential decorations | None | None |
|
||||
|
||||
##### Dangerous Color Combinations
|
||||
|
||||
These commonly fail contrast or cause readability issues:
|
||||
|
||||
- Light gray text on white (the #1 accessibility fail)
|
||||
- Red text on green background (or vice versa): 8% of men can't distinguish these
|
||||
- Blue text on red background (vibrates visually)
|
||||
- Yellow text on white (almost always fails)
|
||||
- Thin light text on images (unpredictable contrast)
|
||||
|
||||
##### Testing
|
||||
|
||||
Don't trust your eyes. Use tools:
|
||||
|
||||
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
||||
- Browser DevTools → Rendering → Emulate vision deficiencies
|
||||
- [Polypane](https://polypane.app/) for real-time testing
|
||||
|
||||
#### Theming: Light & Dark Mode
|
||||
|
||||
##### Dark Mode Is Not Inverted Light Mode
|
||||
|
||||
You can't just swap colors. Dark mode requires different design decisions:
|
||||
|
||||
| Light Mode | Dark Mode |
|
||||
|------------|-----------|
|
||||
| Shadows for depth | Lighter surfaces for depth (no shadows) |
|
||||
| Dark text on light | Light text on dark (reduce font weight) |
|
||||
| Vibrant accents | Desaturate accents slightly |
|
||||
| White backgrounds | Either pure black or a deep surface that fits the brand (a brand-tinted near-black at oklch 12-18% works too) |
|
||||
|
||||
In dark mode, depth comes from surface lightness, not shadow. Build a 3-step surface scale where higher elevations are lighter (e.g. 15% / 20% / 25% lightness). Use the SAME hue and chroma as your brand color (whatever it is for THIS project; do not reach for blue) and only vary the lightness. Reduce body text weight slightly (e.g. 350 instead of 400) because light text on dark reads as heavier than dark text on light.
|
||||
|
||||
##### Token Hierarchy
|
||||
|
||||
Use two layers: primitive tokens (`--blue-500`) and semantic tokens (`--color-primary: var(--blue-500)`). For dark mode, only redefine the semantic layer; primitives stay the same.
|
||||
|
||||
#### Alpha Is A Design Smell
|
||||
|
||||
Heavy use of transparency (rgba, hsla) usually means an incomplete palette. Alpha creates unpredictable contrast, performance overhead, and inconsistency. Define explicit overlay colors for each context instead. Exception: focus rings and interactive states where see-through is needed.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Relying on color alone to convey information. Creating palettes without clear roles for each color. Skipping color blindness testing (8% of men affected).
|
||||
Add at most two variant-specific parameters, such as palette, temperature, or tint behavior. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Craft (deprecated alias)
|
||||
|
||||
`craft` is a deprecated alias for the standard build flow. Builds route through SKILL.md's new-work gate; [new-work.md](new-work.md) carries the direction checkpoint ("Decide, then build"), the identity playbook, and the finishing pass. Invoking `craft` explicitly forces the attended checkpoints: pause at the stated direction for confirmation, and follow [codex.md](codex.md)'s mock flow when the harness generates images. Nothing else differs from a plain build request.
|
||||
`craft` is a deprecated alias for an ordinary request to make new visual work. It adds no setup, interview, checkpoint, tool, or quality behavior. Apply SKILL.md's normal routing: create missing PRODUCT.md through [init.md](init.md), then follow [new-work.md](new-work.md) for visual authority, world and surface decisions, implementation, and finish.
|
||||
|
||||
Do not tell users they need to invoke `craft`. Natural requests such as “build this feature,” “make a landing page,” or “redesign this screen” use the same flow.
|
||||
|
||||
@@ -52,13 +52,13 @@ If browser automation is available, each assessment creates its own new tab. Nev
|
||||
Read relevant source files and visually inspect the live page when browser automation is available. Think like a design director.
|
||||
|
||||
Evaluate:
|
||||
- **AI slop**: Would someone believe "AI made this" immediately? Check all DON'T guidance from the parent Impeccable skill.
|
||||
- **Design specificity**: Is the composition, interaction, and visual language grounded in this product, or could an unrelated product use it unchanged? Make this judgment before seeing detector output.
|
||||
- **Holistic design**: hierarchy, IA, emotional fit, discoverability, composition, typography, color, accessibility, states, copy, and edge cases.
|
||||
- **Cognitive load**: consult the [Cognitive Load Assessment](#cognitive-load-assessment) section below; report checklist failures and decision points with >4 visible options.
|
||||
- **Emotional journey**: peak-end rule, emotional valleys, reassurance at high-stakes moments.
|
||||
- **Nielsen heuristics**: consult the [Heuristics Scoring Guide](#heuristics-scoring-guide) section below; score all 10 heuristics 0-4, marking any heuristic the mode-applicability rule allows as `n/a` instead of forcing a number.
|
||||
|
||||
Return: AI slop verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
Return: design-specificity verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
|
||||
### Assessment B: Detector + Browser Evidence
|
||||
|
||||
@@ -130,11 +130,11 @@ Be honest with scores. A 4 means genuinely excellent. Most real interfaces score
|
||||
|
||||
**Mode applicability**: heuristics 7 (Flexibility and Efficiency) and 10 (Help and Documentation) may be scored `n/a` on Persuade and Experience surfaces (landing pages, campaigns, portfolios, bodies of work), as may any other heuristic that genuinely cannot apply to the surface under review. Write `n/a` in the Score cell with a one-line reason, and renormalize the total to the applicable maximum (e.g. **24/32** when two heuristics are n/a) so the rating band stays proportional. The persisted snapshot must record which heuristics were scored n/a.
|
||||
|
||||
#### Anti-Patterns Verdict
|
||||
#### Design Specificity Verdict
|
||||
|
||||
**Start here.** Does this look AI-generated?
|
||||
**Start here.** Does the result feel authored for this product, or category-interchangeable?
|
||||
|
||||
**LLM assessment**: Your own evaluation of AI slop tells. Cover overall aesthetic feel, layout sameness, generic composition, missed opportunities for personality.
|
||||
**LLM assessment**: Your unanchored evaluation of design specificity. Cover overall coherence, structural sameness, category-interchangeable choices, and missed opportunities for product character.
|
||||
|
||||
**Deterministic scan**: Summarize what the automated detector found, with counts and file locations. Note any additional issues the detector caught that you missed, and flag any false positives.
|
||||
|
||||
@@ -196,7 +196,7 @@ Once the report above is finalized, write it to `.impeccable/critique/` so the u
|
||||
|
||||
Skip this step if the Setup slug was null (vague or root-level target).
|
||||
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, anti-patterns verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, design-specificity verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
|
||||
Codex: exclude Run Notes from the temp body file; Run Notes are final-chat only because persistence, trend read, and temp cleanup happen after the snapshot write.
|
||||
|
||||
|
||||
@@ -1,302 +1,70 @@
|
||||
> **Additional context needed**: what's appropriate for the domain (playful vs professional vs quirky vs elegant).
|
||||
> **Additional context needed**: the brand's emotional range.
|
||||
|
||||
Find the moments where personality and unexpected polish would turn a functional interface into one users remember and tell other people about. Add only where the moment earns it; delight everywhere reads as noise.
|
||||
Make the experience memorable at moments that earn it. Delight is not a layer of generic whimsy; it is product character revealed through a useful interaction, a humane response, or an unexpectedly considered detail.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: delight can be distributed across copy voice, section transitions, discovery rewards, seasonal touches, personality across the whole surface.
|
||||
- **Persuade + Experience:** personality may run through voice, composition, motion, and discovery, provided the artifact remains the focus.
|
||||
- **Operate + Read:** concentrate delight at meaningful moments such as first use, completion, recovery, or mastery. Reliability carries everything else.
|
||||
|
||||
Operate + Read: delight at specific moments, not pages. Completion, first-time actions, error recovery, milestone crossings. Reliability and consistency carry the rest of the experience; delight pushed everywhere reads as noise.
|
||||
## Find the opportunity
|
||||
|
||||
---
|
||||
Inspect the target, DESIGN.md, product voice, repeated-use frequency, and emotional context. Look for:
|
||||
|
||||
## Assess Delight Opportunities
|
||||
- effort worth acknowledging;
|
||||
- waiting that can become informative;
|
||||
- an empty or first-use state that can orient;
|
||||
- an error or recovery moment that needs empathy;
|
||||
- an interaction whose physical or verbal response could express the brand;
|
||||
- a useful capability people might enjoy discovering.
|
||||
|
||||
Identify where delight would enhance (not distract from) the experience:
|
||||
Do not manufacture a celebration for an ordinary click. Ask only when the brand's emotional range or the stakes cannot be inferred.
|
||||
|
||||
1. **Find natural delight moments**:
|
||||
- **Success states**: Completed actions (save, send, publish)
|
||||
- **Empty states**: First-time experiences, onboarding
|
||||
- **Loading states**: Waiting periods that could be entertaining
|
||||
- **Achievements**: Milestones, streaks, completions
|
||||
- **Interactions**: Hover states, clicks, drags
|
||||
- **Errors**: Softening frustrating moments
|
||||
- **Easter eggs**: Hidden discoveries for curious users
|
||||
## Define one delight thesis
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the brand personality? (Playful? Professional? Quirky? Elegant?)
|
||||
- Who's the audience? (Tech-savvy? Creative? Corporate?)
|
||||
- What's the emotional context? (Accomplishment? Exploration? Frustration?)
|
||||
- What's appropriate? (Banking app ≠ gaming app)
|
||||
State in one sentence what the user should feel and why that feeling belongs to this product. Then choose the smallest system that can deliver it:
|
||||
|
||||
3. **Define delight strategy**:
|
||||
- **Subtle sophistication**: Refined micro-interactions (luxury brands)
|
||||
- **Playful personality**: Whimsical illustrations and copy (consumer apps)
|
||||
- **Helpful surprises**: Anticipating needs before users ask (productivity tools)
|
||||
- **Sensory richness**: Satisfying sounds, smooth animations (creative tools)
|
||||
- a distinctive response to a meaningful action;
|
||||
- product-specific language that clarifies while carrying voice;
|
||||
- an interaction or transition with a recognizable material behavior;
|
||||
- an illustration, sound, haptic, or environmental detail grounded in the product world;
|
||||
- a discovery reward that reveals real utility.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer.
|
||||
Derive the treatment from product mechanism and visual world, not a stock catalog.
|
||||
|
||||
**CRITICAL**: Delight should enhance usability, never obscure it. If users notice the delight more than accomplishing their goal, you've gone too far.
|
||||
## Build for the emotional moment
|
||||
|
||||
## Delight Principles
|
||||
- **Success:** match the response to the effort and consequence. Major milestones can expand; routine saves should simply feel certain.
|
||||
- **Waiting:** show truthful progress, useful context, or product-specific activity. Never fake work or delay completion to stage a flourish.
|
||||
- **Empty and first use:** make the next action clear before adding personality.
|
||||
- **Error and recovery:** lead with the problem and recovery. Warmth may reduce stress; jokes must not trivialize loss, money, privacy, or blocked work.
|
||||
- **Repeated interaction:** keep the response satisfying after the hundredth use. Variation is useful only when it remains coherent and predictable enough to trust.
|
||||
- **Discovery:** reward curiosity without hiding required functionality.
|
||||
|
||||
Follow these guidelines:
|
||||
Copy must use the product's language. Generic whimsy is worse than neutral clarity.
|
||||
|
||||
### Delight Amplifies, Never Blocks
|
||||
- Delight moments should be quick (< 1 second)
|
||||
- Never delay core functionality for delight
|
||||
- Make delight skippable or subtle
|
||||
- Respect user's time and task focus
|
||||
## Protect the experience
|
||||
|
||||
### Surprise and Discovery
|
||||
- Hide delightful details for users to discover
|
||||
- Reward exploration and curiosity
|
||||
- Don't announce every delight moment
|
||||
- Let users share discoveries with others
|
||||
Delight must not:
|
||||
|
||||
### Appropriate to Context
|
||||
- Match delight to emotional moment (celebrate success, empathize with errors)
|
||||
- Respect the user's state (don't be playful during critical errors)
|
||||
- Match brand personality and audience expectations
|
||||
- Cultural sensitivity (what's delightful varies by culture)
|
||||
- delay, block, or obscure the primary task;
|
||||
- override platform conventions or accessibility;
|
||||
- add unrequested factual claims;
|
||||
- play sound without consent or ignore mute settings;
|
||||
- become mandatory, unskippable, or exhausting on repeat;
|
||||
- add a dependency or asset cost disproportionate to the moment.
|
||||
|
||||
### Compound Over Time
|
||||
- Delight should remain fresh with repeated use
|
||||
- Vary responses (not same animation every time)
|
||||
- Reveal deeper layers with continued use
|
||||
- Build anticipation through patterns
|
||||
For authored motion, load [animate.md](animate.md). Respect reduced motion, screen readers, keyboard use, touch, localization, and cultural context. Nonessential loops stop when hidden. Make celebration intensity proportional to frequency and consequence.
|
||||
|
||||
## Delight Techniques
|
||||
## Verify
|
||||
|
||||
Add personality and joy through these methods:
|
||||
- The moment is specific enough that a neighboring product could not use it unchanged.
|
||||
- It improves comprehension, confidence, motivation, or emotional recovery.
|
||||
- The interface remains fast and obvious without the flourish.
|
||||
- Repetition does not turn charm into friction.
|
||||
- Reduced-motion, muted, keyboard, touch, and localized paths work.
|
||||
- The result feels like the selected world, not a generic “delight” treatment.
|
||||
|
||||
### Micro-interactions & Animation
|
||||
|
||||
**Button delight**:
|
||||
```css
|
||||
/* Satisfying button press */
|
||||
.button {
|
||||
transition: transform 0.1s, box-shadow 0.1s;
|
||||
}
|
||||
.button:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Ripple effect on click */
|
||||
/* Smooth lift on hover */
|
||||
.button:hover {
|
||||
transform: translateY(-2px);
|
||||
transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1); /* ease-out-quart */
|
||||
}
|
||||
```
|
||||
|
||||
**Loading delight**:
|
||||
- Playful loading animations (not just spinners)
|
||||
- Personality in loading messages (write product-specific ones, not generic AI filler)
|
||||
- Progress indication with encouraging messages
|
||||
- Skeleton screens with subtle animations
|
||||
|
||||
**Success animations**:
|
||||
- Checkmark draw animation
|
||||
- Confetti burst for major achievements
|
||||
- Gentle scale + fade for confirmation
|
||||
- Satisfying sound effects (subtle)
|
||||
|
||||
**Hover surprises**:
|
||||
- Icons that animate on hover
|
||||
- Color shifts or glow effects
|
||||
- Tooltip reveals with personality
|
||||
- Cursor changes (custom cursors for branded experiences)
|
||||
|
||||
### Personality in Copy
|
||||
|
||||
**Playful error messages**:
|
||||
```
|
||||
"Error 404"
|
||||
"This page is playing hide and seek. (And winning)"
|
||||
|
||||
"Connection failed"
|
||||
"Looks like the internet took a coffee break. Want to retry?"
|
||||
```
|
||||
|
||||
**Encouraging empty states**:
|
||||
```
|
||||
"No projects"
|
||||
"Your canvas awaits. Create something amazing."
|
||||
|
||||
"No saved articles"
|
||||
"Nothing on the nightstand yet. Save a story for later."
|
||||
```
|
||||
|
||||
**Playful labels & tooltips**:
|
||||
```
|
||||
"Delete"
|
||||
"Send to void" (for playful brand)
|
||||
|
||||
"Help"
|
||||
"Rescue me" (tooltip)
|
||||
```
|
||||
|
||||
**IMPORTANT**: Match copy personality to brand. Banks shouldn't be wacky, but they can be warm.
|
||||
|
||||
### Illustrations & Visual Personality
|
||||
|
||||
**Custom illustrations**:
|
||||
- Empty state illustrations (not stock icons)
|
||||
- Error state illustrations (friendly monsters, quirky characters)
|
||||
- Loading state illustrations (animated characters)
|
||||
- Success state illustrations (celebrations)
|
||||
|
||||
**Icon personality**:
|
||||
- Custom icon set matching brand personality
|
||||
- Animated icons (subtle motion on hover/click)
|
||||
- Illustrative icons (more detailed than generic)
|
||||
- Consistent style across all icons
|
||||
|
||||
**Background effects**:
|
||||
- Subtle particle effects
|
||||
- Gradient mesh backgrounds
|
||||
- Geometric patterns
|
||||
- Parallax depth
|
||||
- Time-of-day themes (morning vs night)
|
||||
|
||||
### Satisfying Interactions
|
||||
|
||||
**Drag and drop delight**:
|
||||
- Lift effect on drag (shadow, scale)
|
||||
- Snap animation when dropped
|
||||
- Satisfying placement sound
|
||||
- Undo toast ("Dropped in wrong place? [Undo]")
|
||||
|
||||
**Toggle switches**:
|
||||
- Smooth slide with spring physics
|
||||
- Color transition
|
||||
- Haptic feedback on mobile
|
||||
- Optional sound effect
|
||||
|
||||
**Progress & achievements** (Operate surfaces with recurring tasks only; gamification on editorial, portfolio, or one-visit surfaces reads as noise):
|
||||
- Streak counters with celebratory milestones
|
||||
- Progress bars that "celebrate" at 100%
|
||||
- Badge unlocks with animation
|
||||
- Playful stats ("You're on fire! 5 days in a row")
|
||||
|
||||
**Form interactions**:
|
||||
- Input fields that animate on focus
|
||||
- Checkboxes with a satisfying scale pulse when checked
|
||||
- Success state that celebrates valid input
|
||||
- Auto-grow textareas
|
||||
|
||||
### Sound Design
|
||||
|
||||
**Subtle audio cues** (when appropriate):
|
||||
- Notification sounds (distinctive but not annoying)
|
||||
- Success sounds (satisfying "ding")
|
||||
- Error sounds (empathetic, not harsh)
|
||||
- Typing sounds for chat/messaging
|
||||
- Ambient background audio (very subtle)
|
||||
|
||||
**IMPORTANT**:
|
||||
- Respect system sound settings
|
||||
- Provide mute option
|
||||
- Keep volumes quiet (subtle cues, not alarms)
|
||||
- Don't play on every interaction (sound fatigue is real)
|
||||
|
||||
### Easter Eggs & Hidden Delights
|
||||
|
||||
**Discovery rewards**:
|
||||
- Konami code unlocks special theme
|
||||
- Hidden keyboard shortcuts (Cmd+K for special features)
|
||||
- Hover reveals on logos or illustrations
|
||||
- Alt text jokes on images (for screen reader users too!)
|
||||
- A view-source or console colophon (a note on the typefaces, a thank-you, a hiring line)
|
||||
|
||||
**Seasonal touches**:
|
||||
- Holiday themes (subtle, tasteful)
|
||||
- Seasonal color shifts
|
||||
- Weather-based variations
|
||||
- Time-based changes (dark at night, light during day)
|
||||
|
||||
**Contextual personality**:
|
||||
- Different messages based on time of day
|
||||
- Responses to specific user actions
|
||||
- Randomized variations (not same every time)
|
||||
- Progressive reveals with continued use
|
||||
|
||||
### Loading & Waiting States
|
||||
|
||||
**Make waiting engaging**:
|
||||
- Interesting loading messages that rotate
|
||||
- Progress bars with personality
|
||||
- Mini-games during long loads
|
||||
- Fun facts or tips while waiting
|
||||
- Countdown with encouraging messages
|
||||
|
||||
```
|
||||
Loading messages: write ones specific to your product, not generic AI filler:
|
||||
- "Syncing with your team's changes..."
|
||||
- "Fetching this week's issue..."
|
||||
- "Developing your photos..."
|
||||
- "Checking tomorrow's tide tables..."
|
||||
```
|
||||
|
||||
**WARNING**: Avoid cliched loading messages like "Herding pixels", "Teaching robots to dance", "Consulting the magic 8-ball", "Counting backwards from infinity". These are AI-slop copy, instantly recognizable as machine-generated. Write messages that are specific to what your product actually does.
|
||||
|
||||
### Celebration Moments
|
||||
|
||||
**Success celebrations**:
|
||||
- Confetti for major milestones
|
||||
- Animated checkmarks for completions
|
||||
- Progress bar celebrations at 100%
|
||||
- "Achievement unlocked" style notifications
|
||||
- Personalized messages ("You published your 10th article!")
|
||||
|
||||
**Milestone recognition** (same scoping as Progress & achievements: Operate surfaces with recurring tasks):
|
||||
- First-time actions get special treatment
|
||||
- Streak tracking and celebration
|
||||
- Progress toward goals
|
||||
- Anniversary celebrations
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
**Animation libraries**:
|
||||
- Framer Motion (React)
|
||||
- GSAP (universal)
|
||||
- Lottie (After Effects animations)
|
||||
- Canvas confetti (party effects)
|
||||
|
||||
**Sound libraries**:
|
||||
- Howler.js (audio management)
|
||||
- Use-sound (React hook)
|
||||
|
||||
**Physics libraries**:
|
||||
- React Spring (spring physics)
|
||||
- Popmotion (animation primitives)
|
||||
|
||||
**IMPORTANT**: File size matters. Compress images, optimize animations, lazy load delight features.
|
||||
|
||||
**NEVER**:
|
||||
- Delay core functionality for delight
|
||||
- Force users through delightful moments (make skippable)
|
||||
- Use delight to hide poor UX
|
||||
- Overdo it (less is more)
|
||||
- Ignore accessibility (animate responsibly, provide alternatives)
|
||||
- Make every interaction delightful (special moments should be special)
|
||||
- Sacrifice performance for delight
|
||||
- Be inappropriate for context (read the room)
|
||||
|
||||
## Verify Delight Quality
|
||||
|
||||
Test that delight actually delights:
|
||||
|
||||
- **User reactions**: Do users smile? Share screenshots?
|
||||
- **Doesn't annoy**: Still pleasant after 100th time?
|
||||
- **Doesn't block**: Can users opt out or skip?
|
||||
- **Performant**: No jank, no slowdown
|
||||
- **Appropriate**: Matches brand and context
|
||||
- **Accessible**: Works with reduced motion, screen readers
|
||||
|
||||
When the moments feel earned, hand off to `$impeccable polish` for the final pass.
|
||||
When the personality feels earned, hand off to `$impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Generate a `DESIGN.md` file at the project root that captures the current visual design system, so AI agents generating new screens stay on-brand.
|
||||
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): YAML frontmatter carrying machine-readable design tokens, followed by a markdown body with exactly six sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but **do not reorder them and do not rename them**. Section headers must match the spec character-for-character so the file stays parseable by other DESIGN.md-aware tools (Stitch itself, awesome-design-md, skill-rest, etc.).
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): optional YAML frontmatter carrying machine-readable design tokens, followed by up to eight markdown sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but those present stay in the specified order. Use the canonical headings below so the file remains portable across DESIGN.md-aware tools.
|
||||
|
||||
## The frontmatter: token schema
|
||||
|
||||
@@ -43,26 +43,28 @@ components:
|
||||
Rules that matter:
|
||||
|
||||
- **Token refs** use `{path.to.token}` (e.g. `{colors.primary}`, `{rounded.md}`). Components may reference primitives; primitives may not reference each other.
|
||||
- **Stitch validates colors as hex sRGB only** (`#RGB` / `#RGBA` / `#RRGGBB` / `#RRGGBBAA`); OKLCH/HSL/P3 trigger a linter warning, not a hard error. YAML accepts the string either way and our own parser is format-agnostic. Choose based on project posture: (a) if the project has an "OKLCH-only" doctrine or uses Display-P3 values that don't round-trip through sRGB, put OKLCH directly in the frontmatter and accept the Stitch linter warning; (b) if the project wants strict Stitch compliance or plans to use their Tailwind/DTCG export pipeline, put hex in the frontmatter and keep OKLCH in prose as the canonical reference. Never split the source of truth without explicit reason.
|
||||
- **Colors accept any valid CSS color string.** Hex is the recommended default for portability, but preserve an incumbent `rgb()`, `hsl()`, `oklch()`, wide-gamut, or mixed-color value when it is the project's normative source. Never split the source of truth without explicit reason.
|
||||
- **Component sub-tokens** are limited to 8 props: `backgroundColor`, `textColor`, `typography`, `rounded`, `padding`, `size`, `height`, `width`. Shadows, motion, focus rings, backdrop-filter: none of those fit. Carry them in the sidecar (Step 4b).
|
||||
- **Scale keys are open-ended.** Use whatever names the project already uses (`oxblood-deep`, `surface-container-low`). Don't rename to Material defaults.
|
||||
- **Variants are naming convention, not schema.** `button-primary` / `button-primary-hover` / `button-primary-active` as sibling keys.
|
||||
|
||||
## The markdown body: six sections (exact order)
|
||||
## The markdown body: eight sections (canonical order)
|
||||
|
||||
1. `## Overview`
|
||||
2. `## Colors`
|
||||
3. `## Typography`
|
||||
4. `## Elevation`
|
||||
5. `## Components`
|
||||
6. `## Do's and Don'ts`
|
||||
4. `## Layout`
|
||||
5. `## Elevation & Depth`
|
||||
6. `## Shapes`
|
||||
7. `## Components`
|
||||
8. `## Do's and Don'ts`
|
||||
|
||||
Optional evocative subtitles are allowed in the form `## 2. Colors: The [Name] Palette` (Stitch's own outputs do this), but the literal word in each header (Overview, Colors, Typography, Elevation, Components, Do's and Don'ts) must be present. Do NOT add extra top-level sections (Layout Principles, Responsive Behavior, Motion, Agent Prompt Guide). Fold that content into the six spec sections where it naturally belongs.
|
||||
Omit irrelevant sections rather than filling them with invented rules. Put responsive layout in Layout, depth in Elevation & Depth, radius and form language in Shapes, and per-component behavior in Components. Unknown sections are preserved by the format, but new visual guidance should use the canonical structure whenever it fits.
|
||||
|
||||
## When to run
|
||||
|
||||
- The user just ran `$impeccable init` and needs the visual side documented.
|
||||
- The skill noticed no `DESIGN.md` exists and nudged the user to create one.
|
||||
- New-work found a coherent incumbent visual system but no `DESIGN.md`.
|
||||
- The first implementation of a new world is complete and its provisional decisions need to be carbonized.
|
||||
- An existing `DESIGN.md` is stale (the design has drifted).
|
||||
- Before a large redesign, to capture the current state as a reference.
|
||||
|
||||
@@ -71,9 +73,9 @@ If a `DESIGN.md` already exists, **do not silently overwrite it**. Show the user
|
||||
## Two paths
|
||||
|
||||
- **Scan mode** (default): the project has design tokens, components, or rendered output. Extract, then confirm descriptive language. Use when there's code to analyze.
|
||||
- **Seed mode**: the project is pre-implementation (fresh init, nothing built yet). Interview for five high-level answers, write a minimal DESIGN.md marked `<!-- SEED -->`. Re-run in scan mode once there's code.
|
||||
- **Seed mode**: the project is pre-implementation. Ensure PRODUCT.md exists, then reuse new-work's visual-world workshop and write its directional DESIGN.md seed. Re-run in scan mode once there's code.
|
||||
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `$impeccable document --seed` forces seed mode regardless of code presence.
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `$impeccable document --seed` requests new-work's world workshop, but it does not authorize replacing coherent code: when an incumbent system exists, offer scan mode or route an explicit identity-replacement request through new-work.
|
||||
|
||||
## Scan mode (approach C: auto-extract, then confirm descriptive language)
|
||||
|
||||
@@ -97,7 +99,8 @@ Build a structured draft from the discovered tokens. For each token class:
|
||||
- **Typography**: Map observed sizes and weights to the Material hierarchy (display / headline / title / body / label). Note font-family stacks and the scale ratio.
|
||||
- **Elevation**: Catalogue the shadow vocabulary. If the project is flat and uses tonal layering instead, that's a valid answer; state it explicitly.
|
||||
- **Components**: For each common component (button, card, input, chip, list item, tooltip, nav), extract shape (radius), color assignment, hover/focus treatment, internal padding.
|
||||
- **Spacing + layout**: Fold into Overview or relevant Components. The spec does NOT have a Layout section.
|
||||
- **Layout + spacing**: Extract grid, container, breakpoint, rhythm, and density behavior into Layout.
|
||||
- **Shapes**: Extract radius, corner, border, clipping, and recurring form behavior into Shapes.
|
||||
|
||||
### Step 2b: Stage the frontmatter
|
||||
|
||||
@@ -112,19 +115,19 @@ Skip anything the project doesn't have. Empty scale keys or fabricated tokens po
|
||||
|
||||
### Step 3: Ask the user for qualitative language
|
||||
|
||||
The following require creative input that cannot be auto-extracted. Group them into one `AskUserQuestion` interaction:
|
||||
The following require creative input that cannot be auto-extracted. Ask them in two structured rounds of no more than three questions each (or the harness's lower limit), waiting between rounds:
|
||||
|
||||
- **Creative North Star**: a single named metaphor for the whole system ("The Editorial Sanctuary", "The Golden State Curator", "The Lab Notebook"). Offer 2-3 options that honor PRODUCT.md's brand personality.
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, anti-references (what the system should not feel like).
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, and any confirmed visual anti-reference.
|
||||
- **Color character** (for auto-extracted colors): descriptive names ("Deep Muted Teal-Navy", not "blue-800"). Suggest 2-3 options per key color based on hue/saturation.
|
||||
- **Elevation philosophy**: flat/layered/lifted. If shadows exist, is their role ambient or structural?
|
||||
- **Component philosophy**: the feel of buttons, cards, inputs in one phrase ("tactile and confident" vs. "refined and restrained").
|
||||
|
||||
Quote a line from PRODUCT.md when possible so the user sees their own strategic language carry forward.
|
||||
Carry a line from PRODUCT.md only when it is a durable brand commitment that actually constrains the visual system. Page strategy and surface concepts do not belong here.
|
||||
|
||||
### Step 4: Write DESIGN.md
|
||||
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the structure below. Headers must match character-for-character. Optional evocative subtitles (e.g. `## 2. Colors: The Coastal Palette`) are allowed.
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the canonical structure below.
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -136,13 +139,13 @@ colors:
|
||||
|
||||
# Design System: [Project Title]
|
||||
|
||||
## 1. Overview
|
||||
## Overview
|
||||
|
||||
**Creative North Star: "[Named metaphor in quotes]"**
|
||||
|
||||
[2-3 paragraph holistic description: personality, density, aesthetic philosophy. Start from the North Star and work outward. State what this system explicitly rejects (pulled from PRODUCT.md's anti-references). End with a short **Key Characteristics:** bullet list.]
|
||||
[2-3 paragraph holistic description: personality, density, and aesthetic philosophy. Start from the North Star and work outward. State only confirmed visual rejections. End with a short **Key Characteristics:** bullet list.]
|
||||
|
||||
## 2. Colors
|
||||
## Colors
|
||||
|
||||
[Describe the palette character in one sentence.]
|
||||
|
||||
@@ -162,7 +165,7 @@ colors:
|
||||
### Named Rules (optional, powerful)
|
||||
**The [Rule Name] Rule.** [Short, forceful prohibition or doctrine, e.g. "The One Voice Rule. The primary accent is used on ≤10% of any given screen. Its rarity is the point."]
|
||||
|
||||
## 3. Typography
|
||||
## Typography
|
||||
|
||||
**Display Font:** [Family] (with [fallback])
|
||||
**Body Font:** [Family] (with [fallback])
|
||||
@@ -180,7 +183,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [Short doctrine about type use.]
|
||||
|
||||
## 4. Elevation
|
||||
## Layout
|
||||
|
||||
[Describe the grid or spatial model, container behavior, density, responsive changes, and the spacing rhythm. Include exact values only when observed.]
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
[One paragraph: does this system use shadows, tonal layering, or a hybrid? If "no shadows", say so explicitly and describe how depth is conveyed instead.]
|
||||
|
||||
@@ -191,7 +198,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [e.g. "The Flat-By-Default Rule. Surfaces are flat at rest. Shadows appear only as a response to state (hover, elevation, focus)."]
|
||||
|
||||
## 5. Components
|
||||
## Shapes
|
||||
|
||||
[Describe the form language: corner/radius strategy, borders, clipping, and any recurring silhouette or geometry.]
|
||||
|
||||
## Components
|
||||
|
||||
For each component, lead with a short character line, then specify shape, color assignment, states, and any distinctive behavior.
|
||||
|
||||
@@ -223,16 +234,16 @@ For each component, lead with a short character line, then specify shape, color
|
||||
### [Signature Component] (optional; if the project has a distinctive custom component worth documenting)
|
||||
[Description.]
|
||||
|
||||
## 6. Do's and Don'ts
|
||||
## Do's and Don'ts
|
||||
|
||||
Concrete, forceful guardrails. Lead each with "Do" or "Don't". Be specific: include exact colors, pixel values, and named anti-patterns the user mentioned in PRODUCT.md. **Every anti-reference in PRODUCT.md should show up here as a "Don't" with the same language**, so the visual spec carries the strategic line through. Quote PRODUCT.md directly where possible: if PRODUCT.md says *"avoid dark mode with purple gradients, neon accents, glassmorphism"*, the Don'ts here should repeat that by name.
|
||||
Concrete visual guardrails grounded in the incumbent implementation or the user's chosen world. Lead each with "Do" or "Don't" and include exact values only when established. Do not turn a task-specific concept or surface strategy into a system-wide prohibition.
|
||||
|
||||
### Do:
|
||||
- **Do** [specific prescription with exact values / named rule].
|
||||
- **Do** [...]
|
||||
|
||||
### Don't:
|
||||
- **Don't** [specific prohibition, e.g. "use border-left greater than 1px as a colored stripe"].
|
||||
- **Don't** [specific prohibition confirmed by the incumbent system or the user].
|
||||
- **Don't** [...]
|
||||
- **Don't** [...]
|
||||
```
|
||||
@@ -307,7 +318,7 @@ The `html` and `css` fields must be **self-contained, drop-in snippets** that re
|
||||
Aim for a tight set of **5-10 components** that best represent the visual system:
|
||||
|
||||
- **Canonical primitives (always include if the project has them):** button (each variant as a separate component entry), input/text field, navigation, chip/tag, card.
|
||||
- **Signature components (include if distinctive):** hero CTA, featured card, filter pill, a distinctive table or list-row treatment, any custom pattern the user mentioned as important in PRODUCT.md.
|
||||
- **Signature components (include if distinctive):** the recurring custom patterns that actually define the implemented system.
|
||||
- **Skip the rest.** Utility components, form building blocks, wrapper layouts: not worth documenting unless visually distinctive.
|
||||
|
||||
If the project has **no component library yet** (bare landing page, new project), synthesize canonical primitives from the tokens using best-practice defaults consistent with the DESIGN.md's rules. Every `.impeccable/design.json` has *something* to render, even on day zero.
|
||||
@@ -338,64 +349,40 @@ Your own write is the freshest source; subsequent commands in this session don't
|
||||
|
||||
## Seed mode
|
||||
|
||||
For projects with no visual system to extract yet. Produces a minimal scaffold, not a full spec.
|
||||
For projects with no visual system to extract yet. Produces a user-chosen visual-world scaffold, not a fabricated token spec.
|
||||
|
||||
### Step 1: Confirm seed mode
|
||||
### Step 1: Route through new-work's workshop
|
||||
|
||||
Before interviewing: "There's no existing visual system to scan. I'll ask five quick questions to seed a starter DESIGN.md. You can re-run `$impeccable document` once there's code, to capture the real tokens and components. OK?"
|
||||
PRODUCT.md is the prerequisite. If it is missing, load [init.md](init.md) and complete its product interview first. Do not create a visual identity without durable product context.
|
||||
|
||||
If the user prefers to skip, stop. No file.
|
||||
If PRODUCT.md exists, load [new-work.md](new-work.md) and resolve visual authority. Seed mode requires a concrete first surface: use the target the user named, or ask what they want to make first. Run **Select one direction** for A, D, or E so the visual world and its first expression are chosen as one pair. Stop after the directional DESIGN.md seed and surface brief; do not implement. A structured simulated user counts as the user and must get the same choice.
|
||||
|
||||
### Step 2: Five questions
|
||||
If new-work already completed the workshop in this session, use its chosen direction directly. Do not ask again.
|
||||
|
||||
Group into one `AskUserQuestion` interaction. Options must be concrete.
|
||||
### Step 2: Write seed DESIGN.md
|
||||
|
||||
1. **Color strategy.** Pick one:
|
||||
- Restrained: tinted neutrals + one accent ≤10%
|
||||
- Committed: one saturated color carries 30–60% of the surface
|
||||
- Full palette: 3–4 named color roles, each deliberate
|
||||
- Drenched: the surface IS the color
|
||||
|
||||
Then: one hue family or anchor reference ("deep teal", "mustard", "Klim #ff4500 orange").
|
||||
|
||||
2. **Typography direction.** Pick one (specific fonts come later):
|
||||
- Serif display + sans body
|
||||
- Single sans (warm / technical / geometric / humanist; pick a feel)
|
||||
- Display + mono
|
||||
- Mono-forward
|
||||
- Editorial script + sans
|
||||
|
||||
3. **Motion energy.** Pick one:
|
||||
- Restrained: state changes only
|
||||
- Responsive: feedback + transitions, no choreography
|
||||
- Choreographed: orchestrated entrances, scroll-driven sequences
|
||||
|
||||
4. **Three named references.** Brands, products, printed objects. Not adjectives.
|
||||
|
||||
5. **One anti-reference.** What it should NOT feel like. Also named.
|
||||
|
||||
### Step 3: Write seed DESIGN.md
|
||||
|
||||
Use the six-section spec from Scan mode. Populate what the interview answers; leave the rest as honest placeholders. The seed is a scaffold, not a fabricated spec.
|
||||
Use the canonical section order from Scan mode. Populate the selected workshop direction and leave unresolved implementation facts as honest placeholders. The seed commits a world and its invariants; it does not pretend implementation tokens already exist.
|
||||
|
||||
Lead the file with:
|
||||
|
||||
```markdown
|
||||
<!-- SEED: re-run $impeccable document once there's code to capture the actual tokens and components. -->
|
||||
<!-- SEED: established with the user before implementation; re-run $impeccable document once there's code to capture the actual tokens and components. -->
|
||||
```
|
||||
|
||||
Per-section guidance in seed mode:
|
||||
|
||||
- **Overview**: Creative North Star and philosophy phrased from the answers (color strategy + motion energy + references). Reference the user's anti-reference directly.
|
||||
- **Colors**: Color strategy as a Named Rule (e.g. *"The Drenched Rule. The surface IS the color."*). Hue family or anchor reference. No hex values; mark as `[to be resolved during implementation]`.
|
||||
- **Typography**: the direction the user picked (e.g. "Serif display + sans body"). No font names yet: `[font pairing to be chosen at implementation]`.
|
||||
- **Elevation**: inferred from motion energy. Restrained/Responsive → flat by default; Choreographed → layered. One sentence.
|
||||
- **Overview**: the chosen design thesis, layout behavior, material character, imagery stance, motion grammar, and reusable signature. Keep the selected first-surface expression in its surface brief; do not promote its composition into the global world.
|
||||
- **Colors**: the selected palette strategy and roles. Include values only when the user, an existing asset, or new-work's exploration established them; otherwise mark them `[to be resolved during implementation]`.
|
||||
- **Typography**: the selected type character and role relationship. Include font names only when established; otherwise mark the pairing `[to be resolved during implementation]`.
|
||||
- **Layout**: the selected spatial grammar and responsive behavior, without pretending exact measurements are settled.
|
||||
- **Elevation & Depth**: the selected material and depth behavior, stated as an invariant rather than inferred from a generic preset.
|
||||
- **Shapes**: the selected form and corner language.
|
||||
- **Components**: omit entirely; no components exist yet.
|
||||
- **Do's and Don'ts**: carry PRODUCT.md's anti-references directly plus the anti-reference named in Q5.
|
||||
- **Do's and Don'ts**: record the durable guardrails confirmed during the world choice, not task-local refusals.
|
||||
|
||||
Seed mode writes a minimal frontmatter with `name` and `description` only; no colors, typography, rounded, spacing, or components yet. Real tokens land on the next Scan-mode run. Skip the `.impeccable/design.json` sidecar in seed mode for the same reason: nothing to render.
|
||||
|
||||
### Step 4: Confirm
|
||||
### Step 3: Confirm
|
||||
|
||||
1. Show the seed DESIGN.md. Call out that it is a seed (the marker is the literal commitment).
|
||||
2. Tell the user: "Re-run `$impeccable document` once you have some code. That pass will extract real tokens and generate the sidecar."
|
||||
@@ -405,15 +392,15 @@ Your own write is the freshest source; no reload needed.
|
||||
## Style guidelines
|
||||
|
||||
- **Frontmatter first, prose second.** Tokens go in the YAML frontmatter; prose contextualizes them. Don't redefine a token value in two places; the frontmatter is normative.
|
||||
- **Cite PRODUCT.md anti-references by name** in the Do's and Don'ts section. If PRODUCT.md lists "SaaS landing-page clichés" or "generic AI tool marketing" as anti-references, the DESIGN.md Don'ts should repeat those phrases verbatim so the visual spec enforces the strategic line.
|
||||
- **Match the spec, don't invent new sections.** The six section names are fixed. If you have Layout/Motion/Responsive content to document, fold it into Overview (philosophy-level rules) or Components (per-component behavior).
|
||||
- **Carry only durable product constraints.** A binding logo, identity asset, accessibility need, or brand commitment from PRODUCT.md may constrain DESIGN.md. Surface strategy stays in its surface brief.
|
||||
- **Match the spec.** Use its eight canonical sections in order and omit any that are irrelevant. Put motion guidance with the world or component it affects rather than creating a token group the schema does not support.
|
||||
- **Descriptive > technical**: "Gently curved edges (8px radius)" > "rounded-lg". Include the technical value in parens, lead with the description.
|
||||
- **Functional > decorative**: for each token, explain WHERE and WHY it's used, not just WHAT it is.
|
||||
- **Exact values in parens**: hex codes, px/rem values, font weights; always the number in parens alongside the description.
|
||||
- **Use Named Rules**: `**The [Name] Rule.** [short doctrine]`. These are memorable, citable, and much stickier for AI consumers than bullet lists. Stitch's own outputs use them heavily ("The No-Line Rule", "The Ghost Border Fallback"). Aim for 1-3 per section.
|
||||
- **Be forceful**. The voice of a design director. "Prohibited", "forbidden", "never", "always", not "consider", "might", "prefer". Match PRODUCT.md's tone.
|
||||
- **Concrete anti-pattern tests**. Stitch writes things like *"If it looks like a 2014 app, the shadow is too dark and the blur is too small."* A one-sentence audit test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md**. The anti-references section of PRODUCT.md should directly inform the Do's and Don'ts section here. Quote or paraphrase.
|
||||
- **Be decisive where evidence is decisive.** Use hard language for actual invariants and softer language for provisional guidance.
|
||||
- **Use concrete audit tests only when they are grounded in the observed system or a confirmed user decision.** A one-sentence test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md selectively.** Product truth explains why the world fits; it does not supply page composition or a visual don't-list by default.
|
||||
- **Group colors by role**, not by hex-order or hue-order. Primary / Secondary / Tertiary / Neutral is the spec ordering.
|
||||
|
||||
## Pitfalls
|
||||
@@ -423,7 +410,7 @@ Your own write is the freshest source; no reload needed.
|
||||
- Don't invent components that don't exist. If the project only has buttons and cards, only document those.
|
||||
- Don't overwrite an existing DESIGN.md without asking.
|
||||
- Don't duplicate content from PRODUCT.md. DESIGN.md is strictly visual.
|
||||
- Don't add a "Layout Principles" or "Motion" or "Responsive Behavior" top-level section. The spec has six, not nine. Fold that content where it belongs.
|
||||
- Don't replace canonical sections with near-synonyms. Put layout and responsive behavior in `Layout`; put motion with the affected world or component.
|
||||
- Don't rename sections even slightly. "Colors" not "Color Palette & Roles". "Typography" not "Typography Rules". Tooling parsing depends on exact headers.
|
||||
- Don't duplicate token values between frontmatter and prose. If a color is in `colors.primary` as hex, the prose can name it and describe its role but should not reassert a different hex. The frontmatter is normative.
|
||||
- Don't invent frontmatter token groups outside Stitch's schema (no `motion:`, `breakpoints:`, `shadows:` at the top level). Stitch's Zod schema only accepts `colors`, `typography`, `rounded`, `spacing`, `components`. Anything else belongs in the sidecar's `extensions`.
|
||||
|
||||
@@ -4,7 +4,7 @@ Manage the **design detector hook** for the current project.
|
||||
|
||||
The hook runs the impeccable design detector on direct file edits to design-relevant files (`.tsx`, `.jsx`, `.html`, `.vue`, `.svelte`, `.astro`, `.css`, `.scss`, `.sass`, `.less`, `.ts`, `.js`). Claude Code, Codex, and GitHub Copilot use a post-tool-use hook and push a short system reminder into the agent's context after the edit; findings get a correction prompt, pending issues get a re-nudge, and clean UI-ish files get a short ack unless quiet mode is on (`hook.quiet` in config). Plain `.ts` and `.js` files are still scanned, but stay quiet unless the detector finds something. Cursor uses `preToolUse` to block bad proposed writes before they land and stays silent when it allows a clean write.
|
||||
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so Copilot keeps the full rule set per edit instead of deferring.
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. That Stop message also asks for one authored review of detector-blind model reflexes. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit while `context.mjs` supplies the detector-blind review. When no automatic hook is active, `context.mjs` instead supplies that review plus one manual detector command.
|
||||
|
||||
This command toggles the hook **per project** by editing `.impeccable/config.json` (the unified Impeccable config; hook runtime settings live under its `hook` key, and shared detector ignores live under `detector`). Per-developer overrides, including the install consent decision (`hook.consent`) the CLI records, live in the gitignored `.impeccable/config.local.json`. Set `hook.enabled: false` to turn the hook off, `hook.quiet: true` to silence the clean/pending acks, or `hook.auditLog` to a file path for an NDJSON log. The legacy `IMPECCABLE_HOOK_DISABLED`, `IMPECCABLE_HOOK_QUIET`, and `IMPECCABLE_HOOK_LOG` env vars are still honored and override these config values when set.
|
||||
|
||||
|
||||
@@ -1,224 +1,114 @@
|
||||
# Init Flow
|
||||
# Init flow
|
||||
|
||||
The setup command for a project. One codebase crawl feeds everything it writes:
|
||||
|
||||
- **PRODUCT.md** (strategic): root project file for register, target users, product purpose, brand personality, anti-references, strategic design principles. Answers "who/what/why".
|
||||
- **DESIGN.md** (visual): root project file for visual theme, color palette, typography, components, layout. Follows the [DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md). Answers "how it looks".
|
||||
- **`.impeccable/live/config.json`** (live mode): pre-configured so `$impeccable live` boots straight into variant mode with no first-time detour.
|
||||
|
||||
It closes by pointing the user at the best command to run next. Every other impeccable command reads PRODUCT.md and DESIGN.md before doing any work.
|
||||
`init` captures durable product truth in PRODUCT.md. It does not invent a visual world and does not write DESIGN.md; [new-work.md](new-work.md) creates or expands one, and [document.md](document.md) records an incumbent one. Existing runnable web projects may also receive `.impeccable/live/config.json`.
|
||||
|
||||
## Step 1: Load current state
|
||||
|
||||
Check what already exists. PRODUCT.md and DESIGN.md live at the project root, or under `.agents/context/` or `docs/` (case-insensitive). Read whichever are present with your native file tool. Also note whether `.impeccable/live/config.json` already exists (Step 6 leaves it untouched if so).
|
||||
Use the PRODUCT.md path resolved by context.mjs. Update it instead of creating a competing authority. In a child app inheriting root context, confirm shared versus app-specific scope before writing.
|
||||
|
||||
Decision tree:
|
||||
- **Neither file exists (empty project or no context yet)**: do Steps 2-4 (write PRODUCT.md), then decide on DESIGN.md based on whether there's code to analyze.
|
||||
- **PRODUCT.md exists, DESIGN.md missing**: skip to Step 5 and offer to run `$impeccable document` for DESIGN.md.
|
||||
- **PRODUCT.md exists but has no `## Register` section (legacy)**: add it. Infer a hypothesis from the codebase (see Step 2), confirm with the user, write the field.
|
||||
- **PRODUCT.md exists but has no `## Platform` section (legacy)**: add it the same way, but only when the project is native (`ios` / `android` / `adaptive`) or the user wants it explicit; a missing field already means `web`.
|
||||
- **Both exist**: STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask which file to refresh. Skip the one the user doesn't want changed.
|
||||
- **Just DESIGN.md exists (unusual)**: do Steps 2-4 to produce PRODUCT.md.
|
||||
- **No PRODUCT.md:** explore, interview, and write it.
|
||||
- **PRODUCT.md exists:** ask what product knowledge is stale or missing; do not reopen confirmed fields without a reason.
|
||||
- **Legacy PRODUCT.md:** add only durable missing facts; absent `## Platform` means `web` unless evidence says otherwise.
|
||||
- **Only DESIGN.md exists:** leave it untouched and create PRODUCT.md.
|
||||
- **Redesign/rebrand request:** preserve confirmed product truth unless the user changes it. Visual replacement happens later in new-work, not here.
|
||||
|
||||
Never silently overwrite an existing file. Always confirm first.
|
||||
Never silently overwrite an existing file or offer DESIGN.md during init. If another request invoked init, finish PRODUCT.md and resume it. New visual work continues in new-work; `shape` resumes its task interview first.
|
||||
|
||||
If init was invoked as a setup blocker by another command, such as `$impeccable craft landing page`, pause that command here. Complete init, then resume the original command. Your own writes are the freshest source; no reload needed. For craft, resume into shape next; init creates project context, but it is not a substitute for the task-specific shape interview and confirmed design brief.
|
||||
## Step 2: Explore the project
|
||||
|
||||
## Step 2: Explore the codebase
|
||||
Before asking, scan enough to avoid making the user repeat known facts: product docs and copy; package/config and app boundaries; features, workflows, routes, and roles; names, logos, legal/proof assets, and brand commitments; platform/accessibility signals; and the dev command/entry when live mode applies.
|
||||
|
||||
Before asking questions, thoroughly scan the project to discover what you can. This single crawl feeds PRODUCT.md, DESIGN.md, **and** the live-mode framework detection in Step 6, so be thorough once rather than re-scanning later:
|
||||
Treat repository evidence as a hypothesis, not user approval. Note visual maturity without documenting, extending, or replacing the world.
|
||||
|
||||
- **README and docs**: Project purpose, target audience, any stated goals
|
||||
- **Package.json / config files**: Tech stack, dependencies, existing design libraries, **and the framework** (Vite/SPA, Next.js, Nuxt, SvelteKit, Astro, multi-page static) plus the HTML entry the browser actually loads
|
||||
- **Existing components**: Current design patterns, spacing, typography in use
|
||||
- **Brand assets**: Logos, favicons, color values already defined
|
||||
- **Design tokens / CSS variables**: Existing color palettes, font stacks, spacing scales
|
||||
- **Any style guides or brand documentation**
|
||||
Form a platform hypothesis: `web`, `ios`, `android`, or `adaptive` (one product that genuinely adapts its design language per OS). Mobile web remains `web`; a native wrapper around a website does not make its design language native.
|
||||
|
||||
Also form a **register hypothesis** from what you find:
|
||||
## Step 3: Interview for product truth
|
||||
|
||||
- Brand signals: `/`, `/about`, `/pricing`, `/blog/*`, `/docs/*`, hero sections, big typography, scroll-driven sections, landing-page-shaped content.
|
||||
- Product signals: `/app/*`, `/dashboard`, `/settings`, `/(auth)`, forms, data tables, side/top nav, app-shell components.
|
||||
STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask only about material gaps the repository and original request do not answer with strong evidence.
|
||||
|
||||
Register is a hypothesis at this point, not a decision; Step 3 confirms it.
|
||||
Use the structured question tool when available; otherwise ask and wait. Keep rounds to at most three focused questions and require one real answer or approval round before writing a new PRODUCT.md. Confirm inferences.
|
||||
|
||||
Also form a **platform hypothesis**:
|
||||
Start with the unknowns that most change future product decisions:
|
||||
|
||||
- Native signals: React Native / Expo (`react-native`, `expo`), Flutter (`pubspec.yaml`, `flutter`), SwiftUI / UIKit (`.swift`, `.xcodeproj`, an `ios/` app target), Jetpack Compose / Android (`build.gradle`, an `android/` app module, `AndroidManifest.xml`). An `ios/` and/or `android/` directory that is a real app target, not just a Capacitor/Cordova wrapper around a website.
|
||||
- Web signals (the default): a web framework (Vite, Next, Nuxt, SvelteKit, Astro), an HTML entry, a CSS/Tailwind setup, no native app target.
|
||||
1. Who is the primary user, in what situation, and what job are they doing?
|
||||
2. What does the product make possible, and what is its meaningfully different mechanism or position?
|
||||
3. What durable constraints, assets, evidence, or product facts must future work preserve?
|
||||
|
||||
Values: `web` / `ios` / `android` / `adaptive` (one codebase, ships both, adapts per OS). Mobile web is still `web`. Like register, this is a hypothesis; Step 3 confirms it.
|
||||
Confirm ambiguous platform separately. Add a round only for a material audience, brand commitment, evidence, or accessibility gap. Record undecided facts instead of inventing them.
|
||||
|
||||
Note what you've learned and what remains unclear. Also note any rough edges worth a follow-up command (thin hierarchy, flat or gray palette, missing error/empty states, dull copy); Step 7 turns these into concrete recommendations without re-analyzing.
|
||||
Do not ask for an aesthetic direction, emotional feel, visual references, colors, typography, or style during init. If the user volunteers a binding visual constraint, record it without expanding it.
|
||||
|
||||
## Step 3: Ask strategic questions (for PRODUCT.md)
|
||||
### What belongs here
|
||||
|
||||
STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask about anything the codebase doesn't answer with strong, explicit evidence.
|
||||
- users, jobs, workflows, purpose, success, positioning, and operating context;
|
||||
- capabilities, constraints, terminology, evidence, platform, and accessibility;
|
||||
- confirmed voice, assets, and brand commitments.
|
||||
|
||||
### Interview mode, not confirmation mode
|
||||
### What does not belong here
|
||||
|
||||
If the repo is empty or the user's brief is sparse, run a short interview before proposing PRODUCT.md. Do **not** turn a one-sentence request into a complete inferred PRODUCT.md and ask for blanket confirmation.
|
||||
|
||||
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop: one question at a time, with lettered options where the crawl suggests likely answers, waiting for each answer before the next.
|
||||
- Keep skill vocabulary (register, belief ladder, anti-references) out of question text; ask for the thing in words the user would use. For the brand register, ask like a magazine editor profiling the brand: curious and narrative, drawing out the story, the feel, and what a visitor should come to believe.
|
||||
- Ask in focused rounds and wait for answers between them. Keep **one topic per question**; add rounds rather than fold several topics into one either-or choice. Options obey the same rule: an option answers only the question asked; never write a compound option that bundles a feeling with a business outcome or names an additional audience.
|
||||
- Use inferred answers as hypotheses or options, not as finished facts.
|
||||
- Complete at least one real user-answer round before drafting PRODUCT.md, unless every required answer is directly discoverable from repo docs.
|
||||
- Round 1 should establish register, platform, users, purpose, positioning, and desired outcome.
|
||||
- Round 2 should establish brand personality or references, anti-references, and accessibility needs, plus conversion & proof for Persuade surfaces.
|
||||
|
||||
### Minimum viable interview
|
||||
|
||||
Ask enough to complete PRODUCT.md. At minimum, cover register confirmation, **platform confirmation** (`web` / `ios` / `android` / `adaptive`), users, purpose, positioning, brand personality, anti-references, and accessibility needs (plus conversion & proof for Persuade surfaces) unless each answer is directly discoverable from repo context. Never let the template's default `web` stand unconfirmed for a native or cross-platform repo. After at least one interview round, you may propose inferred answers, but the user must confirm them before you write PRODUCT.md. Never synthesize PRODUCT.md from the original task prompt alone.
|
||||
|
||||
### Register (ask first; it shapes everything below)
|
||||
|
||||
Every design task serves one of four visitor modes (see SKILL.md's Registers): **Persuade** (marketing, landing, campaigns), **Experience** (portfolios, albums, bodies of work), **Operate** (app UI, admin, dashboards, tools), and **Read** (documentation, editorial, long-form). PRODUCT.md stores the two-value family that covers them: `brand` covers Persuade and Experience, `product` covers Operate and Read. The brief decides the exact mode per task; the stored register only sets the default family.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [brand / product] surface. Does that match your intent, or should we treat it differently?"*
|
||||
|
||||
If the signal is genuinely split (e.g. a product with a big marketing landing), STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask which register describes the **primary** surface. The register can be overridden per task later, but PRODUCT.md carries one default. Settle the default before drafting any register-dependent questions; never batch Persuade-only questions (Conversion & proof) into the same round as the question that decides the register.
|
||||
|
||||
### Platform (ask right after register)
|
||||
|
||||
Every project targets **web** (includes responsive mobile web), **ios**, **android**, or **adaptive** (one codebase, ships both, adapts per OS: Flutter, React Native, KMP). Platform picks the native rulebook: HIG for `ios`, Material 3 for `android`, both for `adaptive`, none for `web`.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [web / ios / android / adaptive] project. Does that match?"* For cross-platform apps, decide by the **design language the app renders**, not the toolchain: one look on both platforms (Flutter's Material-everywhere default) takes that platform's value; genuine per-OS adaptation (Cupertino on iOS, Material on Android) is `adaptive`. When in doubt, `web`.
|
||||
|
||||
A monorepo shipping both a website and a native app gets a PRODUCT.md per app, each with its own `## Platform`; the root PRODUCT.md carries the primary surface's platform.
|
||||
|
||||
### Users & Purpose
|
||||
- Who uses this? What's their context when using it?
|
||||
- What job are they trying to get done?
|
||||
- What is this for? A purpose stated in README or docs is a hypothesis, not strong evidence; confirm it, don't transcribe it.
|
||||
- What does success look like?
|
||||
- If more than one kind of user is plausible, confirm a primary and secondary audience; don't manufacture a split that isn't there. An audience implied by another answer (a success metric, a CTA) is still unconfirmed; ask before writing it as secondary.
|
||||
- If the surface speaks to a different audience than the people who use the product, ask the user to name both.
|
||||
- For brand: what emotions should the interface evoke? (confidence, delight, calm, urgency) Ask this standalone; don't fold emotions into the success question.
|
||||
- For product: what workflow are they in? What's the primary task on any given screen?
|
||||
|
||||
### Positioning
|
||||
- In one line, what does this do that nothing else does? The single strategic claim every screen reinforces.
|
||||
|
||||
### Brand & Personality
|
||||
- How would you describe the brand personality in 3 words?
|
||||
- Reference sites or apps that capture the right feel? What specifically about them?
|
||||
- Push for specific named references with the *specific* thing about them that fits this brand, not generic "modern" adjectives or category-bucket lanes.
|
||||
- What should this explicitly NOT look like? Any anti-references?
|
||||
|
||||
### Conversion & proof (Persuade surfaces only)
|
||||
|
||||
Ask these only when the primary surface is a Persuade one (marketing, landing, campaigns). Experience and Read surfaces (portfolios, albums, long-form writing, documentation) get no CTA, belief-ladder, or proof questions even when the stored register is `brand`; skip this section and its PRODUCT.md counterpart.
|
||||
|
||||
- What's the primary CTA?
|
||||
- What's the secondary fallback, for visitors not ready for the primary?
|
||||
- The one line a visitor should remember after 10 seconds.
|
||||
- What must the visitor believe, in order, before taking the primary CTA? (The template's belief ladder.)
|
||||
- What proof is on hand? Ask the user to hand over any testimonials, case studies, press, or client/partner logos they already have. If you can receive files directly, collect them; otherwise create `.impeccable/assets/proof/` and ask the user to add files there. Reference supplied files by path; record text proof inline.
|
||||
|
||||
### Accessibility & Inclusion
|
||||
- Specific accessibility requirements? (WCAG level, known user needs)
|
||||
- Considerations for reduced motion, color blindness, or other accommodations?
|
||||
|
||||
Skip questions where the answer is already clear. **Do NOT ask about colors, fonts, radii, or visual styling here.** Those belong in DESIGN.md, not PRODUCT.md.
|
||||
- visual worlds, palettes, typography, components, or page concepts;
|
||||
- visitor mode, narrative, CTA/proof sequence, or other surface strategy;
|
||||
- invented testimonials, customers, benchmarks, pricing, licensing, or deployment claims;
|
||||
- a requirement to decide every optional field.
|
||||
|
||||
## Step 4: Write PRODUCT.md
|
||||
|
||||
Write PRODUCT.md only after the user has confirmed the strategic answers from Step 3. If an inferred answer is uncertain or unconfirmed, ask before writing. Confirmed means what the user actually said yes to; do not pad a confirmed answer with extras they never picked (additional anti-references, audiences, roadmap claims, a WCAG level), whether drawn from the crawl, another answer, or your own option text. If an extra belongs in the doc, ask about it first.
|
||||
|
||||
Synthesize into a strategic document:
|
||||
Write only confirmed facts and explicitly marked open decisions. Omit irrelevant sections rather than filling them with generic prose.
|
||||
|
||||
```markdown
|
||||
# Product
|
||||
|
||||
## Register
|
||||
|
||||
product
|
||||
|
||||
## Platform
|
||||
|
||||
web
|
||||
|
||||
## Users
|
||||
[Who they are, their context, the job to be done. Primary audience; a secondary audience or a surface-vs-user split only when they apply.]
|
||||
[Primary users, their situation, and job. Add other audiences only when confirmed.]
|
||||
|
||||
## Product Purpose
|
||||
[What this product does, why it exists, what success looks like]
|
||||
[What the product does, why it exists, and what success means.]
|
||||
|
||||
## Positioning
|
||||
[The single strategic claim every screen reinforces. Not a visual rule, not an anti-reference.]
|
||||
[The product mechanism or claim a neighboring product could not truthfully copy.]
|
||||
|
||||
## Conversion & proof
|
||||
[Persuade surfaces only (marketing, landing, campaigns). Omit this section entirely, heading included, for the product register and for Experience or Read surfaces such as portfolios, albums, or long-form writing.]
|
||||
- Primary and secondary CTA: [...]
|
||||
- The line a visitor remembers after 10 seconds: [...]
|
||||
- Belief ladder: [...]
|
||||
- Proof on hand: [testimonials, case studies, press, or logos, referenced by path]
|
||||
## Operating Context
|
||||
[Workflows, environments, tools, documents, materials, and rituals that are factual parts of using or evaluating the product.]
|
||||
|
||||
## Brand Personality
|
||||
[Voice, tone, 3-word personality, emotional goals]
|
||||
## Capabilities and Constraints
|
||||
[Confirmed functionality, technical constraints, terminology, and explicitly undecided product facts.]
|
||||
|
||||
## Anti-references
|
||||
[What this should NOT look like. Specific bad-example sites or patterns to avoid.]
|
||||
## Brand Commitments
|
||||
[Existing name, voice, assets, personality, identity constraints, and references the user explicitly made binding. Omit when none exist.]
|
||||
|
||||
## Design Principles
|
||||
[3-5 strategic principles derived from the conversation. Principles like "practice what you preach", "show, don't tell", "expert confidence". NOT visual rules like "use OKLCH" or "magenta accent".]
|
||||
## Evidence on Hand
|
||||
[Real content, data, demonstrations, testimonials, case studies, press, or assets, with paths where applicable. State absences that future work must not fabricate.]
|
||||
|
||||
## Product Principles
|
||||
[Three to five durable strategic principles derived from confirmed answers; no visual recipes.]
|
||||
|
||||
## Accessibility & Inclusion
|
||||
[WCAG level, known user needs, considerations]
|
||||
[Known user needs or required standard. Omit when no product-specific requirement was established.]
|
||||
```
|
||||
|
||||
Register is either `brand` or `product` as a bare value. No prose, no commentary. Platform is `web`, `ios`, `android`, or `adaptive`, also a bare value; omit the section only on legacy files you're leaving untouched, otherwise write `web` explicitly.
|
||||
Platform is the bare value `web`, `ios`, `android`, or `adaptive`. Preserve useful legacy headings. New files go at `PROJECT_ROOT/PRODUCT.md`; otherwise update the resolved file. Write it before any visual-world or surface-concept work.
|
||||
|
||||
Write fields as prose, and use bold sparingly: only where a word carries a decision, never as a label lead-in on every line.
|
||||
### Completion gate
|
||||
|
||||
Write to `PROJECT_ROOT/PRODUCT.md`. If `.impeccable.md` existed, the loader already renamed it; merge into that content rather than starting from scratch.
|
||||
Before loading new-work or resuming shape/build, verify that PRODUCT.md exists at the resolved path and contains the confirmed product record. If the file is absent, init is incomplete. Do not substitute interview notes, a planning packet, or later design prose for the file.
|
||||
|
||||
## Step 5: Decide on DESIGN.md
|
||||
## Step 5: Configure live mode when useful
|
||||
|
||||
Offer `$impeccable document` either way. Two paths:
|
||||
Skip native or non-runnable projects and leave existing config untouched. Otherwise follow [live.md](live.md)'s first-time setup. Any CSP source edit still requires its stated consent.
|
||||
|
||||
- **Code exists** (CSS tokens, components, a running site): "I can generate a DESIGN.md that captures your visual system (colors, typography, components) so variants stay on-brand. Want to do that now?"
|
||||
- **Pre-implementation** (empty project): "I can seed a starter DESIGN.md from five quick questions about color strategy, type direction, motion energy, and references. You can re-run once there's code, to capture the real tokens. Want to do that now?"
|
||||
## Step 6: Wrap up or resume
|
||||
|
||||
If the user agrees, delegate to `$impeccable document` (it auto-detects scan vs seed). Load its reference and follow that flow.
|
||||
Summarize captured and deliberately undecided facts. Do not offer DESIGN.md merely because it is missing.
|
||||
|
||||
If the user prefers to skip, mention they can run `$impeccable document` any time later.
|
||||
Recommend the next action from the actual project state:
|
||||
|
||||
## Step 6: Configure live mode (when code exists)
|
||||
- Empty or early project: ask naturally for the surface to be built, or use `$impeccable shape <surface>` when the user wants a confirmed brief without implementation. New-work will establish a visual world only when the requested work needs one.
|
||||
- Existing coherent interface without DESIGN.md: `$impeccable document` if the user wants the incumbent system recorded independently of a new build.
|
||||
- Existing surface needing work: name the most relevant scoped command.
|
||||
- Web project ready for visual iteration: `$impeccable live` when configured.
|
||||
|
||||
**Skip this step when the platform is native** (`ios` / `android` / `adaptive`): live mode drives a browser overlay. A hybrid wrapper or Expo web target serving HTML doesn't change that.
|
||||
|
||||
If the project has code with HTML entries and a dev server (the same "code exists" condition that puts `$impeccable document` in scan mode), pre-configure live mode now. You already identified the framework and the served HTML entry in Step 2, so this is nearly free, and it spares the user the first-time setup detour when they later run `$impeccable live`.
|
||||
|
||||
**Skip this step for empty / pre-implementation projects** (nothing to inject into yet). Tell the user live mode will configure itself the first time they run it once there's code.
|
||||
|
||||
**If `.impeccable/live/config.json` already exists, leave it untouched** and note that live mode is already configured.
|
||||
|
||||
Otherwise:
|
||||
|
||||
1. Write `.impeccable/live/config.json`. Choose `files` (the HTML entries the browser actually loads), `insertBefore`, and `commentSyntax` from the framework table in [live.md](live.md)'s **First-time setup** section, using the framework you found in Step 2. That table is canonical; do not restate it here. For multi-page static sites, prefer a glob (`["public/**/*.html"]`) over a literal list.
|
||||
2. Run `node .agents/skills/impeccable/scripts/detect-csp.mjs`. If it reports a patchable shape (`append-arrays` / `append-string`), use the **consent prompt template** from live.md before editing any source file. On decline, skip the patch. For `middleware` / `meta-tag` shapes, surface the detected files and ask the user to add `http://localhost:8400` to `script-src` and `connect-src` manually. For `null`, there's nothing to do.
|
||||
3. Set `cspChecked: true` in the config once CSP is handled (patched, declined, manual, or not needed). The schema and per-shape patch details live in live.md's First-time setup; follow it rather than duplicating.
|
||||
|
||||
Writing the config file is harmless and needs no consent; only the CSP **source-file patch** requires a yes.
|
||||
|
||||
## Step 7: Recommend starting points, then wrap up
|
||||
|
||||
Summarize tersely:
|
||||
- Register captured (brand / product) and platform captured (web / ios / android / adaptive)
|
||||
- What was written (PRODUCT.md, DESIGN.md, live config, or a subset)
|
||||
- The 3-5 strategic principles from PRODUCT.md that will guide future work
|
||||
- If DESIGN.md or live config is pending, one line on how to set it up later
|
||||
|
||||
Then recommend the **best commands to run next**, drawn from what your Step 2 crawl already surfaced. Do not run a fresh analysis here; surface observations you already have. Tailor to register **and platform**, offer the 2-4 most relevant (not a menu dump), and give the exact command to type. Group by intent:
|
||||
|
||||
- **Build something new**: `$impeccable craft <feature>` (shape, then build end-to-end) or `$impeccable shape <feature>` (plan first). Lead with this for empty or early-stage projects.
|
||||
- **Improve what's there**: name the specific surface. `$impeccable critique <page>` for a scored UX review; `$impeccable audit <area>` for a11y / perf / responsive checks; `$impeccable polish <component>` for a pre-ship pass. When the crawl flagged a specific weakness, point the matching command at it: thin hierarchy or spacing → `layout`, flat or gray palette → `colorize`, missing error / empty states → `harden` or `onboard`, dull or unclear copy → `clarify`.
|
||||
- **Iterate visually** (web only): `$impeccable live` (configured in Step 6) to pick elements in the browser and generate variants in place. **Skip this group for native platforms.**
|
||||
|
||||
The full command menu is one bare `$impeccable` away; keep this list short and pointed.
|
||||
|
||||
If init was invoked as a blocker by another impeccable command (e.g. the user ran `$impeccable polish` with no PRODUCT.md), resume that original task now. Your own writes are the freshest source; no reload needed.
|
||||
|
||||
Optionally STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask whether they'd like a brief summary of PRODUCT.md appended to AGENTS.md for easier agent reference. If yes, append a short **Design Context** pointer section there.
|
||||
If init was invoked by another request, resume without rerunning context.mjs; new-work owns later visual decisions.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native iOS / iPadOS apps: SwiftUI, UIKit, React Native, Expo, Flutter shipping to Apple hardware.
|
||||
|
||||
On native, register narrows. HIG conformance governs structure, navigation, and interaction whatever the register; brand expresses through the expressive layer the platform provides (tint, type, motion, content). Calm, Duolingo, and Spotify carry strong identity entirely inside HIG conventions.
|
||||
On native, the visitor mode narrows what expression may override. HIG conformance governs structure, navigation, and interaction in every mode; brand expresses through the layer the platform leaves open (tint, type, motion, content).
|
||||
|
||||
## The iOS slop test
|
||||
|
||||
|
||||
@@ -1,185 +1,84 @@
|
||||
Space is the most underused design tool. Find the layout's actual problem (monotone spacing, weak hierarchy, identical card grids) and fix the structure, not the surface.
|
||||
Layout turns product priority into reading order, grouping, rhythm, and usable space. Diagnose the structural problem before moving boxes.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: asymmetric compositions, fluid spacing with `clamp()`, intentional grid-breaking for emphasis. Rhythm through contrast: tight groupings paired with generous separations.
|
||||
- **Persuade + Experience:** composition may be asymmetric, fluid, or intentionally disruptive when the selected world earns it.
|
||||
- **Operate + Read:** predictable structure, stable density, and navigable linearity are affordances.
|
||||
- **Native:** follow [ios.md](ios.md) or [android.md](android.md) for navigation, insets, adaptation, and touch targets.
|
||||
|
||||
Operate + Read: predictable grids, consistent densities, familiar navigation patterns. Responsive behavior is structural (collapse sidebar, responsive table), not fluid typography. Consistency IS an affordance. Read surfaces specifically want navigable linearity: a steady column the reader can follow and a structure they can hold in their head, not compositional surprise.
|
||||
Preserve the established visual world. A layout command changes structure inside it; identity replacement belongs to [new-work.md](new-work.md).
|
||||
|
||||
Native (`ios` / `android` / `adaptive`): structure follows the Layout section of [ios.md](ios.md) / [android.md](android.md) (read it first if Setup hasn't already): platform navigation, insets, and touch targets, never the CSS tooling below.
|
||||
## Two isolated assessments
|
||||
|
||||
---
|
||||
When a sub-agent tool is available and permitted, run these independently; otherwise run them yourself in this order.
|
||||
|
||||
## Two isolated assessments (required)
|
||||
|
||||
Spawn two parallel sub-agents whenever a sub-agent/Task tool is exposed: one for the layout assessment, one for the mechanical pre-scan. If the harness needs explicit user permission for sub-agents, stop and ask before proceeding. Isolation is the point: detector output anchors visual judgment toward what the scan can see, so neither sub-agent gets the other's output. Each assessment runs in its own sub-agent; running either one in this context when a sub-agent tool exists is not permitted, even when it is faster; the fallback below is only for sessions with no sub-agent tool. Give each a self-contained prompt (target files, register, documented spacing scale when present, and its instructions below); do not assume it can read this file.
|
||||
|
||||
**Sub-agent A (layout assessment)**: give it the full [Assess Current Layout](#assess-current-layout) checklist below, verbatim, in its prompt. It works through every item and returns per-item findings citing file, selector, or value.
|
||||
|
||||
**Sub-agent B (mechanical pre-scan)**: run the bundled detector scoped to layout:
|
||||
1. **Layout assessment:** inspect representative states and viewports. Answer every question below with rendered or source evidence:
|
||||
- **Reading order:** Apply the squint test. With detail blurred, can you still identify the primary element, the secondary element, and the major groups in order?
|
||||
- **Grouping:** Are related items close and distinct groups separated, or are containers compensating for weak proximity?
|
||||
- **Rhythm:** Do tight and generous intervals create a deliberate cadence, or is one spacing value repeated until everything has equal weight?
|
||||
- **Structure:** Does the topology match the content and task? Are repeated cards, columns, or sections genuinely equivalent, or merely a framework default?
|
||||
- **Density:** Does the amount of information per region fit use frequency, decision complexity, and visitor mode?
|
||||
- **Adaptation:** At narrow, intermediate, wide, zoomed, and localized states, what reorders, collapses, wraps, scrolls, or remains fixed? Does DOM and focus order still agree with the visual order?
|
||||
- **Extremes:** Do long content, empty states, overlays, sticky elements, safe areas, and small touch targets expose structural failures?
|
||||
2. **Mechanical scan:** run:
|
||||
|
||||
```bash
|
||||
node .agents/skills/impeccable/scripts/detect.mjs --json --scope layout [target files or dirs]
|
||||
```
|
||||
|
||||
A missing `node` on PATH is not permission to skip: hunt for a runtime (`command -v node`, nvm or Homebrew paths, the harness's own bundled node) and run it by full path. If none exists, halt the scan and report that Node must be installed (the parent relays this to the user); do **not** substitute grep for the detector or proceed unscanned. The detector abstains on arbitrary Tailwind spacing (`gap-[13px]`, `p-[7px]`) and ad-hoc `z-index` stacks, so when the project documents a spacing scale, also grep `gap-\[`, `p[trblxy]?-\[`, `m[trblxy]?-\[`, `z-\[` and judge those hits against it. Return the findings JSON plus the grep verdicts.
|
||||
Also inspect arbitrary spacing, overflow, stacking, and container behavior the detector cannot resolve. Keep mechanical evidence out of the first assessment, then synthesize both passes before editing. A clean scan cannot prove hierarchy or rhythm.
|
||||
|
||||
**If no sub-agent tool is exposed (or the user declined)**: run both yourself, assessment first, pre-scan second, so the deterministic findings can't anchor the visual judgment. Keep that order even when the scan feels quicker to start with.
|
||||
## Set the spatial thesis
|
||||
|
||||
**Synthesize** once both are done: merge into a single findings list, noting where they agree and what each caught alone. Fix every finding, or list it as a deliberate exception for the user to accept. A clean scan is a floor, not a verdict: a monotone grid with uniform spacing passes every detector rule, which is exactly what the assessment exists to catch. State in your final summary which path ran (parallel sub-agents or single-context fallback).
|
||||
Before editing, name:
|
||||
|
||||
---
|
||||
- the primary reading or task path;
|
||||
- what belongs together and what must separate;
|
||||
- which element leads and which supports;
|
||||
- the intended density and spacing rhythm;
|
||||
- how the structure changes across containers, viewports, input modes, and content extremes.
|
||||
|
||||
## Assess Current Layout
|
||||
Choose the simplest structural model that expresses those relationships. Use layout primitives according to the relationships they control, and name reusable spacing and container roles semantically.
|
||||
|
||||
This checklist is sub-agent A's brief (on the fallback path, work through it yourself before the pre-scan). Analyze what's weak about the current spatial design:
|
||||
## Apply
|
||||
|
||||
1. **Spacing**:
|
||||
- Is spacing consistent or arbitrary? (Random padding/margin values)
|
||||
- Is all spacing the same? (Equal padding everywhere = no rhythm)
|
||||
- Are related elements grouped tightly, with generous space between groups?
|
||||
- Group by meaning. Use proximity before adding containers or decoration.
|
||||
- Create rhythm through deliberate contrast between tight and generous intervals.
|
||||
- Use a documented spacing scale rather than one-off values. A 4-unit base usually provides the useful middle steps that an 8-only scale misses.
|
||||
- Let hierarchy follow product priority, not framework defaults.
|
||||
- Keep distinct content visually distinct without turning every group into an isolated component.
|
||||
- Make responsive behavior structural: reorder, collapse, reflow, or reveal based on what remains important.
|
||||
- Prefer container-aware components when the same component appears in different contexts.
|
||||
- Use `gap` for sibling rhythm when it expresses the relationship more directly than child margins.
|
||||
- Keep touch targets usable even when their visible marks are small.
|
||||
- Use depth only when it clarifies state or hierarchy.
|
||||
- Make optical corrections only after inspecting the rendered result.
|
||||
|
||||
2. **Visual hierarchy**:
|
||||
- Apply the squint test: blur your (metaphorical) eyes. Can you still identify the most important element, second most important, and clear groupings?
|
||||
- Is hierarchy achieved effectively? (Space and weight alone can be enough; is the current approach working?)
|
||||
- Does whitespace guide the eye to what matters?
|
||||
Variation is not a goal by itself. Repetition should support recognition; break it only when content or priority changes.
|
||||
|
||||
3. **Grid & structure**:
|
||||
- Is there a clear underlying structure, or does the layout feel random?
|
||||
- Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly)
|
||||
## Verify
|
||||
|
||||
4. **Rhythm & variety**:
|
||||
- Does the layout have visual rhythm? (Alternating tight/generous spacing)
|
||||
- Is every section structured the same way? (Monotonous repetition)
|
||||
- Are there intentional moments of surprise or emphasis?
|
||||
- The squint test still reveals the primary, secondary, and major groups in order.
|
||||
- The reading and task path remains clear at every supported size.
|
||||
- Related content groups naturally; unrelated content does not blur together.
|
||||
- Tight and generous spacing create intentional rhythm instead of monotonous repetition.
|
||||
- Density matches use frequency and content complexity.
|
||||
- Long text, empty states, localization, zoom, and dynamic content do not break the structure.
|
||||
- Keyboard, touch, and assistive-technology order agree with the visual order.
|
||||
- The final mechanical scan has no unexplained findings.
|
||||
|
||||
5. **Density**:
|
||||
- Is the layout too cramped? (Not enough breathing room)
|
||||
- Is the layout too sparse? (Excessive whitespace without purpose)
|
||||
- Does density match the content type? (Data-dense UIs need tighter spacing; marketing pages need more air)
|
||||
Answer each item with rendered or source evidence, then rerun the scan. Do not substitute a bare “yes” for verification.
|
||||
|
||||
**CRITICAL**: Layout problems are often the root cause of interfaces feeling "off" even when colors and fonts are fine. Space is a design material; use it with intention.
|
||||
|
||||
## Plan Layout Improvements
|
||||
|
||||
Create a systematic plan:
|
||||
|
||||
- **Spacing system**: Use a consistent scale (a framework's built-in scale like Tailwind's, rem-based tokens, or a custom system). The specific values matter less than consistency.
|
||||
- **Hierarchy strategy**: How will space communicate importance?
|
||||
- **Layout approach**: What structure fits the content? Flex for 1D, Grid for 2D, named areas for complex page layouts.
|
||||
- **Rhythm**: Where should spacing be tight vs generous?
|
||||
|
||||
## Improve Layout Systematically
|
||||
|
||||
### Establish a Spacing System
|
||||
|
||||
- Use a consistent spacing scale (framework scales like Tailwind, rem-based tokens, or a custom scale all work). What matters is that values come from a defined set, not arbitrary numbers.
|
||||
- Prefer a 4pt base scale (4, 8, 12, 16, 24, 32, 48, 64, 96px) over 8pt; 8pt is too coarse and you'll frequently need 12px between 8 and 16.
|
||||
- Name tokens semantically if using custom properties: `--space-xs` through `--space-xl`, not `--spacing-8`
|
||||
- Use `gap` for sibling spacing instead of margins; eliminates margin collapse hacks
|
||||
- Apply `clamp()` for fluid spacing that breathes on larger screens
|
||||
|
||||
### Create Visual Rhythm
|
||||
|
||||
- **Tight grouping** for related elements (8-12px between siblings)
|
||||
- **Generous separation** between distinct sections (48-96px)
|
||||
- **Varied spacing** within sections (not every row needs the same gap)
|
||||
- **Asymmetric compositions**: a deliberate choice when the content invites it (not a default to chase).
|
||||
|
||||
### Choose the Right Layout Tool
|
||||
|
||||
- **Use Flexbox for 1D layouts**: Rows of items, nav bars, button groups, card contents, most component internals.
|
||||
- **Use Grid for 2D layouts**: Page-level structure, dashboards, data-dense interfaces, anything where rows AND columns need coordinated control.
|
||||
- Use named grid areas (`grid-template-areas`) for complex page layouts; redefine at breakpoints.
|
||||
- Use **container queries** for components, viewport queries for page layouts. A card in a narrow sidebar can stay compact while the same card in a main content area expands automatically:
|
||||
|
||||
```css
|
||||
.card-container { container-type: inline-size; }
|
||||
.card { display: grid; gap: var(--space-md); }
|
||||
@container (min-width: 400px) {
|
||||
.card { grid-template-columns: 120px 1fr; }
|
||||
}
|
||||
```
|
||||
|
||||
### Break Card Grid Monotony
|
||||
|
||||
- Don't default to card grids for everything; spacing and alignment create visual grouping naturally
|
||||
- Use cards only when content is truly distinct and actionable. Never nest cards inside cards
|
||||
- Vary card sizes, span columns, or mix cards with non-card content to break repetition
|
||||
|
||||
### Strengthen Visual Hierarchy
|
||||
|
||||
- Use the fewest dimensions needed for clear hierarchy. Space alone can be enough; generous whitespace around an element draws the eye. Some of the most polished designs achieve rhythm with just space and weight. Add color or size contrast only when simpler means aren't sufficient.
|
||||
- The best hierarchy combines 2–3 dimensions at once. A heading that's larger, bolder, AND has more space above it reads as primary without trying:
|
||||
|
||||
| Tool | Strong Hierarchy | Weak Hierarchy |
|
||||
|------|------------------|----------------|
|
||||
| **Size** | 3:1 ratio or more | <2:1 ratio |
|
||||
| **Weight** | Bold vs Regular | Medium vs Regular |
|
||||
| **Color** | High contrast | Similar tones |
|
||||
| **Position** | Top/left (primary) | Bottom/right |
|
||||
| **Space** | Surrounded by white space | Crowded |
|
||||
|
||||
- Be aware of reading flow: in LTR languages, the eye naturally scans top-left to bottom-right, but primary action placement depends on context (e.g., bottom-right in dialogs, top in navigation).
|
||||
- Create clear content groupings through proximity and separation.
|
||||
|
||||
### Manage Depth & Elevation
|
||||
|
||||
- Build a consistent shadow scale (sm → md → lg → xl); shadows should be subtle
|
||||
- Use elevation to reinforce hierarchy, not as decoration
|
||||
|
||||
### Optical Adjustments
|
||||
|
||||
- If an icon looks visually off-center despite being geometrically centered, nudge it. But only if you're confident it actually looks wrong. Don't adjust speculatively.
|
||||
- Text at `margin-left: 0` looks slightly indented because of letterform whitespace; a negative margin (`-0.05em`) optically aligns it. Geometrically centered glyphs often look off-center (play icons need to shift right, arrows shift toward their direction).
|
||||
- Touch targets must be 44×44px minimum even when the visual element is smaller. Expand the hit area with padding or a pseudo-element:
|
||||
|
||||
```css
|
||||
.icon-button { width: 24px; height: 24px; position: relative; }
|
||||
.icon-button::before {
|
||||
content: ''; position: absolute; inset: -10px;
|
||||
}
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
- Use arbitrary spacing values outside your scale
|
||||
- Make all spacing equal (variety creates hierarchy)
|
||||
- Wrap everything in cards (not everything needs a container)
|
||||
- Nest cards inside cards (use spacing and dividers for hierarchy within)
|
||||
- Use identical card grids everywhere (icon + heading + text, repeated)
|
||||
- Default to the hero metric layout (big number, small label, stats, gradient) as a template. If showing real user data, a prominent metric can work, but it should display actual data, not decorative numbers.
|
||||
|
||||
## Verify Layout Improvements
|
||||
|
||||
- **Squint test**: Can you identify primary, secondary, and groupings with blurred vision?
|
||||
- **Rhythm**: Does the page have a satisfying beat of tight and generous spacing?
|
||||
- **Hierarchy**: Is the most important content obvious within 2 seconds?
|
||||
- **Breathing room**: Does the layout feel comfortable, not cramped or wasteful?
|
||||
- **Consistency**: Is the spacing system applied uniformly?
|
||||
- **Responsiveness**: Does the layout adapt gracefully across screen sizes?
|
||||
|
||||
Answer each item above by citing the file, selector, or value that satisfies it; never a bare yes. Then re-run the pre-scan and fix until the count of unresolved items and unaccepted findings is zero.
|
||||
|
||||
When the rhythm and hierarchy land, hand off to `$impeccable polish` for the final pass.
|
||||
When the structure holds, hand off to `$impeccable polish`.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
Each variant MUST declare a `density` param. Drive all spacing tokens in the variant's scoped CSS through `calc(var(--p-density, 1) * <base>)`: paddings, gaps, column widths. Users slide from airy to packed and see layout re-breathe with no regeneration.
|
||||
Every variant declares a coarse `density` parameter and authors spacing against `var(--p-density, 1)`.
|
||||
|
||||
```json
|
||||
{"id":"density","kind":"range","min":0.6,"max":1.4,"step":0.05,"default":1,"label":"Density"}
|
||||
```
|
||||
|
||||
For variants whose topology genuinely changes (stacked vs. side-by-side, grid vs. bento), use a `steps` param whose scoped CSS branches via `:scope[data-p-structure="X"]`. One structure param + one density param is a powerful combo; resist adding a third.
|
||||
|
||||
```json
|
||||
{"id":"structure","kind":"steps","default":"grid","label":"Structure","options":[
|
||||
{"value":"stacked","label":"Stacked"},
|
||||
{"value":"grid","label":"Grid"},
|
||||
{"value":"bento","label":"Bento"}
|
||||
]}
|
||||
```
|
||||
|
||||
See `reference/live.md` for the full params contract.
|
||||
Add one structural parameter only when the topology genuinely branches. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -35,7 +35,7 @@ Chat is overhead. No recap, no tutorial output, no pasting PRODUCT / DESIGN bodi
|
||||
node .agents/skills/impeccable/scripts/live.mjs
|
||||
```
|
||||
|
||||
Output JSON: `{ ok, serverPort, serverToken, pageFiles, hasProduct, product, productPath, hasDesign, design, designPath }`. `pageFiles` is the list of HTML entries the live script was injected into. Keep PRODUCT.md and DESIGN.md in mind for variant generation; **DESIGN.md wins on visual decisions; PRODUCT.md wins on strategic/voice decisions.** When DESIGN.md is missing, identity is **not** absent; extract it from CSS variables, computed styles, and sibling components on the page (see Step 4 Phase A). Identity preservation is the default; departure from existing identity requires an explicit trigger from PRODUCT.md anti-references or the user's freeform prompt.
|
||||
Output JSON: `{ ok, serverPort, serverToken, pageFiles, hasProduct, product, productPath, hasDesign, design, designPath }`. `pageFiles` is the list of HTML entries the live script was injected into. Keep PRODUCT.md, DESIGN.md, and any surface brief already loaded by Setup in mind for variant generation: **DESIGN.md wins on visual decisions; PRODUCT.md wins on durable product and voice decisions; the surface brief wins on this surface's strategy.** When DESIGN.md is missing, identity is **not** absent; extract it from CSS variables, computed styles, and sibling components on the page (see Step 4 Phase A). Identity preservation is the default; departure requires the user's explicit redesign/replacement intent.
|
||||
|
||||
`serverPort` and `serverToken` belong to the small **Impeccable live helper** HTTP server (serves `/live.js`, SSE, and `/poll`). That port is **not** your dev server and is usually not the URL you open to view the app. The browser page is whatever origin serves one of the `pageFiles` entries (Vite / Next / Bun / tunnel / LAN hostname).
|
||||
|
||||
@@ -189,7 +189,7 @@ All three carry `fallback: "agent-driven"`. Follow **Handle fallback** below.
|
||||
|
||||
### 3. Load the action's reference
|
||||
|
||||
If `event.action` is `impeccable` (the default freeform action), use SKILL.md's shared laws plus the loaded register reference (`brand.md` or `product.md`). Do not load a sub-command reference. **Freeform is not a pass to skip parameters:** you still follow the composition budget and the freeform bias in **§7 Parameters** below. Sub-command files list MUST-have signature knobs; freeform has no such file, so sizing knobs from surface weight and primary axes is entirely on you.
|
||||
If `event.action` is `impeccable` (the default freeform action), use SKILL.md's shared laws and decide the visitor mode from the selected surface. Do not load a sub-command reference. **Freeform is not a pass to skip parameters:** you still follow the composition budget and the freeform bias in **§7 Parameters** below. Sub-command files list MUST-have signature knobs; freeform has no such file, so sizing knobs from surface weight and primary axes is entirely on you.
|
||||
|
||||
Any other `event.action` (`bolder`, `quieter`, `distill`, `polish`, `typeset`, `colorize`, `layout`, `adapt`, `animate`, `delight`, `overdrive`): Read `reference/<action>.md` before planning. Each sub-command encodes a specific discipline; skipping its reference produces generic output. Those files may require specific params; layer them on top of the §7 budget, not instead of it.
|
||||
|
||||
@@ -218,7 +218,7 @@ Write down what you see in **one sentence**. The sentence describes the surface
|
||||
|
||||
Be specific. "Modern" is not a color, "elegant" is not a type pairing, "clean" is not a layout. If you can't extract a real value for an axis, skip it rather than fabricate. The point is to record what is, not to describe what you wish it were.
|
||||
|
||||
Do not include adjectives that name an aesthetic family ("editorial-leaning", "terminal-flavored", "brutalist"); those are conclusions, not data. They belong to Phase C lane selection in departure mode, not to identity description. Letting them sneak into Phase A is how the identity-lock collapses into a self-fulfilling prophecy.
|
||||
Do not name an aesthetic family in this sentence; that is a conclusion, not observed identity data. Letting conclusions into Phase A collapses the identity lock into a self-fulfilling prophecy.
|
||||
|
||||
This sentence is the **identity lock**. Every variant must be readable as the same brand if rendered side by side. Skipping this phase is the primary cause of off-brand variants. Absence of DESIGN.md is never an excuse; extract from CSS and computed styles instead.
|
||||
|
||||
@@ -226,10 +226,7 @@ This sentence is the **identity lock**. Every variant must be readable as the sa
|
||||
|
||||
**Default mode**: the existing identity is preserved. Variants vary expression axes within it. *This is the right mode for ~90% of live sessions.* The user picked an element on a real product they're shipping; they expect variants of *their* hero, not three different brands' heroes.
|
||||
|
||||
**Departure mode**: the existing identity is rejected. Variants propose alternatives consistent with PRODUCT.md voice. Trigger only when at least one is true:
|
||||
|
||||
- PRODUCT.md anti-references explicitly call out the current surface ("the current `index.html` is itself an example"; "diffuse away from this"; "the page on screen is the failure"). Generic anti-references that describe what to avoid in general do **not** trigger departure mode; only ones that point at *this* surface specifically.
|
||||
- The user's freeform prompt explicitly asks for departure ("rebuild this from scratch", "what if it weren't editorial at all", "show me something completely different").
|
||||
**Departure mode**: the existing identity is rejected. Variants propose alternatives consistent with durable product and brand truth. Trigger only when the user explicitly asks for departure in the current request or freeform prompt ("redesign this", "rebuild this from scratch", "what if it weren't editorial at all", "show me something completely different"). A stale page critique or an old task note is not replacement authorization.
|
||||
|
||||
If you're unsure, you're in default mode. The cost of being wrong about default is "three on-brand variants with similar feel": recoverable, the user picks none. The cost of being wrong about departure is "three off-brand variants": unrecoverable, the user is annoyed.
|
||||
|
||||
@@ -248,13 +245,13 @@ Three variants → three DIFFERENT axes. The trio reads as *the same brand at th
|
||||
|
||||
**While planning each variant, also name its 2–3 parameter knobs** (per the §7 budget table). Parameters are part of the design, not a decoration added afterward. If the variant explores density, expose a density knob. If it explores color commitment, expose a color-amount range. Deciding "what's tunable" during planning produces better knobs than retrofitting them onto finished HTML.
|
||||
|
||||
**Departure mode.** Each variant anchors to a different **aesthetic direction**, derived from the brand's stated voice and register in PRODUCT.md. Do NOT pick from a fixed catalog of lane categories. The right three directions for this brand are not the same as the right three for another brand, and picking from a list is itself the training-data reflex (the model selects "Swiss-grid, Terminal, Industrial-signage" every time because those are the furthest-from-editorial items in any enumerated list).
|
||||
**Departure mode.** Each variant anchors to a different **aesthetic direction**, derived from PRODUCT.md's audience world and voice plus the current DESIGN.md. Do not pick from a fixed catalog; derive directions from this product.
|
||||
|
||||
Instead, work from the brand:
|
||||
|
||||
1. Read PRODUCT.md's Brand Personality words. What physical, spatial, or material experiences would embody those words if design were not involved? (A personality described as "specific, earned, unmistakable" evokes a hand-stamped letter, a numbered print, a watchmaker's loupe. A personality described as "restless, loud, unfiltered" evokes a concert poster, a spray-painted wall, a megaphone.)
|
||||
1. Read PRODUCT.md's Brand Personality words. Derive physical, spatial, or material experiences that embody them without starting from a design style.
|
||||
2. From those physical experiences, derive three visual directions that are genuinely different from each other AND from the current surface you're departing.
|
||||
3. Avoid the **reflex-reject lanes** in [brand.md](brand.md). Don't trade one monoculture for another. If you find yourself reaching for "Swiss-grid" or "Terminal" or "Industrial-signage" by reflex, you are pattern-matching a catalog in your training data, not reading the brand. Start over from the personality words.
|
||||
3. Reject any direction chosen by reflex rather than derived from the brand. Start over from the personality words when the rationale could fit a neighboring product.
|
||||
4. Each direction must be expressible in one concrete sentence that names a real-world referent ("a museum exhibition label system for a contemporary art gallery" not "clean and minimal"). If your sentence contains only adjectives, it's not concrete enough.
|
||||
5. **While planning each direction, also name its 2–3 parameter knobs** (per the §7 budget table). The same principle as default mode: decide "what's tunable" during planning, not after writing the HTML. A departure-mode hero with 0 parameters is not "bold creative vision," it's a missed opportunity for the user to fine-tune the direction they pick.
|
||||
|
||||
@@ -264,7 +261,7 @@ Instead, work from the brand:
|
||||
|
||||
**Departure mode squint.** Two passes, family before sentence:
|
||||
|
||||
1. **Family pass.** Label each variant with one design-family word of your own choosing (any concrete noun: *exhibition, storefront, cockpit, recipe-card, playbill, field-manual*). If any two variants share a label, or if the label could apply to the other variants equally well, rework. Do not use a fixed vocabulary list for the labels. *This pass is non-negotiable in departure mode and catches the monoculture failure that the sentence pass misses.*
|
||||
1. **Family pass.** Give each variant a concrete family label of your own choosing. If two variants share a label, or a label fits another variant equally well, rework. Do not use a fixed vocabulary. *This pass is non-negotiable in departure mode and catches monoculture the sentence pass misses.*
|
||||
2. **Sentence pass.** Write three one-sentence descriptions side by side. If two of them rhyme ("both feature big type" / "both are stacks of sections" / "both center the CTA"), rework the offender.
|
||||
|
||||
**When the primary axis is color or theme, forbid the trio from sharing theme + dominant hue.** Two dark-plus-one-dark is not distinct. Aim for three color worlds, not three shades of the same.
|
||||
@@ -291,7 +288,7 @@ In **default mode**, the prompt narrows the axes you choose, not the identity. *
|
||||
|
||||
In **departure mode**, the prompt narrows the lanes you draw from, not the families. *"Make it feel like a newspaper front page"* would itself be a departure-mode prompt; honor it but pick three meaningfully different newspaper-adjacent lanes (broadsheet vs. tabloid vs. trade journal), and run the family pass to confirm they don't collapse into one.
|
||||
|
||||
When the prompt and PRODUCT.md anti-references conflict (the prompt asks for X, the anti-references ban X), the anti-references win; they describe the brand's standing position, the prompt is one moment.
|
||||
When the prompt conflicts with a confirmed binding brand commitment or DESIGN.md invariant, preserve the invariant unless the user explicitly revokes or replaces it. Task-local strategy from the matching surface brief may change when the user changes that surface's goal.
|
||||
|
||||
### 6. Write all variants in a single edit
|
||||
|
||||
|
||||
@@ -1,47 +1,178 @@
|
||||
# New identity work
|
||||
# New visual work
|
||||
|
||||
Read this only when the project has no committed visual identity, or the user explicitly asked to replace the current one. A missing DESIGN.md is not enough: code, tokens, chosen type, components, and assets are incumbent design authority. If they exist, preserve and extend them unless the brief says to discard them.
|
||||
This flow owns the durable visual world when authority is absent, expanding, or explicitly replaced, plus only as much task-level shaping as the requested scope needs. PRODUCT.md owns product truth, DESIGN.md confirmed visual truth, and `.impeccable/surfaces/` durable task strategy. Complete [init.md](init.md) first when PRODUCT.md is missing. Missing DESIGN.md does not route back to init.
|
||||
|
||||
This playbook is task-scoped. PRODUCT.md owns durable product facts and DESIGN.md owns durable visual invariants; the direction for one page or feature belongs in the current task, not in either document.
|
||||
## 1. Name the intent
|
||||
|
||||
## Choose the authority
|
||||
- **Greenfield:** no coherent visual implementation.
|
||||
- **Local extension:** a section, feature, component, or state inside an established surface and world.
|
||||
- **New surface:** a whole page, route, screen, flow, or standalone experience inside an established world.
|
||||
- **Expression expansion:** an established brand entering an unresolved whole-surface family or app boundary.
|
||||
- **Redesign/rebrand:** replace the world while preserving unchanged product truth, content, function, native affordances, constraints, and brand commitments.
|
||||
- **Refinement:** leave this flow for the scoped command; preserve the world and scope.
|
||||
|
||||
Classify the work before inventing anything:
|
||||
A plain “redesign this page/site” authorizes replacement. “Redesign this within the current brand/system” means extension or refinement. Ask once only when the wording is genuinely ambiguous.
|
||||
|
||||
- **Extend**: an incumbent system exists and the task adds or improves a surface. Preserve its lineage, semantics, and affordances.
|
||||
- **Surface redesign**: the current identity remains, but this surface may change its topology, hierarchy, and expression.
|
||||
- **New identity**: nothing committed exists, or the user explicitly authorized a rebrand.
|
||||
## 2. Resolve visual authority
|
||||
|
||||
When the evidence is mixed, preserve. Novelty is not permission to erase authored decisions.
|
||||
Read DESIGN.md and representative code, tokens, components, and assets. Choose one path:
|
||||
|
||||
## Find the concept
|
||||
### A. Explicit redesign
|
||||
|
||||
Name the subject, audience, page job, and visitor mode from SKILL.md. Then identify the product's unique mechanism: what it does, proves, or enables that a neighboring product cannot truthfully claim.
|
||||
The old DESIGN.md and implementation are not authority. Keep only unrevoked product facts, content, function, native expectations, constraints, and brand commitments. Establish a replacement world.
|
||||
|
||||
Derive the concept from that mechanism through one primary transformation: information topology, evidence, temporal behavior, or spatial mapping. The transformation must change how the surface is organized or behaves, not merely how it is decorated. This produces stranger and more defensible work than imitating a culturally specific document or object. Borrowing a literal cultural form is allowed only when it is genuinely native to the product and audience, and never as costume.
|
||||
### B. DESIGN.md covers this kind of surface
|
||||
|
||||
For **Operate** and **Read**, start with the task and information structure. Native controls remain native controls; expression comes from hierarchy, density, rhythm, state, and the system around them. For **Persuade** and **Experience** creating a new identity, explore more freely, but keep the product legible and the primary action obvious.
|
||||
Use its invariants and normative tokens. Skip world-building and discover the surface.
|
||||
|
||||
Run `node .agents/skills/impeccable/scripts/concept-seed.mjs` only for Persuade or Experience new-identity work when two or more directions remain equally credible. It is an entropy source, not an authority: never let the draw overrule the strongest fit. When color is genuinely unconstrained, `node .agents/skills/impeccable/scripts/palette.mjs` may break a reflex palette; subject evidence and incumbent color still win.
|
||||
### C. A coherent implementation exists but DESIGN.md does not
|
||||
|
||||
## State the direction
|
||||
Code, assets, tokens, type, and component behavior are incumbent authority. Run [document.md](document.md) in scan mode and confirm extracted invariants before writing DESIGN.md. Do not offer replacement worlds unless the user asked for a redesign.
|
||||
|
||||
Before code, write a task-scoped direction contract of at most 120 words in your reasoning:
|
||||
### D. The brand exists, but a whole-surface family is unresolved
|
||||
|
||||
- the thesis this surface owns;
|
||||
- the structural or behavioral transformation;
|
||||
- what authority is preserved;
|
||||
- the first viewport's composition and primary action;
|
||||
- the signature element the surface will be remembered by.
|
||||
Preserve logo, color/type assets, voice, recognizable component/motion traits, and constraints. Ask what must carry and where expression may expand. Offer two or three compatible ranges, not replacement identities, and merge the choice into DESIGN.md. Use a child-app DESIGN.md when the range is local.
|
||||
|
||||
Do not embed this contract as a comment in the production artifact or turn it into a second design system. In an attended substantial build, confirm it once. In an unattended run, record it and continue.
|
||||
A section, feature, component, or state inside a coherent existing surface stays on B or C. Its surrounding surface is authority even when DESIGN.md is incomplete.
|
||||
|
||||
## Build once, commit fully
|
||||
### E. No confirmed visual authority exists
|
||||
|
||||
Plan one compact token system and one layout source: the concept or the content's real structure. Build the strongest coherent direction once. Commitment means the transformation governs the whole surface; it does not mean every control must be rebuilt as a metaphor.
|
||||
Establish a world. Scaffolds, framework defaults, and stray utilities are not identity.
|
||||
|
||||
Make the first viewport demonstrate the product's mechanism. Pace long surfaces through contrast in density and scale, and cut sections that only repeat claims. Briefs that depend on imagery ship real, verified imagery. Preserve semantic HTML, familiar interaction behavior, accessibility, and the project's technical conventions.
|
||||
## 3. Discover the requested surface
|
||||
|
||||
## Finish proportionally
|
||||
Name this surface's audience, job, visitor mode, real content, primary action/task, evidence, constraints, and memorable moment. PRODUCT.md supplies truth and DESIGN.md the world; neither decides narrative or composition.
|
||||
|
||||
Inspect desktop and mobile, write one honest critique against the brief and direction, patch material defects, then run the detector once. Repeat only when a real defect remains. A separate reviewer is optional when the harness already provides one and the extra cost is earned by the risk; it is not a default step and its presence is not evidence of quality.
|
||||
Ask one attended round of at most three material questions without repeating durable facts. CTA hierarchy, proof sequence, content gaps, and interaction outcomes belong here, not PRODUCT.md. For a fully specified narrow request, state the interpretation and invite correction.
|
||||
|
||||
When `shape` has already completed its discovery interview, reuse those confirmed answers and do not ask this round again.
|
||||
|
||||
Classify the scope before ideation. A section, feature, component, or state that must join an existing page is a local extension. A page, route, screen, flow, or standalone experience may be a new surface. Do not inflate local work into a surface concept merely because it benefits from a novel layout.
|
||||
|
||||
## 4. Shape or select the direction
|
||||
|
||||
Do not select a new world and its first surface concept in separate tournaments. That creates a safe global choice followed by a more interesting local choice whose “lineage” exists only in prose.
|
||||
|
||||
### Local extension inside stable authority: shape, do not seed
|
||||
|
||||
For a local extension on path B or C, inherit both the visual world and the surrounding surface's direction. Resolve only the decisions the addition actually introduces: purpose, content, hierarchy, state or interaction, and how it joins the existing sequence. Use short, related question rounds when those decisions are still open. Do not run `concept-seed.mjs`, generate competing surface metaphors, or offer alternate visual worlds. The result may still have an authored, surprising layout; its novelty must come from the material and the established grammar, not a new identity thesis.
|
||||
|
||||
If a local request reveals a genuine gap in the brand system, name that gap and ask before treating it as path D. Do not silently turn a case-study section or feature into an expression-expansion exercise.
|
||||
|
||||
### A, D, or E: choose a coupled world and first expression
|
||||
|
||||
For a replacement world, unresolved brand expansion, or no authority, make one coupled decision:
|
||||
|
||||
1. **Ground.** Use PRODUCT.md, incumbent commitments that still bind, and the surface discovery above. Name what this surface uniquely does, proves, or enables.
|
||||
2. **Derive pairs.** Generate five to seven grounded directions. Each candidate joins a durable visual system (identity thesis, information/layout grammar, material and type behavior, color strategy, imagery, motion, reusable signature) to a concrete expression for this surface (topology, sequence, focal moment, and implementation consequence). Do not rank yet.
|
||||
3. **Break the ranking rut once.** Run `node .agents/skills/impeccable/scripts/concept-seed.mjs --scope direction`. Promote the assigned grounded pair and weigh its challengers only when they can become both a coherent system and a strong solution to this task.
|
||||
4. **Test coupling and breadth.** Reject a pair if its surface could swap into another candidate unchanged, or if its world is merely the surface motif repeated. Test each survivor on the requested surface plus navigation, quiet and dense content, interaction/state, and one unlike future surface. Compare it with both the category habit and predictable contrarian response.
|
||||
5. **Offer coupled choices.** Present two or three materially different pairs without recommendation cues. For each, show the world rules, this surface's expression, cross-surface consequence, and risk. Ask what is closest, should combine, or feels wrong; rejection is allowed.
|
||||
6. **Resolve once.** The user selects or revises the pair. Extract the durable rules into DESIGN.md and the task-specific strategy into the surface brief; do not reopen either half independently.
|
||||
|
||||
Without an answer mechanism, use the assigned grounded pair only if it survives product fit, coupling, and breadth; mark assumptions. This is fallback, not user choice.
|
||||
|
||||
### B or C, whole surface only: choose a direction inside stable authority
|
||||
|
||||
The visual world supplies the vocabulary; the task concept supplies the sentence.
|
||||
|
||||
1. Derive five to seven structural candidates from the content, mechanism, audience, and confirmed authority. Translate its relationships and behavior, not just its styling.
|
||||
2. Run `node .agents/skills/impeccable/scripts/concept-seed.mjs --scope surface` only when a whole page, route, screen, flow, or standalone experience calls for high-concept exploration. Otherwise shape the strongest grounded structure directly. Never run it for a local extension.
|
||||
3. Name the habitual arrangement and predictable contrarian response. Judge candidates skin-blind: topology, sequence, or interaction must remain different after names and styling disappear.
|
||||
4. When materially different whole-surface choices would help, present two or three neutral options with thesis, sequence, focal moment, signature, implementation consequence, and concrete inherited world rules. Let the user select or revise before code.
|
||||
|
||||
Without an answer mechanism, use the promoted candidate when a roll ran; otherwise use the strongest grounded structure. It must survive both tests.
|
||||
|
||||
For a substantial high-fidelity surface with native image generation, load [codex.md](codex.md) after selection. Probes stay inside the selected direction. For `shape`, stop after selection and continue in [shape.md](shape.md).
|
||||
|
||||
### Write or update DESIGN.md
|
||||
|
||||
For A or E, write or replace DESIGN.md at the resolved project/app boundary using the [format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md). For D, merge only the approved expansion range. Record the chosen durable rules and add:
|
||||
|
||||
`<!-- STATUS: DIRECTIONAL SEED; exact tokens remain provisional until the first implementation pass. -->`
|
||||
|
||||
Do not fabricate YAML tokens; add exact values only after the user, assets, or implementation establishes them. The selected pair authorizes its world and first expression together without another confirmation. A local extension does not change DESIGN.md unless the user approves a durable system addition.
|
||||
|
||||
## 5. Persist the surface brief
|
||||
|
||||
Once the primary target or route is known, persist durable surface-level product/UX strategy separately from PRODUCT.md and DESIGN.md. Prefer a clone-stable source file; map routes and alternate entries as related targets. For a local extension, update the parent surface's record only when the work establishes durable product strategy; do not create a component-level brief by reflex. Read any record first:
|
||||
|
||||
`node .agents/skills/impeccable/scripts/surface-brief.mjs read <primary-target>`
|
||||
|
||||
Exit 0: preserve still-valid decisions and change only what the user changed. For redesign, retain valid product strategy, content, function, and open decisions; replace visual direction and contract. Exit 2: no brief. After the contract, write with `node .agents/skills/impeccable/scripts/surface-brief.mjs write <primary-target> <body-file> [related-target ...]`.
|
||||
|
||||
The body is concise and contains:
|
||||
|
||||
```markdown
|
||||
# Surface brief: [name]
|
||||
|
||||
## Scope
|
||||
[Primary/related route or artifact, visitor mode, and what this surface owns.]
|
||||
|
||||
## Product strategy
|
||||
[Surface-specific audience and job, desired outcome, primary/secondary action or task, content and proof sequence, factual constraints, and explicitly open decisions.]
|
||||
|
||||
## Selected direction
|
||||
[Reference to the applicable DESIGN.md world or expression range, selected surface concept, focal moment, narrative/interaction sequence, and implementation consequence.]
|
||||
|
||||
## Direction contract
|
||||
[The six contract blocks below.]
|
||||
|
||||
## Open decisions
|
||||
[Only unresolved items that later work must not silently invent. Omit when empty.]
|
||||
```
|
||||
|
||||
Commit `.impeccable/surfaces/<target-slug>.md` as stable later-work context. Exclude global truth, exact tokens, transient notes, and work logs.
|
||||
|
||||
## 6. Write the direction contract for a whole surface
|
||||
|
||||
If a competent default could satisfy the concept, sharpen its focal moment until one product-specific move changes implementation. Difficulty must clarify the product, not add spectacle.
|
||||
|
||||
Before code, write a direction contract of at most 150 words in an opening HTML or framework comment. The first 200 characters must name `DIRECTION CONTRACT`.
|
||||
|
||||
- `UNIQUE`: the task thesis tied to the product mechanism;
|
||||
- `NOT-TEMPLATE`: the category-default arrangement this structure refuses;
|
||||
- `OWN-WORLD`: the confirmed DESIGN.md invariants, tokens, and materials it uses;
|
||||
- `STORY`: what the visitor understands, believes, and does;
|
||||
- `FIRST VIEWPORT`: exact composition, hierarchy, action, and where the concept exceeds competent convention;
|
||||
- `FORM`: chosen structure or behavior, signature, implementation consequence, and seed key.
|
||||
|
||||
The contract is task-scoped, inspectable, and subordinate to the user's choice. Put the same six blocks in the surface brief and artifact comment.
|
||||
|
||||
A local extension skips this contract unless the user explicitly wants it to become a distinct authored moment. Use the shaped decisions as the implementation plan instead.
|
||||
|
||||
## 7. Plan, build, and commit
|
||||
|
||||
Plan from the selected direction or local shape and real content, never a category skeleton. In redesign, remove inherited visual tokens.
|
||||
|
||||
Load only needed specialist references. Focal interaction or authored animation reads [animate.md](animate.md), even without the `animate` command.
|
||||
|
||||
Build the strongest coherent direction once. Its grammar governs navigation, actions, controls, content, and transitions without disguising affordances. Give the focal form the scale that gives it force; do not trap it inside a standard hero panel.
|
||||
|
||||
**Make the opening a thesis.** Demonstrate the mechanism immediately; leave an idea, interaction, or evidence, not merely mood.
|
||||
|
||||
**Commit before correcting.** Land the hard move at full strength before refining it. In unattended work, safety is the known risk.
|
||||
|
||||
**Commit at page scale.** Let color, material, image, or type own a region when the world calls for it. Scattered signature decoration is not commitment.
|
||||
|
||||
**Pace the whole surface.** Vary density, scale, image, motion, and quiet inside one grammar. Cut repeated claims; prove the mechanism with real artifact, interaction, data, transformation, or content.
|
||||
|
||||
**Author motion as material.** Motion expresses the world and task. Premium moments go beyond repeated transform/opacity through earned focus, depth, masks, continuity, light, or material change. Bound expensive effects, test in-browser, keep content visible by default, and design reduced motion.
|
||||
|
||||
Preserve semantics, affordances, accessibility, performance, responsiveness, and project conventions. Operate/Read express through topology, hierarchy, density, rhythm, and state; Persuade/Experience may earn drama.
|
||||
|
||||
## 8. Solidify the visual record
|
||||
|
||||
After first implementation of a new/replacement world or approved expansion, refresh DESIGN.md from the build:
|
||||
|
||||
- replace provisional direction with the exact type, color roles, tokens, spacing/radii, components, states, and motion that survived;
|
||||
- add normative YAML tokens only for values the implementation actually uses;
|
||||
- remove the directional-seed status once the record and implementation agree;
|
||||
- preserve broader world invariants and expression ranges;
|
||||
- do not promote the task's story, hero composition, or one-off motif into a global rule unless it is intentionally reusable.
|
||||
|
||||
Ordinary extension does not rewrite DESIGN.md; only approved durable changes do.
|
||||
|
||||
## 9. Finish like a studio
|
||||
|
||||
Inspect desktop and mobile; critique against the brief, DESIGN.md, and the applicable shape, concept, or contract; patch material defects; recheck skin-blind. Follow the quality guidance supplied by `context.mjs` and hooks. Context requests a manual scan only when no automatic detector is active; never add another detector pass. Fix real gaps and classify false positives until none remain. Add a reviewer only when risk earns it.
|
||||
|
||||
@@ -4,7 +4,7 @@ When design SERVES the product: app UIs, admin dashboards, settings panels, data
|
||||
|
||||
## The product slop test
|
||||
|
||||
Not "would someone say AI made this." Familiarity is often a feature here. The test is: would a user fluent in the category's best tools (Linear, Figma, Notion, Raycast, Stripe come to mind) sit down and trust this interface, or pause at every subtly-off component?
|
||||
Familiarity is often a feature here. The test is whether a category-fluent user can trust the interface immediately or must pause at every subtly-off component.
|
||||
|
||||
Product UI's failure mode isn't flatness, it's strangeness without purpose: over-decorated buttons, mismatched form controls, gratuitous motion, display fonts where labels should be, invented affordances for standard tasks. The bar is earned familiarity. The tool should disappear into the task.
|
||||
|
||||
@@ -41,7 +41,7 @@ Every interactive component has: default, hover, focus, active, disabled, loadin
|
||||
- Motion conveys state, not decoration. State change, feedback, loading, reveal: nothing else.
|
||||
- No orchestrated page-load sequences. Product loads into a task; users don't want to watch it load.
|
||||
|
||||
## Product bans (on top of the shared absolute bans)
|
||||
## Product constraints
|
||||
|
||||
- Decorative motion that doesn't convey state.
|
||||
- Inconsistent component vocabulary across screens. If the "save" button looks different in two places, one is wrong.
|
||||
@@ -54,7 +54,7 @@ Every interactive component has: default, hover, focus, active, disabled, loadin
|
||||
|
||||
Product can afford things brand surfaces can't.
|
||||
|
||||
- System fonts and familiar sans defaults (Inter, SF Pro, system-ui stacks).
|
||||
- System fonts and familiar sans defaults.
|
||||
- Standard navigation patterns: top bar + side nav, breadcrumbs, tabs, command palettes.
|
||||
- Density. Tables with many rows, panels with many labels, dense information when users need it.
|
||||
- Consistency over surprise. The same visual vocabulary screen to screen is a virtue; delight is saved for moments, not pages.
|
||||
|
||||
@@ -1,241 +1,98 @@
|
||||
> **Additional context needed**: quality bar (MVP vs flagship).
|
||||
> **Additional context needed**: quality bar and shipping constraints.
|
||||
|
||||
Perform a meticulous final pass to catch all the small details that separate good work from great work. The difference between shipped and polished.
|
||||
Polish is refinement, never concealed redesign. Preserve the incumbent visual world, content, behavior, and everything outside scope. If the concept itself is wrong, say so and recommend redesign or `bolder` instead of smuggling in a replacement.
|
||||
|
||||
Detector and automated QA output are defect evidence only. A clean script result is never proof that the design is strong; gather browser evidence and inspect the real interaction path.
|
||||
A detector result is defect evidence, not proof of quality. Inspect the rendered experience and real interaction path.
|
||||
|
||||
## Design System Discovery
|
||||
## 1. Establish the system
|
||||
|
||||
Aligning the feature to the design system is **not optional**. Polish without alignment is decoration on top of drift, and it makes the next person's job harder. Discovery comes before any other polish work.
|
||||
Read DESIGN.md and representative tokens, shared components, patterns, and neighboring flows. If no formal system exists, use coherent project conventions.
|
||||
|
||||
1. **Find the design system**: Search for design system documentation, component libraries, style guides, or token definitions. Study the core patterns: design principles, target audience, color tokens, spacing scale, typography styles, component API, motion conventions.
|
||||
2. **Note the conventions**: How are shared components imported? What spacing scale is used? Which colors come from tokens vs hard-coded values? What motion and interaction patterns are established? What flow shapes are used for comparable actions (modal vs full-page, inline vs route, save-on-blur vs explicit submit)?
|
||||
3. **Identify drift, then name the root cause**: For every deviation, classify it as a **missing token** (the value should exist in the system but doesn't), a **one-off implementation** (a shared component already exists but wasn't used), or a **conceptual misalignment** (the feature's flow, IA, or hierarchy doesn't match neighboring features). The fix differs by category: patch the value, swap to the shared component, or rework the flow. Fixing the symptom without naming the cause is how drift compounds.
|
||||
Classify each drift before fixing it:
|
||||
|
||||
If a design system exists, polish **must** align the feature with it. If none exists, polish against the conventions visible in the codebase. **If anything about the system is ambiguous, ask. Never guess at design system principles.**
|
||||
- **missing token:** the system needs a reusable value;
|
||||
- **one-off implementation:** an existing shared component or pattern should replace it;
|
||||
- **conceptual mismatch:** the flow, information architecture, or hierarchy differs from comparable product areas;
|
||||
- **local defect:** the implementation is simply incomplete or inconsistent.
|
||||
|
||||
## Pre-Polish Assessment
|
||||
Fix the cause at the narrowest correct level. Ask when a binding system principle cannot be inferred.
|
||||
|
||||
Understand the current state and goals before touching anything:
|
||||
## 2. Gather the evidence
|
||||
|
||||
1. **Review completeness**:
|
||||
- Is it functionally complete?
|
||||
- Are there known issues to preserve (mark with TODOs)?
|
||||
- What's the quality bar? (MVP vs flagship feature?)
|
||||
- When does it ship? (How much time for polish?)
|
||||
Use the feature yourself at representative desktop and mobile sizes. Determine:
|
||||
|
||||
2. **Think experience-first**: Who actually uses this, and what's the best possible experience for them? Effective design beats decorative polish; a feature that looks beautiful but fights the user's flow is not polished. Walk the path from their perspective before opening DevTools.
|
||||
- whether the path is functionally complete;
|
||||
- the intended quality bar and time available;
|
||||
- known constraints or deliberately unfinished work;
|
||||
- the states, content lengths, roles, and input methods users will actually encounter.
|
||||
|
||||
3. **Identify polish areas**:
|
||||
- Visual inconsistencies
|
||||
- Spacing and alignment issues
|
||||
- Interaction state gaps
|
||||
- Copy inconsistencies
|
||||
- Edge cases and error states
|
||||
- Loading and transition smoothness
|
||||
- Information architecture and flow drift (does this feature reveal complexity the way neighboring features do?)
|
||||
If a prior critique exists, use it as one input:
|
||||
|
||||
4. **Pull in any prior critique** (optional signal): If `$impeccable critique` has been run on the same target, its priority issues are a useful prior for what to address first. Resolve the target to a file path or URL, then:
|
||||
```bash
|
||||
slug=$(node .agents/skills/impeccable/scripts/critique-storage.mjs slug "<resolved>")
|
||||
node .agents/skills/impeccable/scripts/critique-storage.mjs latest "$slug"
|
||||
```
|
||||
Exit 0 with body = found; fold the P0/P1 items into your polish list and mention the snapshot path so the user sees what you read. Exit 2 = no snapshot, continue without it. The critique is one input among many. Do your own pass either way.
|
||||
```bash
|
||||
slug=$(node .agents/skills/impeccable/scripts/critique-storage.mjs slug "<resolved target>")
|
||||
node .agents/skills/impeccable/scripts/critique-storage.mjs latest "$slug"
|
||||
```
|
||||
|
||||
5. **Triage cosmetic vs functional**: Classify each issue as **cosmetic** (looks off, doesn't impede the user) or **functional** (breaks, blocks, or confuses the experience). When polish time is tight, functional issues ship first; cosmetic ones can land in a follow-up. Quality should be consistent; never perfect one corner while leaving another rough.
|
||||
Exit 0 returns the latest snapshot; incorporate relevant P0/P1 findings and name the snapshot read. Exit 2 means none exists. Perform an independent pass either way.
|
||||
|
||||
**CRITICAL**: Polish is the last step, not the first. Don't polish work that's not functionally complete.
|
||||
## 3. Triage
|
||||
|
||||
## Polish Systematically
|
||||
Separate functional defects from cosmetic ones and fix in this order:
|
||||
|
||||
Work through these dimensions methodically:
|
||||
1. broken or blocked tasks, data loss, misleading state, and inaccessible paths;
|
||||
2. missing loading, empty, error, success, disabled, and permission states;
|
||||
3. flow, hierarchy, responsive, and design-system drift;
|
||||
4. visual and motion inconsistencies;
|
||||
5. code and asset cleanup.
|
||||
|
||||
### Visual Alignment & Spacing
|
||||
Do not perfect one corner while leaving the rest below the same quality bar.
|
||||
|
||||
- **Pixel-perfect alignment**: Everything lines up to grid
|
||||
- **Consistent spacing**: All gaps use spacing scale (no random 13px gaps)
|
||||
- **Optical alignment**: Adjust for visual weight (icons may need offset for optical centering)
|
||||
- **Responsive consistency**: Spacing and alignment work at all breakpoints
|
||||
- **Grid adherence**: Elements snap to baseline grid
|
||||
## 4. Polish the whole path
|
||||
|
||||
**Check**:
|
||||
- Enable grid overlay and verify alignment
|
||||
- Check spacing with browser inspector
|
||||
- Test at multiple viewport sizes
|
||||
- Look for elements that "feel" off
|
||||
### Flow and hierarchy
|
||||
|
||||
### Information Architecture & Flow
|
||||
- Match neighboring mental models, terminology, disclosure, routing, save behavior, and optimistic or pessimistic patterns.
|
||||
- Make the primary task and current state obvious without flattening every element to equal weight.
|
||||
- Ensure arrival, transition, empty, and recovery paths connect instead of behaving as isolated screens.
|
||||
|
||||
Visual polish on a misshapen flow is wasted work. Match the *shape* of the experience to the system, not just the surface.
|
||||
### Layout and type
|
||||
|
||||
- **Progressive disclosure**: Match how much is revealed when, compared to neighboring features. A settings page exposing 40 fields when the rest of the app reveals 5 at a time is drift, even if every field is perfectly styled.
|
||||
- **Established user flows**: Multi-step actions follow the same shape as comparable flows elsewhere: modal vs full-page, inline edit vs separate route, save-on-blur vs explicit submit, optimistic vs pessimistic updates.
|
||||
- **Hierarchy & complexity**: The same conceptual weight gets the same visual weight throughout. Primary actions don't become tertiary in one corner of the product, and tertiary actions don't shout.
|
||||
- **Empty, loading, and arrival transitions**: How content arrives, updates, and leaves matches how it does in adjacent features.
|
||||
- **Naming and mental model**: The feature uses the same nouns and verbs as the rest of the system. A "Workspace" here shouldn't be a "Project" three screens away.
|
||||
- Align to the project's grid and spacing scale; fix optical as well as mathematical alignment.
|
||||
- Group related content tightly and separate distinct groups generously.
|
||||
- Keep same-role typography consistent; test measure, wrapping, localization expansion, zoom, and font loading.
|
||||
- Verify every supported viewport rather than correcting only the current screenshot.
|
||||
|
||||
### Typography Refinement
|
||||
### Color, imagery, and icons
|
||||
|
||||
- **Hierarchy consistency**: Same elements use same sizes/weights throughout
|
||||
- **Line length**: 45-75 characters for body text
|
||||
- **Line height**: Appropriate for font size and context
|
||||
- **Widows & orphans**: No single words on last line
|
||||
- **Hyphenation**: Appropriate for language and column width
|
||||
- **Kerning**: Adjust letter spacing where needed (especially headlines)
|
||||
- **Font loading**: No FOUT/FOIT flashes
|
||||
- Use semantic tokens and stable color meanings across themes.
|
||||
- Verify text, control, and focus contrast in every state.
|
||||
- Keep icon families, stroke/weight, sizing, and optical alignment coherent.
|
||||
- Prevent image layout shift; use correct aspect ratios, responsive sources, and useful alt text.
|
||||
|
||||
### Color & Contrast
|
||||
### Interaction and state
|
||||
|
||||
- **Contrast ratios**: All text meets WCAG standards
|
||||
- **Consistent token usage**: No hard-coded colors, all use design tokens
|
||||
- **Theme consistency**: Works in all theme variants
|
||||
- **Color meaning**: Same colors mean same things throughout
|
||||
- **Accessible focus**: Focus indicators visible with sufficient contrast
|
||||
- **Gray on color**: Never put gray text on colored backgrounds; use a shade of that color or transparency
|
||||
- Every control needs appropriate default, hover, focus, active, disabled, loading, error, and success behavior.
|
||||
- Preserve visible keyboard focus, logical tab order, labels, and platform-appropriate touch targets.
|
||||
- Keep motion coherent, interruptible, performant, and reduced-motion aware. Do not add animation merely to make polish visible.
|
||||
- Validate long, missing, localized, offline, slow, and permission-limited content where the product can encounter it.
|
||||
|
||||
### Interaction States
|
||||
### Content and code
|
||||
|
||||
Every interactive element needs all states:
|
||||
- Keep terminology, capitalization, punctuation, and factual copy consistent. Ask before changing claims.
|
||||
- Remove debug output, dead code, unused imports, obsolete styles, and polish-created duplication.
|
||||
- Replace custom implementations with shared components where the system owns the pattern.
|
||||
- Promote genuinely reusable values to tokens; do not create a system abstraction for one local exception.
|
||||
|
||||
- **Default**: Resting state
|
||||
- **Hover**: Subtle feedback (color, scale, shadow)
|
||||
- **Focus**: Keyboard focus indicator (never remove without replacement)
|
||||
- **Active**: Click/tap feedback
|
||||
- **Disabled**: Clearly non-interactive
|
||||
- **Loading**: Async action feedback
|
||||
- **Error**: Validation or error state
|
||||
- **Success**: Successful completion
|
||||
## 5. Verify and finish
|
||||
|
||||
**Missing states create confusion and broken experiences**.
|
||||
Walk the complete path again with mouse, keyboard, and touch where applicable. Check:
|
||||
|
||||
### Micro-interactions & Transitions
|
||||
- mobile, intermediate, and wide layouts;
|
||||
- loading, empty, error, success, disabled, long-content, and missing-content states;
|
||||
- zoom, contrast, focus, semantics, screen-reader names, and reduced motion;
|
||||
- console errors, layout shift, interaction latency, image loading, and supported browsers;
|
||||
- agreement with DESIGN.md, neighboring features, and the user's scope.
|
||||
|
||||
- **Smooth transitions**: All state changes animated appropriately (150-300ms)
|
||||
- **Consistent easing**: Use ease-out-quart/quint/expo for natural deceleration. Never bounce or elastic; they feel dated.
|
||||
- **No jank**: Smooth animations; use atmospheric blur/filter/mask/shadow effects when they add polish, but bound expensive paint areas and avoid casual layout-property animation
|
||||
- **Appropriate motion**: Motion serves purpose, not decoration
|
||||
- **Reduced motion**: Respects `prefers-reduced-motion`
|
||||
Follow the quality guidance supplied by `context.mjs` and hooks, then run any other relevant QA commands. Context requests a manual scan only when no automatic detector is active; never add another detector pass. Fix real defects and document only narrow intentional exceptions. A clean scan does not replace visual judgment.
|
||||
|
||||
### Content & Copy
|
||||
|
||||
- **Consistent terminology**: Same things called same names throughout
|
||||
- **Consistent capitalization**: Title Case vs Sentence case applied consistently
|
||||
- **Grammar & spelling**: No typos
|
||||
- **Appropriate length**: Not too wordy, not too terse
|
||||
- **Punctuation consistency**: Periods on sentences, not on labels (unless all labels have them)
|
||||
|
||||
### Icons & Images
|
||||
|
||||
- **Consistent style**: All icons from same family or matching style
|
||||
- **Appropriate sizing**: Icons sized consistently for context
|
||||
- **Proper alignment**: Icons align with adjacent text optically
|
||||
- **Alt text**: All images have descriptive alt text
|
||||
- **Loading states**: Images don't cause layout shift, proper aspect ratios
|
||||
- **Retina support**: 2x assets for high-DPI screens
|
||||
|
||||
### Forms & Inputs
|
||||
|
||||
- **Label consistency**: All inputs properly labeled
|
||||
- **Required indicators**: Clear and consistent
|
||||
- **Error messages**: Helpful and consistent
|
||||
- **Tab order**: Logical keyboard navigation
|
||||
- **Auto-focus**: Appropriate (don't overuse)
|
||||
- **Validation timing**: Consistent (on blur vs on submit)
|
||||
|
||||
### Edge Cases & Error States
|
||||
|
||||
- **Loading states**: All async actions have loading feedback
|
||||
- **Empty states**: Helpful empty states, not just blank space
|
||||
- **Error states**: Clear error messages with recovery paths
|
||||
- **Success states**: Confirmation of successful actions
|
||||
- **Long content**: Handles very long names, descriptions, etc.
|
||||
- **No content**: Handles missing data gracefully
|
||||
- **Offline**: Appropriate offline handling (if applicable)
|
||||
|
||||
### Responsiveness
|
||||
|
||||
- **All breakpoints**: Test mobile, tablet, desktop
|
||||
- **Touch targets**: 44x44px minimum on touch devices
|
||||
- **Readable text**: No text smaller than 14px on mobile
|
||||
- **No horizontal scroll**: Content fits viewport
|
||||
- **Appropriate reflow**: Content adapts logically
|
||||
|
||||
### Performance
|
||||
|
||||
- **Fast initial load**: Optimize critical path
|
||||
- **No layout shift**: Elements don't jump after load (CLS)
|
||||
- **Smooth interactions**: No lag or jank
|
||||
- **Optimized images**: Appropriate formats and sizes
|
||||
- **Lazy loading**: Off-screen content loads lazily
|
||||
|
||||
### Code Quality
|
||||
|
||||
- **Remove console logs**: No debug logging in production
|
||||
- **Remove commented code**: Clean up dead code
|
||||
- **Remove unused imports**: Clean up unused dependencies
|
||||
- **Consistent naming**: Variables and functions follow conventions
|
||||
- **Type safety**: No TypeScript `any` or ignored errors
|
||||
- **Accessibility**: Proper ARIA labels and semantic HTML
|
||||
|
||||
## Polish Checklist
|
||||
|
||||
Go through systematically:
|
||||
|
||||
- [ ] Aligned to the design system (drift named and resolved by root cause)
|
||||
- [ ] Information architecture and flow shape match neighboring features
|
||||
- [ ] Visual alignment perfect at all breakpoints
|
||||
- [ ] Spacing uses design tokens consistently
|
||||
- [ ] Typography hierarchy consistent
|
||||
- [ ] All interactive states implemented
|
||||
- [ ] All transitions smooth (60fps)
|
||||
- [ ] Copy is consistent and polished
|
||||
- [ ] Icons are consistent and properly sized
|
||||
- [ ] All forms properly labeled and validated
|
||||
- [ ] Error states are helpful
|
||||
- [ ] Loading states are clear
|
||||
- [ ] Empty states are welcoming
|
||||
- [ ] Touch targets are 44x44px minimum
|
||||
- [ ] Contrast ratios meet WCAG AA
|
||||
- [ ] Keyboard navigation works
|
||||
- [ ] Focus indicators visible
|
||||
- [ ] No console errors or warnings
|
||||
- [ ] No layout shift on load
|
||||
- [ ] Works in all supported browsers
|
||||
- [ ] Respects reduced motion preference
|
||||
- [ ] Code is clean (no TODOs, console.logs, commented code)
|
||||
|
||||
**IMPORTANT**: Polish is about details. Zoom in. Squint at it. Use it yourself. The little things add up.
|
||||
|
||||
Sweat the details. Zoom in until the alignment is right and the spacing reads as deliberate. Then ship.
|
||||
|
||||
**NEVER**:
|
||||
- Polish before it's functionally complete
|
||||
- Polish without aligning to the design system; that's decoration on drift
|
||||
- Guess at design system principles instead of asking when something is ambiguous
|
||||
- Spend hours on polish if it ships in 30 minutes (triage)
|
||||
- Introduce bugs while polishing (test thoroughly)
|
||||
- Ignore systematic issues (if spacing is off everywhere, fix the system, not just one screen)
|
||||
- Perfect one thing while leaving others rough (consistent quality level)
|
||||
- Create new one-off components when design system equivalents exist
|
||||
- Hard-code values that should use design tokens
|
||||
- Introduce new patterns or flows that diverge from established ones
|
||||
|
||||
## Final Verification
|
||||
|
||||
Before marking as done:
|
||||
|
||||
- **Use it yourself**: Actually interact with the feature.
|
||||
- **Test on real devices**: Not just browser DevTools.
|
||||
- **Ask someone else to review**: Fresh eyes catch things.
|
||||
- **Compare to design**: Match intended design.
|
||||
- **Check all states**: Don't just test happy path.
|
||||
- **Treat automation carefully**: Run detector or QA commands when they are available and relevant, fix their defects, but never cite a clean result as proof that the work is polished.
|
||||
|
||||
## Clean Up
|
||||
|
||||
After polishing, ensure code quality:
|
||||
|
||||
- **Replace custom implementations**: If the design system provides a component you reimplemented, switch to the shared version.
|
||||
- **Remove orphaned code**: Delete unused styles, components, or files made obsolete by polish.
|
||||
- **Consolidate tokens**: If you introduced new values, check whether they should be tokens.
|
||||
- **Verify DRYness**: Look for duplication introduced during polishing and consolidate.
|
||||
Finish with a source diff: remove accidental churn, orphaned code, redundant values, and temporary artifacts. Ship only when the feature is functionally complete and consistently finished across the path.
|
||||
|
||||
@@ -2,7 +2,7 @@ Quiet design is harder than bold design. Subtlety needs precision. Reduce visual
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: "quieter" means more restrained palette, more whitespace, more typographic air. Drama is reduced, not eliminated; the POV stays intact.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Reason over the signals; there is no score to obey:
|
||||
- `critique.latest` with a low `score` or non-zero `p0` / `p1` → `polish` (it reads that snapshot as its backlog), or re-run `critique` if the snapshot looks stale.
|
||||
- `git.changedFiles` pointing at one surface → scope `audit` or `polish` to those files specifically, naming them.
|
||||
- `devServer.running` true → `live` is available for in-browser iteration; if false, don't lead with `live`. **`live` and the bundled `detect.mjs` are web-only.** If `setup.platform` is `ios`, `android`, or `adaptive`, don't lead with either; the browser overlay and the HTML rule engine don't apply to native app code.
|
||||
- Otherwise group by intent exactly as init's "Recommend starting points" step does (build new / improve what's there / iterate visually), tailored to `setup.register`.
|
||||
- Otherwise group by intent (build new / improve what's there / iterate visually), tailored to the current surface and `setup.platform`.
|
||||
|
||||
**If `scan.targets` is non-empty and `setup.platform` is not `ios`/`android`/`adaptive`, run `node .agents/skills/impeccable/scripts/detect.mjs --json <scan.targets joined by spaces>` once** (the bundled detector over local files: no network, no npx; it reads HTML/CSS, so skip it for native projects). `scan.via` tells you what they are: `git-changes` (the markup/style files in your dirty tree, the most relevant set), `source-dir` (e.g. `src`, `app`), `html`, or `root`. Fold the hits into your picks: many quality / contrast hits → `audit` or `polish`; a specific slop family → the matching command (gradient text or eyebrows → `quieter` / `typeset`, flat or gray palette → `colorize`, and so on). It's a real, current signal that beats guessing. If detect errors or the tree is large and slow, skip it and recommend the user run `audit` themselves; never block the suggestion on it.
|
||||
|
||||
|
||||
@@ -1,167 +1,61 @@
|
||||
Shape the UX and UI for a feature before any code is written. This command produces a **design brief**: a structured artifact that guides implementation through discovery, not guesswork.
|
||||
# Shape
|
||||
|
||||
**Scope**: Design planning only. This command does NOT write code. It produces the thinking that makes code good.
|
||||
Discover what should be made and how it should work, then return a confirmed design brief without code.
|
||||
|
||||
**Output**: A design brief that can be handed off to $impeccable craft, or directly to $impeccable for freeform implementation. When visual direction probes are used, the images are supporting artifacts, not the primary output.
|
||||
**Product gate:** when context reports that PRODUCT.md is missing, load and complete [init.md](init.md) before Phase 1. Do not substitute shape questions for the product interview. Once PRODUCT.md exists, return here; product context does not replace task discovery.
|
||||
|
||||
## Philosophy
|
||||
## Phase 1: Discovery interview
|
||||
|
||||
Most AI-generated UIs fail not because of bad code, but because of skipped thinking. They jump to "here's a card grid" without asking "what is the user trying to accomplish?" This command inverts that: understand deeply first, so implementation is precise.
|
||||
Do not write code or choose visual direction yet.
|
||||
|
||||
## Phase 1: Discovery Interview
|
||||
### Cadence
|
||||
|
||||
**Do NOT write any code or make any design decisions during this phase.** Your only job is to understand the feature deeply enough to make excellent design decisions later.
|
||||
- Use the structured question tool when available; otherwise ask and stop.
|
||||
- Ask two or three related questions per round, then wait. One round is the default; add a second only when the answers expose a material gap.
|
||||
- Do not dump a questionnaire, repeat settled facts, or turn obvious facts into menus. Assert the likely reading and invite correction.
|
||||
- A sparse prompt requires at least one answer round. A precise prompt may need only a compact confirmation.
|
||||
|
||||
**Unattended runs:** when no user can respond (a one-shot task, an automated run, or an explicit instruction not to ask questions), answer the interview questions yourself from the brief, record the answers as the design brief, and continue without pausing at any confirmation gate in this file. The thinking is still required; only the waiting is waived.
|
||||
### Round 1: purpose, people, and outcome
|
||||
|
||||
This is a required interaction, not optional guidance. Ask these questions in conversation, adapting based on answers. Don't dump them all at once; have a natural dialogue. STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer.
|
||||
Choose the two or three questions that most change the result:
|
||||
|
||||
### Interview cadence
|
||||
- What is this surface or feature for, and what problem must it solve?
|
||||
- Who specifically reaches it, in what situation and state of mind?
|
||||
- What is the primary thing they must understand or do? What would success look like?
|
||||
- What is uniquely true here that a neighboring product or generic template could not claim?
|
||||
|
||||
Discovery includes at least one user-answer round unless PRODUCT.md, DESIGN.md, or an already-confirmed brief directly answers the needed inputs. With a sparse prompt, do **not** synthesize a complete brief for confirmation on the first response.
|
||||
### Round 2: material, behavior, and boundaries
|
||||
|
||||
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop.
|
||||
- Ask **2-3 questions per round**, then wait for answers.
|
||||
- Treat PRODUCT.md and DESIGN.md as anchors; they reduce repeated questions but do **not** replace shape for craft. Shape is task-specific.
|
||||
- One round is the default. Add a second only if the first answers leave material gaps. Don't run a second round just to feel thorough.
|
||||
- Round 1 should clarify purpose, audience/context, content/scope, and (for brand) visual direction.
|
||||
- Round 2, when needed, fills in whatever's still genuinely missing.
|
||||
Run only for material unresolved decisions:
|
||||
|
||||
**Assert-then-confirm, not menu-with-escape.** When PRODUCT.md and the user's prompt make one option obvious, name it and ask the user to confirm or override. Don't enumerate "Restrained / Committed / Or something else?" as a real choice; "This reads as Restrained, confirm?" beats a four-option menu when the answer is already clear.
|
||||
- What real content, evidence, data, and assets must the experience carry? What are realistic minimum, typical, and maximum ranges?
|
||||
- Which states and transitions matter: first-run, empty, loading, error, success, permissions, overflow, or expert use?
|
||||
- What is the intended fidelity, breadth, and interactivity: exploration, production-ready screen, full flow, or broader surface?
|
||||
- What must remain untouched? What would make the result feel wrong even if it looked polished?
|
||||
- Which platform, framework, performance, accessibility, localization, or delivery constraints are binding?
|
||||
|
||||
### Purpose & Context
|
||||
- What is this feature for? What problem does it solve?
|
||||
- Who specifically will use it? (Not "users"; be specific: role, context, frequency)
|
||||
- What does success look like? How will you know this feature is working?
|
||||
- What's the user's state of mind when they reach this feature? (Rushed? Exploring? Anxious? Focused?)
|
||||
Never ask for CSS values or canned aesthetic lanes. New-work owns visual-world and concept choices.
|
||||
|
||||
### Content & Data
|
||||
- What content or data does this feature display or collect?
|
||||
- What are the realistic ranges? (Minimum, typical, maximum, e.g., 0 items, 5 items, 500 items)
|
||||
- What are the edge cases? (Empty state, error state, first-time use, power user)
|
||||
- Is any content dynamic? What changes and how often?
|
||||
- What visual assets are real content here? Note required images, product shots, illustrations, maps, textures, diagrams, generated objects, or existing project assets.
|
||||
## Phase 2: Resolve the design direction
|
||||
|
||||
### Design Direction
|
||||
For new surfaces, brand expansion, or replacement, follow [new-work.md](new-work.md) through visual authority, any world workshop, and concept choice. Reuse discovery, then return before its contract, persistence, or implementation. Inside an established world, use its concept process only when composition or interaction remains materially open.
|
||||
|
||||
Force a visual decision on three fronts. Skip anything PRODUCT.md or DESIGN.md already answers; ask only what's missing.
|
||||
## Phase 3: Write the brief
|
||||
|
||||
- **Color strategy for this surface.** Pick one: Restrained / Committed / Full palette / Drenched. Can override the project default if the surface earns it (e.g. a drenched hero inside an otherwise Restrained product).
|
||||
- **Theme via scene sentence.** Write one sentence of physical context for this surface: who uses it, where, under what ambient light, in what mood. The sentence forces dark vs light. If it doesn't, add detail until it does.
|
||||
- **Two or three named anchor references.** Specific products, brands, objects. Not adjectives like "modern" or "clean."
|
||||
Write the smallest useful brief:
|
||||
|
||||
### Scope
|
||||
1. **Job and audience:** who arrives, their context, need, and visitor mode.
|
||||
2. **Outcome and proof:** primary task/action, success, real evidence, and product-specific truth.
|
||||
3. **Selected direction:** visual authority, structural/interaction thesis, sequence, focal moment, and implementation consequence.
|
||||
4. **Scope and boundaries:** fidelity, breadth, interactivity, named target, what remains untouched, and explicit anti-goals.
|
||||
5. **States and ranges:** realistic content/data ranges and material states.
|
||||
6. **Interaction and layout:** hierarchy, topology, responsiveness, affordances, feedback, and transitions; intent, not CSS.
|
||||
7. **Constraints and open decisions:** platform, delivery, accessibility, localization, reusable components, and choices a builder must not invent.
|
||||
|
||||
Always ask. Sketch quality and shipped quality are different outputs; don't guess between them.
|
||||
Use three to five bullets when the task is settled; use the full structure only for ambiguous, multi-screen, or standalone planning. Do not restate the conversation.
|
||||
|
||||
- **Fidelity.** Sketch / mid-fi / high-fi / production-ready?
|
||||
- **Breadth.** One screen / a flow / a whole surface?
|
||||
- **Interactivity.** Static visual / interactive prototype / shipped-quality component?
|
||||
- **Time intent.** Quick exploration, or polish until it ships?
|
||||
## Confirm and stop
|
||||
|
||||
Scope answers are task-scoped. Don't write them to PRODUCT.md or DESIGN.md; carry them through the design brief only.
|
||||
Present the brief for explicit confirmation or one correction round, then stop: shape never writes code or a direction contract.
|
||||
|
||||
### Constraints
|
||||
- Are there technical constraints? (Framework, performance budget, browser support)
|
||||
- Are there content constraints? (Localization, dynamic text length, user-generated content)
|
||||
- Mobile/responsive requirements?
|
||||
- Accessibility requirements beyond WCAG AA?
|
||||
|
||||
### Anti-Goals
|
||||
- What should this NOT be? What would be a wrong direction?
|
||||
- What's the biggest risk of getting this wrong?
|
||||
|
||||
## Phase 1.5: Visual Direction Probe (Capability-Gated)
|
||||
|
||||
After the discovery interview, generate a small set of visual direction probes **before** writing the final brief when all of these are true:
|
||||
|
||||
- The work is **net-new** or directionally ambiguous enough that visual exploration will clarify the brief.
|
||||
- The requested fidelity is **mid-fi, high-fi, or production-ready**. Skip for sketch-only planning.
|
||||
- The current harness gives you native image generation (Codex's `image_gen`, an equivalent MCP tool, or similar). Don't ask the user to install APIs or tooling.
|
||||
|
||||
When those conditions are met, this step is mandatory. If image generation isn't natively available, do not ask the user to install APIs or tooling. State in one line that the image step is skipped because the harness lacks native image generation, then proceed. The one-line announcement is required, not optional; it forces a conscious decision instead of letting the step quietly evaporate.
|
||||
|
||||
Use probes to explore visual lanes, not to replace the brief.
|
||||
|
||||
Do not skip probes because the final UI will be semantic, editable, code-native, responsive, or accessible. Those are implementation requirements, not reasons to avoid visual exploration.
|
||||
|
||||
### What to generate
|
||||
|
||||
Generate **2 to 4** distinct direction probes based on the discovery answers, especially:
|
||||
|
||||
- Color strategy
|
||||
- Theme scene sentence
|
||||
- Named anchor references
|
||||
- Scope and fidelity
|
||||
|
||||
The probes should differ in primary visual direction (hierarchy, topology, density, typographic voice, or color strategy), not just palette tweaks.
|
||||
|
||||
### How to use the probes
|
||||
|
||||
- Treat them as **direction tests**, not final designs.
|
||||
- Use them to pressure-test whether the brief is pointing at the right lane.
|
||||
- Ask the user which direction feels closest, what feels off, and what should carry forward.
|
||||
- If the probes reveal a mismatch, revise the brief inputs before finalizing the brief.
|
||||
|
||||
### Important limits
|
||||
|
||||
- Do **not** skip discovery because image generation is available.
|
||||
- Do **not** treat generated imagery as final UX specification, final copy, or final accessibility behavior.
|
||||
- Do **not** use this step for minor refinements of existing work. It's for shaping a new surface or clarifying a big directional choice.
|
||||
|
||||
If image generation isn't natively available, announce the skip in one line and proceed to the design brief.
|
||||
|
||||
## Phase 2: Design Brief
|
||||
|
||||
After the interview and any required probes, present a brief and **end your response**. The user must confirm before any implementation runs. Do not present a brief and then continue to code in the same response, even if the brief feels obvious to you. The user's confirmation is the gate.
|
||||
|
||||
**Choose the brief shape based on how clear the answers are:**
|
||||
|
||||
- **Compact form (3-5 bullets)** when discovery was crisp and the original prompt + PRODUCT.md already pinned scope, content, and direction. State what you're building, the visual lane, and end with one or two specific questions or a clear "confirm or override?" prompt. This is the default for typical craft requests with a clear prompt.
|
||||
- **Full structured form (sections below)** when the task is genuinely ambiguous, multi-screen, or when the user asked for shape as a standalone step. Use this when the discipline of structure earns its weight.
|
||||
|
||||
Don't pad a clear brief into a long one to look thorough. A 70-line brief restating answers the user just gave is noise, not rigor. Equally, don't skip the confirmation pause to look efficient: the pause is the point.
|
||||
|
||||
Present the brief, then **stop and wait for explicit confirmation**. You are not the judge of whether the user already approved. Even when the brief feels obviously right, ask once and wait. The pause is what separates shape from premature implementation.
|
||||
|
||||
### Brief Structure
|
||||
|
||||
**1. Feature Summary** (2-3 sentences)
|
||||
What this is, who it's for, what it needs to accomplish.
|
||||
|
||||
**2. Primary User Action**
|
||||
The single most important thing a user should do or understand here.
|
||||
|
||||
**3. Design Direction**
|
||||
Color strategy (Restrained / Committed / Full palette / Drenched) + the theme scene sentence + 2–3 named anchor references. Reference PRODUCT.md and DESIGN.md where they already answer, and note any per-surface overrides.
|
||||
|
||||
If you ran the Visual Direction Probe step, name which probe direction won and what changed in the brief because of it.
|
||||
|
||||
**4. Scope**
|
||||
Fidelity, breadth, interactivity, and time intent from the Scope section of the interview. Task-scoped; these don't persist beyond the brief.
|
||||
|
||||
**5. Layout Strategy**
|
||||
High-level spatial approach: what gets emphasis, what's secondary, how information flows. Describe the visual hierarchy and rhythm, not specific CSS.
|
||||
|
||||
**6. Key States**
|
||||
List every state the feature needs: default, empty, loading, error, success, edge cases. For each, note what the user needs to see and feel.
|
||||
|
||||
**7. Interaction Model**
|
||||
How users interact with this feature. What happens on click, hover, scroll? What feedback do they get? What's the flow from entry to completion?
|
||||
|
||||
**8. Content Requirements**
|
||||
What copy, labels, empty state messages, error messages, and microcopy are needed. Note any dynamic content and its realistic ranges. For image-led surfaces, also list the required image/media roles and their likely source (project asset, generated raster, semantic SVG/CSS, canvas/WebGL, icon library, or accepted omission).
|
||||
|
||||
**9. Recommended References**
|
||||
Based on the brief, list which impeccable reference files would be most valuable during implementation (e.g., layout.md for complex layouts, animate.md for animated features, interaction-design.md for form-heavy features, typeset.md for typography-driven pages, colorize.md for color-led brands).
|
||||
|
||||
**10. Open Questions**
|
||||
Anything genuinely unresolved. Don't list "open questions" you've already recommended a default for; assert the default and move on. If you'd write `Recommend: X` next to a question, just decide X.
|
||||
|
||||
---
|
||||
|
||||
STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask for explicit confirmation of the brief before finishing.
|
||||
|
||||
If the user disagrees with any part, revisit the relevant discovery questions. A shape run is incomplete until the user confirms direction.
|
||||
|
||||
Once confirmed, the brief is complete. The user can now hand it to $impeccable, or use it to guide any other implementation approach. (If the user wants the full discovery-then-build flow in one step, they should use $impeccable craft instead, which runs this command internally.)
|
||||
When no human or structured answer mechanism exists, mark assumptions plainly, return the brief, and stop.
|
||||
|
||||
@@ -1,301 +1,80 @@
|
||||
Typography carries most of the information on the page. Replace generic defaults (Inter, Roboto, system fallback at flat scale) with type that reflects the brand and scales with intentional contrast.
|
||||
Typography carries information, hierarchy, and voice. Improve it inside the established visual world; do not replace the identity unless the user asked to.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
New identity work: run the font selection procedure in [new-work.md](new-work.md). Fluid `clamp()` scale, ≥1.25 ratio between steps.
|
||||
- **Persuade + Experience:** display type may carry the voice. Use decisive contrast and responsive scale when the composition benefits.
|
||||
- **Operate + Read:** stability, scanability, and measure come first. A single well-tuned family and fixed role scale are often right.
|
||||
- **Native:** follow [ios.md](ios.md) or [android.md](android.md), including platform scaling and accessibility behavior.
|
||||
|
||||
Operate + Read: system fonts and familiar sans stacks are legitimate here. One well-tuned family typically carries the whole UI. Fixed `rem` scale, 1.125–1.2 ratio between more closely-spaced steps. Long-form Read content wants a steady reading measure and a quiet, stable scale, not display-scale drama.
|
||||
If typography replacement would create a new identity, route through [new-work.md](new-work.md) and update DESIGN.md. Otherwise preserve confirmed families and improve their use.
|
||||
|
||||
---
|
||||
## Two isolated assessments
|
||||
|
||||
## Two isolated assessments (required)
|
||||
When a sub-agent tool is available and permitted, run these independently; otherwise run them yourself in this order. Do not let detector findings anchor the design assessment.
|
||||
|
||||
Spawn two parallel sub-agents whenever a sub-agent/Task tool is exposed: one for the typography assessment, one for the mechanical pre-scan. If the harness needs explicit user permission for sub-agents, stop and ask before proceeding. Isolation is the point: detector output anchors visual judgment toward what the scan can see, so neither sub-agent gets the other's output. Each assessment runs in its own sub-agent; running either one in this context when a sub-agent tool exists is not permitted, even when it is faster; the fallback below is only for sessions with no sub-agent tool. Give each a self-contained prompt (target files, register, **DESIGN.md** content when present, and its instructions below); do not assume it can read this file.
|
||||
|
||||
**Sub-agent A (typography assessment)**: give it the full [Assess Current Typography](#assess-current-typography) checklist below, verbatim, in its prompt. It works through every item and returns per-item findings citing file, selector, or value.
|
||||
|
||||
**Sub-agent B (mechanical pre-scan)**: run the bundled detector scoped to type:
|
||||
1. **Typographic assessment:** inspect representative pages and styles. Answer every question below with a file, selector, or computed value:
|
||||
- **Authority and fit:** Which faces, weights, and roles are established? Do they fit the product and selected world, or are they unexamined defaults? Is every family necessary?
|
||||
- **Hierarchy:** Can heading, body, label, metadata, and data roles be distinguished at a glance? Are adjacent sizes or weights too close to carry different jobs?
|
||||
- **Scale and consistency:** Is there a deliberate role scale, or a collection of arbitrary values? Do repeated roles stay identical across screens and states?
|
||||
- **Reading:** Does body copy stay within a comfortable 45–75 character measure? Are line height, paragraph rhythm, contrast, and tracking tuned to the actual face, width, language, and surface?
|
||||
- **Stress:** What happens with long headings, localization expansion, zoom, narrow containers, missing weights, and font fallback?
|
||||
- **Delivery:** Are only used assets loaded? Do fallback metrics, loading strategy, and variable-font settings avoid invisible text and disruptive reflow?
|
||||
2. **Mechanical scan:** run:
|
||||
|
||||
```bash
|
||||
node .agents/skills/impeccable/scripts/detect.mjs --json --scope type [target files or dirs]
|
||||
```
|
||||
|
||||
A missing `node` on PATH is not permission to skip: hunt for a runtime (`command -v node`, nvm or Homebrew paths, the harness's own bundled node) and run it by full path. If none exists, halt the scan and report that Node must be installed (the parent relays this to the user); do **not** substitute grep for the detector or proceed unscanned. The scan checks literal font sizes against the **DESIGN.md** ramp but abstains on `em`, `%`, `clamp()`, and line-heights, so also grep `font-size\s*:`, `fontSize`, `text-\[`, `leading-\[` and judge those hits against the spec. Return the findings JSON plus the grep verdicts.
|
||||
Also inspect dynamic or arbitrary font values the detector cannot interpret. Synthesize both assessments before editing, noting what each caught alone. A clean scan is a floor, not proof of good typography.
|
||||
|
||||
**If no sub-agent tool is exposed (or the user declined)**: run both yourself, assessment first, pre-scan second, so the deterministic findings can't anchor the visual judgment. Keep that order even when the scan feels quicker to start with.
|
||||
## Set the system
|
||||
|
||||
**Synthesize** once both are done: merge into a single findings list, noting where they agree and what each caught alone. Fix every finding, or list it as a deliberate exception for the user to accept. A clean scan is a floor, not a verdict: a generic font stack at a flat scale passes every detector rule, which is exactly what the assessment exists to catch. State in your final summary which path ran (parallel sub-agents or single-context fallback).
|
||||
Before editing, state:
|
||||
|
||||
---
|
||||
- the roles the interface needs;
|
||||
- the intended contrast between those roles;
|
||||
- the reading measure and density;
|
||||
- which existing faces and weights are authoritative;
|
||||
- any performance, localization, or accessibility constraints.
|
||||
|
||||
## Assess Current Typography
|
||||
Use the fewest roles and families that make the hierarchy unmistakable. Combine size, weight, space, and tone deliberately instead of asking size alone to do all the work. Role names and tokens should describe purpose rather than values.
|
||||
|
||||
This checklist is sub-agent A's brief (on the fallback path, work through it yourself before the pre-scan). Analyze what's weak or generic about the current type:
|
||||
## Apply
|
||||
|
||||
1. **Font choices**:
|
||||
- Are we using invisible defaults? (Inter, Roboto, Arial, Open Sans, system defaults)
|
||||
- Does the font match the brand personality? (A playful brand shouldn't use a corporate typeface)
|
||||
- Are there too many font families? (More than 2-3 is almost always a mess)
|
||||
- Keep body copy comfortably readable and zoomable. Use 1rem / 16px as the ordinary web body floor unless a dense role, platform convention, or user setting justifies otherwise.
|
||||
- Keep prose in the 45–75ch range. Tune line height inversely with measure: wider lines generally need more leading.
|
||||
- Compensate light text on dark surfaces on all three perceptual axes: slightly more line height, a touch more tracking, and one step more weight when the face needs it.
|
||||
- Tune line height to the face, width, language, and contrast, not a universal ratio.
|
||||
- Keep repeated roles consistent across screens and states.
|
||||
- Use numeric, tabular, code, and label features when their content benefits.
|
||||
- Load only used font assets and weights. Provide metric-compatible fallbacks and avoid blocking text.
|
||||
- Let marketing display type respond to available space when useful; keep dense product and reading surfaces spatially predictable.
|
||||
- Preserve browser zoom, user font settings, Dynamic Type, and platform text scaling.
|
||||
- Use paragraph spacing or first-line indentation as the primary paragraph rhythm; combining both usually double-marks the boundary.
|
||||
|
||||
2. **Hierarchy**:
|
||||
- Can you tell headings from body from captions at a glance?
|
||||
- Are font sizes too close together? (14px, 15px, 16px = muddy hierarchy)
|
||||
- Are weight contrasts strong enough? (Medium vs Regular is barely visible)
|
||||
Do not make type decorative at the expense of comprehension, or introduce a second family without a clear role it alone can perform.
|
||||
|
||||
3. **Sizing & scale**:
|
||||
- Is there a consistent type scale, or are sizes arbitrary?
|
||||
- Does body text meet minimum readability? (16px+)
|
||||
- Is the sizing strategy appropriate for the context? (Fixed `rem` scales for app UIs and long-form reading, where a steady measure beats display scale; fluid `clamp()` for marketing-page headings)
|
||||
## Verify
|
||||
|
||||
4. **Readability**:
|
||||
- Are line lengths comfortable? (45-75 characters ideal)
|
||||
- Is line-height appropriate for the font and context?
|
||||
- Is there enough contrast between text and background?
|
||||
- Primary, secondary, body, and metadata roles are recognizable without reading the copy.
|
||||
- Long text remains comfortable across relevant widths and languages.
|
||||
- The typography belongs to the product and its established world.
|
||||
- Loading does not create disruptive reflow or invisible text.
|
||||
- Zoom, text scaling, focus, contrast, and reduced viewport paths remain usable.
|
||||
- The final mechanical scan has no unexplained findings.
|
||||
|
||||
5. **Consistency**:
|
||||
- Are the same elements styled the same way throughout?
|
||||
- Are font weights used consistently? (Not bold in one section, semibold in another for the same role)
|
||||
- Is letter-spacing intentional or default everywhere?
|
||||
Answer each item with rendered or source evidence, then rerun the scan. Do not substitute a bare “yes” for verification.
|
||||
|
||||
**CRITICAL**: The goal isn't to make text "fancier." It's to make it clearer, more readable, and more intentional. Good typography is invisible; bad typography is distracting.
|
||||
|
||||
## Plan Typography Improvements
|
||||
|
||||
Consult the [Reference Material](#reference-material) section below for detailed guidance on scales, pairing, and loading strategies.
|
||||
|
||||
Create a systematic plan:
|
||||
|
||||
- **Font selection**: Do fonts need replacing? What fits the brand/context?
|
||||
- **Type scale**: Establish a modular scale (e.g., 1.25 ratio) with clear hierarchy
|
||||
- **Weight strategy**: Which weights serve which roles? (Regular for body, Semibold for labels, Bold for headings, or whatever fits)
|
||||
- **Spacing**: Line-heights, letter-spacing, and margins between typographic elements
|
||||
|
||||
## Improve Typography Systematically
|
||||
|
||||
### Font Selection
|
||||
|
||||
If fonts need replacing:
|
||||
- Choose fonts that reflect the brand personality
|
||||
- Pair with genuine contrast (serif + sans, geometric + humanist), or use a single family in multiple weights
|
||||
- Ensure web font loading doesn't cause layout shift (`font-display: swap`, metric-matched fallbacks)
|
||||
|
||||
### Establish Hierarchy
|
||||
|
||||
Build a clear type scale:
|
||||
- **5 sizes cover most needs**: caption, secondary, body, subheading, heading
|
||||
- **Use a consistent ratio** between levels (1.25, 1.333, or 1.5)
|
||||
- **Combine dimensions**: Size + weight + color + space for strong hierarchy. Don't rely on size alone
|
||||
- **App UIs**: Use a fixed `rem`-based type scale, optionally adjusted at 1-2 breakpoints. Fluid sizing undermines the spatial predictability that dense, container-based layouts need
|
||||
- **Marketing / content pages**: Use fluid sizing via `clamp(min, preferred, max)` for headings and display text. Keep body text fixed
|
||||
|
||||
### Fix Readability
|
||||
|
||||
- Set `max-width` on text containers using `ch` units (`max-width: 65ch`)
|
||||
- Adjust line-height per context: tighter for headings (1.1-1.2), looser for body (1.5-1.7)
|
||||
- Increase line-height slightly for light-on-dark text
|
||||
- Ensure body text is at least 16px / 1rem
|
||||
|
||||
### Refine Details
|
||||
|
||||
- Use `tabular-nums` for data tables and numbers that should align
|
||||
- Apply proper `letter-spacing`: slightly open for small caps and uppercase, default or tight for large display text
|
||||
- Use semantic token names (`--text-body`, `--text-heading`), not value names (`--font-16`)
|
||||
- Set `font-kerning: normal` and consider OpenType features where appropriate
|
||||
|
||||
### Weight Consistency
|
||||
|
||||
- Define clear roles for each weight and stick to them
|
||||
- Don't use more than 3-4 weights (Regular, Medium, Semibold, Bold is plenty)
|
||||
- Load only the weights you actually use (each weight adds to page load)
|
||||
|
||||
**NEVER**:
|
||||
- Use more than 2-3 font families
|
||||
- Pick sizes arbitrarily; commit to a scale
|
||||
- Set body text below 16px
|
||||
- Use decorative/display fonts for body text
|
||||
- Disable browser zoom (`user-scalable=no`)
|
||||
- Use `px` for font sizes; use `rem` to respect user settings
|
||||
- Default to Inter/Roboto/Open Sans when personality matters
|
||||
- Pair fonts that are similar but not identical (two geometric sans-serifs)
|
||||
|
||||
## Verify Typography Improvements
|
||||
|
||||
- **Hierarchy**: Can you identify heading vs body vs caption instantly?
|
||||
- **Readability**: Is body text comfortable to read in long passages?
|
||||
- **Consistency**: Are same-role elements styled identically throughout?
|
||||
- **Personality**: Does the typography reflect the brand?
|
||||
- **Performance**: Are web fonts loading efficiently without layout shift?
|
||||
- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%?
|
||||
|
||||
Answer each item above by citing the file, selector, or value that satisfies it; never a bare yes. Then re-run the pre-scan and fix until the count of unresolved items and unaccepted findings is zero.
|
||||
|
||||
When the type carries the hierarchy on its own, hand off to `$impeccable polish` for the final pass.
|
||||
When the hierarchy holds, hand off to `$impeccable polish`.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
Each variant MUST declare a `scale` param controlling the hierarchy ratio. Express all font sizes in the variant's scoped CSS through `calc(var(--p-scale, 1) * <base>)` or, better, scale the type ramp via `clamp(min, calc(var(--p-scale, 1) * Npx), max)`. Users slide from subdued to commanding.
|
||||
Every variant declares a coarse `scale` parameter and authors its type ramp against `var(--p-scale, 1)`.
|
||||
|
||||
```json
|
||||
{"id":"scale","kind":"range","min":0.85,"max":1.3,"step":0.05,"default":1,"label":"Scale"}
|
||||
```
|
||||
|
||||
Where the variant riffs on a specific pairing, expose the pairing choice as a `steps` param (e.g. "serif display + sans body" vs. "mono display + sans body" vs. "all-sans"). Each branch routes through `:scope[data-p-pairing="X"]` selectors in scoped CSS.
|
||||
|
||||
See `reference/live.md` for the full params contract.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `typography.md` and live inline now so the typeset flow has its deep typography reference in one place. `bolder.md` also references this section.
|
||||
|
||||
### Typography
|
||||
|
||||
#### Classic Typography Principles
|
||||
|
||||
##### Vertical Rhythm
|
||||
|
||||
Your line-height should be the base unit for ALL vertical spacing. If body text has `line-height: 1.5` on `16px` type (= 24px), spacing values should be multiples of 24px. This creates subconscious harmony; text and space share a mathematical foundation.
|
||||
|
||||
##### Modular Scale & Hierarchy
|
||||
|
||||
The common mistake: too many font sizes that are too close together (14px, 15px, 16px, 18px...). This creates muddy hierarchy.
|
||||
|
||||
**Use fewer sizes with more contrast.** A 5-size system covers most needs:
|
||||
|
||||
| Role | Typical Ratio | Use Case |
|
||||
|------|---------------|----------|
|
||||
| xs | 0.75rem | Captions, legal |
|
||||
| sm | 0.875rem | Secondary UI, metadata |
|
||||
| base | 1rem | Body text |
|
||||
| lg | 1.25-1.5rem | Subheadings, lead text |
|
||||
| xl+ | 2-4rem | Headlines, hero text |
|
||||
|
||||
Popular ratios: 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth). Pick one and commit.
|
||||
|
||||
##### Readability & Measure
|
||||
|
||||
Use `ch` units for character-based measure (`max-width: 65ch`). Line-height scales inversely with line length: narrow columns need tighter leading, wide columns need more.
|
||||
|
||||
**Non-obvious**: Light text on dark backgrounds needs compensation on three axes, not just one. Bump line-height by 0.05–0.1, add a touch of letter-spacing (0.01–0.02em), and optionally step the body weight up one notch (regular → medium). The perceived weight drops across all three; fix all three.
|
||||
|
||||
**Paragraph rhythm**: Pick either space between paragraphs OR first-line indentation. Never both. Digital usually wants space; editorial/long-form can justify indent-only.
|
||||
|
||||
#### Font Selection & Pairing
|
||||
|
||||
The tactical selection procedure and the reflex-reject list live in [new-work.md](new-work.md) (loaded for new identity work). The rest of this section covers the adjacent knowledge: anti-reflex corrections, system font use, and pairing rules.
|
||||
|
||||
##### Anti-reflexes worth defending against
|
||||
|
||||
- A technical/utilitarian brief does NOT need a serif "for warmth." Most tech tools should look like tech tools.
|
||||
- An editorial/premium brief does NOT need the same expressive serif everyone is using right now. Premium can be Swiss-modern, can be neo-grotesque, can be a literal monospace, can be a quiet humanist sans.
|
||||
- A children's product does NOT need a rounded display font. Kids' books use real type.
|
||||
- A "modern" brief does NOT need a geometric sans. The most modern thing you can do is not use the font everyone else is using.
|
||||
|
||||
**System fonts are underrated**: `-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui` looks native, loads instantly, and is highly readable. Consider this for apps where performance > personality.
|
||||
|
||||
##### Pairing Principles
|
||||
|
||||
**The non-obvious truth**: You often don't need a second font. One well-chosen font family in multiple weights creates cleaner hierarchy than two competing typefaces. Only add a second font when you need genuine contrast (e.g., display headlines + body serif).
|
||||
|
||||
When pairing, contrast on multiple axes:
|
||||
- Serif + Sans (structure contrast)
|
||||
- Geometric + Humanist (personality contrast)
|
||||
- Condensed display + Wide body (proportion contrast)
|
||||
|
||||
##### Web Font Loading
|
||||
|
||||
The layout shift problem: fonts load late, text reflows, and users see content jump. Here's the fix:
|
||||
|
||||
```css
|
||||
/* 1. Use font-display: swap for visibility */
|
||||
@font-face {
|
||||
font-family: 'CustomFont';
|
||||
src: url('font.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* 2. Match fallback metrics to minimize shift */
|
||||
@font-face {
|
||||
font-family: 'CustomFont-Fallback';
|
||||
src: local('Arial');
|
||||
size-adjust: 105%; /* Scale to match x-height */
|
||||
ascent-override: 90%; /* Match ascender height */
|
||||
descent-override: 20%; /* Match descender depth */
|
||||
line-gap-override: 10%; /* Match line spacing */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'CustomFont', 'CustomFont-Fallback', sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
Tools like [Fontaine](https://github.com/unjs/fontaine) calculate these overrides automatically.
|
||||
|
||||
**`swap` vs `optional`**: `swap` shows fallback text immediately and FOUT-swaps when the web font arrives. `optional` uses the fallback if the web font misses a small load budget (~100ms) and avoids the shift entirely. Pick `optional` when zero layout shift matters more than seeing the branded font on slow networks.
|
||||
|
||||
**Preload the critical weight only**: typically the regular-weight body font used above the fold. Preloading every weight costs more bandwidth than it saves.
|
||||
|
||||
**Variable fonts for 3+ weights or styles**: a single variable font file is usually smaller than three static weight files, gives fractional weight control, and pairs well with `font-optical-sizing: auto`. For 1–2 weights, static is fine.
|
||||
|
||||
#### Modern Web Typography
|
||||
|
||||
##### Fluid Type
|
||||
|
||||
Fluid typography via `clamp(min, preferred, max)` scales text smoothly with the viewport. The middle value (e.g., `5vw + 1rem`) controls scaling rate (higher vw = faster scaling). Add a rem offset so it doesn't collapse to 0 on small screens.
|
||||
|
||||
**Use fluid type for**: Headings and display text on marketing/content pages where text dominates the layout and needs to breathe across viewport sizes.
|
||||
|
||||
**Use fixed `rem` scales for**: App UIs, dashboards, and data-dense interfaces. No major app design system (Material, Polaris, Primer, Carbon) uses fluid type in product UI; fixed scales with optional breakpoint adjustments give the spatial predictability that container-based layouts need. Body text should also be fixed even on marketing pages, since the size difference across viewports is too small to warrant it.
|
||||
|
||||
**Bound your clamp()**: keep `max-size ≤ ~2.5 × min-size`. Wider ratios break the browser's zoom and reflow behaviour and make large viewports feel like the page is shouting.
|
||||
|
||||
**Scale container width and font-size together** so effective character measure stays in the 45–75ch band at every viewport. A heading that widens faster than its container drifts out of the comfortable measure at the top end.
|
||||
|
||||
##### OpenType Features
|
||||
|
||||
Most developers don't know these exist. Use them for polish:
|
||||
|
||||
```css
|
||||
/* Proper fractions */
|
||||
.recipe-amount { font-variant-numeric: diagonal-fractions; }
|
||||
|
||||
/* Small caps for abbreviations */
|
||||
abbr { font-variant-caps: all-small-caps; }
|
||||
|
||||
/* Disable ligatures in code */
|
||||
code { font-variant-ligatures: none; }
|
||||
|
||||
/* Enable kerning (usually on by default, but be explicit) */
|
||||
body { font-kerning: normal; }
|
||||
```
|
||||
|
||||
Check what features your font supports at [Wakamai Fondue](https://wakamaifondue.com/).
|
||||
|
||||
##### Rendering polish
|
||||
|
||||
```css
|
||||
/* Variable fonts: pick the right optical-size master automatically */
|
||||
body { font-optical-sizing: auto; }
|
||||
```
|
||||
|
||||
**ALL-CAPS tracking**: capitals sit too close at default spacing. Add 5–12% letter-spacing (`letter-spacing: 0.05em` to `0.12em`) to short all-caps labels, eyebrows, and small headings. Real small caps (via `font-variant-caps`) need the same treatment, slightly gentler.
|
||||
|
||||
#### Typography System Architecture
|
||||
|
||||
Name tokens semantically (`--text-body`, `--text-heading`), not by value (`--font-size-16`). Include font stacks, size scale, weights, line-heights, and letter-spacing in your token system.
|
||||
|
||||
#### Accessibility Considerations
|
||||
|
||||
Beyond contrast ratios (which are well-documented), consider:
|
||||
|
||||
- **Never disable zoom**: `user-scalable=no` breaks accessibility. If your layout breaks at 200% zoom, fix the layout.
|
||||
- **Use rem/em for font sizes**: This respects user browser settings. Never `px` for body text.
|
||||
- **Minimum 16px body text**: Smaller than this strains eyes and fails WCAG on mobile.
|
||||
- **Adequate touch targets**: Text links need padding or line-height that creates 44px+ tap targets.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: More than 2-3 font families per project. Skipping fallback font definitions. Ignoring font loading performance (FOUT/FOIT). Using decorative fonts for body text.
|
||||
Add at most one pairing or weight parameter when it represents a real system choice. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"craft": {
|
||||
"description": "Full confirmed-brief-then-build flow. Runs multi-round shape discovery first, resolves visual probe and north-star mock gates when available, then builds and visually iterates. Use when building a new feature end-to-end.",
|
||||
"description": "Deprecated compatibility alias for an ordinary Impeccable new-work request. It adds no behavior; natural build and redesign requests use the same flow.",
|
||||
"argumentHint": "[feature description]"
|
||||
},
|
||||
"init": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Concept-seed picker: the dice half of the new-work concept procedure.
|
||||
* External concept seed: the dice half of new-work's coupled-direction and
|
||||
* established-world surface procedures.
|
||||
*
|
||||
* The model derives a grounded shortlist of candidate FORMS from the
|
||||
* audience's world and the subject's cultural home (see
|
||||
@@ -12,10 +13,9 @@
|
||||
*
|
||||
* This script rolls them from outside, the same trick that made the
|
||||
* palette seed work:
|
||||
* - BUILD INDEX (2-5): which entry of the model's own resonance-ordered
|
||||
* shortlist to build. The dice never choose an ungrounded ingredient;
|
||||
* they only refuse the argmax rut. (Index 1 is excluded: that's the
|
||||
* concept every run would ship anyway.)
|
||||
* - PROMOTED INDEX: which entry of the model's own resonance-ordered
|
||||
* shortlist must be taken seriously beside its favorites. The dice never
|
||||
* choose an ungrounded ingredient; they only refuse the argmax rut.
|
||||
* - CHALLENGERS (3): outside forms from concept-ingredients.json, weighed
|
||||
* against the derived candidates on exactly two axes — audience
|
||||
* identification and product clarity. They win only when they beat the
|
||||
@@ -23,8 +23,8 @@
|
||||
* material and win over thin categories, which is the intended shape.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/concept-seed.mjs # roll at random
|
||||
* node scripts/concept-seed.mjs --from <key> # deterministic (hash key)
|
||||
* node scripts/concept-seed.mjs --scope direction
|
||||
* node scripts/concept-seed.mjs --scope surface --from <key>
|
||||
*
|
||||
* Env vars:
|
||||
* IMPECCABLE_CONCEPT_SEED — same as --from; for reproducible eval runs.
|
||||
@@ -40,6 +40,12 @@ const pool = JSON.parse(readFileSync(join(here, 'concept-ingredients.json'), 'ut
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const fromIdx = args.indexOf('--from');
|
||||
const scopeIdx = args.indexOf('--scope');
|
||||
const scope = scopeIdx !== -1 ? args[scopeIdx + 1] : 'surface';
|
||||
if (scope !== 'surface' && scope !== 'direction') {
|
||||
process.stderr.write('concept-seed: --scope must be direction or surface\n');
|
||||
process.exit(1);
|
||||
}
|
||||
// When no key is supplied, generate one and print it: a user reporting a
|
||||
// bad outcome can hand us the key and we replay the exact roll.
|
||||
const key = fromIdx !== -1
|
||||
@@ -47,7 +53,7 @@ const key = fromIdx !== -1
|
||||
: (process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex'));
|
||||
|
||||
function hashUnit(k, salt) {
|
||||
const h = crypto.createHash('sha256').update(`${salt}:${k}`).digest();
|
||||
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${k}`).digest();
|
||||
return h.readUInt32BE(0) / 0xffffffff;
|
||||
}
|
||||
const unit = (salt) => hashUnit(key, salt);
|
||||
@@ -67,22 +73,48 @@ for (let i = 0; picks.length < 3 && i < 60; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write(`CONCEPT SEED (key: ${key}; rerun with --from ${key} to reproduce this roll)
|
||||
BUILD INDEX: ${buildIndex}
|
||||
After ordering your derived candidates by resonance, build the page whose
|
||||
form comes from candidate number ${buildIndex}, exactly as if it had ranked
|
||||
first: full commitment. Your top-ranked candidate is what every run in this
|
||||
category would ship; the assignment exists to refuse that rut, not to
|
||||
punish it.
|
||||
CHALLENGERS (weigh against your derived candidates on the same two axes,
|
||||
audience identification and product clarity; a challenger wins only when
|
||||
it beats the grounded list on both):
|
||||
const promotedInstruction = scope === 'direction'
|
||||
? `After ordering the grounded coupled directions by product fit, promote
|
||||
candidate ${buildIndex} into the serious shortlist. Each candidate must join
|
||||
a durable visual system to a concrete expression for the requested first
|
||||
surface; select or revise that pair as one decision. It must survive the
|
||||
current task plus navigation, quiet and dense content, interaction and state,
|
||||
and a substantially different future surface.`
|
||||
: `After ordering the task's grounded structural candidates by resonance,
|
||||
promote candidate ${buildIndex} into the serious shortlist. In an attended
|
||||
run, present it beside the strongest materially different candidates and
|
||||
let the user select or revise the surface concept. In a truly unattended
|
||||
run, use it when it survives audience identification and product clarity.`;
|
||||
|
||||
const challengerInstruction = scope === 'direction'
|
||||
? `A challenger enters only when it can supply both reusable identity grammar
|
||||
and a strong first-surface structure, not a one-page costume or a style pasted
|
||||
onto an unrelated layout. Weigh audience identification, product clarity,
|
||||
current-surface force, and cross-surface system breadth.`
|
||||
: `A challenger wins only when it beats the grounded list on both audience
|
||||
identification and product clarity. It may change task topology or
|
||||
interaction, but never the committed visual identity.`;
|
||||
|
||||
const authorityInstruction = scope === 'direction'
|
||||
? `PRODUCT.md and explicit incumbent brand commitments constrain every coupled
|
||||
direction. The seed never chooses exact colors, fonts, tokens, or a user
|
||||
preference, and it never permits the world and first surface to be selected
|
||||
independently.`
|
||||
: `PRODUCT.md and DESIGN.md constrain every surface candidate's identity
|
||||
vocabulary; they do not cancel task-level composition. The seed never
|
||||
authorizes a new palette, type system, material world, or unfamiliar control
|
||||
behavior.`;
|
||||
|
||||
process.stdout.write(`${scope.toUpperCase()} CONCEPT SEED (key: ${key}; rerun with --scope ${scope} --from ${key} to reproduce this roll)
|
||||
PROMOTED INDEX: ${buildIndex}
|
||||
${promotedInstruction}
|
||||
The promotion exists to refuse the model's ranking rut, not to outrank the
|
||||
user or the brief.
|
||||
CHALLENGERS:
|
||||
1. ${picks[0]}
|
||||
2. ${picks[1]}
|
||||
3. ${picks[2]}
|
||||
If a challenger wins, it replaces the assigned candidate. If the surface is
|
||||
an existing world whose incumbent carries a deliberate, ownable idea, the
|
||||
incumbent IS the chosen candidate: intensify its lineage and ignore the
|
||||
roll entirely. The same override applies when the user, PRODUCT.md, or
|
||||
DESIGN.md pins a direction: pinned direction beats the roll, always.
|
||||
${challengerInstruction}
|
||||
${authorityInstruction}
|
||||
A user- or brief-pinned decision beats the roll, always.
|
||||
`);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* output is always valid JSON.
|
||||
*
|
||||
* Signals:
|
||||
* - setup: PRODUCT.md / DESIGN.md presence, register, whether code exists
|
||||
* - setup: PRODUCT.md / DESIGN.md presence and whether code exists
|
||||
* - critique: the latest cached critique score (.impeccable/critique)
|
||||
* - git: branch + files changed vs the default branch (a scope hint)
|
||||
* - devServer: whether a local dev server answers on a common port (gates live)
|
||||
@@ -21,7 +21,7 @@ import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { loadContext, extractRegister, extractPlatform } from './context.mjs';
|
||||
import { loadContext, extractPlatform } from './context.mjs';
|
||||
import { getCritiqueDir } from './lib/impeccable-paths.mjs';
|
||||
|
||||
/** Is there code here at all, or just context files / an empty repo? */
|
||||
@@ -196,7 +196,6 @@ export async function gatherSignals(cwd = process.cwd()) {
|
||||
hasDesign: ctx.hasDesign,
|
||||
designPath: ctx.designPath,
|
||||
hasCode: hasCode(cwd),
|
||||
register: extractRegister(ctx.product),
|
||||
platform: extractPlatform(ctx.product),
|
||||
},
|
||||
critique: { latest: latestCritique(cwd) },
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* Context loader: prints PRODUCT.md (and DESIGN.md if present) as one
|
||||
* markdown block on stdout, or prints a `NO_PRODUCT_MD:` message when no
|
||||
* Context loader: prints PRODUCT.md, DESIGN.md when present, the matching
|
||||
* persisted surface brief when one can be resolved, and native-platform
|
||||
* guidance selected from PRODUCT.md. It prints a
|
||||
* `NO_PRODUCT_MD:` message when no
|
||||
* PRODUCT.md is found anywhere. The skill keys off that message to branch:
|
||||
* from-scratch build commands (init / teach / craft / shape) and clear
|
||||
* from-scratch build requests (plus init / teach / shape) and clear
|
||||
* build/shape intent divert into the init flow, while scoped commands proceed
|
||||
* using the existing code as context.
|
||||
*
|
||||
@@ -23,10 +25,13 @@ import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { parseTargetOptions } from './lib/target-args.mjs';
|
||||
import { IMPECCABLE_COMMAND } from './lib/provider.mjs';
|
||||
import { IMPECCABLE_COMMAND, IMPECCABLE_PROVIDER_ID } from './lib/provider.mjs';
|
||||
import { renderLlmOnlySlopReview } from './lib/slop-review.mjs';
|
||||
import { resolveSurfaceBrief } from './lib/surface-briefs.mjs';
|
||||
|
||||
const PRODUCT_NAMES = ['PRODUCT.md', 'Product.md', 'product.md'];
|
||||
const DESIGN_NAMES = ['DESIGN.md', 'Design.md', 'design.md'];
|
||||
const SKILL_REFERENCE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'reference');
|
||||
const FALLBACK_DIRS = ['.agents/context', 'docs'];
|
||||
const MONOREPO_MARKER_FILES = ['pnpm-workspace.yaml', 'turbo.json', 'nx.json', 'lerna.json'];
|
||||
const MONOREPO_FALLBACK_PROJECT_DIRS = ['apps', 'packages'];
|
||||
@@ -41,6 +46,8 @@ const WORKSPACE_DISCOVERY_IGNORED_DIRS = new Set([
|
||||
'.turbo',
|
||||
'.cache',
|
||||
'coverage',
|
||||
'vendor',
|
||||
'vendors',
|
||||
]);
|
||||
const VISUAL_SOURCE_DIRS = ['src', 'app', 'pages', 'components', 'site', 'public', 'styles'];
|
||||
const STYLE_EXTENSIONS = new Set(['.css', '.scss', '.sass', '.less', '.styl']);
|
||||
@@ -73,6 +80,12 @@ export function loadContext(cwd = process.cwd(), options = {}) {
|
||||
const designPath = resolved.designPath;
|
||||
const product = productPath ? safeRead(productPath) : null;
|
||||
const design = designPath ? safeRead(designPath) : null;
|
||||
const platform = extractPlatform(product);
|
||||
const surfaceResolution = resolveSurfaceBrief(
|
||||
resolved.projectRoot,
|
||||
hasTargetOption(options) ? options.targetPath : null,
|
||||
);
|
||||
const surfaceBrief = surfaceResolution.brief;
|
||||
return {
|
||||
hasProduct: !!product,
|
||||
product,
|
||||
@@ -83,7 +96,18 @@ export function loadContext(cwd = process.cwd(), options = {}) {
|
||||
contextDir: resolved.contextDir,
|
||||
productContextDir: productPath ? path.dirname(productPath) : null,
|
||||
designContextDir: designPath ? path.dirname(designPath) : null,
|
||||
hasSurfaceBrief: !!surfaceBrief,
|
||||
surfaceBrief: surfaceBrief?.text ?? null,
|
||||
surfaceBriefPath: surfaceBrief?.path ? path.relative(absCwd, surfaceBrief.path) : null,
|
||||
surfaceBriefReason: surfaceResolution.reason,
|
||||
surfaceBriefCandidates: surfaceResolution.candidates.map((brief) => ({
|
||||
slug: brief.slug,
|
||||
path: path.relative(absCwd, brief.path),
|
||||
primaryTarget: brief.primaryTarget,
|
||||
relatedTargets: brief.relatedTargets,
|
||||
})),
|
||||
hasVisualImplementation: hasVisualImplementation(resolved.projectRoot),
|
||||
platform,
|
||||
projectRoot: resolved.projectRoot,
|
||||
repoRoot: resolved.repoRoot,
|
||||
isMonorepo: resolved.isMonorepo,
|
||||
@@ -696,6 +720,19 @@ function safeRead(p) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadNativePlatformReferences(platform) {
|
||||
const names = platform === 'adaptive'
|
||||
? ['ios', 'android']
|
||||
: platform === 'ios' || platform === 'android'
|
||||
? [platform]
|
||||
: [];
|
||||
return names.flatMap((name) => {
|
||||
const filePath = path.join(SKILL_REFERENCE_DIR, `${name}.md`);
|
||||
const content = safeRead(filePath);
|
||||
return content ? [{ name, filePath, content }] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort evidence that the project already has an incumbent visual
|
||||
* implementation. DESIGN.md is documentation, not the only source of design
|
||||
@@ -719,9 +756,11 @@ export function hasVisualImplementation(projectRoot) {
|
||||
let styledComponents = 0;
|
||||
|
||||
const inspectFile = (filePath) => {
|
||||
if (scannedFiles++ >= VISUAL_SCAN_FILE_LIMIT) return false;
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
if (!STYLE_EXTENSIONS.has(ext) && !UI_EXTENSIONS.has(ext)) return false;
|
||||
const base = path.basename(filePath).toLowerCase();
|
||||
if (/\.min\.[a-z]+$/.test(base)) return false;
|
||||
if (scannedFiles++ >= VISUAL_SCAN_FILE_LIMIT) return false;
|
||||
let body;
|
||||
try {
|
||||
body = fs.readFileSync(filePath, 'utf-8').slice(0, 64 * 1024);
|
||||
@@ -729,18 +768,28 @@ export function hasVisualImplementation(projectRoot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const base = path.basename(filePath).toLowerCase();
|
||||
const evidence = body
|
||||
.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.replace(/<!--[\s\S]*?-->/g, '')
|
||||
.replace(/^\s*\/\/.*$/gm, '');
|
||||
if (STYLE_EXTENSIONS.has(ext)) {
|
||||
const customProperties = body.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const visualDeclarations = body.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
if (/\b(?:tokens?|theme|design-system)\b/.test(base) && body.trim().length > 80) return true;
|
||||
const customProperties = evidence.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const visualDeclarations = evidence.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
if (/\b(?:tokens?|theme|design-system)\b/.test(base) && evidence.trim().length > 80) return true;
|
||||
if (customProperties >= 3 || visualDeclarations >= 5) return true;
|
||||
}
|
||||
|
||||
if ((ext === '.html' || ext === '.htm') && body.length > 600 && /<style\b|<link[^>]+stylesheet/i.test(body)) {
|
||||
if ((ext === '.html' || ext === '.htm') && evidence.length > 600 && /<style\b|<link[^>]+stylesheet/i.test(evidence)) {
|
||||
return true;
|
||||
}
|
||||
if (!['.html', '.htm'].includes(ext) && body.length > 300 && /class(?:Name)?\s*=|style\s*=|styled\(|css`/i.test(body)) {
|
||||
if (!['.html', '.htm'].includes(ext) && evidence.length > 300) {
|
||||
const embeddedCustomProperties = evidence.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const embeddedVisualDeclarations = evidence.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
const classTokens = [...evidence.matchAll(/class(?:Name)?\s*=\s*["'`]([^"'`]+)["'`]/gi)]
|
||||
.reduce((count, match) => count + match[1].trim().split(/\s+/).length, 0);
|
||||
if ((embeddedCustomProperties >= 3 && embeddedVisualDeclarations >= 3) || embeddedVisualDeclarations >= 5 || classTokens >= 12) return true;
|
||||
}
|
||||
if (!['.html', '.htm'].includes(ext) && evidence.length > 300 && /class(?:Name)?\s*=|style\s*=|styled\(|css`/i.test(evidence)) {
|
||||
styledComponents += 1;
|
||||
if (styledComponents >= 3) return true;
|
||||
}
|
||||
@@ -781,9 +830,9 @@ function escapeRegExp(value) {
|
||||
|
||||
/**
|
||||
* Read the first non-empty line under a bare `## <heading>` section of
|
||||
* PRODUCT.md (e.g. `## Register`, `## Platform`). Returns null when the
|
||||
* PRODUCT.md (for example `## Platform`). Returns null when the
|
||||
* section is absent. The heading match is exact (`\s*$`) so near-miss
|
||||
* headings like `## Register guidelines` don't shadow the real field.
|
||||
* near-miss headings don't shadow the real field.
|
||||
*/
|
||||
export function extractSectionValue(product, heading) {
|
||||
if (!product) return null;
|
||||
@@ -802,16 +851,6 @@ export function extractSectionValue(product, heading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the register (`brand` or `product`) out of PRODUCT.md by looking
|
||||
* for a `## Register` section and reading the first non-empty line that
|
||||
* follows it. Returns null when the file is legacy / register-less.
|
||||
*/
|
||||
export function extractRegister(product) {
|
||||
const word = (extractSectionValue(product, 'Register') || '').toLowerCase();
|
||||
return word === 'brand' || word === 'product' ? word : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the platform (`web`, `ios`, `android`, or `adaptive`) out of PRODUCT.md
|
||||
* by looking for a `## Platform` section and reading the first non-empty line
|
||||
@@ -985,30 +1024,35 @@ async function cli() {
|
||||
const parts = ctx.hasVisualImplementation
|
||||
? [
|
||||
'NO_PRODUCT_MD: This project has no PRODUCT.md yet, but it does have an incumbent visual implementation. ' +
|
||||
'For `init` or `teach`, load reference/init.md and create PRODUCT.md. For `craft`, `shape`, or other work ' +
|
||||
'against the existing product, read its CSS, tokens, components, and assets first and proceed without blocking; ' +
|
||||
`offer \`${IMPECCABLE_COMMAND} init\` as a follow-up. Only treat the work as greenfield when the user explicitly ` +
|
||||
'asks to discard or replace the current identity.',
|
||||
'EXISTING_VISUAL_SYSTEM: Code and assets are the incumbent design authority. Missing DESIGN.md is a documentation ' +
|
||||
'gap, not permission to invent a replacement identity. Preserve and extend the implementation unless the user ' +
|
||||
'explicitly requests a rebrand, or inspection proves the detected files contain no coherent visual decisions.',
|
||||
'For `init`, `teach`, `shape`, or any request to create a new surface or replacement visual world, load reference/init.md and create PRODUCT.md with the user first. ' +
|
||||
'After init writes PRODUCT.md, reference/new-work.md preserves and documents the incumbent system for an ' +
|
||||
'extension or replaces it with the user for a redesign/rebrand. Other ' +
|
||||
'narrow refinement commands may read the CSS, tokens, components, and assets and proceed without blocking, then ' +
|
||||
`offer \`${IMPECCABLE_COMMAND} init\` as a follow-up.`,
|
||||
'BUILD_INIT_REQUIRED: Before shape or any new-surface/redesign flow, init must capture PRODUCT.md with the human or structured ' +
|
||||
'simulated user. Init writes product truth only; reference/new-work.md owns every visual decision.',
|
||||
'SCOPED_EXISTING_ALLOWED: Narrow refinement commands may use the incumbent implementation as authority without ' +
|
||||
'blocking on context setup; they must preserve it and offer init afterward.',
|
||||
'EXISTING_VISUAL_SYSTEM: For refinement or extension, code and assets are incumbent design authority and missing ' +
|
||||
'DESIGN.md is a documentation gap. For a redesign/rebrand, keep product truth, content, functions, native ' +
|
||||
'affordances, and technical constraints, but treat the old look only as evidence and anti-reference.',
|
||||
]
|
||||
: [
|
||||
'NO_PRODUCT_MD: This project has no PRODUCT.md yet. ' +
|
||||
'For `init`, `teach`, `craft`, `shape`, ' +
|
||||
'For `init`, `teach`, `shape`, ' +
|
||||
'or wording that clearly maps to a from-scratch build/shape flow, load ' +
|
||||
'reference/init.md and write PRODUCT.md first, unless no user can ' +
|
||||
'respond (a one-shot or automated run, or the user said not to ask): ' +
|
||||
'then write a one-paragraph understanding of the product, audience, ' +
|
||||
'and the page\'s job from the brief, and continue. For any other ' +
|
||||
'reference/init.md, complete its human or structured simulated-user interview, and write PRODUCT.md before ' +
|
||||
'designing. If no answer mechanism truly exists, init may infer only from the explicit brief and must label its ' +
|
||||
'assumptions. It never writes DESIGN.md. For any other ' +
|
||||
'(scoped) command against existing code, proceed using the code as ' +
|
||||
`context and offer \`${IMPECCABLE_COMMAND} init\` as a suggestion (do not block).`,
|
||||
'NEW_WORK: No committed design context was found. If this task produces ' +
|
||||
'new design (a build from scratch, or a redesign that discards the ' +
|
||||
'current look), you MUST read reference/new-work.md before making any ' +
|
||||
'design decision. Scoped fixes to existing code do not need it.',
|
||||
'PRODUCT_INIT_REQUIRED: No product context or visual authority was found. New builds and redesigns ' +
|
||||
'must finish reference/init.md for PRODUCT.md, then reference/new-work.md establishes the world and surface. Scoped ' +
|
||||
'fixes to existing code do not need the new-surface flow.',
|
||||
];
|
||||
appendSurfaceBriefContext(parts, ctx);
|
||||
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
|
||||
appendHookFallback(parts, ctx);
|
||||
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
|
||||
parts.push(buildMissingTargetDirective());
|
||||
}
|
||||
@@ -1020,37 +1064,29 @@ async function cli() {
|
||||
if (ctx.hasDesign) {
|
||||
parts.push(`# DESIGN.md\n\n${ctx.design.trim()}`);
|
||||
}
|
||||
appendSurfaceBriefContext(parts, ctx);
|
||||
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
|
||||
appendHookFallback(parts, ctx);
|
||||
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
|
||||
parts.push(buildMissingTargetDirective());
|
||||
}
|
||||
const register = extractRegister(ctx.product);
|
||||
// The register field survives as a family hint (brand = Persuade/Experience,
|
||||
// product = Operate/Read); SKILL.md's mode section carries the essentials
|
||||
// inline, so no register-file read is mandated here. What IS mandated:
|
||||
// the new-work playbook when no committed design system exists yet.
|
||||
if (!ctx.hasDesign) {
|
||||
parts.push(ctx.hasVisualImplementation
|
||||
? 'EXISTING_VISUAL_SYSTEM: PRODUCT.md exists and DESIGN.md is missing, but code contains incumbent visual decisions. ' +
|
||||
'Treat CSS, tokens, components, and assets as design authority. Do not route to new identity work merely because the ' +
|
||||
'document is absent; preserve and extend the implementation unless the user explicitly asks to discard it.'
|
||||
: 'NEW_WORK: PRODUCT.md exists but no DESIGN.md or incumbent visual implementation was found. If this task produces ' +
|
||||
'new design or a redesign that discards the current look, you MUST read reference/new-work.md before making any ' +
|
||||
'design decision. Scoped fixes to existing code do not need it.');
|
||||
? 'INCUMBENT_WORLD_UNDOCUMENTED: PRODUCT.md exists and DESIGN.md is missing, but code contains incumbent visual decisions. ' +
|
||||
'For shape or a new-surface/redesign request, load reference/new-work.md: an extension documents and preserves the code-defined world; ' +
|
||||
'a redesign replaces it with the user and uses the old look only as evidence and anti-reference. Narrow refinement ' +
|
||||
'commands may proceed using the implementation directly.'
|
||||
: 'WORLD_DISCOVERY_REQUIRED: PRODUCT.md exists but no DESIGN.md or incumbent visual implementation was found. ' +
|
||||
'For a new build or redesign, load reference/new-work.md and establish the visual world with the human or structured ' +
|
||||
'simulated user before developing the task concept. Scoped fixes to existing code do not need this flow.');
|
||||
}
|
||||
if (register) {
|
||||
parts.push(`REGISTER: \`${register}\` (family hint: brand = Persuade/Experience surfaces, product = Operate/Read). Derive the visitor's mode per SKILL.md.`);
|
||||
}
|
||||
const platform = extractPlatform(ctx.product);
|
||||
const nativeRefs =
|
||||
platform === 'adaptive' ? ['ios', 'android'] : platform === 'ios' || platform === 'android' ? [platform] : [];
|
||||
if (nativeRefs.length) {
|
||||
const refList = nativeRefs.map(p => `\`reference/${p}.md\``).join(' and ');
|
||||
const label = platform === 'adaptive' ? '`adaptive` (both iOS and Android)' : `\`${platform}\``;
|
||||
const platformReferences = loadNativePlatformReferences(ctx.platform);
|
||||
for (const reference of platformReferences) {
|
||||
parts.push(
|
||||
`NEXT STEP: This project targets ${label}. Also read ${refList} for native conventions, in addition to SKILL.md's mode guidance.`,
|
||||
`# NATIVE PLATFORM REFERENCE: ${reference.name.toUpperCase()} (reference/${reference.name}.md)\n\n${reference.content.trim()}`,
|
||||
);
|
||||
} else if (!platform) {
|
||||
}
|
||||
if (!ctx.platform) {
|
||||
// A `## Platform` section that names something we don't recognize (a
|
||||
// toolchain like `flutter`, a typo) would otherwise silently fall back to
|
||||
// web — the wrong default exactly when the user tried to say "native".
|
||||
@@ -1078,6 +1114,72 @@ function pathExistsForTarget(cwd, targetPath) {
|
||||
return fs.existsSync(abs);
|
||||
}
|
||||
|
||||
const HOOK_MANIFESTS_BY_PROVIDER = Object.freeze({
|
||||
'claude-code': ['.claude/settings.local.json', '.claude/settings.json'],
|
||||
codex: ['.codex/hooks.json'],
|
||||
agents: ['.codex/hooks.json'],
|
||||
cursor: ['.cursor/hooks.json'],
|
||||
github: ['.github/hooks/impeccable.json'],
|
||||
});
|
||||
|
||||
function truthyEnv(value) {
|
||||
return typeof value === 'string' && /^(1|true|yes|on)$/i.test(value.trim());
|
||||
}
|
||||
|
||||
function valueHasHookMarker(value) {
|
||||
if (typeof value === 'string') {
|
||||
return value.includes('skills/impeccable/scripts/hook.mjs')
|
||||
|| value.includes('skills/impeccable/scripts/hook-before-edit.mjs');
|
||||
}
|
||||
if (Array.isArray(value)) return value.some(valueHasHookMarker);
|
||||
if (value && typeof value === 'object') return Object.values(value).some(valueHasHookMarker);
|
||||
return false;
|
||||
}
|
||||
|
||||
function hookEnabledAt(root) {
|
||||
if (truthyEnv(process.env.IMPECCABLE_HOOK_DISABLED)) return false;
|
||||
let enabled = true;
|
||||
for (const name of ['.impeccable/config.json', '.impeccable/config.local.json']) {
|
||||
const raw = readJson(path.join(root, name));
|
||||
if (raw?.hook && Object.prototype.hasOwnProperty.call(raw.hook, 'enabled')) {
|
||||
enabled = raw.hook.enabled !== false;
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
const STOP_REVIEW_PROVIDERS = new Set(['claude-code', 'codex', 'agents']);
|
||||
|
||||
function automaticHookMode(ctx) {
|
||||
if (ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive') {
|
||||
return 'none';
|
||||
}
|
||||
const activeRoot = path.resolve(ctx.projectRoot || process.cwd());
|
||||
if (!hookEnabledAt(activeRoot)) return 'none';
|
||||
const manifests = HOOK_MANIFESTS_BY_PROVIDER[IMPECCABLE_PROVIDER_ID] || [];
|
||||
const roots = [...new Set([process.cwd(), ctx.projectRoot, ctx.repoRoot].filter(Boolean).map((root) => path.resolve(root)))];
|
||||
for (const root of roots) {
|
||||
for (const rel of manifests) {
|
||||
const raw = readJson(path.join(root, rel));
|
||||
if (raw?.hooks && valueHasHookMarker(raw.hooks)) {
|
||||
return STOP_REVIEW_PROVIDERS.has(IMPECCABLE_PROVIDER_ID) ? 'stop' : 'per-edit';
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'none';
|
||||
}
|
||||
|
||||
function appendHookFallback(parts, ctx) {
|
||||
const hookMode = automaticHookMode(ctx);
|
||||
if (hookMode === 'stop') return;
|
||||
const native = ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive';
|
||||
parts.push(renderLlmOnlySlopReview({
|
||||
automaticDetector: hookMode === 'per-edit',
|
||||
manualDetector: hookMode === 'none' && !native,
|
||||
scriptsPath: path.dirname(fileURLToPath(import.meta.url)),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildResolvedContextDirective(ctx, options, { targetExists = null } = {}) {
|
||||
const targetPath = hasTargetOption(options) ? options.targetPath : null;
|
||||
return `RESOLVED_CONTEXT:\n${JSON.stringify({
|
||||
@@ -1087,10 +1189,29 @@ function buildResolvedContextDirective(ctx, options, { targetExists = null } = {
|
||||
repoRoot: ctx.repoRoot,
|
||||
productPath: ctx.productPath,
|
||||
designPath: ctx.designPath,
|
||||
surfaceBriefPath: ctx.surfaceBriefPath,
|
||||
surfaceBriefReason: ctx.surfaceBriefReason,
|
||||
surfaceBriefCandidates: ctx.surfaceBriefCandidates,
|
||||
hasVisualImplementation: ctx.hasVisualImplementation,
|
||||
platform: ctx.platform,
|
||||
}, null, 2)}`;
|
||||
}
|
||||
|
||||
function appendSurfaceBriefContext(parts, ctx) {
|
||||
if (ctx.hasSurfaceBrief && ctx.surfaceBrief) {
|
||||
parts.push(`# SURFACE BRIEF (${ctx.surfaceBriefPath})\n\n${ctx.surfaceBrief.trim()}`);
|
||||
return;
|
||||
}
|
||||
if (!ctx.surfaceBriefCandidates?.length) return;
|
||||
const helper = path.join(path.dirname(fileURLToPath(import.meta.url)), 'surface-brief.mjs');
|
||||
parts.push(
|
||||
'SURFACE_CONTEXT_AVAILABLE: Persisted surface briefs exist, but none was selected unambiguously for this invocation. ' +
|
||||
'Resolve the requested surface to its concrete primary or related source path, then run ' +
|
||||
`\`node ${helper} read <path>\` once before changing that surface. Candidates:\n` +
|
||||
JSON.stringify(ctx.surfaceBriefCandidates, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
function shouldWarnMissingTarget(ctx, targetProvided, targetExists = null) {
|
||||
if (ctx.isMonorepo && targetProvided && targetExists === false) return true;
|
||||
return !!(
|
||||
|
||||
@@ -29,8 +29,9 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { getCritiqueDir } from './lib/impeccable-paths.mjs';
|
||||
import { slugFromTarget } from './lib/target-slug.mjs';
|
||||
|
||||
const SLUG_MAX = 50;
|
||||
export { slugFromTarget } from './lib/target-slug.mjs';
|
||||
|
||||
/**
|
||||
* Mechanically derive a slug from a resolved target. Returns null if the
|
||||
@@ -40,46 +41,6 @@ const SLUG_MAX = 50;
|
||||
* concrete artifact before calling this — we never slug a natural-language
|
||||
* phrase.
|
||||
*/
|
||||
export function slugFromTarget(resolved, { cwd = process.cwd() } = {}) {
|
||||
if (!resolved || typeof resolved !== 'string') return null;
|
||||
const trimmed = resolved.trim();
|
||||
if (!trimmed) return null;
|
||||
|
||||
// URL
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
let url;
|
||||
try { url = new URL(trimmed); } catch { return null; }
|
||||
const hostPath = `${url.hostname}${url.pathname}`;
|
||||
return kebab(hostPath);
|
||||
}
|
||||
|
||||
// File path. Make it project-relative so two devs critiquing the same
|
||||
// checkout get the same slug regardless of where their repo is cloned.
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
|
||||
let rel = path.relative(cwd, abs);
|
||||
// If the target is outside cwd, fall back to the basename so we still
|
||||
// produce a stable slug (vs the absolute path, which would include
|
||||
// home dirs / usernames).
|
||||
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
rel = path.basename(abs);
|
||||
}
|
||||
if (!rel || rel === '.' || rel === '') return null;
|
||||
return kebab(rel);
|
||||
}
|
||||
|
||||
function kebab(s) {
|
||||
const slug = s
|
||||
.toLowerCase()
|
||||
.replace(/[/\\.]+/g, '-')
|
||||
.replace(/[^a-z0-9-]+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
if (!slug) return null;
|
||||
// Cap from the tail — the tail (filename) is more identifying than the
|
||||
// top-level directory.
|
||||
return slug.length <= SLUG_MAX ? slug : slug.slice(slug.length - SLUG_MAX).replace(/^-/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename-safe UTC ISO timestamp: hyphens for separators, trailing Z.
|
||||
* Plain colons aren't allowed on Windows filesystems.
|
||||
|
||||
@@ -312,17 +312,6 @@ const ANTIPATTERNS = [
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'numbered-section-markers',
|
||||
category: 'slop',
|
||||
scopes: ['layout'],
|
||||
severity: 'advisory',
|
||||
name: 'Numbered section markers (01 / 02 / 03)',
|
||||
description:
|
||||
'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'em-dash-overuse',
|
||||
category: 'slop',
|
||||
|
||||
@@ -280,22 +280,6 @@ const REGEX_ANALYZERS = [
|
||||
if (count === 0) return [];
|
||||
return [finding('marketing-buzzword', filePath, `${count} buzzword phrase${count === 1 ? '' : 's'}: "${firstSample}"`)];
|
||||
},
|
||||
// Numbered section markers (01 / 02 / 03 ...)
|
||||
(content, filePath) => {
|
||||
const text = stripHtmlToText(content);
|
||||
const re = /\b(0[1-9]|1[0-2])\b/g;
|
||||
const seen = new Set();
|
||||
let m;
|
||||
while ((m = re.exec(text)) !== null) seen.add(m[1]);
|
||||
if (seen.size < 3) return [];
|
||||
const sorted = [...seen].sort();
|
||||
let sequential = 0;
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
if (parseInt(sorted[i], 10) === parseInt(sorted[i - 1], 10) + 1) sequential++;
|
||||
}
|
||||
if (sequential < 2) return [];
|
||||
return [finding('numbered-section-markers', filePath, `Sequence: ${sorted.slice(0, 6).join(', ')}`)];
|
||||
},
|
||||
// Aphoristic cadence: manufactured-contrast + short-rebuttal
|
||||
(content, filePath) => {
|
||||
const text = stripHtmlToText(content);
|
||||
@@ -430,21 +414,20 @@ function runRegexMatchers(lines, filePath, lineOffset = 0, blockContext = null,
|
||||
}
|
||||
|
||||
/** Page-level analyzers that scan rendered text content (em-dash use,
|
||||
* buzzword phrases, numbered section markers, aphoristic cadence).
|
||||
* buzzword phrases, aphoristic cadence).
|
||||
* These are detector-agnostic — they work on any HTML/text source
|
||||
* and don't need a parsed DOM. Exported so detectHtml can call them
|
||||
* for `.html` files (which otherwise skip the regex engine). */
|
||||
const TEXT_CONTENT_ANALYZER_IDS = [
|
||||
'em-dash-overuse',
|
||||
'marketing-buzzword',
|
||||
'numbered-section-markers',
|
||||
'aphoristic-cadence',
|
||||
];
|
||||
|
||||
function runTextContentAnalyzers(content, filePath, options = {}) {
|
||||
const profile = options?.profile;
|
||||
if (!shouldRunPageAnalyzers(content, filePath)) return [];
|
||||
// The 4 text-content analyzers are at indices 3-6 in REGEX_ANALYZERS.
|
||||
// The 3 text-content analyzers are at indices 3-5 in REGEX_ANALYZERS.
|
||||
const findings = [];
|
||||
for (let i = 0; i < TEXT_CONTENT_ANALYZER_IDS.length; i++) {
|
||||
const analyzer = REGEX_ANALYZERS[3 + i];
|
||||
@@ -535,7 +518,6 @@ function detectText(content, filePath, options = {}) {
|
||||
'monotonous-spacing',
|
||||
'em-dash-overuse',
|
||||
'marketing-buzzword',
|
||||
'numbered-section-markers',
|
||||
'aphoristic-cadence',
|
||||
'dark-glow',
|
||||
];
|
||||
|
||||
@@ -210,17 +210,6 @@ const ANTIPATTERNS = [
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'numbered-section-markers',
|
||||
category: 'slop',
|
||||
scopes: ['layout'],
|
||||
severity: 'advisory',
|
||||
name: 'Numbered section markers (01 / 02 / 03)',
|
||||
description:
|
||||
'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'em-dash-overuse',
|
||||
category: 'slop',
|
||||
|
||||
@@ -352,27 +352,57 @@ function isAccentColor(cssColor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveHeroHeadingSizePx(value) {
|
||||
const input = String(value || '').trim().toLowerCase();
|
||||
if (!input) return 0;
|
||||
|
||||
const simpleLengthPx = (token) => {
|
||||
const match = /^(-?\d*\.?\d+)\s*(px|rem|em|%)?$/.exec(String(token || '').trim());
|
||||
if (!match) return null;
|
||||
const amount = Number(match[1]);
|
||||
if (!Number.isFinite(amount)) return null;
|
||||
if (match[2] === 'rem' || match[2] === 'em') return amount * 16;
|
||||
if (match[2] === '%') return amount * 0.16;
|
||||
return amount;
|
||||
};
|
||||
|
||||
const direct = simpleLengthPx(input);
|
||||
if (direct !== null) return direct;
|
||||
|
||||
// Static CSS engines cannot resolve viewport units, but clamp's min/max
|
||||
// bounds still tell us whether the heading can ever reach hero scale.
|
||||
const clamp = /^clamp\((.*)\)$/.exec(input);
|
||||
if (clamp) {
|
||||
const parts = clamp[1].split(',');
|
||||
if (parts.length === 3) {
|
||||
const bounds = [simpleLengthPx(parts[0]), simpleLengthPx(parts[2])]
|
||||
.filter((candidate) => candidate !== null);
|
||||
if (bounds.length > 0) return Math.max(...bounds);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sibling-relationship rule. Anchor on a hero-scale h1, look at the
|
||||
// previousElementSibling, and gate on EITHER the classic tracked-
|
||||
// uppercase eyebrow OR the modern accent-colored bold eyebrow.
|
||||
function checkHeroEyebrow(opts) {
|
||||
const {
|
||||
headingTag, headingText, headingFontSize,
|
||||
headingInApplicationContext,
|
||||
siblingTag, siblingText, siblingTextTransform,
|
||||
siblingFontSize, siblingLetterSpacing,
|
||||
siblingFontWeight, siblingColor,
|
||||
siblingHasAccentDashPseudo,
|
||||
} = opts;
|
||||
if (headingTag !== 'h1') return [];
|
||||
// We previously gated on headingFontSize >= 48 to anchor "hero scale".
|
||||
// But modern hero h1s use clamp() / vw / var(--text-*), none of which
|
||||
// jsdom can resolve — the computed value comes back as "2em" or
|
||||
// "var(--text-9xl)" and parseFloat returns 2 or NaN. The gate fails
|
||||
// on virtually every Tailwind v4 / framework build. The other gates
|
||||
// (sibling text 2-60 chars, font-size ≤ 14px, accent-bold OR
|
||||
// tracked-caps) are tight enough to avoid false positives on non-
|
||||
// hero h1s — a tiny tan label directly above any h1 is the
|
||||
// antipattern regardless of how big the h1 ends up.
|
||||
// This is specifically a marketing-hero cliché, not a ban on compact
|
||||
// context labels in product UI (for example, a station name inside a tab
|
||||
// panel). Browser-computed sizes are reliable; the static adapter also
|
||||
// resolves ordinary px/rem/em and clamp() bounds before reaching here.
|
||||
if (headingInApplicationContext) return [];
|
||||
if (!(headingFontSize >= 48)) return [];
|
||||
if (!siblingTag) return [];
|
||||
// An h2 above an h1 is a different anti-pattern (heading hierarchy / dual
|
||||
// headings) — never an eyebrow.
|
||||
@@ -1938,6 +1968,7 @@ function checkElementHeroEyebrowDOM(el) {
|
||||
headingTag: tag,
|
||||
headingText: el.textContent || '',
|
||||
headingFontSize: parseFloat(headStyle.fontSize) || 0,
|
||||
headingInApplicationContext: !!el.closest('[role="tabpanel"], [role="dialog"], [role="application"], dialog'),
|
||||
siblingTag: sibling.tagName.toLowerCase(),
|
||||
siblingText: sibling.textContent || '',
|
||||
siblingTextTransform: sibStyle.textTransform || '',
|
||||
@@ -3367,7 +3398,8 @@ function checkElementHeroEyebrow(el, style, tag, window, customPropMap) {
|
||||
return checkHeroEyebrow({
|
||||
headingTag: tag,
|
||||
headingText: el.textContent || '',
|
||||
headingFontSize: parseFloat(headingFontSizeRaw) || 0,
|
||||
headingFontSize: resolveHeroHeadingSizePx(headingFontSizeRaw),
|
||||
headingInApplicationContext: !!el.closest?.('[role="tabpanel"], [role="dialog"], [role="application"], dialog'),
|
||||
siblingTag: sibling.tagName.toLowerCase(),
|
||||
siblingText: sibling.textContent || '',
|
||||
siblingTextTransform: sibStyle.textTransform || '',
|
||||
|
||||
@@ -46,6 +46,7 @@ import path from 'node:path';
|
||||
import { pathToFileURL, fileURLToPath } from 'node:url';
|
||||
import { extractPlatform, loadContext } from './context.mjs';
|
||||
import { IMPECCABLE_COMMAND } from './lib/provider.mjs';
|
||||
import { renderStopSlopReview } from './lib/slop-review.mjs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -1868,22 +1869,42 @@ export const CONTRACT_MAX_CHARS = 1800;
|
||||
// Cap contract sections per Stop emission so many touched artifacts cannot
|
||||
// stack an unbounded message.
|
||||
export const CONTRACT_AUDIT_MAX_FILES = 3;
|
||||
export const CONTRACT_EXTS = new Set(['.html', '.htm', '.astro', '.svelte', '.vue', '.jsx', '.tsx']);
|
||||
export const CONTRACT_REQUIRED_FIELDS = ['UNIQUE', 'NOT-TEMPLATE', 'OWN-WORLD', 'STORY', 'FIRST VIEWPORT', 'FORM'];
|
||||
|
||||
/**
|
||||
* Extract the artifact's own direction-contract comment: the first HTML
|
||||
* comment in the head of the file, when its opening chars identify it as a
|
||||
* contract/concept block. Returns the trimmed, length-capped body, or null
|
||||
* when the file carries none (no comment, unclosed comment, marker missing,
|
||||
* or the comment starts past the head window).
|
||||
* Extract the artifact's own direction-contract comment from the head of an
|
||||
* HTML or component file. Supports HTML-family comments and JSX block
|
||||
* comments so the contract works in the Astro/Svelte/Vue/React scaffolds the
|
||||
* skill actually builds. Returns the trimmed, length-capped body, or null
|
||||
* when the file carries no valid contract block.
|
||||
*/
|
||||
export function extractDirectionContract(content) {
|
||||
if (typeof content !== 'string' || !content) return null;
|
||||
const head = content.slice(0, CONTRACT_HEAD_CHARS);
|
||||
const m = /<!--([\s\S]*?)-->/.exec(head);
|
||||
if (!m) return null;
|
||||
const body = m[1].trim();
|
||||
if (!body || !/contract|concept/i.test(body.slice(0, CONTRACT_MARKER_CHARS))) return null;
|
||||
return body.slice(0, CONTRACT_MAX_CHARS);
|
||||
const candidates = [];
|
||||
for (const pattern of [/<!--([\s\S]*?)-->/g, /\{\/\*([\s\S]*?)\*\/\}/g]) {
|
||||
for (const match of head.matchAll(pattern)) {
|
||||
const index = match.index ?? 0;
|
||||
const linePrefix = head.slice(head.lastIndexOf('\n', index - 1) + 1, index).trim();
|
||||
if (linePrefix.startsWith('//')) continue;
|
||||
candidates.push({ index, body: match[1].trim() });
|
||||
}
|
||||
}
|
||||
candidates.sort((a, b) => a.index - b.index);
|
||||
for (const candidate of candidates) {
|
||||
if (!candidate.body || !/direction\s+contract|concept\s+contract/i.test(candidate.body.slice(0, CONTRACT_MARKER_CHARS))) continue;
|
||||
return candidate.body.slice(0, CONTRACT_MAX_CHARS);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function missingDirectionContractFields(contract) {
|
||||
const body = typeof contract === 'string' ? contract : '';
|
||||
return CONTRACT_REQUIRED_FIELDS.filter((field) => {
|
||||
const label = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s+/g, '\\s+');
|
||||
return !new RegExp(`\\b${label}\\s*:`, 'i').test(body);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1899,7 +1920,11 @@ export function renderContractAudit(entries, opts = {}) {
|
||||
const shown = entries.slice(0, CONTRACT_AUDIT_MAX_FILES);
|
||||
const blocks = shown.map(({ filePath, contract }) => {
|
||||
const display = relativize(filePath, cwd);
|
||||
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}`;
|
||||
const missing = missingDirectionContractFields(contract);
|
||||
const integrity = missing.length > 0
|
||||
? `\n\nContract integrity defect: missing ${missing.join(', ')}. Repair the contract and the implementation together.`
|
||||
: '';
|
||||
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}${integrity}`;
|
||||
});
|
||||
return [
|
||||
`${ENVELOPE_PREFIX} Direction-contract audit. Before finishing, audit the rendered page against the contract it opens with, promise by promise.`,
|
||||
@@ -1984,9 +2009,22 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
return result({ skipped: 'native-platform', platform, durationMs: Date.now() - started });
|
||||
}
|
||||
|
||||
const session = ensureSession(cache, sessionId);
|
||||
const needsSlopReview = session.llmSlopReviewed !== true;
|
||||
|
||||
const det = detector || await loadDetector();
|
||||
if (!det || typeof det.detectText !== 'function') {
|
||||
return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
|
||||
if (!needsSlopReview) return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
|
||||
session.llmSlopReviewed = true;
|
||||
session.updatedAt = Date.now();
|
||||
persistCache(projectCwd, cache);
|
||||
const text = renderStopSlopReview();
|
||||
return {
|
||||
exitCode: 0,
|
||||
stdout: payload(text, 'Stop', harness),
|
||||
emission: { kind: 'stop-llm-slop-review', llmSlopReview: true },
|
||||
audit: { ...audit, emitted: true, detectorMissing: true, llmSlopReview: true, chars: text.length, durationMs: Date.now() - started },
|
||||
};
|
||||
}
|
||||
const scanOptions = designSystemOptions(config, det, projectCwd);
|
||||
|
||||
@@ -2013,10 +2051,11 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
? configuredExt.engine === 'html'
|
||||
: (ext === '.html' || ext === '.htm');
|
||||
|
||||
// Direction-contract audit: HTML artifacts only, at most once per file
|
||||
// Direction-contract audit: HTML and component artifacts, at most once per file
|
||||
// per session. The flag lives on the same session cache entry the
|
||||
// finding dedupe uses, so a second Stop fire stays quiet about it.
|
||||
if (useHtmlEngine) {
|
||||
const contractCapable = useHtmlEngine || CONTRACT_EXTS.has(ext);
|
||||
if (contractCapable) {
|
||||
const fileEntry = ensureFile(cache, sessionId, filePath);
|
||||
if (!fileEntry.contractAudited) {
|
||||
const contract = extractDirectionContract(content);
|
||||
@@ -2046,10 +2085,15 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
}
|
||||
audit.scannedFiles = scanned;
|
||||
|
||||
if (freshGroups.length === 0 && contractEntries.length === 0) {
|
||||
if (freshGroups.length === 0 && contractEntries.length === 0 && !needsSlopReview) {
|
||||
return result({ emitted: false, skipped: 'stop-clean', durationMs: Date.now() - started });
|
||||
}
|
||||
|
||||
if (needsSlopReview) {
|
||||
session.llmSlopReviewed = true;
|
||||
session.updatedAt = Date.now();
|
||||
}
|
||||
|
||||
// Fresh findings and first-time contract audits earn the cache write;
|
||||
// both mark this batch as surfaced so the next Stop fire is silent
|
||||
// unless new issues appear.
|
||||
@@ -2064,6 +2108,9 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
if (contractEntries.length > 0) {
|
||||
parts.push(renderContractAudit(contractEntries, { cwd: projectCwd }));
|
||||
}
|
||||
if (needsSlopReview) {
|
||||
parts.push(renderStopSlopReview());
|
||||
}
|
||||
const text = appendDesignSystemNote(parts.join('\n\n'), scanOptions);
|
||||
return {
|
||||
exitCode: 0,
|
||||
@@ -2074,6 +2121,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
...(contractEntries.length > 0
|
||||
? { contractFiles: contractEntries.map((entry) => entry.filePath) }
|
||||
: {}),
|
||||
...(needsSlopReview ? { llmSlopReview: true } : {}),
|
||||
},
|
||||
audit: {
|
||||
...audit,
|
||||
@@ -2081,6 +2129,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
freshFiles: freshGroups.length,
|
||||
freshFindings: freshGroups.reduce((sum, group) => sum + group.findings.length, 0),
|
||||
...(contractEntries.length > 0 ? { contractAudits: contractEntries.length } : {}),
|
||||
...(needsSlopReview ? { llmSlopReview: true } : {}),
|
||||
chars: text.length,
|
||||
durationMs: Date.now() - started,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Source scripts default to slash commands. The provider build replaces only
|
||||
// this exact declaration, avoiding heuristic rewrites across executable code.
|
||||
export const IMPECCABLE_COMMAND_PREFIX = "$";
|
||||
export const IMPECCABLE_PROVIDER_ID = "agents";
|
||||
export const IMPECCABLE_COMMAND = `${IMPECCABLE_COMMAND_PREFIX}impeccable`;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
export const LLM_ONLY_SLOP_ITEMS = Object.freeze([
|
||||
'Monospace used merely to signal “technical” or “developer.”',
|
||||
'Light or dark mode chosen by category habit rather than the actual use scene.',
|
||||
'Everything wrapped in cards, or identical icon-heading-text cards repeated as the page structure.',
|
||||
'Hero-metric scaffolds: one oversized number, a small label, supporting stats, and an accent treatment.',
|
||||
'Decorative glassmorphism, meaningless sparklines, or generic rounded rectangles with drop shadows.',
|
||||
'A modal chosen by reflex when the task does not require interruption or protected focus.',
|
||||
]);
|
||||
|
||||
export function renderLlmOnlySlopReview({ manualDetector = false, automaticDetector = false, scriptsPath = null } = {}) {
|
||||
const lines = [
|
||||
automaticDetector
|
||||
? 'AI_SLOP_REVIEW_REQUIRED: The automatic detector covers mechanical rules, but this harness has no reliable late review. Before finishing changed UI, inspect the authored result for detector-blind model reflexes:'
|
||||
: 'AI_SLOP_REVIEW_REQUIRED: The automatic Impeccable design hook is not available for this session. Before finishing changed UI, inspect the authored result for detector-blind model reflexes:',
|
||||
...LLM_ONLY_SLOP_ITEMS.map((item) => `- ${item}`),
|
||||
'Fix reflexes, not intentional choices required by the brief or established visual authority.',
|
||||
];
|
||||
if (manualDetector && scriptsPath) {
|
||||
lines.push(`Then run the mechanical detector once over the changed web UI: \`node ${scriptsPath}/detect.mjs --json <changed targets>\`. Do not run it earlier during concept selection.`);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
export function renderStopSlopReview() {
|
||||
return [
|
||||
'[impeccable@1] Detector-blind AI-slop review. The mechanical pass is complete; now inspect the rendered result for model reflexes it cannot reliably detect:',
|
||||
...LLM_ONLY_SLOP_ITEMS.map((item) => `- ${item}`),
|
||||
'Fix reflexes, not intentional choices required by the brief or established visual authority. Do not rerun the detector; this is the authored judgment layer.',
|
||||
].join('\n');
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { slugFromTarget } from './target-slug.mjs';
|
||||
|
||||
export const SURFACE_BRIEF_VERSION = 1;
|
||||
|
||||
export function getSurfaceBriefDir(projectRoot) {
|
||||
return path.join(projectRoot, '.impeccable', 'surfaces');
|
||||
}
|
||||
|
||||
export function normalizeSurfaceTarget(target, { projectRoot = process.cwd() } = {}) {
|
||||
if (!target || typeof target !== 'string' || !target.trim()) return null;
|
||||
const trimmed = target.trim();
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
try {
|
||||
const url = new URL(trimmed);
|
||||
url.hash = '';
|
||||
url.search = '';
|
||||
return url.toString().replace(/\/$/, '') || url.origin;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (/^route:/i.test(trimmed)) {
|
||||
const route = trimmed.slice(trimmed.indexOf(':') + 1).trim();
|
||||
if (!route.startsWith('/') || route.includes('..')) return null;
|
||||
const normalizedRoute = route.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
|
||||
return `route:${normalizedRoute}`;
|
||||
}
|
||||
if (trimmed === '/') return 'route:/';
|
||||
if (trimmed.startsWith('/')) {
|
||||
const absolute = path.resolve(trimmed);
|
||||
const relativeToProject = path.relative(projectRoot, absolute);
|
||||
const isProjectFile = relativeToProject && !relativeToProject.startsWith('..') && !path.isAbsolute(relativeToProject);
|
||||
if (!isProjectFile && !fs.existsSync(absolute) && !trimmed.includes('..')) {
|
||||
const normalizedRoute = trimmed.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
|
||||
return `route:${normalizedRoute}`;
|
||||
}
|
||||
}
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
|
||||
const rel = path.relative(projectRoot, abs);
|
||||
if (!rel || rel === '.' || rel.startsWith('..') || path.isAbsolute(rel)) return null;
|
||||
return rel.split(path.sep).join('/');
|
||||
}
|
||||
|
||||
export function surfaceBriefPathForTarget(target, { projectRoot = process.cwd() } = {}) {
|
||||
const normalized = normalizeSurfaceTarget(target, { projectRoot });
|
||||
if (!normalized) return null;
|
||||
const slugInput = normalized.startsWith('route:') ? `route${normalized.slice('route:'.length)}` : normalized;
|
||||
const slug = slugFromTarget(slugInput, { cwd: projectRoot });
|
||||
return slug ? path.join(getSurfaceBriefDir(projectRoot), `${slug}.md`) : null;
|
||||
}
|
||||
|
||||
export function parseSurfaceBrief(text, filePath = null) {
|
||||
const match = String(text || '').match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
||||
const meta = {};
|
||||
if (match) {
|
||||
for (const line of match[1].split(/\r?\n/)) {
|
||||
const colon = line.indexOf(':');
|
||||
if (colon < 0) continue;
|
||||
const key = line.slice(0, colon).trim();
|
||||
const raw = line.slice(colon + 1).trim();
|
||||
if (!key) continue;
|
||||
if (/^(?:\[|\{|\")/.test(raw) || /^(?:true|false|null|-?\d+(?:\.\d+)?)$/.test(raw)) {
|
||||
try { meta[key] = JSON.parse(raw); continue; } catch { /* keep string */ }
|
||||
}
|
||||
meta[key] = raw.replace(/^['"]|['"]$/g, '');
|
||||
}
|
||||
}
|
||||
const primaryTarget = typeof meta.primary_target === 'string' ? meta.primary_target : null;
|
||||
const relatedTargets = Array.isArray(meta.related_targets)
|
||||
? meta.related_targets.filter((value) => typeof value === 'string')
|
||||
: [];
|
||||
return {
|
||||
path: filePath,
|
||||
text: String(text || ''),
|
||||
body: match ? String(text || '').slice(match[0].length).trim() : String(text || '').trim(),
|
||||
meta,
|
||||
slug: typeof meta.slug === 'string' ? meta.slug : filePath ? path.basename(filePath, '.md') : null,
|
||||
primaryTarget,
|
||||
relatedTargets,
|
||||
targets: [primaryTarget, ...relatedTargets].filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
export function listSurfaceBriefs(projectRoot = process.cwd()) {
|
||||
const dir = getSurfaceBriefDir(projectRoot);
|
||||
let names;
|
||||
try {
|
||||
names = fs.readdirSync(dir).filter((name) => name.endsWith('.md')).sort();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return names.flatMap((name) => {
|
||||
const filePath = path.join(dir, name);
|
||||
try {
|
||||
return [parseSurfaceBrief(fs.readFileSync(filePath, 'utf-8'), filePath)];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveSurfaceBrief(projectRoot = process.cwd(), target = null) {
|
||||
const briefs = listSurfaceBriefs(projectRoot);
|
||||
if (!target) {
|
||||
return {
|
||||
brief: briefs.length === 1 ? briefs[0] : null,
|
||||
candidates: briefs,
|
||||
reason: briefs.length === 1 ? 'only-brief' : briefs.length > 1 ? 'ambiguous' : 'none',
|
||||
};
|
||||
}
|
||||
|
||||
const normalized = normalizeSurfaceTarget(target, { projectRoot });
|
||||
if (!normalized) return { brief: null, candidates: briefs, reason: 'invalid-target' };
|
||||
const exactPath = surfaceBriefPathForTarget(normalized, { projectRoot });
|
||||
const exact = briefs.find((brief) => brief.path === exactPath && (!brief.targets.length || brief.targets.includes(normalized)));
|
||||
if (exact) return { brief: exact, candidates: briefs, reason: 'slug' };
|
||||
const mapped = briefs.filter((brief) => brief.targets.includes(normalized));
|
||||
return {
|
||||
brief: mapped.length === 1 ? mapped[0] : null,
|
||||
candidates: mapped.length > 1 ? mapped : briefs,
|
||||
reason: mapped.length === 1 ? 'mapping' : mapped.length > 1 ? 'ambiguous-target' : 'not-found',
|
||||
};
|
||||
}
|
||||
|
||||
export function writeSurfaceBrief({
|
||||
projectRoot = process.cwd(),
|
||||
primaryTarget,
|
||||
relatedTargets = [],
|
||||
body,
|
||||
}) {
|
||||
const normalizedPrimary = normalizeSurfaceTarget(primaryTarget, { projectRoot });
|
||||
if (!normalizedPrimary) throw new Error('surface brief requires a concrete project-relative primary target or URL');
|
||||
const normalizedRelated = [...new Set(relatedTargets
|
||||
.map((target) => normalizeSurfaceTarget(target, { projectRoot }))
|
||||
.filter((target) => target && target !== normalizedPrimary))];
|
||||
const slug = slugFromTarget(normalizedPrimary, { cwd: projectRoot });
|
||||
const filePath = surfaceBriefPathForTarget(normalizedPrimary, { projectRoot });
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
const frontmatter = [
|
||||
'---',
|
||||
`version: ${SURFACE_BRIEF_VERSION}`,
|
||||
`slug: ${JSON.stringify(slug)}`,
|
||||
`primary_target: ${JSON.stringify(normalizedPrimary)}`,
|
||||
`related_targets: ${JSON.stringify(normalizedRelated)}`,
|
||||
'---',
|
||||
].join('\n');
|
||||
fs.writeFileSync(filePath, `${frontmatter}\n\n${String(body || '').trim()}\n`, 'utf-8');
|
||||
return filePath;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import path from 'node:path';
|
||||
|
||||
const SLUG_MAX = 50;
|
||||
|
||||
/** Derive one clone-stable slug from a concrete file path or URL. */
|
||||
export function slugFromTarget(resolved, { cwd = process.cwd() } = {}) {
|
||||
if (!resolved || typeof resolved !== 'string') return null;
|
||||
const trimmed = resolved.trim();
|
||||
if (!trimmed) return null;
|
||||
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
let url;
|
||||
try { url = new URL(trimmed); } catch { return null; }
|
||||
return kebab(`${url.hostname}${url.pathname}`);
|
||||
}
|
||||
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
|
||||
let rel = path.relative(cwd, abs);
|
||||
if (rel.startsWith('..') || path.isAbsolute(rel)) rel = path.basename(abs);
|
||||
if (!rel || rel === '.') return null;
|
||||
return kebab(rel);
|
||||
}
|
||||
|
||||
export function kebab(value) {
|
||||
const slug = String(value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[/\\.]+/g, '-')
|
||||
.replace(/[^a-z0-9-]+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
if (!slug) return null;
|
||||
return slug.length <= SLUG_MAX ? slug : slug.slice(slug.length - SLUG_MAX).replace(/^-/, '');
|
||||
}
|
||||
@@ -2592,7 +2592,7 @@
|
||||
minWidth: '16px', height: '16px', padding: '0 4px',
|
||||
borderRadius: '999px',
|
||||
background: tuneOpen ? C.brand : BP.hairline,
|
||||
color: tuneOpen ? 'oklch(98% 0 0)' : 'inherit',
|
||||
color: tuneOpen ? C.ink : 'inherit',
|
||||
fontFamily: MONO, fontSize: '9.5px', fontWeight: '600',
|
||||
lineHeight: '1',
|
||||
boxSizing: 'border-box',
|
||||
@@ -3131,7 +3131,7 @@
|
||||
position: 'absolute', top: '2px',
|
||||
left: initial ? '18px' : '2px',
|
||||
width: '16px', height: '16px', borderRadius: '50%',
|
||||
background: 'oklch(98% 0 0)',
|
||||
background: C.ink,
|
||||
transition: 'left 0.18s ' + EASE,
|
||||
boxShadow: '0 1px 2px oklch(0% 0 0 / 0.2)',
|
||||
});
|
||||
@@ -3165,7 +3165,7 @@
|
||||
const b = el('button', {
|
||||
padding: '5px 4px', border: 'none', borderRadius: '3px',
|
||||
background: active ? C.brand : 'transparent',
|
||||
color: active ? 'oklch(98% 0 0)' : P.text,
|
||||
color: active ? C.ink : P.text,
|
||||
fontFamily: FONT, fontSize: '10.5px', fontWeight: '500',
|
||||
cursor: 'pointer', whiteSpace: 'nowrap',
|
||||
transition: 'background 0.1s ease, color 0.1s ease',
|
||||
@@ -3178,7 +3178,7 @@
|
||||
segBtns.forEach(({ btn, val }) => {
|
||||
const on = val === o.value;
|
||||
btn.style.background = on ? C.brand : 'transparent';
|
||||
btn.style.color = on ? 'oklch(98% 0 0)' : P.text;
|
||||
btn.style.color = on ? C.ink : P.text;
|
||||
});
|
||||
applyParamValue(variantEl, p, o.value);
|
||||
queueCheckpoint('param_changed');
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { resolveProjectRoot } from './context.mjs';
|
||||
import {
|
||||
listSurfaceBriefs,
|
||||
resolveSurfaceBrief,
|
||||
surfaceBriefPathForTarget,
|
||||
writeSurfaceBrief,
|
||||
} from './lib/surface-briefs.mjs';
|
||||
|
||||
function summary(brief, projectRoot) {
|
||||
return {
|
||||
slug: brief.slug,
|
||||
path: path.relative(projectRoot, brief.path).split(path.sep).join('/'),
|
||||
primaryTarget: brief.primaryTarget,
|
||||
relatedTargets: brief.relatedTargets,
|
||||
};
|
||||
}
|
||||
|
||||
function main(argv) {
|
||||
const [command, target, bodyFile, ...relatedTargets] = argv;
|
||||
const projectRoot = resolveProjectRoot(process.cwd(), target ? { targetPath: target } : {});
|
||||
if (command === 'path') {
|
||||
const filePath = surfaceBriefPathForTarget(target, { projectRoot });
|
||||
if (!filePath) throw new Error('surface brief path requires a concrete target');
|
||||
process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
|
||||
return;
|
||||
}
|
||||
if (command === 'list') {
|
||||
process.stdout.write(`${JSON.stringify(listSurfaceBriefs(projectRoot).map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
|
||||
return;
|
||||
}
|
||||
if (command === 'read') {
|
||||
const result = resolveSurfaceBrief(projectRoot, target || null);
|
||||
if (result.brief) {
|
||||
process.stdout.write(result.brief.text);
|
||||
return;
|
||||
}
|
||||
if (result.candidates.length) process.stderr.write(`${JSON.stringify(result.candidates.map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
|
||||
process.exit(2);
|
||||
}
|
||||
if (command === 'write') {
|
||||
if (!target || !bodyFile) throw new Error('usage: surface-brief.mjs write <primary-target> <body-file>');
|
||||
const filePath = writeSurfaceBrief({
|
||||
projectRoot,
|
||||
primaryTarget: target,
|
||||
relatedTargets,
|
||||
body: fs.readFileSync(bodyFile, 'utf-8'),
|
||||
});
|
||||
process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
|
||||
return;
|
||||
}
|
||||
throw new Error('usage: surface-brief.mjs <path|list|read|write> [target] [body-file] [related-target ...]');
|
||||
}
|
||||
|
||||
function isMainModule() {
|
||||
if (!process.argv[1]) return false;
|
||||
try {
|
||||
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1]);
|
||||
} catch {
|
||||
return import.meta.url === pathToFileURL(process.argv[1]).href;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMainModule()) {
|
||||
try {
|
||||
main(process.argv.slice(2));
|
||||
} catch (error) {
|
||||
process.stderr.write(`${error?.message || error}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"name": "impeccable",
|
||||
"description": "Design fluency for frontend development. 1 skill with 23 commands (/impeccable polish, /impeccable audit, /impeccable critique, etc.) and curated anti-pattern detection.",
|
||||
"version": "4.0.0-alpha.9",
|
||||
"version": "4.0.0-alpha.10",
|
||||
"author": {
|
||||
"name": "Paul Bakaus",
|
||||
"email": "paul@paulbakaus.com"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "impeccable",
|
||||
"description": "Design fluency for frontend development. 1 skill with 23 commands (/impeccable polish, /impeccable audit, /impeccable critique, etc.) and curated anti-pattern detection.",
|
||||
"version": "4.0.0-alpha.9",
|
||||
"version": "4.0.0-alpha.10",
|
||||
"author": {
|
||||
"name": "Paul Bakaus",
|
||||
"email": "paul@paulbakaus.com"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: impeccable
|
||||
description: Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.
|
||||
version: 4.0.0-alpha.9
|
||||
version: 4.0.0-alpha.10
|
||||
user-invocable: true
|
||||
argument-hint: "[craft|shape · audit|critique · animate|bolder|colorize|delight|layout|overdrive|quieter|typeset · adapt|clarify|distill · harden|onboard|optimize|polish · init|document|extract|live] [target]"
|
||||
license: Apache 2.0
|
||||
@@ -10,56 +10,55 @@ allowed-tools:
|
||||
- Bash(node .claude/skills/impeccable/scripts/*)
|
||||
---
|
||||
|
||||
Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft.
|
||||
This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as a award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft.
|
||||
|
||||
Approach every design task as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. The client has already rejected work that felt templated; they are paying for a point of view. Claude is capable of extraordinary work. Don't hold back.
|
||||
Core principles:
|
||||
- Go all out. No hedging, no shortcuts. The deliverable must be complete (except assets the user must provide).
|
||||
- Dream big and bold. Distinct, beautiful, outstanding and highly inspiring work.
|
||||
- Iterate with tools available to you (e.g. visual understanding, browser screenshots) until you think this meets the bar.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Run `node .claude/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). It prints the project's context and its directives; follow what it prints. Once its output is in the conversation, never rerun it on a later turn.
|
||||
2. `craft` and `shape` are build-path exceptions: the new-work gate below owns their flow, and on unattended runs its checkpoints resolve without pausing. For any other invoked sub-command (`audit`, `polish`, `live`, ...), immediately read **`reference/<command>.md`** after `context.mjs` (the `.native` variant from the Commands table when the platform is `ios`/`android`/`adaptive`) and follow it. This read is a hard gate: do not inspect the target, run command-specific scripts, or edit files until the reference is loaded.
|
||||
3. Read at least one project file (CSS / tokens / theme / a representative component) to learn what world you're in. If PRODUCT.md's `## Platform` is `ios` or `android`, also read `reference/<platform>.md` (`adaptive` reads both).
|
||||
1. Run `node .claude/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). Pass a named source file or route as `--target <path>`. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it.
|
||||
2. Before acting, load the one playbook that owns the request: the Commands table's reference for an explicit or clearly implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Then inspect the target and at least one representative source of incumbent visual truth (tokens, theme, CSS, component, or asset) before editing.
|
||||
|
||||
## How to design
|
||||
|
||||
**The brief wins.** Where the brief pins down a direction (a named aesthetic, an era, a place, a material, a specific font or palette), follow it exactly, including when it asks for a look this skill warns is saturated. Redirecting a pinned direction toward your own taste is a failure, not a save.
|
||||
|
||||
**Existing worlds are sacred.** Most of impeccable's work happens inside a site or app that already exists. When the surface has a committed design system (real tokens, deliberately chosen faces, a palette the brand owns), work inside that world: extend it, sharpen it, leave it unmistakably the same brand, and never degrade a working page's performance. Inventing parallel colors, fonts, or styles on an existing surface is a defect, not creativity. A scoped refinement keeps the named scope's content and media footprint unless the brief explicitly changes them; build the added emphasis by recomposing what is already there through hierarchy, proportion, rhythm, and the system's own motifs.
|
||||
|
||||
**New identity work reads the playbook first.** When nothing committed exists (greenfield, or a codebase with no real tokens or chosen faces), or the user explicitly asks for a redesign that discards the current look, you MUST read [reference/new-work.md](reference/new-work.md) before making any design decision. Missing DESIGN.md alone does not make work greenfield: code, tokens, chosen type, components, and assets are incumbent design authority. Preserve and extend them unless the user asked to replace them. Producing a genuinely new identity without the playbook yields the generic default this skill exists to prevent. Scoped fixes inside an existing world don't need it; the craft floor below governs them. `context.mjs` prints the appropriate authority directive.
|
||||
- **The brief wins.** Honor pinned aesthetics, eras, materials, fonts, and palettes even when they conflict with a saturated-pattern warning. Redirecting a clear brief toward your taste is failure.
|
||||
- **Refinement preserves; redesign replaces.** Refinement keeps the incumbent identity, behavior, copy, and everything outside scope. Ask before replacing factual copy or adding claims. Redesign keeps product truth, content, function, native affordances, and constraints, but treats the old look as evidence and anti-reference; choose a replacement world in new-work and replace DESIGN.md. Never split the difference into polish on the discarded look.
|
||||
- **Visual authority is evidence, not a filename.** Missing DESIGN.md alone does not make a project greenfield; new-work decides whether to preserve, expand, or replace the incumbent world.
|
||||
|
||||
## Modes
|
||||
|
||||
Name the visitor's mode before designing; the page's grammar follows from it, and most ruined pages are one mode wearing another mode's grammar. **The mode belongs to the surface, not the subject**: a landing page for a dense technical tool is still Persuade, with Persuade's full permission to be striking; a docs page for a fashion house is still Read. Deciding a page can be plain because its subject is workmanlike is the same category error in reverse. The brief and the surface decide the mode; PRODUCT.md's `register` field survives only as a family hint (`brand` covers Persuade and Experience, `product` covers Operate and Read). Depth beyond the paragraphs below: [reference/new-work.md](reference/new-work.md) when inventing identity, [reference/operate.md](reference/operate.md) for substantial Operate and Read work.
|
||||
Choose the mode from the requested surface, not the product, and persist it only in that surface brief. A tool's landing page is still Persuade; a fashion house's documentation is still Read. See [new-work.md](reference/new-work.md) for new surfaces and [operate.md](reference/operate.md) for deeper Operate/Read guidance.
|
||||
|
||||
**Persuade** (the surface exists to win someone over; design IS the product). The deliverable is an impression that stops the scroll, earns the click, converts. Spans every genre; don't collapse them into one look. On new surfaces, briefs that imply imagery must ship real, verified imagery; a colored rectangle where a photo belongs reads as incomplete. New Persuade surfaces take their typeface procedure and reject list from [reference/new-work.md](reference/new-work.md).
|
||||
|
||||
**Operate** (the surface is a tool someone works in; design SERVES the task). A person getting something done: scanability and consistency outrank expressiveness. These surfaces earn trust by feeling native to their platform: system font stacks and workhorse UI faces are legitimate and often correct here (the Persuade reject list does not apply). The brand lives in the details: focus states, empty states, microcopy, one owned accent. The usage scene is part of the spec: an interface read outdoors, in motion, or at a glance must survive its real ambient light, and the theme follows the scene, not the category's habit.
|
||||
|
||||
**Read** (the surface exists to be understood; long-form, reference, guidance). The deliverable is comprehension, and comprehension is earned twice: a structure the reader can hold in their head with nothing standing between them and the answer, and a reading experience good enough to stay in, through typographic quality and whatever visual or interactive support genuinely helps the reader follow. The brand lives in type, spacing, and small accents.
|
||||
|
||||
**Experience** (the surface presents a body of work; the page IS the work). The artifact leads, the interface recedes, and the visitor meets the work itself in the first viewport at every screen size. Boldness here means trusting the work.
|
||||
- **Persuade:** win someone over; design is the product. Earn attention and action. Ship real imagery when the brief needs it; follow the committed world, not category habit.
|
||||
- **Operate:** help someone do work. Scanability, consistency, native expectations, and the real usage scene outrank expression. Brand lives in precise details.
|
||||
- **Read:** make something understood. Structure for comprehension, then make the reading experience worth staying in.
|
||||
- **Experience:** present a body of work. Let the artifact lead from the first viewport; the interface recedes.
|
||||
|
||||
## Craft floor
|
||||
|
||||
Build to this floor without announcing it. The design detector (the project hook, `node .claude/skills/impeccable/scripts/detect.mjs --json <file>`, or `audit`) verifies most of it mechanically; resolve every finding before finalizing. Fix real defects, but use context judgment rather than distorting intentional design to appease a false positive. Classify any intentional exception explicitly and use the hook system's narrowest appropriate waiver when it must persist.
|
||||
Build to this floor without announcing it.
|
||||
|
||||
- Contrast: body text ≥4.5:1 against its background (placeholders too); large text ≥3:1. 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.
|
||||
- Shadows describe real light: an offset and a soft blur. A zero-offset colored halo is decoration announcing itself.
|
||||
- Spacing has rhythm: generous separations, tight groupings; cramped padding reads as broken; the space above a heading exceeds the space below it. Verify computed spacing, not intended spacing.
|
||||
- Type: body line length 65-75ch; display clamp() max ≤6rem; letter-spacing ≥-0.04em; `text-wrap: balance` on headings; modular scale ≥1.25 between steps; light-on-dark adds 0.05-0.1 line-height. Pair faces on a contrast axis, never two similar-but-not-identical ones; one family with committed weight contrast beats a timid pair. Test headings at every breakpoint; overflow means reduce the clamp or rewrite the copy.
|
||||
- Motion is part of the build: one orchestrated moment beats scattered effects; ease-out exponential curves; reveals enhance an already-visible default (content gated on a class-triggered transition ships blank in hidden tabs and headless renderers). Responsive down to mobile and visible keyboard focus are part of the floor.
|
||||
- Ship real content (no placeholders, dead links, or fake controls) and cover the interaction states people will actually hit (hover, focus, disabled, loading, error, empty).
|
||||
- Copy is design material: name things the way the page's own people speak, make every control say what it does, and make every error say what happened and what to do next.
|
||||
- Before finishing, re-read the brief: every requirement it names must exist on the page, findable in seconds. A beautiful page missing an asked-for feature is unfinished.
|
||||
- **Contrast:** body and placeholder text ≥4.5:1; large text ≥3:1. On colored surfaces, tint secondary text from that hue or the foreground instead of using gray.
|
||||
- **Depth:** shadows describe light with offset and soft blur; zero-offset colored halos are decoration.
|
||||
- **Spacing:** tight groups, generous separation, no cramped containers; space above a heading exceeds space below. Verify computed values.
|
||||
- **Type:** body measure 65–75ch; display max 6rem and tracking floor -0.04em; balance headings; use clear scale/weight contrast; test overflow at every breakpoint.
|
||||
- **Motion:** author one coherent moment instead of scattered effects. Use exponential ease-out and an already-visible default. Premium motion is not transform/opacity alone: it may add focus, depth, masks, light, or material change through blur/filter, backdrop-filter, clip-path/masks, or shadow when smooth. Always provide reduced motion.
|
||||
- **Shipping:** real content, working controls, responsive composition, keyboard focus, and the states users hit: hover, disabled, loading, error, and empty.
|
||||
- **Copy:** use the product's language; controls name their action, errors name the problem and recovery.
|
||||
- **Coverage:** every brief requirement must exist and be findable within seconds.
|
||||
|
||||
Before finishing changed UI, follow the quality guidance supplied by `context.mjs` and hooks. Context requests a manual scan only when no automatic detector is active; never add a second detector pass.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Category | Description | Reference |
|
||||
|---|---|---|---|
|
||||
| `craft [feature]` | Build | The standard build flow with attended checkpoints | [reference/new-work.md](reference/new-work.md) |
|
||||
| `craft [feature]` | Build | Deprecated alias for an ordinary new-work request | [reference/craft.md](reference/craft.md) |
|
||||
| `shape [feature]` | Build | Plan UX/UI before writing code | [reference/shape.md](reference/shape.md) |
|
||||
| `init` | Build | Set up project context: PRODUCT.md, DESIGN.md, live config, next steps | [reference/init.md](reference/init.md) |
|
||||
| `init` | Build | Capture durable product context in PRODUCT.md | [reference/init.md](reference/init.md) |
|
||||
| `document` | Build | Generate DESIGN.md from existing project code | [reference/document.md](reference/document.md) |
|
||||
| `extract [target]` | Build | Pull reusable tokens and components into design system | [reference/extract.md](reference/extract.md) |
|
||||
| `critique [target]` | Evaluate | UX design review with heuristic scoring | [reference/critique.md](reference/critique.md) |
|
||||
@@ -81,7 +80,14 @@ Build to this floor without announcing it. The design detector (the project hook
|
||||
| `optimize [target]` | Fix | Diagnose and fix UI performance | [reference/optimize.md](reference/optimize.md) |
|
||||
| `live` | Iterate | Visual variant mode: pick elements in the browser, generate alternatives | [reference/live.md](reference/live.md) |
|
||||
|
||||
Routing: **no argument** → read [reference/routing.md](reference/routing.md) and present the context-aware menu (never auto-run a command). **First word matches a command** (or `pin` / `unpin` / `hooks`) → load its reference (native variant on native platforms) and follow it; everything after the command name is the target. **Intent clearly maps to one command** ("fix the spacing" → `layout`, "rewrite this error" → `clarify`) → same; if two fit, ask once. **Otherwise** → general design invocation: apply Setup and this file's guidance; builds flow through the new-work gate above, whose playbook carries the direction checkpoint and the finishing pass. `teach` routes to `init`, and `craft` routes to the standard build flow with attended checkpoints. If setup diverted into `init` for a build request, finish init, refresh context, then resume.
|
||||
Routing:
|
||||
|
||||
- **No argument:** read [routing.md](reference/routing.md) and present its context-aware menu; never auto-run a command.
|
||||
- **Explicit or clearly implied command:** load its reference (native variant on native platforms) and follow it. Ask once if two commands fit.
|
||||
- **Otherwise:** treat the request as general design work. Missing PRODUCT.md routes through init; new surfaces and replacement worlds use new-work.
|
||||
- `teach` aliases `init`. `craft` is a deprecated alias for ordinary new-work and adds nothing. `shape` owns task discovery, then enters new-work only for visual-world and surface-concept decisions.
|
||||
|
||||
After init writes PRODUCT.md, resume without rerunning `context.mjs`.
|
||||
|
||||
**Pin / Unpin:** `node .claude/skills/impeccable/scripts/pin.mjs <pin|unpin> <command>` creates or removes a standalone `/<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native Android apps: Jetpack Compose, Android Views, React Native, Expo, Flutter shipping to Android hardware.
|
||||
|
||||
On native, register narrows. Material Design 3 governs structure, navigation, and interaction whatever the register; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
On native, the visitor mode narrows what expression may override. Material Design 3 governs structure, navigation, and interaction in every mode; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
|
||||
## The Android slop test
|
||||
|
||||
|
||||
@@ -1,203 +1,88 @@
|
||||
> **Additional context needed**: performance constraints.
|
||||
|
||||
Add motion that conveys state, gives feedback, and clarifies hierarchy. Cut motion that exists only for decoration. Animation fatigue is a real cost; spend the budget on the moments that need it.
|
||||
Use motion to explain state, relationship, and hierarchy, or to create one authored moment the surface has earned. Decoration without purpose is animation debt.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: motion is part of the voice; one well-rehearsed entrance beats scattered micro-interactions. The saturated AI default is fade-and-rise reveals on every scrolled section; that's a tell, not a choreography. Reserve scroll-triggered motion for moments that earn it.
|
||||
- **Persuade + Experience:** motion may carry the voice. Prefer one rehearsed focal sequence to repeated section reveals.
|
||||
- **Operate + Read:** motion serves feedback, state, and continuity. Keep routine transitions fast and do not make users wait through page-load choreography.
|
||||
- **Native (`ios` / `android` / `adaptive`):** follow the Motion section of [ios.md](ios.md) or [android.md](android.md), including the platform's Reduce Motion behavior. Do not apply the web tooling below.
|
||||
|
||||
Operate + Read: 150–250 ms on most transitions. Motion conveys state: feedback, reveal, loading, transitions between views. No page-load choreography; users are in a task and won't wait for it.
|
||||
## Find the job
|
||||
|
||||
Native (`ios` / `android` / `adaptive`): implementation follows the Motion section of [ios.md](ios.md) / [android.md](android.md) (read it first if Setup hasn't already): system transitions and OS Reduce Motion, never the web tooling below.
|
||||
Inspect the existing motion language, interaction states, target devices, and performance budget. Find only the places where motion would:
|
||||
|
||||
---
|
||||
- acknowledge an action;
|
||||
- make a state change or spatial relationship legible;
|
||||
- preserve continuity through navigation or layout change;
|
||||
- direct attention at a meaningful moment;
|
||||
- embody the selected visual world.
|
||||
|
||||
## Assess Animation Opportunities
|
||||
Ask only when a material constraint cannot be inferred. Do not animate a static area merely because it exists.
|
||||
|
||||
Analyze where motion would improve the experience:
|
||||
## Set the motion thesis
|
||||
|
||||
1. **Identify static areas**:
|
||||
- **Missing feedback**: Actions without visual acknowledgment (button clicks, form submission, etc.)
|
||||
- **Jarring transitions**: Instant state changes that feel abrupt (show/hide, page loads, route changes)
|
||||
- **Unclear relationships**: Spatial or hierarchical relationships that aren't obvious
|
||||
- **Lack of delight**: Functional but joyless interactions
|
||||
- **Missed guidance**: Opportunities to direct attention or explain behavior
|
||||
Write a short plan before implementation:
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the personality? (Playful vs serious, energetic vs calm)
|
||||
- What's the performance budget? (Mobile-first? Complex page?)
|
||||
- Who's the audience? (Motion-sensitive users? Power users who want speed?)
|
||||
- What matters most? (One hero animation vs many micro-interactions?)
|
||||
- **Focal moment:** the one sequence or interaction that deserves authorship, if any.
|
||||
- **Continuity:** the state, layout, or navigation changes that need explanation.
|
||||
- **Feedback:** the controls and outcomes that need acknowledgment.
|
||||
- **Budget:** which effects may be expensive, how often they run, and the reduced-motion equivalent.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and call the AskUserQuestion tool to clarify.
|
||||
The focal moment must come from this product and surface concept. A generic fade-and-rise, hover lift, parallax layer, or scroll reveal is not a thesis.
|
||||
|
||||
**CRITICAL**: Respect `prefers-reduced-motion`. Always provide non-animated alternatives for users who need them.
|
||||
## Choose material by meaning
|
||||
|
||||
## Plan Animation Strategy
|
||||
Transform and opacity are reliable foundations, not the entire palette. Choose properties for what the transition communicates:
|
||||
|
||||
Create a purposeful animation plan:
|
||||
- **Continuity and relationship:** shared-element motion, FLIP-style transforms, view transitions, or deliberate spatial movement.
|
||||
- **Focus and depth:** bounded blur, filter, backdrop, light, or shadow changes.
|
||||
- **Reveal and composition:** masks, clip paths, cropping, or controlled occlusion.
|
||||
- **Material and energy:** color, gradient position, texture, distortion, or shader effects when the world and runtime support them.
|
||||
- **State and feedback:** the smallest change that makes cause and result unmistakable.
|
||||
|
||||
- **Feedback layer**: Which interactions need acknowledgment?
|
||||
- **Transition layer**: Which state changes need smoothing?
|
||||
- **Entrance moment**: The ONE entrance worth rehearsing, where the mode invites it. Not every surface wants one.
|
||||
- **Delight layer**: Where can we surprise and delight?
|
||||
Do not stack techniques for spectacle. One strong material idea, carried through the focal sequence and quiet supporting states, is usually enough.
|
||||
|
||||
**IMPORTANT**: One well-orchestrated experience beats scattered animations everywhere. Focus on high-impact moments.
|
||||
Sibling stagger is appropriate when a list appears as a list. Cap the total delay, and never reinterpret every scrolled section as a staggered list.
|
||||
|
||||
## Implement Animations
|
||||
## Timing and easing
|
||||
|
||||
Add motion systematically across these categories:
|
||||
Timing should express distance and consequence:
|
||||
|
||||
### Micro-interactions
|
||||
- **Button feedback**:
|
||||
- Hover: Subtle scale (1.02-1.05), color shift, shadow increase
|
||||
- Click: Quick scale down then up (0.95 → 1), ripple effect
|
||||
- Loading: Spinner or pulse state
|
||||
- **Form interactions**:
|
||||
- Input focus: Border color transition, slight scale or glow
|
||||
- Validation: Shake on error, check mark on success, smooth color transitions
|
||||
- **Toggle switches**: Smooth slide + color transition (200-300ms)
|
||||
- **Checkboxes/radio**: Check mark animation, ripple effect
|
||||
- **Like/favorite**: Scale + rotation, particle effects, color transition
|
||||
| Duration | Typical use |
|
||||
|---|---|
|
||||
| 100–150 ms | immediate feedback |
|
||||
| 150–300 ms | routine state change |
|
||||
| 300–500 ms | layout, overlay, or view transition |
|
||||
| 500–800 ms | a deliberately authored focal entrance |
|
||||
|
||||
### State Transitions
|
||||
- **Show/hide**: Fade + slide (not instant), appropriate timing (200-300ms)
|
||||
- **Expand/collapse**: Height transition with overflow handling, icon rotation
|
||||
- **Loading states**: Skeleton screen fades, spinner animations, progress bars
|
||||
- **Success/error**: Color transitions, icon animations, gentle scale pulse
|
||||
- **Enable/disable**: Opacity transitions, cursor changes
|
||||
Exit faster than entrance. Use natural deceleration such as `cubic-bezier(0.16, 1, 0.3, 1)` for confident arrivals; do not use bounce or elastic curves by reflex. Long feedback feels like latency.
|
||||
|
||||
### Entrance Animations
|
||||
- **The one entrance moment** (where the mode invites it): a committed entrance for primary content (scale, parallax, or a creative effect)
|
||||
- **Modal/drawer entry**: Smooth slide + fade, backdrop fade, focus management
|
||||
- **List rhythm**: Sibling stagger is legitimate for cards-in-a-grid or list-items-appearing. Whole-section fade-on-scroll is not a list and is not legitimate. Cap total stagger time: 10 items at 50ms each = 500ms total. For more items, reduce per-item delay or cap the staggered count.
|
||||
## Implement to the runtime
|
||||
|
||||
Use CSS custom properties for clean stagger: `animation-delay: calc(var(--i, 0) * 50ms)` with `style="--i: 0"`, `style="--i: 1"`, etc. on each item.
|
||||
- Use CSS transitions and keyframes for declarative state and bounded sequences.
|
||||
- Use Web Animations API or the project's existing motion library for interruption, sequencing, and dynamic values.
|
||||
- Use View Transitions or shared-element techniques when continuity across states is the point.
|
||||
- Use scroll-driven motion only when the scroll relationship itself carries meaning, with a robust fallback.
|
||||
- Do not add a dependency for an effect the existing stack can express cleanly.
|
||||
|
||||
### Navigation & Flow
|
||||
- **Page transitions**: Crossfade between routes, shared element transitions
|
||||
- **Tab switching**: Slide indicator, content fade/slide
|
||||
- **Carousel/slider**: Smooth transforms, snap points, momentum
|
||||
- **Scroll effects**: Parallax layers, sticky headers with state changes, scroll progress indicators
|
||||
Keep content visible in the default state so failed scripts do not hide the page. Avoid casually animating layout-driving properties such as `width`, `height`, `top`, `left`, and margins; use FLIP, transforms, or grid techniques when appropriate. Bound blur, filter, shadow, canvas, and shader work to isolated regions. Apply `will-change` only during known animation. Measure on target viewports and devices rather than assuming transform means fast.
|
||||
|
||||
### Feedback & Guidance
|
||||
- **Hover hints**: Tooltip fade-ins, cursor changes, element highlights
|
||||
- **Drag & drop**: Lift effect (shadow + scale), drop zone highlights, smooth repositioning
|
||||
- **Copy/paste**: Brief highlight flash on paste, "copied" confirmation
|
||||
- **Focus flow**: Highlight path through form or workflow
|
||||
## Accessibility and control
|
||||
|
||||
### Delight Moments
|
||||
- **Empty states**: Subtle floating animations on illustrations
|
||||
- **Completed actions**: Confetti, check mark flourish, success celebrations
|
||||
- **Easter eggs**: Hidden interactions for discovery
|
||||
- **Contextual animation**: Weather effects, time-of-day themes, seasonal touches
|
||||
Honor `prefers-reduced-motion` with an intentional alternative. Preserve state change and hierarchy while removing travel, parallax, flashing, or prolonged sequences. Do not replace every animation globally with `0.01ms` if that destroys useful feedback. Motion must never block focus, interaction, reading, or task completion.
|
||||
|
||||
## Technical Implementation
|
||||
Respect autoplay and sound preferences. Any nonessential loop must stop when offscreen or hidden.
|
||||
|
||||
Use appropriate techniques for each animation:
|
||||
## Verify
|
||||
|
||||
### Timing & Easing
|
||||
- The focal motion is specific to the selected world and surface.
|
||||
- Every supporting animation explains feedback, state, or relationship.
|
||||
- Interruption and repeated use behave correctly.
|
||||
- Desktop, mobile, keyboard, and reduced-motion paths remain usable.
|
||||
- Expensive effects stay smooth on the target device.
|
||||
- Removing an animation would lose meaning or authored character, not merely decoration.
|
||||
|
||||
**Duration: the 100/300/500 rule.** Timing matters more than easing for "feels right":
|
||||
|
||||
| Duration | Use Case | Examples |
|
||||
|----------|----------|----------|
|
||||
| **100–150ms** | Instant feedback | Button press, toggle, color change |
|
||||
| **200–300ms** | State changes | Menu open, tooltip, hover state |
|
||||
| **300–500ms** | Layout changes | Accordion, modal, drawer |
|
||||
| **500–800ms** | Entrance animations | Page load, hero reveal |
|
||||
|
||||
**Easing curves (use these, not CSS defaults):**
|
||||
```css
|
||||
/* Recommended: natural deceleration */
|
||||
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* Smooth */
|
||||
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Slightly snappier */
|
||||
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Confident, decisive */
|
||||
|
||||
/* AVOID: feel dated and tacky */
|
||||
/* bounce: cubic-bezier(0.34, 1.56, 0.64, 1); */
|
||||
/* elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6); */
|
||||
```
|
||||
|
||||
**Exit animations are faster than entrances.** Use ~75% of enter duration.
|
||||
|
||||
### CSS Animations
|
||||
```css
|
||||
/* Prefer for simple, declarative animations */
|
||||
- transitions for state changes
|
||||
- @keyframes for complex sequences
|
||||
- transform and opacity for reliable movement
|
||||
- blur, filters, masks, clip paths, shadows, and color shifts for premium atmospheric effects when verified smooth
|
||||
```
|
||||
|
||||
### JavaScript Animation
|
||||
```javascript
|
||||
/* Use for complex, interactive animations */
|
||||
- Web Animations API for programmatic control
|
||||
- Framer Motion for React
|
||||
- GSAP for complex sequences
|
||||
```
|
||||
|
||||
### Motion Materials
|
||||
|
||||
Transform and opacity are reliable defaults, not the whole palette. Premium interfaces often need atmospheric properties. Match material to effect:
|
||||
|
||||
- **Transform / opacity**: movement, press feedback, simple reveals, list choreography
|
||||
- **Blur / filter / backdrop-filter**: focus pulls, depth, glass or lens effects, softened entrances
|
||||
- **Clip-path / masks**: wipes, reveals, editorial cropping, product-like transitions
|
||||
- **Shadow / glow / color filters**: energy, affordance, focus, warmth, active state
|
||||
- **Grid-template-rows or FLIP-style transforms**: expanding and reflowing layout without animating `height` directly
|
||||
|
||||
The hard rule isn't "transform and opacity only." It's: avoid animating layout-driving properties casually (`width`, `height`, `top`, `left`, margins), keep expensive effects bounded to small or isolated areas, and verify smoothness in-browser on target viewports.
|
||||
|
||||
### Performance
|
||||
- **Layout safety**: Avoid casual animation of layout-driving properties (`width`, `height`, `top`, `left`, margins)
|
||||
- **will-change**: Add sparingly for known expensive animations only (e.g. on `:hover` or an `.animating` class), never preemptively across the whole page
|
||||
- **Scroll triggers**: Use Intersection Observer instead of scroll event listeners; unobserve after the animation fires once
|
||||
- **Bound expensive effects**: Keep blur/filter/shadow areas small or isolated, use `contain` where appropriate
|
||||
- **Monitor FPS**: Ensure 60fps on target devices
|
||||
|
||||
### Perceived Performance
|
||||
|
||||
Nobody cares how fast your site *is*, only how fast it feels. The 80ms threshold: anything under ~80ms feels instant because our brains buffer sensory input for that long to synchronize perception. Target this for micro-interactions.
|
||||
|
||||
- **Preemptive start**: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening.
|
||||
- **Early completion**: Show content progressively, don't wait for everything (progressive images, streaming HTML, skeleton fade-ins).
|
||||
- **Optimistic UI**: Update the interface immediately, handle failures gracefully. Use for low-stakes actions (likes, follows). Avoid for payments or destructive operations.
|
||||
- **Easing affects perceived duration**: Ease-in (accelerating toward completion) makes tasks feel shorter because the peak-end effect weights final moments heavily. Ease-out feels satisfying for entrances.
|
||||
- **Caution**: Too-fast responses can decrease perceived value for complex operations (search, analysis). Sometimes a brief delay signals "real work" is happening.
|
||||
|
||||
### Accessibility
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
- Use bounce or elastic easing curves; they feel dated and draw attention to the animation itself
|
||||
- Animate layout properties casually (`width`, `height`, `top`, `left`, margins) when transform, FLIP, or grid-based techniques would work
|
||||
- Use durations over 500ms for feedback (it feels laggy)
|
||||
- Animate without purpose (every animation needs a reason)
|
||||
- Ignore `prefers-reduced-motion` (this is an accessibility violation)
|
||||
- Animate everything (animation fatigue makes interfaces feel exhausting)
|
||||
- Block interaction during animations unless intentional
|
||||
|
||||
## Verify Quality
|
||||
|
||||
Test animations thoroughly:
|
||||
|
||||
- **Smooth at 60fps**: No jank on target devices
|
||||
- **Feels natural**: Easing curves feel organic, not robotic
|
||||
- **Appropriate timing**: Not too fast (jarring) or too slow (laggy)
|
||||
- **Reduced motion works**: Animations disabled or simplified appropriately
|
||||
- **Doesn't block**: Users can interact during/after animations
|
||||
- **Adds value**: Makes interface clearer or more delightful
|
||||
|
||||
When the motion clarifies state instead of decorating it, hand off to `/impeccable polish` for the final pass.
|
||||
When motion earns its place, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -52,11 +52,11 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
|
||||
**Score 0-4**: 0=Desktop-only (breaks on mobile), 1=Major issues (some breakpoints, many failures), 2=Partial (works on mobile, rough edges), 3=Good (responsive, minor touch target or overflow issues), 4=Excellent (fluid, all viewports, proper touch targets)
|
||||
|
||||
### 5. Anti-Patterns (CRITICAL)
|
||||
### 5. Implementation Integrity (CRITICAL)
|
||||
|
||||
Check against ALL the **DON'T** guidelines from the parent impeccable skill (already loaded in this context). Look for AI slop tells (AI color palette, gradient text, glassmorphism, hero metrics, card grids, generic fonts) and general design anti-patterns (gray on color, nested cards, bounce easing, redundant copy).
|
||||
Run the bundled detector and verify each finding in context. Look for repeated implementation shortcuts, design-system drift, misleading or decorative content, and structure that is interchangeable with an unrelated product. Keep deterministic findings separate from visual judgment and call out false positives.
|
||||
|
||||
**Score 0-4**: 0=AI slop gallery (5+ tells), 1=Heavy AI aesthetic (3-4 tells), 2=Some tells (1-2 noticeable), 3=Mostly clean (subtle issues only), 4=No AI tells (distinctive, intentional design)
|
||||
**Score 0-4**: 0=systemic drift, 1=major repeated failures, 2=several verified issues, 3=minor isolated issues, 4=coherent and intentional
|
||||
|
||||
## Generate Report
|
||||
|
||||
@@ -68,13 +68,13 @@ Check against ALL the **DON'T** guidelines from the parent impeccable skill (alr
|
||||
| 2 | Performance | ? | |
|
||||
| 3 | Responsive Design | ? | |
|
||||
| 4 | Theming | ? | |
|
||||
| 5 | Anti-Patterns | ? | |
|
||||
| 5 | Implementation Integrity | ? | |
|
||||
| **Total** | | **??/20** | **[Rating band]** |
|
||||
|
||||
**Rating bands**: 18-20 Excellent (minor polish), 14-17 Good (address weak dimensions), 10-13 Acceptable (significant work needed), 6-9 Poor (major overhaul), 0-5 Critical (fundamental issues)
|
||||
|
||||
### Anti-Patterns Verdict
|
||||
**Start here.** Pass/fail: Does this look AI-generated? List specific tells. Be brutally honest.
|
||||
### Implementation Integrity Verdict
|
||||
**Start here.** Pass/fail: does the implementation express a coherent product-specific system? Cite verified evidence and detector findings.
|
||||
|
||||
### Executive Summary
|
||||
- Audit Health Score: **??/20** ([rating band])
|
||||
@@ -93,7 +93,7 @@ Tag every issue with **P0-P3 severity**:
|
||||
For each issue, document:
|
||||
- **[P?] Issue name**
|
||||
- **Location**: Component, file, line
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Anti-Pattern
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Implementation Integrity
|
||||
- **Impact**: How it affects users
|
||||
- **WCAG/Standard**: Which standard it violates (if applicable)
|
||||
- **Recommendation**: How to fix it
|
||||
@@ -132,4 +132,3 @@ After presenting the summary, tell the user:
|
||||
- Skip positive findings (celebrate what works)
|
||||
- Forget to prioritize (everything can't be P0)
|
||||
- Report false positives without verification
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
- **Hard-coded colors**: raw hex instead of semantic system colors (iOS) / Material color roles (Android) / design tokens
|
||||
- **Broken dark appearance**: missing dark variants, poor contrast in dark, quick inverts
|
||||
- **Dynamic Color** (Android 12+): no static fallback scheme, or ignored where it fits
|
||||
- **Off-platform materials**: hand-rolled blur/glassmorphism instead of system materials or tonal elevation
|
||||
- **Off-platform materials**: hand-rolled visual materials where system materials or tonal elevation are expected
|
||||
|
||||
**Score 0-4**: 0=Hard-coded everything, 1=Minimal tokens, 2=Partial (tokens exist, inconsistently used), 3=Good (minor hard-coded values), 4=Excellent (semantic throughout, both appearances first-class)
|
||||
|
||||
@@ -48,7 +48,7 @@ Score against the loaded platform reference(s), including their slop tests. **Ch
|
||||
- **Off-platform navigation**: custom global nav, overloaded tab bars, iOS patterns on Android or vice versa
|
||||
- **Web-shaped controls**: HTML-style buttons, custom toggles, hover-dependent affordances
|
||||
- **Icon drift**: mixed icon sets instead of SF Symbols / Material Symbols
|
||||
- **AI tells**: the shared absolute bans still apply (AI palette, gradient text, hero metrics)
|
||||
- **System drift**: repeated shortcuts or decorative patterns that conflict with the product, platform, or established design system
|
||||
|
||||
**Score 0-4**: 0=Web port (nothing native), 1=Heavy violations (3-4 kinds), 2=Some (1-2 noticeable), 3=Mostly conformant (subtle issues), 4=Fully native (a fluent user trusts every screen)
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
## Why it reads flat
|
||||
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing, the specificity of the copy. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
|
||||
## The amplification
|
||||
|
||||
- **Amplify what the system already owns.** Reuse its motif and its type scale at full strength, turned up for this section rather than invented for it. The bolder version should look more like the same brand, not less.
|
||||
- **Let the content carry the weight.** Flat copy makes a flat design, and no amount of size fixes a generic claim. Make every word specific enough to earn its place, and let the section's real evidence do the work that a decorative addition would otherwise fake.
|
||||
- **Keep content true.** Existing claims are part of the scope: preserve them unless the user supplies replacements. If real evidence is essential to the direction but absent, ask for it.
|
||||
- **Commit, then clarify.** Half-measures read as noise. Make the one decisive move completely, then quiet everything around it so the move is legible. If every element got louder, the section got flatter.
|
||||
- **Give it its own rhythm.** The target should read as a peak in the scroll, a shift in density or pace from what surrounds it, not simply more of the same.
|
||||
|
||||
|
||||
@@ -1,288 +1,94 @@
|
||||
> **Additional context needed**: audience technical level and users' mental state in context.
|
||||
> **Additional context needed**: audience knowledge and emotional state.
|
||||
|
||||
Find the unclear, confusing, or poorly written interface text and rewrite it. Vague copy creates support tickets and abandonment; specific copy gets users through the task.
|
||||
Rewrite unclear interface text so users understand what happened, what matters, and what to do next. Preserve factual meaning, product terminology, and brand voice.
|
||||
|
||||
## Audit the language
|
||||
|
||||
---
|
||||
Read the entire interaction path, not isolated strings. Identify:
|
||||
|
||||
## Assess Current Copy
|
||||
- ambiguous nouns, verbs, and actions;
|
||||
- internal jargon or assumed knowledge;
|
||||
- vague labels, outcomes, and system states;
|
||||
- missing consequences, recovery, or timing;
|
||||
- inconsistent terminology and capitalization;
|
||||
- redundant headings, intros, helper text, and confirmations;
|
||||
- text that breaks at realistic widths or in translation;
|
||||
- tone that ignores stress, risk, success, or urgency.
|
||||
|
||||
Identify what makes the text unclear or ineffective:
|
||||
Infer audience and task from product context and surrounding UI. Ask before changing factual claims, legal meaning, or a term that may be domain-specific.
|
||||
|
||||
1. **Find clarity problems**:
|
||||
- **Jargon**: Technical terms users won't understand
|
||||
- **Ambiguity**: Multiple interpretations possible
|
||||
- **Passive voice**: "Your file has been uploaded" vs "We uploaded your file"
|
||||
- **Length**: Too wordy or too terse
|
||||
- **Assumptions**: Assuming user knowledge they don't have
|
||||
- **Missing context**: Users don't know what to do or why
|
||||
- **Tone mismatch**: Too formal, too casual, or inappropriate for situation
|
||||
## Set the message hierarchy
|
||||
|
||||
2. **Understand the context**:
|
||||
- Who's the audience? (Technical? General? First-time users?)
|
||||
- What's the user's mental state? (Stressed during error? Confident during success?)
|
||||
- What's the action? (What do we want users to do?)
|
||||
- What's the constraint? (Character limits? Space limitations?)
|
||||
For each state, decide:
|
||||
|
||||
**CRITICAL**: Clear copy helps users succeed. Unclear copy creates frustration, errors, and support tickets.
|
||||
1. the one fact the user needs now;
|
||||
2. the action available next;
|
||||
3. supporting context that changes the decision;
|
||||
4. the appropriate tone for this moment.
|
||||
|
||||
## Plan Copy Improvements
|
||||
Say each idea once. If the heading already explains the state, the introduction should add new information or disappear.
|
||||
|
||||
Create a strategy for clearer communication:
|
||||
## Rewrite by function
|
||||
|
||||
- **Primary message**: What's the ONE thing users need to know?
|
||||
- **Action needed**: What should users do next (if anything)?
|
||||
- **Tone**: How should this feel? (Helpful? Apologetic? Encouraging?)
|
||||
- **Constraints**: Length limits, brand voice, localization considerations
|
||||
### Actions and navigation
|
||||
|
||||
**IMPORTANT**: Good UX writing is invisible. Users should understand immediately without noticing the words.
|
||||
Use a specific verb and object when the outcome is not already obvious. Labels should describe what will happen, not the gesture used to trigger it. Keep the same noun and verb for the same concept throughout the product.
|
||||
|
||||
## Improve Copy Systematically
|
||||
For destructive actions, name the object and consequence. Prefer undo over confirmation when recovery is safe. When confirmation is necessary, name the action on both the message and button instead of using `Yes`, `No`, `OK`, or `Submit`.
|
||||
|
||||
Refine text across these common areas:
|
||||
### Forms
|
||||
|
||||
### Error Messages
|
||||
**Bad**: "Error 403: Forbidden"
|
||||
**Good**: "You don't have permission to view this page. Contact your admin for access."
|
||||
Use persistent labels; placeholders are examples, not labels. Put format and eligibility requirements before submission. Explain why information is requested only when it is not obvious. Required and optional treatment should be consistent.
|
||||
|
||||
**Bad**: "Invalid input"
|
||||
**Good**: "Email addresses need an @ symbol. Try: name@example.com"
|
||||
Validation says what needs attention and how to correct it without blaming the user. Keep related instructions near the field and announce errors accessibly.
|
||||
|
||||
**Principles**:
|
||||
- Explain what went wrong in plain language
|
||||
- Suggest how to fix it
|
||||
- Don't blame the user
|
||||
- Include examples when helpful
|
||||
- Link to help/support if applicable
|
||||
|
||||
### Form Labels & Instructions
|
||||
**Bad**: "DOB (MM/DD/YYYY)"
|
||||
**Good**: "Date of birth" (with placeholder showing format)
|
||||
|
||||
**Bad**: "Enter value here"
|
||||
**Good**: "Your email address" or "Company name"
|
||||
|
||||
**Principles**:
|
||||
- Use clear, specific labels (not generic placeholders)
|
||||
- Show format expectations with examples
|
||||
- Explain why you're asking (when not obvious)
|
||||
- Put instructions before the field, not after
|
||||
- Keep required field indicators clear
|
||||
|
||||
### Button & CTA Text
|
||||
**Bad**: "Click here" | "Submit" | "OK"
|
||||
**Good**: "Create account" | "Save changes" | "Got it, thanks"
|
||||
### Errors and permissions
|
||||
|
||||
**Principles**:
|
||||
- Describe the action specifically
|
||||
- Use active voice (verb + noun)
|
||||
- Match user's mental model
|
||||
- Be specific ("Save" is better than "OK")
|
||||
An actionable error answers:
|
||||
|
||||
### Help Text & Tooltips
|
||||
**Bad**: "This is the username field"
|
||||
**Good**: "Choose a username. You can change this later in Settings."
|
||||
1. what failed;
|
||||
2. why, when known and useful;
|
||||
3. how to recover or what alternative remains.
|
||||
|
||||
**Principles**:
|
||||
- Add value (don't just repeat the label)
|
||||
- Answer the implicit question ("What is this?" or "Why do you need this?")
|
||||
- Keep it brief but complete
|
||||
- Link to detailed docs if needed
|
||||
Do not expose internal codes as the primary message. Do not promise a cause or resolution the system cannot know. Treat privacy, payment, deletion, access loss, and blocked work seriously; warmth is welcome, jokes are not.
|
||||
|
||||
### Empty States
|
||||
**Bad**: "No items"
|
||||
**Good**: "No projects yet. Create your first project to get started."
|
||||
### Loading, empty, and success states
|
||||
|
||||
**Principles**:
|
||||
- Explain why it's empty (if not obvious)
|
||||
- Show next action clearly
|
||||
- Make it welcoming, not dead-end
|
||||
Loading text names the real operation and sets an honest expectation when the wait is meaningful. Show determinate progress when available; never invent progress.
|
||||
|
||||
### Success Messages
|
||||
**Bad**: "Success"
|
||||
**Good**: "Settings saved! Your changes will take effect immediately."
|
||||
An empty state distinguishes first use, no results, filters, permissions, and failure. Explain the state and provide the next useful action.
|
||||
|
||||
**Principles**:
|
||||
- Confirm what happened
|
||||
- Explain what happens next (if relevant)
|
||||
- Be brief but complete
|
||||
- Match the user's emotional moment (celebrate big wins)
|
||||
|
||||
### Loading States
|
||||
**Bad**: "Loading..." (for 30+ seconds)
|
||||
**Good**: "Analyzing your data... this usually takes 30-60 seconds"
|
||||
|
||||
**Principles**:
|
||||
- Set expectations (how long?)
|
||||
- Explain what's happening (when it's not obvious)
|
||||
- Show progress when possible
|
||||
- Offer escape hatch if appropriate ("Cancel")
|
||||
Success confirms the completed outcome and mentions the next consequence only when it changes what the user should do. Routine success should be brief.
|
||||
|
||||
### Confirmation Dialogs
|
||||
**Bad**: "Are you sure?"
|
||||
**Good**: "Delete 'Project Alpha'? This can't be undone."
|
||||
### Help and instructional text
|
||||
|
||||
**Principles**:
|
||||
- State the specific action
|
||||
- Explain consequences (especially for destructive actions)
|
||||
- Use clear button labels ("Delete project" not "Yes")
|
||||
- Don't overuse confirmations (only for risky actions)
|
||||
Helper text answers an implicit question instead of restating the control. Use progressive disclosure for uncommon detail. Link text must make sense out of context; icon-only controls need accessible names.
|
||||
|
||||
### Navigation & Wayfinding
|
||||
**Bad**: Generic labels like "Items" | "Things" | "Stuff"
|
||||
**Good**: Specific labels like "Your projects" | "Team members" | "Settings"
|
||||
## Voice, accessibility, and localization
|
||||
|
||||
**Principles**:
|
||||
- Be specific and descriptive
|
||||
- Use language users understand (not internal jargon)
|
||||
- Make hierarchy clear
|
||||
- Consider information scent (breadcrumbs, current location)
|
||||
Voice stays consistent; tone adapts to the moment. Use plain language without flattening terminology the audience genuinely knows.
|
||||
|
||||
## Apply Clarity Principles
|
||||
- Write complete translatable messages rather than concatenated fragments.
|
||||
- Keep variables and numbers structured so translators can reorder them.
|
||||
- Allow expansion instead of abbreviating prematurely.
|
||||
- Make alt text convey the image's information; use empty alt for decoration.
|
||||
- Keep screen-reader names aligned with visible labels and outcomes.
|
||||
- Do not rely on punctuation, color, or iconography to carry the message alone.
|
||||
|
||||
Every piece of copy should follow these rules:
|
||||
Maintain a short terminology glossary when inconsistency spans the product. Do not vary words for literary effect in an interface.
|
||||
|
||||
1. **Be specific**: "Enter email" not "Enter value"
|
||||
2. **Be concise**: Cut unnecessary words (but don't sacrifice clarity)
|
||||
3. **Be active**: "Save changes" not "Changes will be saved"
|
||||
4. **Be human**: "Oops, something went wrong" not "System error encountered"
|
||||
5. **Tell users what to do**, not just what happened
|
||||
6. **Be consistent**: Use same terms throughout (don't vary for variety)
|
||||
## Verify
|
||||
|
||||
**NEVER**:
|
||||
- Use jargon without explanation
|
||||
- Blame users ("You made an error" → "This field is required")
|
||||
- Be vague ("Something went wrong" without explanation)
|
||||
- Use passive voice unnecessarily
|
||||
- Write overly long explanations (be concise)
|
||||
- Use humor for errors (be empathetic instead)
|
||||
- Assume technical knowledge
|
||||
- Vary terminology (pick one term and stick with it)
|
||||
- Repeat information (headers restating intros, redundant explanations)
|
||||
- Use placeholders as the only labels (they disappear when users type)
|
||||
Read the flow in context and test:
|
||||
|
||||
## Verify Improvements
|
||||
- comprehension without hidden product knowledge;
|
||||
- actionability at errors, empty states, and decision points;
|
||||
- factual accuracy and consistent terminology;
|
||||
- scanability at target widths and 200% zoom;
|
||||
- long names, localization expansion, pluralization, and dynamic values;
|
||||
- accessible names and announced state changes;
|
||||
- tone appropriate to consequence and emotional context.
|
||||
|
||||
Test that copy improvements work:
|
||||
The final copy is as short as it can be without removing meaning or recovery.
|
||||
|
||||
- **Comprehension**: Can users understand without context?
|
||||
- **Actionability**: Do users know what to do next?
|
||||
- **Brevity**: Is it as short as possible while remaining clear?
|
||||
- **Consistency**: Does it match terminology elsewhere?
|
||||
- **Tone**: Is it appropriate for the situation?
|
||||
|
||||
When the copy reads cleanly, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `ux-writing.md` and live inline now so the clarify flow has its deep UX-writing reference in one place.
|
||||
|
||||
### UX Writing
|
||||
|
||||
#### The Button Label Problem
|
||||
|
||||
**Never use "OK", "Submit", or "Yes/No".** These are lazy and ambiguous. Use specific verb + object patterns:
|
||||
|
||||
| Bad | Good | Why |
|
||||
|-----|------|-----|
|
||||
| OK | Save changes | Says what will happen |
|
||||
| Submit | Create account | Outcome-focused |
|
||||
| Yes | Delete message | Confirms the action |
|
||||
| Cancel | Keep editing | Clarifies what "cancel" means |
|
||||
| Click here | Download PDF | Describes the destination |
|
||||
|
||||
**For destructive actions**, name the destruction:
|
||||
- "Delete" not "Remove" (delete is permanent, remove implies recoverable)
|
||||
- "Delete 5 items" not "Delete selected" (show the count)
|
||||
|
||||
#### Error Messages: The Formula
|
||||
|
||||
Every error message should answer: (1) What happened? (2) Why? (3) How to fix it? Example: "Email address isn't valid. Please include an @ symbol." not "Invalid input".
|
||||
|
||||
##### Error Message Templates
|
||||
|
||||
| Situation | Template |
|
||||
|-----------|----------|
|
||||
| **Format error** | "[Field] needs to be [format]. Example: [example]" |
|
||||
| **Missing required** | "Please enter [what's missing]" |
|
||||
| **Permission denied** | "You don't have access to [thing]. [What to do instead]" |
|
||||
| **Network error** | "We couldn't reach [thing]. Check your connection and [action]." |
|
||||
| **Server error** | "Something went wrong on our end. We're looking into it. [Alternative action]" |
|
||||
|
||||
##### Don't Blame the User
|
||||
|
||||
Reframe errors: "Please enter a date in MM/DD/YYYY format" not "You entered an invalid date".
|
||||
|
||||
#### Empty States Are Opportunities
|
||||
|
||||
Empty states are onboarding moments: (1) Acknowledge briefly, (2) Explain the value of filling it, (3) Provide a clear action. "No projects yet. Create your first one to get started." not just "No items".
|
||||
|
||||
#### Voice vs Tone
|
||||
|
||||
**Voice** is your brand's personality, consistent everywhere.
|
||||
**Tone** adapts to the moment.
|
||||
|
||||
| Moment | Tone Shift |
|
||||
|--------|------------|
|
||||
| Success | Celebratory, brief: "Done! Your changes are live." |
|
||||
| Error | Empathetic, helpful: "That didn't work. Here's what to try..." |
|
||||
| Loading | Reassuring: "Saving your work..." |
|
||||
| Destructive confirm | Serious, clear: "Delete this project? This can't be undone." |
|
||||
|
||||
**Never use humor for errors.** Users are already frustrated. Be helpful, not cute.
|
||||
|
||||
#### Writing for Accessibility
|
||||
|
||||
**Link text** must have standalone meaning: "View pricing plans" not "Click here". **Alt text** describes information, not the image: "Revenue increased 40% in Q4" not "Chart". Use `alt=""` for decorative images. **Icon buttons** need `aria-label` for screen reader context.
|
||||
|
||||
#### Writing for Translation
|
||||
|
||||
##### Plan for Expansion
|
||||
|
||||
German text is ~30% longer than English. Allocate space:
|
||||
|
||||
| Language | Expansion |
|
||||
|----------|-----------|
|
||||
| German | +30% |
|
||||
| French | +20% |
|
||||
| Finnish | +30-40% |
|
||||
| Chinese | -30% (fewer chars, but same width) |
|
||||
|
||||
##### Translation-Friendly Patterns
|
||||
|
||||
Keep numbers separate ("New messages: 3" not "You have 3 new messages"). Use full sentences as single strings (word order varies by language). Avoid abbreviations ("5 minutes ago" not "5 mins ago"). Give translators context about where strings appear.
|
||||
|
||||
#### Consistency: The Terminology Problem
|
||||
|
||||
Pick one term and stick with it:
|
||||
|
||||
| Inconsistent | Consistent |
|
||||
|--------------|------------|
|
||||
| Delete / Remove / Trash | Delete |
|
||||
| Settings / Preferences / Options | Settings |
|
||||
| Sign in / Log in / Enter | Sign in |
|
||||
| Create / Add / New | Create |
|
||||
|
||||
Build a terminology glossary and enforce it. Variety creates confusion.
|
||||
|
||||
#### Avoid Redundant Copy
|
||||
|
||||
If the heading explains it, the intro is redundant. If the button is clear, don't explain it again. Say it once, say it well.
|
||||
|
||||
#### Loading States
|
||||
|
||||
Be specific: "Saving your draft..." not "Loading...". For long waits, set expectations ("This usually takes 30 seconds") or show progress.
|
||||
|
||||
#### Confirmation Dialogs: Use Sparingly
|
||||
|
||||
Most confirmation dialogs are design failures; consider undo instead. When you must confirm: name the action, explain consequences, use specific button labels ("Delete project" / "Keep project", not "Yes" / "No").
|
||||
|
||||
#### Form Instructions
|
||||
|
||||
Show format with placeholders, not instructions. For non-obvious fields, explain why you're asking.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Jargon without explanation. Blaming users ("You made an error" → "This field is required"). Vague errors ("Something went wrong"). Varying terminology for variety. Humor for errors.
|
||||
When the language reads cleanly, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,105 +1,38 @@
|
||||
# Codex: Visual Direction & Asset Production
|
||||
# Codex: Surface Probes & Asset Production
|
||||
|
||||
This file is loaded by `/impeccable craft` when the harness has native image generation (currently Codex via `image_gen`). Other harnesses skip it. It covers the two craft steps that depend on real image generation: landing the visual direction, and producing the raster assets the implementation will compose.
|
||||
Load this from [new-work.md](new-work.md) only when the harness has native image generation and a substantial, high-fidelity surface would benefit from seeing the shortlisted concept before code. PRODUCT.md and DESIGN.md are preconditions. New-work has already resolved the visual world; this file must not reopen it.
|
||||
|
||||
Read this *before* generating any images. The order matters, and the per-step user pauses are what keep generated imagery from drifting away from the brief.
|
||||
The purpose of a probe is to test composition, narrative, hierarchy, density, focal moment, signature use, and image requirements. It is not a second identity workshop. Keep DESIGN.md's palette, typography direction, material language, component character, imagery stance, and motion grammar fixed.
|
||||
|
||||
### Four stop points before code
|
||||
## Generate the smallest useful probe set
|
||||
|
||||
Steps A through D each end with the user. Do not advance past any of them on your own read of the situation.
|
||||
Generate one to three high-fidelity north-star comps using the native image-generation capability. Base them on the real content and the surface concepts already developed with the user.
|
||||
|
||||
1. **STOP after Step A questions.** Wait for answers.
|
||||
2. **STOP after Step B palette generation.** Wait for "confirm palette."
|
||||
3. **STOP after Step C mocks.** Wait for direction approval or delegation.
|
||||
4. **Only after Step D approves a direction** do you return to the build (new-work.md's plan, then code).
|
||||
- When the user shortlisted multiple concepts, show one clear expression of each.
|
||||
- When one concept is already selected, vary only the structural uncertainty that the image can resolve: topology, sequence, density, hierarchy, focal composition, or interaction framing.
|
||||
- Show enough beyond the opening moment to prove the concept can govern the whole requested surface.
|
||||
- Do not generate a palette artifact, ask new atmosphere questions, introduce a different type voice, or invent a new motif. If the committed world cannot support the concept, return to the concept shortlist rather than changing the world.
|
||||
|
||||
Prior shape approval does **not** satisfy any of these. Shape's "confirm or override" advances you into Step A; it is not a substitute for it.
|
||||
Treat each comp as a direction test, not a screenshot specification. Core UI text, responsive behavior, accessibility, semantics, and interaction states remain implementation responsibilities.
|
||||
|
||||
## Step A: Explore Directions with the User
|
||||
## One approval point
|
||||
|
||||
Before generating anything, run a brief direction conversation grounded in the shape brief.
|
||||
Show the probes together and ask what should carry forward, what feels false to the world, and whether the selected surface concept should be approved, combined, revised, or rejected. Then stop and wait. A structured simulated user counts as attended and receives the same question.
|
||||
|
||||
**Step A is required even when shape just produced a confirmed brief.** The shape questions and Step A questions cover different ground: shape pins purpose, content, scope; Step A pins palette, atmosphere, and named visual references for the comps you're about to generate. The only time you can skip Step A is when the user has already answered these exact palette/atmosphere/reference questions in the same session.
|
||||
Do not begin code until the user approves a direction or explicitly delegates the choice. If they delegate, choose using the task brief, PRODUCT.md, and DESIGN.md, and state the evidence. Approval refines the task concept; it does not modify DESIGN.md.
|
||||
|
||||
Ask **2-3 targeted questions** about visual lane, color strategy, atmosphere, and named anchor references. Don't enumerate generic menus; tie each question to the shape brief's answers. Example shape-grounded questions:
|
||||
After approval, summarize the composition and the parts of the comp that must not be literalized. Return to new-work.md and write the direction contract from the approved surface concept before code.
|
||||
|
||||
- "Brief says 'specimen-page restraint.' Are we closer to a quiet typographic page or a wider editorial spread with hero imagery?"
|
||||
- "Palette strategy from shape was 'Committed.' Which one color carries the surface (a brand-driven pick rather than a default warm-or-cool framing)? (And no, the answer isn't a cream/sand body bg; that's the saturated AI default.)"
|
||||
## Inventory implementation fidelity
|
||||
|
||||
**STOP and wait for answers.** These pin the palette before any pixel gets generated. Do not proceed to Step B until the user has responded.
|
||||
Before building, inventory the approved comp's major visible ingredients and choose an implementation medium for each: semantic HTML/CSS/SVG, existing project asset, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
## Step B: Generate the Brand Palette First
|
||||
Pay special attention to the dominant composition, signature use, image-native content, second-fold system, and any interaction the still image only implies. If the concept depends on a photograph, architectural scene, product object, portrait, or other raster-native material, do not silently replace it with generic CSS scenery.
|
||||
|
||||
Generate **one** palette artifact before any mocks. This is a small, focused image: typography pairing on the chosen background, primary + accent color swatches, one signature ornament or motif. Single image, single pass.
|
||||
Treat the comp as a north star, not something to trace. Do not rasterize core UI text or controls. Do not substitute a different visual driver after approval without asking.
|
||||
|
||||
Why palette first: mocks generated against a vague color sense produce noise that drowns out the structural decisions. A confirmed palette is the first concrete contract for everything downstream.
|
||||
## Produce only the assets the build needs
|
||||
|
||||
Show the palette to the user. Ask one question: "This is the palette I'm locking in for the mocks. Confirm, or call out what to shift?"
|
||||
When clean raster ingredients are required and a scoped subagent is available and authorized, use `impeccable_asset_producer`. Give it the approved comp, output paths, required dimensions and formats, transparency needs, crop notes, and what must remain semantic code. Otherwise produce the minimum required assets with the native image-generation capability in the current thread.
|
||||
|
||||
**STOP and wait for confirmation.** Do not generate mocks against an unconfirmed palette. "Probably good enough" is the wrong call here; the palette is the contract for everything downstream.
|
||||
|
||||
## Step C: Generate 1-3 Visual Mocks Against the Palette
|
||||
|
||||
Once the palette is confirmed, generate **1 to 3** high-fidelity north-star comps. Each mock must use the confirmed palette and typography. Mocks differ in *structural* direction (hierarchy, topology, density, composition), not in color or motif.
|
||||
|
||||
- Brand work: push visual identity, composition, mood, and signature motifs.
|
||||
- Product work: push hierarchy, topology, density, tone, grounded in realistic product structure.
|
||||
- Landing pages and long-form brand surfaces: show enough of the second fold to establish the system beyond the hero.
|
||||
|
||||
Use the `image_gen` tool directly (or via the imagegen skill when available). Don't ask the user to install anything.
|
||||
|
||||
## Step D: Approval Loop
|
||||
|
||||
Show the comps. Ask what carries forward. Iterate until **one direction is approved** or the user explicitly delegates.
|
||||
|
||||
**STOP and wait for the approval or the delegation.** Do not begin Step E or return to the build until a single direction is named. If the user delegates, pick the strongest direction and explain it from the brief, not personal taste.
|
||||
|
||||
Before moving to assets, summarize what to carry into code and what *not* to literalize from the mock. This is the handoff between visual exploration and semantic implementation.
|
||||
|
||||
## Step E: Mock Fidelity Inventory
|
||||
|
||||
Inventory the approved mock's major visible ingredients. For each, decide implementation: semantic HTML/CSS/SVG, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
Common ingredients to inventory:
|
||||
|
||||
- Hero silhouette and dominant composition
|
||||
- Signature motifs (planets, devices, portraits, charts, route lines, insets, badges, etc.)
|
||||
- Nav and primary-action treatment (when the surface has one)
|
||||
- Section sequence, especially the second fold
|
||||
- Image-native content the concept depends on
|
||||
- Typography, density, color/material treatment, motion cues
|
||||
|
||||
Treat the mock as a north star, not a screenshot to trace. Don't rasterize core UI text. But if the live result lacks the mock's major ingredients, the implementation is wrong.
|
||||
|
||||
If a photographic, architectural, product, or place-led mock becomes generic CSS scenery, decorative diagrams, bullets, or copy, stop and fix it. That's a broken implementation, not a harmless interpretation.
|
||||
|
||||
Don't substitute a different hero composition or visual driver post-approval without user sign-off.
|
||||
|
||||
## Step F: Asset Slicing via the Asset Producer
|
||||
|
||||
Raster ingredients identified in Step E need clean production assets. Use the bundled `impeccable_asset_producer` subagent rather than producing inline.
|
||||
|
||||
Spawn it as a scoped subagent. If you do not have explicit permission to use agents, stop and ask:
|
||||
|
||||
```text
|
||||
Asset production will work better as a scoped subagent job. Should I spawn the Impeccable asset producer subagent for this step?
|
||||
```
|
||||
|
||||
Pass to the agent:
|
||||
|
||||
- Approved mock path or screenshot reference
|
||||
- Crop paths or a contact sheet with crop ids
|
||||
- Output directory
|
||||
- Required dimensions, format, transparency needs
|
||||
- Avoid list
|
||||
- Notes on what should remain semantic HTML/CSS/SVG instead of raster
|
||||
|
||||
Attach image generation capability to the spawned agent when the harness supports it. Do **not** load image-generation reference material into the parent thread.
|
||||
|
||||
Inline asset production is allowed only if the user declines subagents, the harness cannot spawn the authorized agent, or the user explicitly asks for single-thread mode.
|
||||
|
||||
Prefer HTML/CSS/SVG/canvas when they can credibly reproduce an ingredient; reach for real, generated, or stock imagery when the mock or subject matter calls for actual visual content.
|
||||
|
||||
## After This File
|
||||
|
||||
Once Steps A through F are complete, return to the build: implement per new-work.md and SKILL.md's craft floor. The implementation builds against the confirmed palette, approved mock, and the assets the producer wrote.
|
||||
Return to [new-work.md](new-work.md) for the direction contract, implementation, and finishing pass.
|
||||
|
||||
@@ -1,257 +1,86 @@
|
||||
> **Additional context needed**: existing brand colors.
|
||||
|
||||
Replace timid grayscale or single-accent designs with a strategic palette: pick a color strategy, choose a hue family that fits the brand, then apply color with intent. More color ≠ better. Strategic color beats rainbow vomit.
|
||||
Introduce color as hierarchy, meaning, and atmosphere. Preserve confirmed brand and semantic conventions; do not replace a visual world under the guise of colorizing it.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: palette IS voice. Pick a color strategy first per SKILL.md (Restrained / Committed / Full palette / Drenched) and follow its dosage. Committed, Full palette, and Drenched deliberately exceed the ≤10% rule; that rule is Restrained only. Unexpected combinations are allowed; a dominant color can own the page when the chosen strategy calls for it.
|
||||
- **Persuade + Experience:** color may carry the voice and own large regions when the selected world calls for it.
|
||||
- **Operate + Read:** color primarily encodes action, selection, status, wayfinding, and reading hierarchy. Rarity gives an accent force.
|
||||
|
||||
Operate + Read: semantic-first and almost always Restrained. Accent color is reserved for primary action, current selection, and state indicators. Not decoration. Every color has a consistent meaning across every screen.
|
||||
## Audit before choosing
|
||||
|
||||
---
|
||||
Read DESIGN.md, tokens, assets, current themes, and representative states. Identify:
|
||||
|
||||
## Assess Color Opportunity
|
||||
- which colors are confirmed brand commitments;
|
||||
- current surface, text, action, and semantic roles;
|
||||
- places where grayscale obscures hierarchy or state;
|
||||
- contrast failures and color-only communication;
|
||||
- light/dark or data-visualization requirements;
|
||||
- whether the task asks for more color or a new identity.
|
||||
|
||||
Analyze the current state and identify opportunities:
|
||||
If a new identity is required, use [new-work.md](new-work.md). Ask only when a binding brand decision cannot be inferred.
|
||||
|
||||
1. **Understand current state**:
|
||||
- **Color absence**: Pure grayscale? Limited neutrals? One timid accent?
|
||||
- **Missed opportunities**: Where could color add meaning, hierarchy, or delight?
|
||||
- **Context**: What's appropriate for this domain and audience?
|
||||
- **Brand**: Are there existing brand colors we should use?
|
||||
## Choose a strategy
|
||||
|
||||
2. **Identify where color adds value**:
|
||||
- **Semantic meaning**: Success (green), error (red), warning (yellow/orange), info (blue)
|
||||
- **Hierarchy**: Drawing attention to important elements
|
||||
- **Categorization**: Different sections, types, or states
|
||||
- **Emotional tone**: Warmth, energy, trust, creativity
|
||||
- **Wayfinding**: Helping users navigate and understand structure
|
||||
- **Delight**: Moments of visual interest and personality
|
||||
Name the intended emotional temperature, dominant relationship, contrast range, and color dosage before editing. The strategy may be restrained or immersive; it must follow the brief and selected world rather than a fixed percentage rule.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and call the AskUserQuestion tool to clarify.
|
||||
Build roles, not a bag of swatches:
|
||||
|
||||
**CRITICAL**: More color ≠ better. Strategic color beats rainbow vomit every time. Every color should have a purpose.
|
||||
- canvas and elevated surfaces;
|
||||
- primary and secondary text;
|
||||
- action, focus, and selection;
|
||||
- borders and separators;
|
||||
- success, warning, error, and information;
|
||||
- data categories or scales when needed.
|
||||
|
||||
## Plan Color Strategy
|
||||
Use the project's existing color space. For a new web palette, prefer OKLCH because lightness and chroma can be adjusted predictably. Choose hue from product meaning and visual direction, never from a default category association.
|
||||
|
||||
Create a purposeful color introduction plan:
|
||||
## Apply at system scale
|
||||
|
||||
- **Color palette**: What colors match the brand/context? (Choose 2-4 colors max beyond neutrals)
|
||||
- **Dominant color**: Which color owns 60% of colored elements?
|
||||
- **Accent colors**: Which colors provide contrast and highlights? (30% and 10%)
|
||||
- **Application strategy**: Where does each color appear and why?
|
||||
- Let the strongest color own a deliberate region or role instead of scattering tiny accents.
|
||||
- Keep the primary action easy to find; do not spend its color on decoration.
|
||||
- Tint neutrals only when the brand hue genuinely creates cohesion. Neutral gray is valid when it serves the world.
|
||||
- On colored surfaces, derive secondary text from the foreground or surface hue rather than using washed-out generic gray.
|
||||
- Keep semantic meanings consistent, but respect platform and domain conventions instead of assuming fixed hues.
|
||||
- For data, use distinct lightness, chroma, shape, label, or pattern so color is not the only code.
|
||||
- In dark mode, design surface elevation and contrast explicitly; do not invert the light theme mechanically.
|
||||
- Define primitive values and semantic tokens when the project has a token system. Theme changes should normally remap semantic roles.
|
||||
|
||||
**IMPORTANT**: Color should enhance hierarchy and meaning, not create chaos. Less is more when it matters more.
|
||||
Decoration without a relationship to hierarchy, state, content, or the visual world is not a color strategy.
|
||||
|
||||
## Introduce Color Strategically
|
||||
## Contrast and perception
|
||||
|
||||
Add color systematically across these dimensions:
|
||||
Verify computed foreground/background pairs:
|
||||
|
||||
### Semantic Color
|
||||
- **State indicators**:
|
||||
- Success: Green tones (emerald, forest, mint)
|
||||
- Error: Red/pink tones (rose, crimson, coral)
|
||||
- Warning: Orange/amber tones
|
||||
- Info: Blue tones (sky, ocean, indigo)
|
||||
- Neutral: Gray/slate for inactive states
|
||||
| Content | WCAG AA minimum |
|
||||
|---|---|
|
||||
| body text | 4.5:1 |
|
||||
| large text | 3:1 |
|
||||
| controls, icons, focus indicators | 3:1 |
|
||||
|
||||
- **Status badges**: Colored backgrounds or borders for states (active, pending, completed, etc.)
|
||||
- **Progress indicators**: Colored bars, rings, or charts showing completion or health
|
||||
Do not rely on eyesight alone. Check interactive states, overlays, text on images, disabled content, and both themes. Simulate common vision deficiencies. Information conveyed by color also needs text, shape, iconography, or position.
|
||||
|
||||
### Accent Color Application
|
||||
- **Primary actions**: Color the most important buttons/CTAs
|
||||
- **Links**: Add color to clickable text (maintain accessibility)
|
||||
- **Icons**: Colorize key icons for recognition and personality
|
||||
- **Headers/titles**: Add color to section headers or key labels
|
||||
- **Hover states**: Introduce color on interaction
|
||||
When deriving OKLCH ramps, vary lightness and reduce chroma near white and black. Do not keep high chroma at extreme lightness merely to make the math uniform. Prefer explicit colors over chains of translucent overlays when alpha would make contrast context-dependent.
|
||||
|
||||
### Background & Surfaces
|
||||
- **Tinted backgrounds**: If you replace pure gray, tint toward the brand hue, not toward a generic-warm-or-cool pair. The default-warm-tint (`oklch(97% 0.01 60)` and its neighbors) is now the AI cream/sand giveaway. Be specific to the brand or stay neutral.
|
||||
- **Colored sections**: Use subtle background colors to separate areas
|
||||
- **Gradient backgrounds**: Add depth with subtle, intentional gradients (not generic purple-blue)
|
||||
- **Cards & surfaces**: Tint cards or surfaces toward the brand, not "for warmth" by reflex
|
||||
## Verify
|
||||
|
||||
**Use OKLCH for color**: It's perceptually uniform, meaning equal steps in lightness *look* equal. Great for generating harmonious scales.
|
||||
|
||||
### Data Visualization
|
||||
- **Charts & graphs**: Use color to encode categories or values
|
||||
- **Heatmaps**: Color intensity shows density or importance
|
||||
- **Comparison**: Color coding for different datasets or timeframes
|
||||
|
||||
### Borders & Accents
|
||||
- **Hairline borders**: 1px colored borders on full perimeter (not side-stripes; see the absolute ban on `border-left/right > 1px`)
|
||||
- **Underlines**: Color underlines for emphasis or active states
|
||||
- **Dividers**: Subtle colored dividers instead of gray lines
|
||||
- **Focus rings**: Colored focus indicators matching brand
|
||||
- **Surface tints**: A 4-8% background wash of the accent color instead of a stripe
|
||||
|
||||
**NEVER**: `border-left` or `border-right` greater than 1px as a colored accent stripe. This is one of the three absolute bans in the parent skill. If you want to mark a card as "active" or "warning", use a full hairline border, a background tint, a leading glyph, or a numbered prefix. Not a side stripe.
|
||||
|
||||
### Typography Color
|
||||
- **Colored headings**: Use brand colors for section headings (maintain contrast)
|
||||
- **Highlight text**: Color for emphasis or categories
|
||||
- **Labels & tags**: Small colored labels for metadata or categories
|
||||
|
||||
### Decorative Elements
|
||||
- **Illustrations**: Add colored illustrations or icons
|
||||
- **Shapes**: Geometric shapes in brand colors as background elements
|
||||
- **Gradients**: Colorful gradient overlays or mesh backgrounds
|
||||
- **Blobs/organic shapes**: Soft colored shapes for visual interest
|
||||
|
||||
## Balance & Refinement
|
||||
|
||||
Ensure color addition improves rather than overwhelms:
|
||||
|
||||
### Maintain Hierarchy
|
||||
- **Dominant color** (60%): Primary brand color or most used accent
|
||||
- **Secondary color** (30%): Supporting color for variety
|
||||
- **Accent color** (10%): High contrast for key moments
|
||||
- **Neutrals** (remaining): Gray/black/white for structure
|
||||
|
||||
### Accessibility
|
||||
- **Contrast ratios**: Ensure WCAG compliance (4.5:1 for text, 3:1 for UI components)
|
||||
- **Don't rely on color alone**: Use icons, labels, or patterns alongside color
|
||||
- **Test for color blindness**: Verify red/green combinations work for all users
|
||||
|
||||
### Cohesion
|
||||
- **Consistent palette**: Use colors from defined palette, not arbitrary choices
|
||||
- **Systematic application**: Same color meanings throughout (green always = success)
|
||||
- **Temperature consistency**: Warm palette stays warm, cool stays cool
|
||||
|
||||
**NEVER**:
|
||||
- Use every color in the rainbow (choose 2-4 colors beyond neutrals)
|
||||
- Apply color randomly without semantic meaning
|
||||
- Put gray text on colored backgrounds. It looks washed out; use a darker shade of the background color or transparency instead
|
||||
- Violate WCAG contrast requirements
|
||||
- Use color as the only indicator (accessibility issue)
|
||||
- Make everything colorful (defeats the purpose)
|
||||
- Default to purple-blue gradients (AI slop aesthetic)
|
||||
|
||||
## Verify Color Addition
|
||||
|
||||
Test that colorization improves the experience:
|
||||
|
||||
- **Better hierarchy**: Does color guide attention appropriately?
|
||||
- **Clearer meaning**: Does color help users understand states/categories?
|
||||
- **More engaging**: Does the interface feel warmer and more inviting?
|
||||
- **Still accessible**: Do all color combinations meet WCAG standards?
|
||||
- **Not overwhelming**: Is color balanced and purposeful?
|
||||
- Every color has a stable role or a world-specific atmospheric purpose.
|
||||
- Attention lands on the intended action, content, or state.
|
||||
- The palette works across quiet, dense, interactive, error, and empty states.
|
||||
- Light and dark themes are each composed, not mechanically inverted.
|
||||
- Contrast and non-color cues pass in all relevant states.
|
||||
- The result is recognizably this product, not a generic “colorful” treatment.
|
||||
|
||||
When the palette earns its place, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
When invoked from live mode, each variant MUST declare a `color-amount` param so the user can dial between a restrained accent and a drenched surface without regeneration. Author the variant's CSS against `var(--p-color-amount, 0.5)`, typically as the alpha multiplier on backgrounds, or as a scaling factor on the chroma axis in an OKLCH expression. 0 = neutral/monochrome, 1 = full saturation / dominant coverage.
|
||||
When invoked from live mode, every variant declares a `color-amount` parameter. Author CSS against `var(--p-color-amount, 0.5)` so the user can move from neutral to the variant's full color strategy without regeneration.
|
||||
|
||||
```json
|
||||
{"id":"color-amount","kind":"range","min":0,"max":1,"step":0.05,"default":0.5,"label":"Color amount"}
|
||||
```
|
||||
|
||||
Layer 1-2 variant-specific params on top: palette selection (`steps` with named options), temperature warmth, or tint vs. true color. See `reference/live.md` for the full params contract.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `color-and-contrast.md` and live inline now so the colorize flow has its deep color reference in one place.
|
||||
|
||||
### Color & Contrast
|
||||
|
||||
#### Color Spaces: Use OKLCH
|
||||
|
||||
**Stop using HSL.** Use OKLCH (or LCH) instead. It's perceptually uniform, meaning equal steps in lightness *look* equal, unlike HSL where 50% lightness in yellow looks bright while 50% in blue looks dark.
|
||||
|
||||
The OKLCH function takes three components: `oklch(lightness chroma hue)` where lightness is 0-100%, chroma is roughly 0-0.4, and hue is 0-360. To build a primary color and its lighter / darker variants, hold the chroma+hue roughly constant and vary the lightness, but **reduce chroma as you approach white or black**, because high chroma at extreme lightness looks garish.
|
||||
|
||||
The hue you pick is a brand decision and should not come from a default. Do not reach for blue (hue 250) or warm orange (hue 60) by reflex; those are the dominant AI-design defaults, not the right answer for any specific brand.
|
||||
|
||||
#### Building Functional Palettes
|
||||
|
||||
##### Tinted Neutrals
|
||||
|
||||
**Pure gray is dead.** A neutral with zero chroma feels lifeless next to a colored brand. Add a tiny chroma value (0.005-0.015) to all your neutrals, hued toward whatever your brand color is. The chroma is small enough not to read as "tinted" consciously, but it creates subconscious cohesion between brand color and UI surfaces.
|
||||
|
||||
The hue you tint toward should come from THIS project's brand, not from a "warm = friendly, cool = tech" formula. If your brand color is teal, your neutrals lean toward teal. If your brand color is amber, they lean toward amber. The point is cohesion with the SPECIFIC brand, not a stock palette.
|
||||
|
||||
**Avoid** the trap of always tinting toward warm orange or always tinting toward cool blue. Those are the two laziest defaults and they create their own monoculture across projects.
|
||||
|
||||
##### Palette Structure
|
||||
|
||||
A complete system needs:
|
||||
|
||||
| Role | Purpose | Example |
|
||||
|------|---------|---------|
|
||||
| **Primary** | Brand, CTAs, key actions | 1 color, 3-5 shades |
|
||||
| **Neutral** | Text, backgrounds, borders | 9-11 shade scale |
|
||||
| **Semantic** | Success, error, warning, info | 4 colors, 2-3 shades each |
|
||||
| **Surface** | Cards, modals, overlays | 2-3 elevation levels |
|
||||
|
||||
**Skip secondary/tertiary unless you need them.** Most apps work fine with one accent color. Adding more creates decision fatigue and visual noise.
|
||||
|
||||
##### The 60-30-10 Rule (Applied Correctly)
|
||||
|
||||
This rule is about **visual weight**, not pixel count:
|
||||
|
||||
- **60%**: Neutral backgrounds, white space, base surfaces
|
||||
- **30%**: Secondary colors: text, borders, inactive states
|
||||
- **10%**: Accent: CTAs, highlights, focus states
|
||||
|
||||
The common mistake: using the accent color everywhere because it's "the brand color." Accent colors work *because* they're rare. Overuse kills their power.
|
||||
|
||||
#### Contrast & Accessibility
|
||||
|
||||
##### WCAG Requirements
|
||||
|
||||
| Content Type | AA Minimum | AAA Target |
|
||||
|--------------|------------|------------|
|
||||
| Body text | 4.5:1 | 7:1 |
|
||||
| Large text (18px+ or 14px bold) | 3:1 | 4.5:1 |
|
||||
| UI components, icons | 3:1 | 4.5:1 |
|
||||
| Non-essential decorations | None | None |
|
||||
|
||||
##### Dangerous Color Combinations
|
||||
|
||||
These commonly fail contrast or cause readability issues:
|
||||
|
||||
- Light gray text on white (the #1 accessibility fail)
|
||||
- Red text on green background (or vice versa): 8% of men can't distinguish these
|
||||
- Blue text on red background (vibrates visually)
|
||||
- Yellow text on white (almost always fails)
|
||||
- Thin light text on images (unpredictable contrast)
|
||||
|
||||
##### Testing
|
||||
|
||||
Don't trust your eyes. Use tools:
|
||||
|
||||
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
||||
- Browser DevTools → Rendering → Emulate vision deficiencies
|
||||
- [Polypane](https://polypane.app/) for real-time testing
|
||||
|
||||
#### Theming: Light & Dark Mode
|
||||
|
||||
##### Dark Mode Is Not Inverted Light Mode
|
||||
|
||||
You can't just swap colors. Dark mode requires different design decisions:
|
||||
|
||||
| Light Mode | Dark Mode |
|
||||
|------------|-----------|
|
||||
| Shadows for depth | Lighter surfaces for depth (no shadows) |
|
||||
| Dark text on light | Light text on dark (reduce font weight) |
|
||||
| Vibrant accents | Desaturate accents slightly |
|
||||
| White backgrounds | Either pure black or a deep surface that fits the brand (a brand-tinted near-black at oklch 12-18% works too) |
|
||||
|
||||
In dark mode, depth comes from surface lightness, not shadow. Build a 3-step surface scale where higher elevations are lighter (e.g. 15% / 20% / 25% lightness). Use the SAME hue and chroma as your brand color (whatever it is for THIS project; do not reach for blue) and only vary the lightness. Reduce body text weight slightly (e.g. 350 instead of 400) because light text on dark reads as heavier than dark text on light.
|
||||
|
||||
##### Token Hierarchy
|
||||
|
||||
Use two layers: primitive tokens (`--blue-500`) and semantic tokens (`--color-primary: var(--blue-500)`). For dark mode, only redefine the semantic layer; primitives stay the same.
|
||||
|
||||
#### Alpha Is A Design Smell
|
||||
|
||||
Heavy use of transparency (rgba, hsla) usually means an incomplete palette. Alpha creates unpredictable contrast, performance overhead, and inconsistency. Define explicit overlay colors for each context instead. Exception: focus rings and interactive states where see-through is needed.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Relying on color alone to convey information. Creating palettes without clear roles for each color. Skipping color blindness testing (8% of men affected).
|
||||
Add at most two variant-specific parameters, such as palette, temperature, or tint behavior. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Craft (deprecated alias)
|
||||
|
||||
`craft` is a deprecated alias for the standard build flow. Builds route through SKILL.md's new-work gate; [new-work.md](new-work.md) carries the direction checkpoint ("Decide, then build"), the identity playbook, and the finishing pass. Invoking `craft` explicitly forces the attended checkpoints: pause at the stated direction for confirmation, and follow [codex.md](codex.md)'s mock flow when the harness generates images. Nothing else differs from a plain build request.
|
||||
`craft` is a deprecated alias for an ordinary request to make new visual work. It adds no setup, interview, checkpoint, tool, or quality behavior. Apply SKILL.md's normal routing: create missing PRODUCT.md through [init.md](init.md), then follow [new-work.md](new-work.md) for visual authority, world and surface decisions, implementation, and finish.
|
||||
|
||||
Do not tell users they need to invoke `craft`. Natural requests such as “build this feature,” “make a landing page,” or “redesign this screen” use the same flow.
|
||||
|
||||
@@ -43,13 +43,13 @@ If browser automation is available, each assessment creates its own new tab. Nev
|
||||
Read relevant source files and visually inspect the live page when browser automation is available. Think like a design director.
|
||||
|
||||
Evaluate:
|
||||
- **AI slop**: Would someone believe "AI made this" immediately? Check all DON'T guidance from the parent Impeccable skill.
|
||||
- **Design specificity**: Is the composition, interaction, and visual language grounded in this product, or could an unrelated product use it unchanged? Make this judgment before seeing detector output.
|
||||
- **Holistic design**: hierarchy, IA, emotional fit, discoverability, composition, typography, color, accessibility, states, copy, and edge cases.
|
||||
- **Cognitive load**: consult the [Cognitive Load Assessment](#cognitive-load-assessment) section below; report checklist failures and decision points with >4 visible options.
|
||||
- **Emotional journey**: peak-end rule, emotional valleys, reassurance at high-stakes moments.
|
||||
- **Nielsen heuristics**: consult the [Heuristics Scoring Guide](#heuristics-scoring-guide) section below; score all 10 heuristics 0-4, marking any heuristic the mode-applicability rule allows as `n/a` instead of forcing a number.
|
||||
|
||||
Return: AI slop verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
Return: design-specificity verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
|
||||
### Assessment B: Detector + Browser Evidence
|
||||
|
||||
@@ -115,11 +115,11 @@ Be honest with scores. A 4 means genuinely excellent. Most real interfaces score
|
||||
|
||||
**Mode applicability**: heuristics 7 (Flexibility and Efficiency) and 10 (Help and Documentation) may be scored `n/a` on Persuade and Experience surfaces (landing pages, campaigns, portfolios, bodies of work), as may any other heuristic that genuinely cannot apply to the surface under review. Write `n/a` in the Score cell with a one-line reason, and renormalize the total to the applicable maximum (e.g. **24/32** when two heuristics are n/a) so the rating band stays proportional. The persisted snapshot must record which heuristics were scored n/a.
|
||||
|
||||
#### Anti-Patterns Verdict
|
||||
#### Design Specificity Verdict
|
||||
|
||||
**Start here.** Does this look AI-generated?
|
||||
**Start here.** Does the result feel authored for this product, or category-interchangeable?
|
||||
|
||||
**LLM assessment**: Your own evaluation of AI slop tells. Cover overall aesthetic feel, layout sameness, generic composition, missed opportunities for personality.
|
||||
**LLM assessment**: Your unanchored evaluation of design specificity. Cover overall coherence, structural sameness, category-interchangeable choices, and missed opportunities for product character.
|
||||
|
||||
**Deterministic scan**: Summarize what the automated detector found, with counts and file locations. Note any additional issues the detector caught that you missed, and flag any false positives.
|
||||
|
||||
@@ -176,7 +176,7 @@ Once the report above is finalized, write it to `.impeccable/critique/` so the u
|
||||
|
||||
Skip this step if the Setup slug was null (vague or root-level target).
|
||||
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, anti-patterns verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, design-specificity verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
|
||||
2. **Pass the structured metadata** through `IMPECCABLE_CRITIQUE_META` (JSON), then run the write command:
|
||||
```bash
|
||||
|
||||
@@ -1,302 +1,70 @@
|
||||
> **Additional context needed**: what's appropriate for the domain (playful vs professional vs quirky vs elegant).
|
||||
> **Additional context needed**: the brand's emotional range.
|
||||
|
||||
Find the moments where personality and unexpected polish would turn a functional interface into one users remember and tell other people about. Add only where the moment earns it; delight everywhere reads as noise.
|
||||
Make the experience memorable at moments that earn it. Delight is not a layer of generic whimsy; it is product character revealed through a useful interaction, a humane response, or an unexpectedly considered detail.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: delight can be distributed across copy voice, section transitions, discovery rewards, seasonal touches, personality across the whole surface.
|
||||
- **Persuade + Experience:** personality may run through voice, composition, motion, and discovery, provided the artifact remains the focus.
|
||||
- **Operate + Read:** concentrate delight at meaningful moments such as first use, completion, recovery, or mastery. Reliability carries everything else.
|
||||
|
||||
Operate + Read: delight at specific moments, not pages. Completion, first-time actions, error recovery, milestone crossings. Reliability and consistency carry the rest of the experience; delight pushed everywhere reads as noise.
|
||||
## Find the opportunity
|
||||
|
||||
---
|
||||
Inspect the target, DESIGN.md, product voice, repeated-use frequency, and emotional context. Look for:
|
||||
|
||||
## Assess Delight Opportunities
|
||||
- effort worth acknowledging;
|
||||
- waiting that can become informative;
|
||||
- an empty or first-use state that can orient;
|
||||
- an error or recovery moment that needs empathy;
|
||||
- an interaction whose physical or verbal response could express the brand;
|
||||
- a useful capability people might enjoy discovering.
|
||||
|
||||
Identify where delight would enhance (not distract from) the experience:
|
||||
Do not manufacture a celebration for an ordinary click. Ask only when the brand's emotional range or the stakes cannot be inferred.
|
||||
|
||||
1. **Find natural delight moments**:
|
||||
- **Success states**: Completed actions (save, send, publish)
|
||||
- **Empty states**: First-time experiences, onboarding
|
||||
- **Loading states**: Waiting periods that could be entertaining
|
||||
- **Achievements**: Milestones, streaks, completions
|
||||
- **Interactions**: Hover states, clicks, drags
|
||||
- **Errors**: Softening frustrating moments
|
||||
- **Easter eggs**: Hidden discoveries for curious users
|
||||
## Define one delight thesis
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the brand personality? (Playful? Professional? Quirky? Elegant?)
|
||||
- Who's the audience? (Tech-savvy? Creative? Corporate?)
|
||||
- What's the emotional context? (Accomplishment? Exploration? Frustration?)
|
||||
- What's appropriate? (Banking app ≠ gaming app)
|
||||
State in one sentence what the user should feel and why that feeling belongs to this product. Then choose the smallest system that can deliver it:
|
||||
|
||||
3. **Define delight strategy**:
|
||||
- **Subtle sophistication**: Refined micro-interactions (luxury brands)
|
||||
- **Playful personality**: Whimsical illustrations and copy (consumer apps)
|
||||
- **Helpful surprises**: Anticipating needs before users ask (productivity tools)
|
||||
- **Sensory richness**: Satisfying sounds, smooth animations (creative tools)
|
||||
- a distinctive response to a meaningful action;
|
||||
- product-specific language that clarifies while carrying voice;
|
||||
- an interaction or transition with a recognizable material behavior;
|
||||
- an illustration, sound, haptic, or environmental detail grounded in the product world;
|
||||
- a discovery reward that reveals real utility.
|
||||
|
||||
If any of these are unclear from the codebase, STOP and call the AskUserQuestion tool to clarify.
|
||||
Derive the treatment from product mechanism and visual world, not a stock catalog.
|
||||
|
||||
**CRITICAL**: Delight should enhance usability, never obscure it. If users notice the delight more than accomplishing their goal, you've gone too far.
|
||||
## Build for the emotional moment
|
||||
|
||||
## Delight Principles
|
||||
- **Success:** match the response to the effort and consequence. Major milestones can expand; routine saves should simply feel certain.
|
||||
- **Waiting:** show truthful progress, useful context, or product-specific activity. Never fake work or delay completion to stage a flourish.
|
||||
- **Empty and first use:** make the next action clear before adding personality.
|
||||
- **Error and recovery:** lead with the problem and recovery. Warmth may reduce stress; jokes must not trivialize loss, money, privacy, or blocked work.
|
||||
- **Repeated interaction:** keep the response satisfying after the hundredth use. Variation is useful only when it remains coherent and predictable enough to trust.
|
||||
- **Discovery:** reward curiosity without hiding required functionality.
|
||||
|
||||
Follow these guidelines:
|
||||
Copy must use the product's language. Generic whimsy is worse than neutral clarity.
|
||||
|
||||
### Delight Amplifies, Never Blocks
|
||||
- Delight moments should be quick (< 1 second)
|
||||
- Never delay core functionality for delight
|
||||
- Make delight skippable or subtle
|
||||
- Respect user's time and task focus
|
||||
## Protect the experience
|
||||
|
||||
### Surprise and Discovery
|
||||
- Hide delightful details for users to discover
|
||||
- Reward exploration and curiosity
|
||||
- Don't announce every delight moment
|
||||
- Let users share discoveries with others
|
||||
Delight must not:
|
||||
|
||||
### Appropriate to Context
|
||||
- Match delight to emotional moment (celebrate success, empathize with errors)
|
||||
- Respect the user's state (don't be playful during critical errors)
|
||||
- Match brand personality and audience expectations
|
||||
- Cultural sensitivity (what's delightful varies by culture)
|
||||
- delay, block, or obscure the primary task;
|
||||
- override platform conventions or accessibility;
|
||||
- add unrequested factual claims;
|
||||
- play sound without consent or ignore mute settings;
|
||||
- become mandatory, unskippable, or exhausting on repeat;
|
||||
- add a dependency or asset cost disproportionate to the moment.
|
||||
|
||||
### Compound Over Time
|
||||
- Delight should remain fresh with repeated use
|
||||
- Vary responses (not same animation every time)
|
||||
- Reveal deeper layers with continued use
|
||||
- Build anticipation through patterns
|
||||
For authored motion, load [animate.md](animate.md). Respect reduced motion, screen readers, keyboard use, touch, localization, and cultural context. Nonessential loops stop when hidden. Make celebration intensity proportional to frequency and consequence.
|
||||
|
||||
## Delight Techniques
|
||||
## Verify
|
||||
|
||||
Add personality and joy through these methods:
|
||||
- The moment is specific enough that a neighboring product could not use it unchanged.
|
||||
- It improves comprehension, confidence, motivation, or emotional recovery.
|
||||
- The interface remains fast and obvious without the flourish.
|
||||
- Repetition does not turn charm into friction.
|
||||
- Reduced-motion, muted, keyboard, touch, and localized paths work.
|
||||
- The result feels like the selected world, not a generic “delight” treatment.
|
||||
|
||||
### Micro-interactions & Animation
|
||||
|
||||
**Button delight**:
|
||||
```css
|
||||
/* Satisfying button press */
|
||||
.button {
|
||||
transition: transform 0.1s, box-shadow 0.1s;
|
||||
}
|
||||
.button:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Ripple effect on click */
|
||||
/* Smooth lift on hover */
|
||||
.button:hover {
|
||||
transform: translateY(-2px);
|
||||
transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1); /* ease-out-quart */
|
||||
}
|
||||
```
|
||||
|
||||
**Loading delight**:
|
||||
- Playful loading animations (not just spinners)
|
||||
- Personality in loading messages (write product-specific ones, not generic AI filler)
|
||||
- Progress indication with encouraging messages
|
||||
- Skeleton screens with subtle animations
|
||||
|
||||
**Success animations**:
|
||||
- Checkmark draw animation
|
||||
- Confetti burst for major achievements
|
||||
- Gentle scale + fade for confirmation
|
||||
- Satisfying sound effects (subtle)
|
||||
|
||||
**Hover surprises**:
|
||||
- Icons that animate on hover
|
||||
- Color shifts or glow effects
|
||||
- Tooltip reveals with personality
|
||||
- Cursor changes (custom cursors for branded experiences)
|
||||
|
||||
### Personality in Copy
|
||||
|
||||
**Playful error messages**:
|
||||
```
|
||||
"Error 404"
|
||||
"This page is playing hide and seek. (And winning)"
|
||||
|
||||
"Connection failed"
|
||||
"Looks like the internet took a coffee break. Want to retry?"
|
||||
```
|
||||
|
||||
**Encouraging empty states**:
|
||||
```
|
||||
"No projects"
|
||||
"Your canvas awaits. Create something amazing."
|
||||
|
||||
"No saved articles"
|
||||
"Nothing on the nightstand yet. Save a story for later."
|
||||
```
|
||||
|
||||
**Playful labels & tooltips**:
|
||||
```
|
||||
"Delete"
|
||||
"Send to void" (for playful brand)
|
||||
|
||||
"Help"
|
||||
"Rescue me" (tooltip)
|
||||
```
|
||||
|
||||
**IMPORTANT**: Match copy personality to brand. Banks shouldn't be wacky, but they can be warm.
|
||||
|
||||
### Illustrations & Visual Personality
|
||||
|
||||
**Custom illustrations**:
|
||||
- Empty state illustrations (not stock icons)
|
||||
- Error state illustrations (friendly monsters, quirky characters)
|
||||
- Loading state illustrations (animated characters)
|
||||
- Success state illustrations (celebrations)
|
||||
|
||||
**Icon personality**:
|
||||
- Custom icon set matching brand personality
|
||||
- Animated icons (subtle motion on hover/click)
|
||||
- Illustrative icons (more detailed than generic)
|
||||
- Consistent style across all icons
|
||||
|
||||
**Background effects**:
|
||||
- Subtle particle effects
|
||||
- Gradient mesh backgrounds
|
||||
- Geometric patterns
|
||||
- Parallax depth
|
||||
- Time-of-day themes (morning vs night)
|
||||
|
||||
### Satisfying Interactions
|
||||
|
||||
**Drag and drop delight**:
|
||||
- Lift effect on drag (shadow, scale)
|
||||
- Snap animation when dropped
|
||||
- Satisfying placement sound
|
||||
- Undo toast ("Dropped in wrong place? [Undo]")
|
||||
|
||||
**Toggle switches**:
|
||||
- Smooth slide with spring physics
|
||||
- Color transition
|
||||
- Haptic feedback on mobile
|
||||
- Optional sound effect
|
||||
|
||||
**Progress & achievements** (Operate surfaces with recurring tasks only; gamification on editorial, portfolio, or one-visit surfaces reads as noise):
|
||||
- Streak counters with celebratory milestones
|
||||
- Progress bars that "celebrate" at 100%
|
||||
- Badge unlocks with animation
|
||||
- Playful stats ("You're on fire! 5 days in a row")
|
||||
|
||||
**Form interactions**:
|
||||
- Input fields that animate on focus
|
||||
- Checkboxes with a satisfying scale pulse when checked
|
||||
- Success state that celebrates valid input
|
||||
- Auto-grow textareas
|
||||
|
||||
### Sound Design
|
||||
|
||||
**Subtle audio cues** (when appropriate):
|
||||
- Notification sounds (distinctive but not annoying)
|
||||
- Success sounds (satisfying "ding")
|
||||
- Error sounds (empathetic, not harsh)
|
||||
- Typing sounds for chat/messaging
|
||||
- Ambient background audio (very subtle)
|
||||
|
||||
**IMPORTANT**:
|
||||
- Respect system sound settings
|
||||
- Provide mute option
|
||||
- Keep volumes quiet (subtle cues, not alarms)
|
||||
- Don't play on every interaction (sound fatigue is real)
|
||||
|
||||
### Easter Eggs & Hidden Delights
|
||||
|
||||
**Discovery rewards**:
|
||||
- Konami code unlocks special theme
|
||||
- Hidden keyboard shortcuts (Cmd+K for special features)
|
||||
- Hover reveals on logos or illustrations
|
||||
- Alt text jokes on images (for screen reader users too!)
|
||||
- A view-source or console colophon (a note on the typefaces, a thank-you, a hiring line)
|
||||
|
||||
**Seasonal touches**:
|
||||
- Holiday themes (subtle, tasteful)
|
||||
- Seasonal color shifts
|
||||
- Weather-based variations
|
||||
- Time-based changes (dark at night, light during day)
|
||||
|
||||
**Contextual personality**:
|
||||
- Different messages based on time of day
|
||||
- Responses to specific user actions
|
||||
- Randomized variations (not same every time)
|
||||
- Progressive reveals with continued use
|
||||
|
||||
### Loading & Waiting States
|
||||
|
||||
**Make waiting engaging**:
|
||||
- Interesting loading messages that rotate
|
||||
- Progress bars with personality
|
||||
- Mini-games during long loads
|
||||
- Fun facts or tips while waiting
|
||||
- Countdown with encouraging messages
|
||||
|
||||
```
|
||||
Loading messages: write ones specific to your product, not generic AI filler:
|
||||
- "Syncing with your team's changes..."
|
||||
- "Fetching this week's issue..."
|
||||
- "Developing your photos..."
|
||||
- "Checking tomorrow's tide tables..."
|
||||
```
|
||||
|
||||
**WARNING**: Avoid cliched loading messages like "Herding pixels", "Teaching robots to dance", "Consulting the magic 8-ball", "Counting backwards from infinity". These are AI-slop copy, instantly recognizable as machine-generated. Write messages that are specific to what your product actually does.
|
||||
|
||||
### Celebration Moments
|
||||
|
||||
**Success celebrations**:
|
||||
- Confetti for major milestones
|
||||
- Animated checkmarks for completions
|
||||
- Progress bar celebrations at 100%
|
||||
- "Achievement unlocked" style notifications
|
||||
- Personalized messages ("You published your 10th article!")
|
||||
|
||||
**Milestone recognition** (same scoping as Progress & achievements: Operate surfaces with recurring tasks):
|
||||
- First-time actions get special treatment
|
||||
- Streak tracking and celebration
|
||||
- Progress toward goals
|
||||
- Anniversary celebrations
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
**Animation libraries**:
|
||||
- Framer Motion (React)
|
||||
- GSAP (universal)
|
||||
- Lottie (After Effects animations)
|
||||
- Canvas confetti (party effects)
|
||||
|
||||
**Sound libraries**:
|
||||
- Howler.js (audio management)
|
||||
- Use-sound (React hook)
|
||||
|
||||
**Physics libraries**:
|
||||
- React Spring (spring physics)
|
||||
- Popmotion (animation primitives)
|
||||
|
||||
**IMPORTANT**: File size matters. Compress images, optimize animations, lazy load delight features.
|
||||
|
||||
**NEVER**:
|
||||
- Delay core functionality for delight
|
||||
- Force users through delightful moments (make skippable)
|
||||
- Use delight to hide poor UX
|
||||
- Overdo it (less is more)
|
||||
- Ignore accessibility (animate responsibly, provide alternatives)
|
||||
- Make every interaction delightful (special moments should be special)
|
||||
- Sacrifice performance for delight
|
||||
- Be inappropriate for context (read the room)
|
||||
|
||||
## Verify Delight Quality
|
||||
|
||||
Test that delight actually delights:
|
||||
|
||||
- **User reactions**: Do users smile? Share screenshots?
|
||||
- **Doesn't annoy**: Still pleasant after 100th time?
|
||||
- **Doesn't block**: Can users opt out or skip?
|
||||
- **Performant**: No jank, no slowdown
|
||||
- **Appropriate**: Matches brand and context
|
||||
- **Accessible**: Works with reduced motion, screen readers
|
||||
|
||||
When the moments feel earned, hand off to `/impeccable polish` for the final pass.
|
||||
When the personality feels earned, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Generate a `DESIGN.md` file at the project root that captures the current visual design system, so AI agents generating new screens stay on-brand.
|
||||
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): YAML frontmatter carrying machine-readable design tokens, followed by a markdown body with exactly six sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but **do not reorder them and do not rename them**. Section headers must match the spec character-for-character so the file stays parseable by other DESIGN.md-aware tools (Stitch itself, awesome-design-md, skill-rest, etc.).
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): optional YAML frontmatter carrying machine-readable design tokens, followed by up to eight markdown sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but those present stay in the specified order. Use the canonical headings below so the file remains portable across DESIGN.md-aware tools.
|
||||
|
||||
## The frontmatter: token schema
|
||||
|
||||
@@ -43,26 +43,28 @@ components:
|
||||
Rules that matter:
|
||||
|
||||
- **Token refs** use `{path.to.token}` (e.g. `{colors.primary}`, `{rounded.md}`). Components may reference primitives; primitives may not reference each other.
|
||||
- **Stitch validates colors as hex sRGB only** (`#RGB` / `#RGBA` / `#RRGGBB` / `#RRGGBBAA`); OKLCH/HSL/P3 trigger a linter warning, not a hard error. YAML accepts the string either way and our own parser is format-agnostic. Choose based on project posture: (a) if the project has an "OKLCH-only" doctrine or uses Display-P3 values that don't round-trip through sRGB, put OKLCH directly in the frontmatter and accept the Stitch linter warning; (b) if the project wants strict Stitch compliance or plans to use their Tailwind/DTCG export pipeline, put hex in the frontmatter and keep OKLCH in prose as the canonical reference. Never split the source of truth without explicit reason.
|
||||
- **Colors accept any valid CSS color string.** Hex is the recommended default for portability, but preserve an incumbent `rgb()`, `hsl()`, `oklch()`, wide-gamut, or mixed-color value when it is the project's normative source. Never split the source of truth without explicit reason.
|
||||
- **Component sub-tokens** are limited to 8 props: `backgroundColor`, `textColor`, `typography`, `rounded`, `padding`, `size`, `height`, `width`. Shadows, motion, focus rings, backdrop-filter: none of those fit. Carry them in the sidecar (Step 4b).
|
||||
- **Scale keys are open-ended.** Use whatever names the project already uses (`oxblood-deep`, `surface-container-low`). Don't rename to Material defaults.
|
||||
- **Variants are naming convention, not schema.** `button-primary` / `button-primary-hover` / `button-primary-active` as sibling keys.
|
||||
|
||||
## The markdown body: six sections (exact order)
|
||||
## The markdown body: eight sections (canonical order)
|
||||
|
||||
1. `## Overview`
|
||||
2. `## Colors`
|
||||
3. `## Typography`
|
||||
4. `## Elevation`
|
||||
5. `## Components`
|
||||
6. `## Do's and Don'ts`
|
||||
4. `## Layout`
|
||||
5. `## Elevation & Depth`
|
||||
6. `## Shapes`
|
||||
7. `## Components`
|
||||
8. `## Do's and Don'ts`
|
||||
|
||||
Optional evocative subtitles are allowed in the form `## 2. Colors: The [Name] Palette` (Stitch's own outputs do this), but the literal word in each header (Overview, Colors, Typography, Elevation, Components, Do's and Don'ts) must be present. Do NOT add extra top-level sections (Layout Principles, Responsive Behavior, Motion, Agent Prompt Guide). Fold that content into the six spec sections where it naturally belongs.
|
||||
Omit irrelevant sections rather than filling them with invented rules. Put responsive layout in Layout, depth in Elevation & Depth, radius and form language in Shapes, and per-component behavior in Components. Unknown sections are preserved by the format, but new visual guidance should use the canonical structure whenever it fits.
|
||||
|
||||
## When to run
|
||||
|
||||
- The user just ran `/impeccable init` and needs the visual side documented.
|
||||
- The skill noticed no `DESIGN.md` exists and nudged the user to create one.
|
||||
- New-work found a coherent incumbent visual system but no `DESIGN.md`.
|
||||
- The first implementation of a new world is complete and its provisional decisions need to be carbonized.
|
||||
- An existing `DESIGN.md` is stale (the design has drifted).
|
||||
- Before a large redesign, to capture the current state as a reference.
|
||||
|
||||
@@ -71,9 +73,9 @@ If a `DESIGN.md` already exists, **do not silently overwrite it**. Show the user
|
||||
## Two paths
|
||||
|
||||
- **Scan mode** (default): the project has design tokens, components, or rendered output. Extract, then confirm descriptive language. Use when there's code to analyze.
|
||||
- **Seed mode**: the project is pre-implementation (fresh init, nothing built yet). Interview for five high-level answers, write a minimal DESIGN.md marked `<!-- SEED -->`. Re-run in scan mode once there's code.
|
||||
- **Seed mode**: the project is pre-implementation. Ensure PRODUCT.md exists, then reuse new-work's visual-world workshop and write its directional DESIGN.md seed. Re-run in scan mode once there's code.
|
||||
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` forces seed mode regardless of code presence.
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` requests new-work's world workshop, but it does not authorize replacing coherent code: when an incumbent system exists, offer scan mode or route an explicit identity-replacement request through new-work.
|
||||
|
||||
## Scan mode (approach C: auto-extract, then confirm descriptive language)
|
||||
|
||||
@@ -97,7 +99,8 @@ Build a structured draft from the discovered tokens. For each token class:
|
||||
- **Typography**: Map observed sizes and weights to the Material hierarchy (display / headline / title / body / label). Note font-family stacks and the scale ratio.
|
||||
- **Elevation**: Catalogue the shadow vocabulary. If the project is flat and uses tonal layering instead, that's a valid answer; state it explicitly.
|
||||
- **Components**: For each common component (button, card, input, chip, list item, tooltip, nav), extract shape (radius), color assignment, hover/focus treatment, internal padding.
|
||||
- **Spacing + layout**: Fold into Overview or relevant Components. The spec does NOT have a Layout section.
|
||||
- **Layout + spacing**: Extract grid, container, breakpoint, rhythm, and density behavior into Layout.
|
||||
- **Shapes**: Extract radius, corner, border, clipping, and recurring form behavior into Shapes.
|
||||
|
||||
### Step 2b: Stage the frontmatter
|
||||
|
||||
@@ -112,19 +115,19 @@ Skip anything the project doesn't have. Empty scale keys or fabricated tokens po
|
||||
|
||||
### Step 3: Ask the user for qualitative language
|
||||
|
||||
The following require creative input that cannot be auto-extracted. Group them into one `AskUserQuestion` interaction:
|
||||
The following require creative input that cannot be auto-extracted. Ask them in two structured rounds of no more than three questions each (or the harness's lower limit), waiting between rounds:
|
||||
|
||||
- **Creative North Star**: a single named metaphor for the whole system ("The Editorial Sanctuary", "The Golden State Curator", "The Lab Notebook"). Offer 2-3 options that honor PRODUCT.md's brand personality.
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, anti-references (what the system should not feel like).
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, and any confirmed visual anti-reference.
|
||||
- **Color character** (for auto-extracted colors): descriptive names ("Deep Muted Teal-Navy", not "blue-800"). Suggest 2-3 options per key color based on hue/saturation.
|
||||
- **Elevation philosophy**: flat/layered/lifted. If shadows exist, is their role ambient or structural?
|
||||
- **Component philosophy**: the feel of buttons, cards, inputs in one phrase ("tactile and confident" vs. "refined and restrained").
|
||||
|
||||
Quote a line from PRODUCT.md when possible so the user sees their own strategic language carry forward.
|
||||
Carry a line from PRODUCT.md only when it is a durable brand commitment that actually constrains the visual system. Page strategy and surface concepts do not belong here.
|
||||
|
||||
### Step 4: Write DESIGN.md
|
||||
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the structure below. Headers must match character-for-character. Optional evocative subtitles (e.g. `## 2. Colors: The Coastal Palette`) are allowed.
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the canonical structure below.
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -136,13 +139,13 @@ colors:
|
||||
|
||||
# Design System: [Project Title]
|
||||
|
||||
## 1. Overview
|
||||
## Overview
|
||||
|
||||
**Creative North Star: "[Named metaphor in quotes]"**
|
||||
|
||||
[2-3 paragraph holistic description: personality, density, aesthetic philosophy. Start from the North Star and work outward. State what this system explicitly rejects (pulled from PRODUCT.md's anti-references). End with a short **Key Characteristics:** bullet list.]
|
||||
[2-3 paragraph holistic description: personality, density, and aesthetic philosophy. Start from the North Star and work outward. State only confirmed visual rejections. End with a short **Key Characteristics:** bullet list.]
|
||||
|
||||
## 2. Colors
|
||||
## Colors
|
||||
|
||||
[Describe the palette character in one sentence.]
|
||||
|
||||
@@ -162,7 +165,7 @@ colors:
|
||||
### Named Rules (optional, powerful)
|
||||
**The [Rule Name] Rule.** [Short, forceful prohibition or doctrine, e.g. "The One Voice Rule. The primary accent is used on ≤10% of any given screen. Its rarity is the point."]
|
||||
|
||||
## 3. Typography
|
||||
## Typography
|
||||
|
||||
**Display Font:** [Family] (with [fallback])
|
||||
**Body Font:** [Family] (with [fallback])
|
||||
@@ -180,7 +183,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [Short doctrine about type use.]
|
||||
|
||||
## 4. Elevation
|
||||
## Layout
|
||||
|
||||
[Describe the grid or spatial model, container behavior, density, responsive changes, and the spacing rhythm. Include exact values only when observed.]
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
[One paragraph: does this system use shadows, tonal layering, or a hybrid? If "no shadows", say so explicitly and describe how depth is conveyed instead.]
|
||||
|
||||
@@ -191,7 +198,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [e.g. "The Flat-By-Default Rule. Surfaces are flat at rest. Shadows appear only as a response to state (hover, elevation, focus)."]
|
||||
|
||||
## 5. Components
|
||||
## Shapes
|
||||
|
||||
[Describe the form language: corner/radius strategy, borders, clipping, and any recurring silhouette or geometry.]
|
||||
|
||||
## Components
|
||||
|
||||
For each component, lead with a short character line, then specify shape, color assignment, states, and any distinctive behavior.
|
||||
|
||||
@@ -223,16 +234,16 @@ For each component, lead with a short character line, then specify shape, color
|
||||
### [Signature Component] (optional; if the project has a distinctive custom component worth documenting)
|
||||
[Description.]
|
||||
|
||||
## 6. Do's and Don'ts
|
||||
## Do's and Don'ts
|
||||
|
||||
Concrete, forceful guardrails. Lead each with "Do" or "Don't". Be specific: include exact colors, pixel values, and named anti-patterns the user mentioned in PRODUCT.md. **Every anti-reference in PRODUCT.md should show up here as a "Don't" with the same language**, so the visual spec carries the strategic line through. Quote PRODUCT.md directly where possible: if PRODUCT.md says *"avoid dark mode with purple gradients, neon accents, glassmorphism"*, the Don'ts here should repeat that by name.
|
||||
Concrete visual guardrails grounded in the incumbent implementation or the user's chosen world. Lead each with "Do" or "Don't" and include exact values only when established. Do not turn a task-specific concept or surface strategy into a system-wide prohibition.
|
||||
|
||||
### Do:
|
||||
- **Do** [specific prescription with exact values / named rule].
|
||||
- **Do** [...]
|
||||
|
||||
### Don't:
|
||||
- **Don't** [specific prohibition, e.g. "use border-left greater than 1px as a colored stripe"].
|
||||
- **Don't** [specific prohibition confirmed by the incumbent system or the user].
|
||||
- **Don't** [...]
|
||||
- **Don't** [...]
|
||||
```
|
||||
@@ -307,7 +318,7 @@ The `html` and `css` fields must be **self-contained, drop-in snippets** that re
|
||||
Aim for a tight set of **5-10 components** that best represent the visual system:
|
||||
|
||||
- **Canonical primitives (always include if the project has them):** button (each variant as a separate component entry), input/text field, navigation, chip/tag, card.
|
||||
- **Signature components (include if distinctive):** hero CTA, featured card, filter pill, a distinctive table or list-row treatment, any custom pattern the user mentioned as important in PRODUCT.md.
|
||||
- **Signature components (include if distinctive):** the recurring custom patterns that actually define the implemented system.
|
||||
- **Skip the rest.** Utility components, form building blocks, wrapper layouts: not worth documenting unless visually distinctive.
|
||||
|
||||
If the project has **no component library yet** (bare landing page, new project), synthesize canonical primitives from the tokens using best-practice defaults consistent with the DESIGN.md's rules. Every `.impeccable/design.json` has *something* to render, even on day zero.
|
||||
@@ -338,64 +349,40 @@ Your own write is the freshest source; subsequent commands in this session don't
|
||||
|
||||
## Seed mode
|
||||
|
||||
For projects with no visual system to extract yet. Produces a minimal scaffold, not a full spec.
|
||||
For projects with no visual system to extract yet. Produces a user-chosen visual-world scaffold, not a fabricated token spec.
|
||||
|
||||
### Step 1: Confirm seed mode
|
||||
### Step 1: Route through new-work's workshop
|
||||
|
||||
Before interviewing: "There's no existing visual system to scan. I'll ask five quick questions to seed a starter DESIGN.md. You can re-run `/impeccable document` once there's code, to capture the real tokens and components. OK?"
|
||||
PRODUCT.md is the prerequisite. If it is missing, load [init.md](init.md) and complete its product interview first. Do not create a visual identity without durable product context.
|
||||
|
||||
If the user prefers to skip, stop. No file.
|
||||
If PRODUCT.md exists, load [new-work.md](new-work.md) and resolve visual authority. Seed mode requires a concrete first surface: use the target the user named, or ask what they want to make first. Run **Select one direction** for A, D, or E so the visual world and its first expression are chosen as one pair. Stop after the directional DESIGN.md seed and surface brief; do not implement. A structured simulated user counts as the user and must get the same choice.
|
||||
|
||||
### Step 2: Five questions
|
||||
If new-work already completed the workshop in this session, use its chosen direction directly. Do not ask again.
|
||||
|
||||
Group into one `AskUserQuestion` interaction. Options must be concrete.
|
||||
### Step 2: Write seed DESIGN.md
|
||||
|
||||
1. **Color strategy.** Pick one:
|
||||
- Restrained: tinted neutrals + one accent ≤10%
|
||||
- Committed: one saturated color carries 30–60% of the surface
|
||||
- Full palette: 3–4 named color roles, each deliberate
|
||||
- Drenched: the surface IS the color
|
||||
|
||||
Then: one hue family or anchor reference ("deep teal", "mustard", "Klim #ff4500 orange").
|
||||
|
||||
2. **Typography direction.** Pick one (specific fonts come later):
|
||||
- Serif display + sans body
|
||||
- Single sans (warm / technical / geometric / humanist; pick a feel)
|
||||
- Display + mono
|
||||
- Mono-forward
|
||||
- Editorial script + sans
|
||||
|
||||
3. **Motion energy.** Pick one:
|
||||
- Restrained: state changes only
|
||||
- Responsive: feedback + transitions, no choreography
|
||||
- Choreographed: orchestrated entrances, scroll-driven sequences
|
||||
|
||||
4. **Three named references.** Brands, products, printed objects. Not adjectives.
|
||||
|
||||
5. **One anti-reference.** What it should NOT feel like. Also named.
|
||||
|
||||
### Step 3: Write seed DESIGN.md
|
||||
|
||||
Use the six-section spec from Scan mode. Populate what the interview answers; leave the rest as honest placeholders. The seed is a scaffold, not a fabricated spec.
|
||||
Use the canonical section order from Scan mode. Populate the selected workshop direction and leave unresolved implementation facts as honest placeholders. The seed commits a world and its invariants; it does not pretend implementation tokens already exist.
|
||||
|
||||
Lead the file with:
|
||||
|
||||
```markdown
|
||||
<!-- SEED: re-run /impeccable document once there's code to capture the actual tokens and components. -->
|
||||
<!-- SEED: established with the user before implementation; re-run /impeccable document once there's code to capture the actual tokens and components. -->
|
||||
```
|
||||
|
||||
Per-section guidance in seed mode:
|
||||
|
||||
- **Overview**: Creative North Star and philosophy phrased from the answers (color strategy + motion energy + references). Reference the user's anti-reference directly.
|
||||
- **Colors**: Color strategy as a Named Rule (e.g. *"The Drenched Rule. The surface IS the color."*). Hue family or anchor reference. No hex values; mark as `[to be resolved during implementation]`.
|
||||
- **Typography**: the direction the user picked (e.g. "Serif display + sans body"). No font names yet: `[font pairing to be chosen at implementation]`.
|
||||
- **Elevation**: inferred from motion energy. Restrained/Responsive → flat by default; Choreographed → layered. One sentence.
|
||||
- **Overview**: the chosen design thesis, layout behavior, material character, imagery stance, motion grammar, and reusable signature. Keep the selected first-surface expression in its surface brief; do not promote its composition into the global world.
|
||||
- **Colors**: the selected palette strategy and roles. Include values only when the user, an existing asset, or new-work's exploration established them; otherwise mark them `[to be resolved during implementation]`.
|
||||
- **Typography**: the selected type character and role relationship. Include font names only when established; otherwise mark the pairing `[to be resolved during implementation]`.
|
||||
- **Layout**: the selected spatial grammar and responsive behavior, without pretending exact measurements are settled.
|
||||
- **Elevation & Depth**: the selected material and depth behavior, stated as an invariant rather than inferred from a generic preset.
|
||||
- **Shapes**: the selected form and corner language.
|
||||
- **Components**: omit entirely; no components exist yet.
|
||||
- **Do's and Don'ts**: carry PRODUCT.md's anti-references directly plus the anti-reference named in Q5.
|
||||
- **Do's and Don'ts**: record the durable guardrails confirmed during the world choice, not task-local refusals.
|
||||
|
||||
Seed mode writes a minimal frontmatter with `name` and `description` only; no colors, typography, rounded, spacing, or components yet. Real tokens land on the next Scan-mode run. Skip the `.impeccable/design.json` sidecar in seed mode for the same reason: nothing to render.
|
||||
|
||||
### Step 4: Confirm
|
||||
### Step 3: Confirm
|
||||
|
||||
1. Show the seed DESIGN.md. Call out that it is a seed (the marker is the literal commitment).
|
||||
2. Tell the user: "Re-run `/impeccable document` once you have some code. That pass will extract real tokens and generate the sidecar."
|
||||
@@ -405,15 +392,15 @@ Your own write is the freshest source; no reload needed.
|
||||
## Style guidelines
|
||||
|
||||
- **Frontmatter first, prose second.** Tokens go in the YAML frontmatter; prose contextualizes them. Don't redefine a token value in two places; the frontmatter is normative.
|
||||
- **Cite PRODUCT.md anti-references by name** in the Do's and Don'ts section. If PRODUCT.md lists "SaaS landing-page clichés" or "generic AI tool marketing" as anti-references, the DESIGN.md Don'ts should repeat those phrases verbatim so the visual spec enforces the strategic line.
|
||||
- **Match the spec, don't invent new sections.** The six section names are fixed. If you have Layout/Motion/Responsive content to document, fold it into Overview (philosophy-level rules) or Components (per-component behavior).
|
||||
- **Carry only durable product constraints.** A binding logo, identity asset, accessibility need, or brand commitment from PRODUCT.md may constrain DESIGN.md. Surface strategy stays in its surface brief.
|
||||
- **Match the spec.** Use its eight canonical sections in order and omit any that are irrelevant. Put motion guidance with the world or component it affects rather than creating a token group the schema does not support.
|
||||
- **Descriptive > technical**: "Gently curved edges (8px radius)" > "rounded-lg". Include the technical value in parens, lead with the description.
|
||||
- **Functional > decorative**: for each token, explain WHERE and WHY it's used, not just WHAT it is.
|
||||
- **Exact values in parens**: hex codes, px/rem values, font weights; always the number in parens alongside the description.
|
||||
- **Use Named Rules**: `**The [Name] Rule.** [short doctrine]`. These are memorable, citable, and much stickier for AI consumers than bullet lists. Stitch's own outputs use them heavily ("The No-Line Rule", "The Ghost Border Fallback"). Aim for 1-3 per section.
|
||||
- **Be forceful**. The voice of a design director. "Prohibited", "forbidden", "never", "always", not "consider", "might", "prefer". Match PRODUCT.md's tone.
|
||||
- **Concrete anti-pattern tests**. Stitch writes things like *"If it looks like a 2014 app, the shadow is too dark and the blur is too small."* A one-sentence audit test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md**. The anti-references section of PRODUCT.md should directly inform the Do's and Don'ts section here. Quote or paraphrase.
|
||||
- **Be decisive where evidence is decisive.** Use hard language for actual invariants and softer language for provisional guidance.
|
||||
- **Use concrete audit tests only when they are grounded in the observed system or a confirmed user decision.** A one-sentence test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md selectively.** Product truth explains why the world fits; it does not supply page composition or a visual don't-list by default.
|
||||
- **Group colors by role**, not by hex-order or hue-order. Primary / Secondary / Tertiary / Neutral is the spec ordering.
|
||||
|
||||
## Pitfalls
|
||||
@@ -423,7 +410,7 @@ Your own write is the freshest source; no reload needed.
|
||||
- Don't invent components that don't exist. If the project only has buttons and cards, only document those.
|
||||
- Don't overwrite an existing DESIGN.md without asking.
|
||||
- Don't duplicate content from PRODUCT.md. DESIGN.md is strictly visual.
|
||||
- Don't add a "Layout Principles" or "Motion" or "Responsive Behavior" top-level section. The spec has six, not nine. Fold that content where it belongs.
|
||||
- Don't replace canonical sections with near-synonyms. Put layout and responsive behavior in `Layout`; put motion with the affected world or component.
|
||||
- Don't rename sections even slightly. "Colors" not "Color Palette & Roles". "Typography" not "Typography Rules". Tooling parsing depends on exact headers.
|
||||
- Don't duplicate token values between frontmatter and prose. If a color is in `colors.primary` as hex, the prose can name it and describe its role but should not reassert a different hex. The frontmatter is normative.
|
||||
- Don't invent frontmatter token groups outside Stitch's schema (no `motion:`, `breakpoints:`, `shadows:` at the top level). Stitch's Zod schema only accepts `colors`, `typography`, `rounded`, `spacing`, `components`. Anything else belongs in the sidecar's `extensions`.
|
||||
|
||||
@@ -4,7 +4,7 @@ Manage the **design detector hook** for the current project.
|
||||
|
||||
The hook runs the impeccable design detector on direct file edits to design-relevant files (`.tsx`, `.jsx`, `.html`, `.vue`, `.svelte`, `.astro`, `.css`, `.scss`, `.sass`, `.less`, `.ts`, `.js`). Claude Code, Codex, and GitHub Copilot use a post-tool-use hook and push a short system reminder into the agent's context after the edit; findings get a correction prompt, pending issues get a re-nudge, and clean UI-ish files get a short ack unless quiet mode is on (`hook.quiet` in config). Plain `.ts` and `.js` files are still scanned, but stay quiet unless the detector finds something. Cursor uses `preToolUse` to block bad proposed writes before they land and stays silent when it allows a clean write.
|
||||
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so Copilot keeps the full rule set per edit instead of deferring.
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. That Stop message also asks for one authored review of detector-blind model reflexes. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit while `context.mjs` supplies the detector-blind review. When no automatic hook is active, `context.mjs` instead supplies that review plus one manual detector command.
|
||||
|
||||
This command toggles the hook **per project** by editing `.impeccable/config.json` (the unified Impeccable config; hook runtime settings live under its `hook` key, and shared detector ignores live under `detector`). Per-developer overrides, including the install consent decision (`hook.consent`) the CLI records, live in the gitignored `.impeccable/config.local.json`. Set `hook.enabled: false` to turn the hook off, `hook.quiet: true` to silence the clean/pending acks, or `hook.auditLog` to a file path for an NDJSON log. The legacy `IMPECCABLE_HOOK_DISABLED`, `IMPECCABLE_HOOK_QUIET`, and `IMPECCABLE_HOOK_LOG` env vars are still honored and override these config values when set.
|
||||
|
||||
|
||||
@@ -1,224 +1,114 @@
|
||||
# Init Flow
|
||||
# Init flow
|
||||
|
||||
The setup command for a project. One codebase crawl feeds everything it writes:
|
||||
|
||||
- **PRODUCT.md** (strategic): root project file for register, target users, product purpose, brand personality, anti-references, strategic design principles. Answers "who/what/why".
|
||||
- **DESIGN.md** (visual): root project file for visual theme, color palette, typography, components, layout. Follows the [DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md). Answers "how it looks".
|
||||
- **`.impeccable/live/config.json`** (live mode): pre-configured so `/impeccable live` boots straight into variant mode with no first-time detour.
|
||||
|
||||
It closes by pointing the user at the best command to run next. Every other impeccable command reads PRODUCT.md and DESIGN.md before doing any work.
|
||||
`init` captures durable product truth in PRODUCT.md. It does not invent a visual world and does not write DESIGN.md; [new-work.md](new-work.md) creates or expands one, and [document.md](document.md) records an incumbent one. Existing runnable web projects may also receive `.impeccable/live/config.json`.
|
||||
|
||||
## Step 1: Load current state
|
||||
|
||||
Check what already exists. PRODUCT.md and DESIGN.md live at the project root, or under `.agents/context/` or `docs/` (case-insensitive). Read whichever are present with your native file tool. Also note whether `.impeccable/live/config.json` already exists (Step 6 leaves it untouched if so).
|
||||
Use the PRODUCT.md path resolved by context.mjs. Update it instead of creating a competing authority. In a child app inheriting root context, confirm shared versus app-specific scope before writing.
|
||||
|
||||
Decision tree:
|
||||
- **Neither file exists (empty project or no context yet)**: do Steps 2-4 (write PRODUCT.md), then decide on DESIGN.md based on whether there's code to analyze.
|
||||
- **PRODUCT.md exists, DESIGN.md missing**: skip to Step 5 and offer to run `/impeccable document` for DESIGN.md.
|
||||
- **PRODUCT.md exists but has no `## Register` section (legacy)**: add it. Infer a hypothesis from the codebase (see Step 2), confirm with the user, write the field.
|
||||
- **PRODUCT.md exists but has no `## Platform` section (legacy)**: add it the same way, but only when the project is native (`ios` / `android` / `adaptive`) or the user wants it explicit; a missing field already means `web`.
|
||||
- **Both exist**: STOP and call the AskUserQuestion tool to clarify. Ask which file to refresh. Skip the one the user doesn't want changed.
|
||||
- **Just DESIGN.md exists (unusual)**: do Steps 2-4 to produce PRODUCT.md.
|
||||
- **No PRODUCT.md:** explore, interview, and write it.
|
||||
- **PRODUCT.md exists:** ask what product knowledge is stale or missing; do not reopen confirmed fields without a reason.
|
||||
- **Legacy PRODUCT.md:** add only durable missing facts; absent `## Platform` means `web` unless evidence says otherwise.
|
||||
- **Only DESIGN.md exists:** leave it untouched and create PRODUCT.md.
|
||||
- **Redesign/rebrand request:** preserve confirmed product truth unless the user changes it. Visual replacement happens later in new-work, not here.
|
||||
|
||||
Never silently overwrite an existing file. Always confirm first.
|
||||
Never silently overwrite an existing file or offer DESIGN.md during init. If another request invoked init, finish PRODUCT.md and resume it. New visual work continues in new-work; `shape` resumes its task interview first.
|
||||
|
||||
If init was invoked as a setup blocker by another command, such as `/impeccable craft landing page`, pause that command here. Complete init, then resume the original command. Your own writes are the freshest source; no reload needed. For craft, resume into shape next; init creates project context, but it is not a substitute for the task-specific shape interview and confirmed design brief.
|
||||
## Step 2: Explore the project
|
||||
|
||||
## Step 2: Explore the codebase
|
||||
Before asking, scan enough to avoid making the user repeat known facts: product docs and copy; package/config and app boundaries; features, workflows, routes, and roles; names, logos, legal/proof assets, and brand commitments; platform/accessibility signals; and the dev command/entry when live mode applies.
|
||||
|
||||
Before asking questions, thoroughly scan the project to discover what you can. This single crawl feeds PRODUCT.md, DESIGN.md, **and** the live-mode framework detection in Step 6, so be thorough once rather than re-scanning later:
|
||||
Treat repository evidence as a hypothesis, not user approval. Note visual maturity without documenting, extending, or replacing the world.
|
||||
|
||||
- **README and docs**: Project purpose, target audience, any stated goals
|
||||
- **Package.json / config files**: Tech stack, dependencies, existing design libraries, **and the framework** (Vite/SPA, Next.js, Nuxt, SvelteKit, Astro, multi-page static) plus the HTML entry the browser actually loads
|
||||
- **Existing components**: Current design patterns, spacing, typography in use
|
||||
- **Brand assets**: Logos, favicons, color values already defined
|
||||
- **Design tokens / CSS variables**: Existing color palettes, font stacks, spacing scales
|
||||
- **Any style guides or brand documentation**
|
||||
Form a platform hypothesis: `web`, `ios`, `android`, or `adaptive` (one product that genuinely adapts its design language per OS). Mobile web remains `web`; a native wrapper around a website does not make its design language native.
|
||||
|
||||
Also form a **register hypothesis** from what you find:
|
||||
## Step 3: Interview for product truth
|
||||
|
||||
- Brand signals: `/`, `/about`, `/pricing`, `/blog/*`, `/docs/*`, hero sections, big typography, scroll-driven sections, landing-page-shaped content.
|
||||
- Product signals: `/app/*`, `/dashboard`, `/settings`, `/(auth)`, forms, data tables, side/top nav, app-shell components.
|
||||
STOP and call the AskUserQuestion tool to clarify. Ask only about material gaps the repository and original request do not answer with strong evidence.
|
||||
|
||||
Register is a hypothesis at this point, not a decision; Step 3 confirms it.
|
||||
Use the structured question tool when available; otherwise ask and wait. Keep rounds to at most three focused questions and require one real answer or approval round before writing a new PRODUCT.md. Confirm inferences.
|
||||
|
||||
Also form a **platform hypothesis**:
|
||||
Start with the unknowns that most change future product decisions:
|
||||
|
||||
- Native signals: React Native / Expo (`react-native`, `expo`), Flutter (`pubspec.yaml`, `flutter`), SwiftUI / UIKit (`.swift`, `.xcodeproj`, an `ios/` app target), Jetpack Compose / Android (`build.gradle`, an `android/` app module, `AndroidManifest.xml`). An `ios/` and/or `android/` directory that is a real app target, not just a Capacitor/Cordova wrapper around a website.
|
||||
- Web signals (the default): a web framework (Vite, Next, Nuxt, SvelteKit, Astro), an HTML entry, a CSS/Tailwind setup, no native app target.
|
||||
1. Who is the primary user, in what situation, and what job are they doing?
|
||||
2. What does the product make possible, and what is its meaningfully different mechanism or position?
|
||||
3. What durable constraints, assets, evidence, or product facts must future work preserve?
|
||||
|
||||
Values: `web` / `ios` / `android` / `adaptive` (one codebase, ships both, adapts per OS). Mobile web is still `web`. Like register, this is a hypothesis; Step 3 confirms it.
|
||||
Confirm ambiguous platform separately. Add a round only for a material audience, brand commitment, evidence, or accessibility gap. Record undecided facts instead of inventing them.
|
||||
|
||||
Note what you've learned and what remains unclear. Also note any rough edges worth a follow-up command (thin hierarchy, flat or gray palette, missing error/empty states, dull copy); Step 7 turns these into concrete recommendations without re-analyzing.
|
||||
Do not ask for an aesthetic direction, emotional feel, visual references, colors, typography, or style during init. If the user volunteers a binding visual constraint, record it without expanding it.
|
||||
|
||||
## Step 3: Ask strategic questions (for PRODUCT.md)
|
||||
### What belongs here
|
||||
|
||||
STOP and call the AskUserQuestion tool to clarify. Ask about anything the codebase doesn't answer with strong, explicit evidence.
|
||||
- users, jobs, workflows, purpose, success, positioning, and operating context;
|
||||
- capabilities, constraints, terminology, evidence, platform, and accessibility;
|
||||
- confirmed voice, assets, and brand commitments.
|
||||
|
||||
### Interview mode, not confirmation mode
|
||||
### What does not belong here
|
||||
|
||||
If the repo is empty or the user's brief is sparse, run a short interview before proposing PRODUCT.md. Do **not** turn a one-sentence request into a complete inferred PRODUCT.md and ask for blanket confirmation.
|
||||
|
||||
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop: one question at a time, with lettered options where the crawl suggests likely answers, waiting for each answer before the next.
|
||||
- Keep skill vocabulary (register, belief ladder, anti-references) out of question text; ask for the thing in words the user would use. For the brand register, ask like a magazine editor profiling the brand: curious and narrative, drawing out the story, the feel, and what a visitor should come to believe.
|
||||
- Ask in focused rounds and wait for answers between them. Keep **one topic per question**; add rounds rather than fold several topics into one either-or choice. Options obey the same rule: an option answers only the question asked; never write a compound option that bundles a feeling with a business outcome or names an additional audience.
|
||||
- Use inferred answers as hypotheses or options, not as finished facts.
|
||||
- Complete at least one real user-answer round before drafting PRODUCT.md, unless every required answer is directly discoverable from repo docs.
|
||||
- Round 1 should establish register, platform, users, purpose, positioning, and desired outcome.
|
||||
- Round 2 should establish brand personality or references, anti-references, and accessibility needs, plus conversion & proof for Persuade surfaces.
|
||||
|
||||
### Minimum viable interview
|
||||
|
||||
Ask enough to complete PRODUCT.md. At minimum, cover register confirmation, **platform confirmation** (`web` / `ios` / `android` / `adaptive`), users, purpose, positioning, brand personality, anti-references, and accessibility needs (plus conversion & proof for Persuade surfaces) unless each answer is directly discoverable from repo context. Never let the template's default `web` stand unconfirmed for a native or cross-platform repo. After at least one interview round, you may propose inferred answers, but the user must confirm them before you write PRODUCT.md. Never synthesize PRODUCT.md from the original task prompt alone.
|
||||
|
||||
### Register (ask first; it shapes everything below)
|
||||
|
||||
Every design task serves one of four visitor modes (see SKILL.md's Registers): **Persuade** (marketing, landing, campaigns), **Experience** (portfolios, albums, bodies of work), **Operate** (app UI, admin, dashboards, tools), and **Read** (documentation, editorial, long-form). PRODUCT.md stores the two-value family that covers them: `brand` covers Persuade and Experience, `product` covers Operate and Read. The brief decides the exact mode per task; the stored register only sets the default family.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [brand / product] surface. Does that match your intent, or should we treat it differently?"*
|
||||
|
||||
If the signal is genuinely split (e.g. a product with a big marketing landing), STOP and call the AskUserQuestion tool to clarify. Ask which register describes the **primary** surface. The register can be overridden per task later, but PRODUCT.md carries one default. Settle the default before drafting any register-dependent questions; never batch Persuade-only questions (Conversion & proof) into the same round as the question that decides the register.
|
||||
|
||||
### Platform (ask right after register)
|
||||
|
||||
Every project targets **web** (includes responsive mobile web), **ios**, **android**, or **adaptive** (one codebase, ships both, adapts per OS: Flutter, React Native, KMP). Platform picks the native rulebook: HIG for `ios`, Material 3 for `android`, both for `adaptive`, none for `web`.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [web / ios / android / adaptive] project. Does that match?"* For cross-platform apps, decide by the **design language the app renders**, not the toolchain: one look on both platforms (Flutter's Material-everywhere default) takes that platform's value; genuine per-OS adaptation (Cupertino on iOS, Material on Android) is `adaptive`. When in doubt, `web`.
|
||||
|
||||
A monorepo shipping both a website and a native app gets a PRODUCT.md per app, each with its own `## Platform`; the root PRODUCT.md carries the primary surface's platform.
|
||||
|
||||
### Users & Purpose
|
||||
- Who uses this? What's their context when using it?
|
||||
- What job are they trying to get done?
|
||||
- What is this for? A purpose stated in README or docs is a hypothesis, not strong evidence; confirm it, don't transcribe it.
|
||||
- What does success look like?
|
||||
- If more than one kind of user is plausible, confirm a primary and secondary audience; don't manufacture a split that isn't there. An audience implied by another answer (a success metric, a CTA) is still unconfirmed; ask before writing it as secondary.
|
||||
- If the surface speaks to a different audience than the people who use the product, ask the user to name both.
|
||||
- For brand: what emotions should the interface evoke? (confidence, delight, calm, urgency) Ask this standalone; don't fold emotions into the success question.
|
||||
- For product: what workflow are they in? What's the primary task on any given screen?
|
||||
|
||||
### Positioning
|
||||
- In one line, what does this do that nothing else does? The single strategic claim every screen reinforces.
|
||||
|
||||
### Brand & Personality
|
||||
- How would you describe the brand personality in 3 words?
|
||||
- Reference sites or apps that capture the right feel? What specifically about them?
|
||||
- Push for specific named references with the *specific* thing about them that fits this brand, not generic "modern" adjectives or category-bucket lanes.
|
||||
- What should this explicitly NOT look like? Any anti-references?
|
||||
|
||||
### Conversion & proof (Persuade surfaces only)
|
||||
|
||||
Ask these only when the primary surface is a Persuade one (marketing, landing, campaigns). Experience and Read surfaces (portfolios, albums, long-form writing, documentation) get no CTA, belief-ladder, or proof questions even when the stored register is `brand`; skip this section and its PRODUCT.md counterpart.
|
||||
|
||||
- What's the primary CTA?
|
||||
- What's the secondary fallback, for visitors not ready for the primary?
|
||||
- The one line a visitor should remember after 10 seconds.
|
||||
- What must the visitor believe, in order, before taking the primary CTA? (The template's belief ladder.)
|
||||
- What proof is on hand? Ask the user to hand over any testimonials, case studies, press, or client/partner logos they already have. If you can receive files directly, collect them; otherwise create `.impeccable/assets/proof/` and ask the user to add files there. Reference supplied files by path; record text proof inline.
|
||||
|
||||
### Accessibility & Inclusion
|
||||
- Specific accessibility requirements? (WCAG level, known user needs)
|
||||
- Considerations for reduced motion, color blindness, or other accommodations?
|
||||
|
||||
Skip questions where the answer is already clear. **Do NOT ask about colors, fonts, radii, or visual styling here.** Those belong in DESIGN.md, not PRODUCT.md.
|
||||
- visual worlds, palettes, typography, components, or page concepts;
|
||||
- visitor mode, narrative, CTA/proof sequence, or other surface strategy;
|
||||
- invented testimonials, customers, benchmarks, pricing, licensing, or deployment claims;
|
||||
- a requirement to decide every optional field.
|
||||
|
||||
## Step 4: Write PRODUCT.md
|
||||
|
||||
Write PRODUCT.md only after the user has confirmed the strategic answers from Step 3. If an inferred answer is uncertain or unconfirmed, ask before writing. Confirmed means what the user actually said yes to; do not pad a confirmed answer with extras they never picked (additional anti-references, audiences, roadmap claims, a WCAG level), whether drawn from the crawl, another answer, or your own option text. If an extra belongs in the doc, ask about it first.
|
||||
|
||||
Synthesize into a strategic document:
|
||||
Write only confirmed facts and explicitly marked open decisions. Omit irrelevant sections rather than filling them with generic prose.
|
||||
|
||||
```markdown
|
||||
# Product
|
||||
|
||||
## Register
|
||||
|
||||
product
|
||||
|
||||
## Platform
|
||||
|
||||
web
|
||||
|
||||
## Users
|
||||
[Who they are, their context, the job to be done. Primary audience; a secondary audience or a surface-vs-user split only when they apply.]
|
||||
[Primary users, their situation, and job. Add other audiences only when confirmed.]
|
||||
|
||||
## Product Purpose
|
||||
[What this product does, why it exists, what success looks like]
|
||||
[What the product does, why it exists, and what success means.]
|
||||
|
||||
## Positioning
|
||||
[The single strategic claim every screen reinforces. Not a visual rule, not an anti-reference.]
|
||||
[The product mechanism or claim a neighboring product could not truthfully copy.]
|
||||
|
||||
## Conversion & proof
|
||||
[Persuade surfaces only (marketing, landing, campaigns). Omit this section entirely, heading included, for the product register and for Experience or Read surfaces such as portfolios, albums, or long-form writing.]
|
||||
- Primary and secondary CTA: [...]
|
||||
- The line a visitor remembers after 10 seconds: [...]
|
||||
- Belief ladder: [...]
|
||||
- Proof on hand: [testimonials, case studies, press, or logos, referenced by path]
|
||||
## Operating Context
|
||||
[Workflows, environments, tools, documents, materials, and rituals that are factual parts of using or evaluating the product.]
|
||||
|
||||
## Brand Personality
|
||||
[Voice, tone, 3-word personality, emotional goals]
|
||||
## Capabilities and Constraints
|
||||
[Confirmed functionality, technical constraints, terminology, and explicitly undecided product facts.]
|
||||
|
||||
## Anti-references
|
||||
[What this should NOT look like. Specific bad-example sites or patterns to avoid.]
|
||||
## Brand Commitments
|
||||
[Existing name, voice, assets, personality, identity constraints, and references the user explicitly made binding. Omit when none exist.]
|
||||
|
||||
## Design Principles
|
||||
[3-5 strategic principles derived from the conversation. Principles like "practice what you preach", "show, don't tell", "expert confidence". NOT visual rules like "use OKLCH" or "magenta accent".]
|
||||
## Evidence on Hand
|
||||
[Real content, data, demonstrations, testimonials, case studies, press, or assets, with paths where applicable. State absences that future work must not fabricate.]
|
||||
|
||||
## Product Principles
|
||||
[Three to five durable strategic principles derived from confirmed answers; no visual recipes.]
|
||||
|
||||
## Accessibility & Inclusion
|
||||
[WCAG level, known user needs, considerations]
|
||||
[Known user needs or required standard. Omit when no product-specific requirement was established.]
|
||||
```
|
||||
|
||||
Register is either `brand` or `product` as a bare value. No prose, no commentary. Platform is `web`, `ios`, `android`, or `adaptive`, also a bare value; omit the section only on legacy files you're leaving untouched, otherwise write `web` explicitly.
|
||||
Platform is the bare value `web`, `ios`, `android`, or `adaptive`. Preserve useful legacy headings. New files go at `PROJECT_ROOT/PRODUCT.md`; otherwise update the resolved file. Write it before any visual-world or surface-concept work.
|
||||
|
||||
Write fields as prose, and use bold sparingly: only where a word carries a decision, never as a label lead-in on every line.
|
||||
### Completion gate
|
||||
|
||||
Write to `PROJECT_ROOT/PRODUCT.md`. If `.impeccable.md` existed, the loader already renamed it; merge into that content rather than starting from scratch.
|
||||
Before loading new-work or resuming shape/build, verify that PRODUCT.md exists at the resolved path and contains the confirmed product record. If the file is absent, init is incomplete. Do not substitute interview notes, a planning packet, or later design prose for the file.
|
||||
|
||||
## Step 5: Decide on DESIGN.md
|
||||
## Step 5: Configure live mode when useful
|
||||
|
||||
Offer `/impeccable document` either way. Two paths:
|
||||
Skip native or non-runnable projects and leave existing config untouched. Otherwise follow [live.md](live.md)'s first-time setup. Any CSP source edit still requires its stated consent.
|
||||
|
||||
- **Code exists** (CSS tokens, components, a running site): "I can generate a DESIGN.md that captures your visual system (colors, typography, components) so variants stay on-brand. Want to do that now?"
|
||||
- **Pre-implementation** (empty project): "I can seed a starter DESIGN.md from five quick questions about color strategy, type direction, motion energy, and references. You can re-run once there's code, to capture the real tokens. Want to do that now?"
|
||||
## Step 6: Wrap up or resume
|
||||
|
||||
If the user agrees, delegate to `/impeccable document` (it auto-detects scan vs seed). Load its reference and follow that flow.
|
||||
Summarize captured and deliberately undecided facts. Do not offer DESIGN.md merely because it is missing.
|
||||
|
||||
If the user prefers to skip, mention they can run `/impeccable document` any time later.
|
||||
Recommend the next action from the actual project state:
|
||||
|
||||
## Step 6: Configure live mode (when code exists)
|
||||
- Empty or early project: ask naturally for the surface to be built, or use `/impeccable shape <surface>` when the user wants a confirmed brief without implementation. New-work will establish a visual world only when the requested work needs one.
|
||||
- Existing coherent interface without DESIGN.md: `/impeccable document` if the user wants the incumbent system recorded independently of a new build.
|
||||
- Existing surface needing work: name the most relevant scoped command.
|
||||
- Web project ready for visual iteration: `/impeccable live` when configured.
|
||||
|
||||
**Skip this step when the platform is native** (`ios` / `android` / `adaptive`): live mode drives a browser overlay. A hybrid wrapper or Expo web target serving HTML doesn't change that.
|
||||
|
||||
If the project has code with HTML entries and a dev server (the same "code exists" condition that puts `/impeccable document` in scan mode), pre-configure live mode now. You already identified the framework and the served HTML entry in Step 2, so this is nearly free, and it spares the user the first-time setup detour when they later run `/impeccable live`.
|
||||
|
||||
**Skip this step for empty / pre-implementation projects** (nothing to inject into yet). Tell the user live mode will configure itself the first time they run it once there's code.
|
||||
|
||||
**If `.impeccable/live/config.json` already exists, leave it untouched** and note that live mode is already configured.
|
||||
|
||||
Otherwise:
|
||||
|
||||
1. Write `.impeccable/live/config.json`. Choose `files` (the HTML entries the browser actually loads), `insertBefore`, and `commentSyntax` from the framework table in [live.md](live.md)'s **First-time setup** section, using the framework you found in Step 2. That table is canonical; do not restate it here. For multi-page static sites, prefer a glob (`["public/**/*.html"]`) over a literal list.
|
||||
2. Run `node .claude/skills/impeccable/scripts/detect-csp.mjs`. If it reports a patchable shape (`append-arrays` / `append-string`), use the **consent prompt template** from live.md before editing any source file. On decline, skip the patch. For `middleware` / `meta-tag` shapes, surface the detected files and ask the user to add `http://localhost:8400` to `script-src` and `connect-src` manually. For `null`, there's nothing to do.
|
||||
3. Set `cspChecked: true` in the config once CSP is handled (patched, declined, manual, or not needed). The schema and per-shape patch details live in live.md's First-time setup; follow it rather than duplicating.
|
||||
|
||||
Writing the config file is harmless and needs no consent; only the CSP **source-file patch** requires a yes.
|
||||
|
||||
## Step 7: Recommend starting points, then wrap up
|
||||
|
||||
Summarize tersely:
|
||||
- Register captured (brand / product) and platform captured (web / ios / android / adaptive)
|
||||
- What was written (PRODUCT.md, DESIGN.md, live config, or a subset)
|
||||
- The 3-5 strategic principles from PRODUCT.md that will guide future work
|
||||
- If DESIGN.md or live config is pending, one line on how to set it up later
|
||||
|
||||
Then recommend the **best commands to run next**, drawn from what your Step 2 crawl already surfaced. Do not run a fresh analysis here; surface observations you already have. Tailor to register **and platform**, offer the 2-4 most relevant (not a menu dump), and give the exact command to type. Group by intent:
|
||||
|
||||
- **Build something new**: `/impeccable craft <feature>` (shape, then build end-to-end) or `/impeccable shape <feature>` (plan first). Lead with this for empty or early-stage projects.
|
||||
- **Improve what's there**: name the specific surface. `/impeccable critique <page>` for a scored UX review; `/impeccable audit <area>` for a11y / perf / responsive checks; `/impeccable polish <component>` for a pre-ship pass. When the crawl flagged a specific weakness, point the matching command at it: thin hierarchy or spacing → `layout`, flat or gray palette → `colorize`, missing error / empty states → `harden` or `onboard`, dull or unclear copy → `clarify`.
|
||||
- **Iterate visually** (web only): `/impeccable live` (configured in Step 6) to pick elements in the browser and generate variants in place. **Skip this group for native platforms.**
|
||||
|
||||
The full command menu is one bare `/impeccable` away; keep this list short and pointed.
|
||||
|
||||
If init was invoked as a blocker by another impeccable command (e.g. the user ran `/impeccable polish` with no PRODUCT.md), resume that original task now. Your own writes are the freshest source; no reload needed.
|
||||
|
||||
Optionally STOP and call the AskUserQuestion tool to clarify. Ask whether they'd like a brief summary of PRODUCT.md appended to CLAUDE.md for easier agent reference. If yes, append a short **Design Context** pointer section there.
|
||||
If init was invoked by another request, resume without rerunning context.mjs; new-work owns later visual decisions.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native iOS / iPadOS apps: SwiftUI, UIKit, React Native, Expo, Flutter shipping to Apple hardware.
|
||||
|
||||
On native, register narrows. HIG conformance governs structure, navigation, and interaction whatever the register; brand expresses through the expressive layer the platform provides (tint, type, motion, content). Calm, Duolingo, and Spotify carry strong identity entirely inside HIG conventions.
|
||||
On native, the visitor mode narrows what expression may override. HIG conformance governs structure, navigation, and interaction in every mode; brand expresses through the layer the platform leaves open (tint, type, motion, content).
|
||||
|
||||
## The iOS slop test
|
||||
|
||||
|
||||
@@ -1,185 +1,84 @@
|
||||
Space is the most underused design tool. Find the layout's actual problem (monotone spacing, weak hierarchy, identical card grids) and fix the structure, not the surface.
|
||||
Layout turns product priority into reading order, grouping, rhythm, and usable space. Diagnose the structural problem before moving boxes.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: asymmetric compositions, fluid spacing with `clamp()`, intentional grid-breaking for emphasis. Rhythm through contrast: tight groupings paired with generous separations.
|
||||
- **Persuade + Experience:** composition may be asymmetric, fluid, or intentionally disruptive when the selected world earns it.
|
||||
- **Operate + Read:** predictable structure, stable density, and navigable linearity are affordances.
|
||||
- **Native:** follow [ios.md](ios.md) or [android.md](android.md) for navigation, insets, adaptation, and touch targets.
|
||||
|
||||
Operate + Read: predictable grids, consistent densities, familiar navigation patterns. Responsive behavior is structural (collapse sidebar, responsive table), not fluid typography. Consistency IS an affordance. Read surfaces specifically want navigable linearity: a steady column the reader can follow and a structure they can hold in their head, not compositional surprise.
|
||||
Preserve the established visual world. A layout command changes structure inside it; identity replacement belongs to [new-work.md](new-work.md).
|
||||
|
||||
Native (`ios` / `android` / `adaptive`): structure follows the Layout section of [ios.md](ios.md) / [android.md](android.md) (read it first if Setup hasn't already): platform navigation, insets, and touch targets, never the CSS tooling below.
|
||||
## Two isolated assessments
|
||||
|
||||
---
|
||||
When a sub-agent tool is available and permitted, run these independently; otherwise run them yourself in this order.
|
||||
|
||||
## Two isolated assessments (required)
|
||||
|
||||
Spawn two parallel sub-agents whenever a sub-agent/Task tool is exposed: one for the layout assessment, one for the mechanical pre-scan. If the harness needs explicit user permission for sub-agents, stop and ask before proceeding. Isolation is the point: detector output anchors visual judgment toward what the scan can see, so neither sub-agent gets the other's output. Each assessment runs in its own sub-agent; running either one in this context when a sub-agent tool exists is not permitted, even when it is faster; the fallback below is only for sessions with no sub-agent tool. Give each a self-contained prompt (target files, register, documented spacing scale when present, and its instructions below); do not assume it can read this file.
|
||||
|
||||
**Sub-agent A (layout assessment)**: give it the full [Assess Current Layout](#assess-current-layout) checklist below, verbatim, in its prompt. It works through every item and returns per-item findings citing file, selector, or value.
|
||||
|
||||
**Sub-agent B (mechanical pre-scan)**: run the bundled detector scoped to layout:
|
||||
1. **Layout assessment:** inspect representative states and viewports. Answer every question below with rendered or source evidence:
|
||||
- **Reading order:** Apply the squint test. With detail blurred, can you still identify the primary element, the secondary element, and the major groups in order?
|
||||
- **Grouping:** Are related items close and distinct groups separated, or are containers compensating for weak proximity?
|
||||
- **Rhythm:** Do tight and generous intervals create a deliberate cadence, or is one spacing value repeated until everything has equal weight?
|
||||
- **Structure:** Does the topology match the content and task? Are repeated cards, columns, or sections genuinely equivalent, or merely a framework default?
|
||||
- **Density:** Does the amount of information per region fit use frequency, decision complexity, and visitor mode?
|
||||
- **Adaptation:** At narrow, intermediate, wide, zoomed, and localized states, what reorders, collapses, wraps, scrolls, or remains fixed? Does DOM and focus order still agree with the visual order?
|
||||
- **Extremes:** Do long content, empty states, overlays, sticky elements, safe areas, and small touch targets expose structural failures?
|
||||
2. **Mechanical scan:** run:
|
||||
|
||||
```bash
|
||||
node .claude/skills/impeccable/scripts/detect.mjs --json --scope layout [target files or dirs]
|
||||
```
|
||||
|
||||
A missing `node` on PATH is not permission to skip: hunt for a runtime (`command -v node`, nvm or Homebrew paths, the harness's own bundled node) and run it by full path. If none exists, halt the scan and report that Node must be installed (the parent relays this to the user); do **not** substitute grep for the detector or proceed unscanned. The detector abstains on arbitrary Tailwind spacing (`gap-[13px]`, `p-[7px]`) and ad-hoc `z-index` stacks, so when the project documents a spacing scale, also grep `gap-\[`, `p[trblxy]?-\[`, `m[trblxy]?-\[`, `z-\[` and judge those hits against it. Return the findings JSON plus the grep verdicts.
|
||||
Also inspect arbitrary spacing, overflow, stacking, and container behavior the detector cannot resolve. Keep mechanical evidence out of the first assessment, then synthesize both passes before editing. A clean scan cannot prove hierarchy or rhythm.
|
||||
|
||||
**If no sub-agent tool is exposed (or the user declined)**: run both yourself, assessment first, pre-scan second, so the deterministic findings can't anchor the visual judgment. Keep that order even when the scan feels quicker to start with.
|
||||
## Set the spatial thesis
|
||||
|
||||
**Synthesize** once both are done: merge into a single findings list, noting where they agree and what each caught alone. Fix every finding, or list it as a deliberate exception for the user to accept. A clean scan is a floor, not a verdict: a monotone grid with uniform spacing passes every detector rule, which is exactly what the assessment exists to catch. State in your final summary which path ran (parallel sub-agents or single-context fallback).
|
||||
Before editing, name:
|
||||
|
||||
---
|
||||
- the primary reading or task path;
|
||||
- what belongs together and what must separate;
|
||||
- which element leads and which supports;
|
||||
- the intended density and spacing rhythm;
|
||||
- how the structure changes across containers, viewports, input modes, and content extremes.
|
||||
|
||||
## Assess Current Layout
|
||||
Choose the simplest structural model that expresses those relationships. Use layout primitives according to the relationships they control, and name reusable spacing and container roles semantically.
|
||||
|
||||
This checklist is sub-agent A's brief (on the fallback path, work through it yourself before the pre-scan). Analyze what's weak about the current spatial design:
|
||||
## Apply
|
||||
|
||||
1. **Spacing**:
|
||||
- Is spacing consistent or arbitrary? (Random padding/margin values)
|
||||
- Is all spacing the same? (Equal padding everywhere = no rhythm)
|
||||
- Are related elements grouped tightly, with generous space between groups?
|
||||
- Group by meaning. Use proximity before adding containers or decoration.
|
||||
- Create rhythm through deliberate contrast between tight and generous intervals.
|
||||
- Use a documented spacing scale rather than one-off values. A 4-unit base usually provides the useful middle steps that an 8-only scale misses.
|
||||
- Let hierarchy follow product priority, not framework defaults.
|
||||
- Keep distinct content visually distinct without turning every group into an isolated component.
|
||||
- Make responsive behavior structural: reorder, collapse, reflow, or reveal based on what remains important.
|
||||
- Prefer container-aware components when the same component appears in different contexts.
|
||||
- Use `gap` for sibling rhythm when it expresses the relationship more directly than child margins.
|
||||
- Keep touch targets usable even when their visible marks are small.
|
||||
- Use depth only when it clarifies state or hierarchy.
|
||||
- Make optical corrections only after inspecting the rendered result.
|
||||
|
||||
2. **Visual hierarchy**:
|
||||
- Apply the squint test: blur your (metaphorical) eyes. Can you still identify the most important element, second most important, and clear groupings?
|
||||
- Is hierarchy achieved effectively? (Space and weight alone can be enough; is the current approach working?)
|
||||
- Does whitespace guide the eye to what matters?
|
||||
Variation is not a goal by itself. Repetition should support recognition; break it only when content or priority changes.
|
||||
|
||||
3. **Grid & structure**:
|
||||
- Is there a clear underlying structure, or does the layout feel random?
|
||||
- Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly)
|
||||
## Verify
|
||||
|
||||
4. **Rhythm & variety**:
|
||||
- Does the layout have visual rhythm? (Alternating tight/generous spacing)
|
||||
- Is every section structured the same way? (Monotonous repetition)
|
||||
- Are there intentional moments of surprise or emphasis?
|
||||
- The squint test still reveals the primary, secondary, and major groups in order.
|
||||
- The reading and task path remains clear at every supported size.
|
||||
- Related content groups naturally; unrelated content does not blur together.
|
||||
- Tight and generous spacing create intentional rhythm instead of monotonous repetition.
|
||||
- Density matches use frequency and content complexity.
|
||||
- Long text, empty states, localization, zoom, and dynamic content do not break the structure.
|
||||
- Keyboard, touch, and assistive-technology order agree with the visual order.
|
||||
- The final mechanical scan has no unexplained findings.
|
||||
|
||||
5. **Density**:
|
||||
- Is the layout too cramped? (Not enough breathing room)
|
||||
- Is the layout too sparse? (Excessive whitespace without purpose)
|
||||
- Does density match the content type? (Data-dense UIs need tighter spacing; marketing pages need more air)
|
||||
Answer each item with rendered or source evidence, then rerun the scan. Do not substitute a bare “yes” for verification.
|
||||
|
||||
**CRITICAL**: Layout problems are often the root cause of interfaces feeling "off" even when colors and fonts are fine. Space is a design material; use it with intention.
|
||||
|
||||
## Plan Layout Improvements
|
||||
|
||||
Create a systematic plan:
|
||||
|
||||
- **Spacing system**: Use a consistent scale (a framework's built-in scale like Tailwind's, rem-based tokens, or a custom system). The specific values matter less than consistency.
|
||||
- **Hierarchy strategy**: How will space communicate importance?
|
||||
- **Layout approach**: What structure fits the content? Flex for 1D, Grid for 2D, named areas for complex page layouts.
|
||||
- **Rhythm**: Where should spacing be tight vs generous?
|
||||
|
||||
## Improve Layout Systematically
|
||||
|
||||
### Establish a Spacing System
|
||||
|
||||
- Use a consistent spacing scale (framework scales like Tailwind, rem-based tokens, or a custom scale all work). What matters is that values come from a defined set, not arbitrary numbers.
|
||||
- Prefer a 4pt base scale (4, 8, 12, 16, 24, 32, 48, 64, 96px) over 8pt; 8pt is too coarse and you'll frequently need 12px between 8 and 16.
|
||||
- Name tokens semantically if using custom properties: `--space-xs` through `--space-xl`, not `--spacing-8`
|
||||
- Use `gap` for sibling spacing instead of margins; eliminates margin collapse hacks
|
||||
- Apply `clamp()` for fluid spacing that breathes on larger screens
|
||||
|
||||
### Create Visual Rhythm
|
||||
|
||||
- **Tight grouping** for related elements (8-12px between siblings)
|
||||
- **Generous separation** between distinct sections (48-96px)
|
||||
- **Varied spacing** within sections (not every row needs the same gap)
|
||||
- **Asymmetric compositions**: a deliberate choice when the content invites it (not a default to chase).
|
||||
|
||||
### Choose the Right Layout Tool
|
||||
|
||||
- **Use Flexbox for 1D layouts**: Rows of items, nav bars, button groups, card contents, most component internals.
|
||||
- **Use Grid for 2D layouts**: Page-level structure, dashboards, data-dense interfaces, anything where rows AND columns need coordinated control.
|
||||
- Use named grid areas (`grid-template-areas`) for complex page layouts; redefine at breakpoints.
|
||||
- Use **container queries** for components, viewport queries for page layouts. A card in a narrow sidebar can stay compact while the same card in a main content area expands automatically:
|
||||
|
||||
```css
|
||||
.card-container { container-type: inline-size; }
|
||||
.card { display: grid; gap: var(--space-md); }
|
||||
@container (min-width: 400px) {
|
||||
.card { grid-template-columns: 120px 1fr; }
|
||||
}
|
||||
```
|
||||
|
||||
### Break Card Grid Monotony
|
||||
|
||||
- Don't default to card grids for everything; spacing and alignment create visual grouping naturally
|
||||
- Use cards only when content is truly distinct and actionable. Never nest cards inside cards
|
||||
- Vary card sizes, span columns, or mix cards with non-card content to break repetition
|
||||
|
||||
### Strengthen Visual Hierarchy
|
||||
|
||||
- Use the fewest dimensions needed for clear hierarchy. Space alone can be enough; generous whitespace around an element draws the eye. Some of the most polished designs achieve rhythm with just space and weight. Add color or size contrast only when simpler means aren't sufficient.
|
||||
- The best hierarchy combines 2–3 dimensions at once. A heading that's larger, bolder, AND has more space above it reads as primary without trying:
|
||||
|
||||
| Tool | Strong Hierarchy | Weak Hierarchy |
|
||||
|------|------------------|----------------|
|
||||
| **Size** | 3:1 ratio or more | <2:1 ratio |
|
||||
| **Weight** | Bold vs Regular | Medium vs Regular |
|
||||
| **Color** | High contrast | Similar tones |
|
||||
| **Position** | Top/left (primary) | Bottom/right |
|
||||
| **Space** | Surrounded by white space | Crowded |
|
||||
|
||||
- Be aware of reading flow: in LTR languages, the eye naturally scans top-left to bottom-right, but primary action placement depends on context (e.g., bottom-right in dialogs, top in navigation).
|
||||
- Create clear content groupings through proximity and separation.
|
||||
|
||||
### Manage Depth & Elevation
|
||||
|
||||
- Build a consistent shadow scale (sm → md → lg → xl); shadows should be subtle
|
||||
- Use elevation to reinforce hierarchy, not as decoration
|
||||
|
||||
### Optical Adjustments
|
||||
|
||||
- If an icon looks visually off-center despite being geometrically centered, nudge it. But only if you're confident it actually looks wrong. Don't adjust speculatively.
|
||||
- Text at `margin-left: 0` looks slightly indented because of letterform whitespace; a negative margin (`-0.05em`) optically aligns it. Geometrically centered glyphs often look off-center (play icons need to shift right, arrows shift toward their direction).
|
||||
- Touch targets must be 44×44px minimum even when the visual element is smaller. Expand the hit area with padding or a pseudo-element:
|
||||
|
||||
```css
|
||||
.icon-button { width: 24px; height: 24px; position: relative; }
|
||||
.icon-button::before {
|
||||
content: ''; position: absolute; inset: -10px;
|
||||
}
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
- Use arbitrary spacing values outside your scale
|
||||
- Make all spacing equal (variety creates hierarchy)
|
||||
- Wrap everything in cards (not everything needs a container)
|
||||
- Nest cards inside cards (use spacing and dividers for hierarchy within)
|
||||
- Use identical card grids everywhere (icon + heading + text, repeated)
|
||||
- Default to the hero metric layout (big number, small label, stats, gradient) as a template. If showing real user data, a prominent metric can work, but it should display actual data, not decorative numbers.
|
||||
|
||||
## Verify Layout Improvements
|
||||
|
||||
- **Squint test**: Can you identify primary, secondary, and groupings with blurred vision?
|
||||
- **Rhythm**: Does the page have a satisfying beat of tight and generous spacing?
|
||||
- **Hierarchy**: Is the most important content obvious within 2 seconds?
|
||||
- **Breathing room**: Does the layout feel comfortable, not cramped or wasteful?
|
||||
- **Consistency**: Is the spacing system applied uniformly?
|
||||
- **Responsiveness**: Does the layout adapt gracefully across screen sizes?
|
||||
|
||||
Answer each item above by citing the file, selector, or value that satisfies it; never a bare yes. Then re-run the pre-scan and fix until the count of unresolved items and unaccepted findings is zero.
|
||||
|
||||
When the rhythm and hierarchy land, hand off to `/impeccable polish` for the final pass.
|
||||
When the structure holds, hand off to `/impeccable polish`.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
Each variant MUST declare a `density` param. Drive all spacing tokens in the variant's scoped CSS through `calc(var(--p-density, 1) * <base>)`: paddings, gaps, column widths. Users slide from airy to packed and see layout re-breathe with no regeneration.
|
||||
Every variant declares a coarse `density` parameter and authors spacing against `var(--p-density, 1)`.
|
||||
|
||||
```json
|
||||
{"id":"density","kind":"range","min":0.6,"max":1.4,"step":0.05,"default":1,"label":"Density"}
|
||||
```
|
||||
|
||||
For variants whose topology genuinely changes (stacked vs. side-by-side, grid vs. bento), use a `steps` param whose scoped CSS branches via `:scope[data-p-structure="X"]`. One structure param + one density param is a powerful combo; resist adding a third.
|
||||
|
||||
```json
|
||||
{"id":"structure","kind":"steps","default":"grid","label":"Structure","options":[
|
||||
{"value":"stacked","label":"Stacked"},
|
||||
{"value":"grid","label":"Grid"},
|
||||
{"value":"bento","label":"Bento"}
|
||||
]}
|
||||
```
|
||||
|
||||
See `reference/live.md` for the full params contract.
|
||||
Add one structural parameter only when the topology genuinely branches. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -33,7 +33,7 @@ Chat is overhead. No recap, no tutorial output, no pasting PRODUCT / DESIGN bodi
|
||||
node .claude/skills/impeccable/scripts/live.mjs
|
||||
```
|
||||
|
||||
Output JSON: `{ ok, serverPort, serverToken, pageFiles, hasProduct, product, productPath, hasDesign, design, designPath }`. `pageFiles` is the list of HTML entries the live script was injected into. Keep PRODUCT.md and DESIGN.md in mind for variant generation; **DESIGN.md wins on visual decisions; PRODUCT.md wins on strategic/voice decisions.** When DESIGN.md is missing, identity is **not** absent; extract it from CSS variables, computed styles, and sibling components on the page (see Step 4 Phase A). Identity preservation is the default; departure from existing identity requires an explicit trigger from PRODUCT.md anti-references or the user's freeform prompt.
|
||||
Output JSON: `{ ok, serverPort, serverToken, pageFiles, hasProduct, product, productPath, hasDesign, design, designPath }`. `pageFiles` is the list of HTML entries the live script was injected into. Keep PRODUCT.md, DESIGN.md, and any surface brief already loaded by Setup in mind for variant generation: **DESIGN.md wins on visual decisions; PRODUCT.md wins on durable product and voice decisions; the surface brief wins on this surface's strategy.** When DESIGN.md is missing, identity is **not** absent; extract it from CSS variables, computed styles, and sibling components on the page (see Step 4 Phase A). Identity preservation is the default; departure requires the user's explicit redesign/replacement intent.
|
||||
|
||||
`serverPort` and `serverToken` belong to the small **Impeccable live helper** HTTP server (serves `/live.js`, SSE, and `/poll`). That port is **not** your dev server and is usually not the URL you open to view the app. The browser page is whatever origin serves one of the `pageFiles` entries (Vite / Next / Bun / tunnel / LAN hostname).
|
||||
|
||||
@@ -187,7 +187,7 @@ All three carry `fallback: "agent-driven"`. Follow **Handle fallback** below.
|
||||
|
||||
### 3. Load the action's reference
|
||||
|
||||
If `event.action` is `impeccable` (the default freeform action), use SKILL.md's shared laws plus the loaded register reference (`brand.md` or `product.md`). Do not load a sub-command reference. **Freeform is not a pass to skip parameters:** you still follow the composition budget and the freeform bias in **§7 Parameters** below. Sub-command files list MUST-have signature knobs; freeform has no such file, so sizing knobs from surface weight and primary axes is entirely on you.
|
||||
If `event.action` is `impeccable` (the default freeform action), use SKILL.md's shared laws and decide the visitor mode from the selected surface. Do not load a sub-command reference. **Freeform is not a pass to skip parameters:** you still follow the composition budget and the freeform bias in **§7 Parameters** below. Sub-command files list MUST-have signature knobs; freeform has no such file, so sizing knobs from surface weight and primary axes is entirely on you.
|
||||
|
||||
Any other `event.action` (`bolder`, `quieter`, `distill`, `polish`, `typeset`, `colorize`, `layout`, `adapt`, `animate`, `delight`, `overdrive`): Read `reference/<action>.md` before planning. Each sub-command encodes a specific discipline; skipping its reference produces generic output. Those files may require specific params; layer them on top of the §7 budget, not instead of it.
|
||||
|
||||
@@ -216,7 +216,7 @@ Write down what you see in **one sentence**. The sentence describes the surface
|
||||
|
||||
Be specific. "Modern" is not a color, "elegant" is not a type pairing, "clean" is not a layout. If you can't extract a real value for an axis, skip it rather than fabricate. The point is to record what is, not to describe what you wish it were.
|
||||
|
||||
Do not include adjectives that name an aesthetic family ("editorial-leaning", "terminal-flavored", "brutalist"); those are conclusions, not data. They belong to Phase C lane selection in departure mode, not to identity description. Letting them sneak into Phase A is how the identity-lock collapses into a self-fulfilling prophecy.
|
||||
Do not name an aesthetic family in this sentence; that is a conclusion, not observed identity data. Letting conclusions into Phase A collapses the identity lock into a self-fulfilling prophecy.
|
||||
|
||||
This sentence is the **identity lock**. Every variant must be readable as the same brand if rendered side by side. Skipping this phase is the primary cause of off-brand variants. Absence of DESIGN.md is never an excuse; extract from CSS and computed styles instead.
|
||||
|
||||
@@ -224,10 +224,7 @@ This sentence is the **identity lock**. Every variant must be readable as the sa
|
||||
|
||||
**Default mode**: the existing identity is preserved. Variants vary expression axes within it. *This is the right mode for ~90% of live sessions.* The user picked an element on a real product they're shipping; they expect variants of *their* hero, not three different brands' heroes.
|
||||
|
||||
**Departure mode**: the existing identity is rejected. Variants propose alternatives consistent with PRODUCT.md voice. Trigger only when at least one is true:
|
||||
|
||||
- PRODUCT.md anti-references explicitly call out the current surface ("the current `index.html` is itself an example"; "diffuse away from this"; "the page on screen is the failure"). Generic anti-references that describe what to avoid in general do **not** trigger departure mode; only ones that point at *this* surface specifically.
|
||||
- The user's freeform prompt explicitly asks for departure ("rebuild this from scratch", "what if it weren't editorial at all", "show me something completely different").
|
||||
**Departure mode**: the existing identity is rejected. Variants propose alternatives consistent with durable product and brand truth. Trigger only when the user explicitly asks for departure in the current request or freeform prompt ("redesign this", "rebuild this from scratch", "what if it weren't editorial at all", "show me something completely different"). A stale page critique or an old task note is not replacement authorization.
|
||||
|
||||
If you're unsure, you're in default mode. The cost of being wrong about default is "three on-brand variants with similar feel": recoverable, the user picks none. The cost of being wrong about departure is "three off-brand variants": unrecoverable, the user is annoyed.
|
||||
|
||||
@@ -246,13 +243,13 @@ Three variants → three DIFFERENT axes. The trio reads as *the same brand at th
|
||||
|
||||
**While planning each variant, also name its 2–3 parameter knobs** (per the §7 budget table). Parameters are part of the design, not a decoration added afterward. If the variant explores density, expose a density knob. If it explores color commitment, expose a color-amount range. Deciding "what's tunable" during planning produces better knobs than retrofitting them onto finished HTML.
|
||||
|
||||
**Departure mode.** Each variant anchors to a different **aesthetic direction**, derived from the brand's stated voice and register in PRODUCT.md. Do NOT pick from a fixed catalog of lane categories. The right three directions for this brand are not the same as the right three for another brand, and picking from a list is itself the training-data reflex (the model selects "Swiss-grid, Terminal, Industrial-signage" every time because those are the furthest-from-editorial items in any enumerated list).
|
||||
**Departure mode.** Each variant anchors to a different **aesthetic direction**, derived from PRODUCT.md's audience world and voice plus the current DESIGN.md. Do not pick from a fixed catalog; derive directions from this product.
|
||||
|
||||
Instead, work from the brand:
|
||||
|
||||
1. Read PRODUCT.md's Brand Personality words. What physical, spatial, or material experiences would embody those words if design were not involved? (A personality described as "specific, earned, unmistakable" evokes a hand-stamped letter, a numbered print, a watchmaker's loupe. A personality described as "restless, loud, unfiltered" evokes a concert poster, a spray-painted wall, a megaphone.)
|
||||
1. Read PRODUCT.md's Brand Personality words. Derive physical, spatial, or material experiences that embody them without starting from a design style.
|
||||
2. From those physical experiences, derive three visual directions that are genuinely different from each other AND from the current surface you're departing.
|
||||
3. Avoid the **reflex-reject lanes** in [brand.md](brand.md). Don't trade one monoculture for another. If you find yourself reaching for "Swiss-grid" or "Terminal" or "Industrial-signage" by reflex, you are pattern-matching a catalog in your training data, not reading the brand. Start over from the personality words.
|
||||
3. Reject any direction chosen by reflex rather than derived from the brand. Start over from the personality words when the rationale could fit a neighboring product.
|
||||
4. Each direction must be expressible in one concrete sentence that names a real-world referent ("a museum exhibition label system for a contemporary art gallery" not "clean and minimal"). If your sentence contains only adjectives, it's not concrete enough.
|
||||
5. **While planning each direction, also name its 2–3 parameter knobs** (per the §7 budget table). The same principle as default mode: decide "what's tunable" during planning, not after writing the HTML. A departure-mode hero with 0 parameters is not "bold creative vision," it's a missed opportunity for the user to fine-tune the direction they pick.
|
||||
|
||||
@@ -262,7 +259,7 @@ Instead, work from the brand:
|
||||
|
||||
**Departure mode squint.** Two passes, family before sentence:
|
||||
|
||||
1. **Family pass.** Label each variant with one design-family word of your own choosing (any concrete noun: *exhibition, storefront, cockpit, recipe-card, playbill, field-manual*). If any two variants share a label, or if the label could apply to the other variants equally well, rework. Do not use a fixed vocabulary list for the labels. *This pass is non-negotiable in departure mode and catches the monoculture failure that the sentence pass misses.*
|
||||
1. **Family pass.** Give each variant a concrete family label of your own choosing. If two variants share a label, or a label fits another variant equally well, rework. Do not use a fixed vocabulary. *This pass is non-negotiable in departure mode and catches monoculture the sentence pass misses.*
|
||||
2. **Sentence pass.** Write three one-sentence descriptions side by side. If two of them rhyme ("both feature big type" / "both are stacks of sections" / "both center the CTA"), rework the offender.
|
||||
|
||||
**When the primary axis is color or theme, forbid the trio from sharing theme + dominant hue.** Two dark-plus-one-dark is not distinct. Aim for three color worlds, not three shades of the same.
|
||||
@@ -289,7 +286,7 @@ In **default mode**, the prompt narrows the axes you choose, not the identity. *
|
||||
|
||||
In **departure mode**, the prompt narrows the lanes you draw from, not the families. *"Make it feel like a newspaper front page"* would itself be a departure-mode prompt; honor it but pick three meaningfully different newspaper-adjacent lanes (broadsheet vs. tabloid vs. trade journal), and run the family pass to confirm they don't collapse into one.
|
||||
|
||||
When the prompt and PRODUCT.md anti-references conflict (the prompt asks for X, the anti-references ban X), the anti-references win; they describe the brand's standing position, the prompt is one moment.
|
||||
When the prompt conflicts with a confirmed binding brand commitment or DESIGN.md invariant, preserve the invariant unless the user explicitly revokes or replaces it. Task-local strategy from the matching surface brief may change when the user changes that surface's goal.
|
||||
|
||||
### 6. Write all variants in a single edit
|
||||
|
||||
|
||||
@@ -1,47 +1,178 @@
|
||||
# New identity work
|
||||
# New visual work
|
||||
|
||||
Read this only when the project has no committed visual identity, or the user explicitly asked to replace the current one. A missing DESIGN.md is not enough: code, tokens, chosen type, components, and assets are incumbent design authority. If they exist, preserve and extend them unless the brief says to discard them.
|
||||
This flow owns the durable visual world when authority is absent, expanding, or explicitly replaced, plus only as much task-level shaping as the requested scope needs. PRODUCT.md owns product truth, DESIGN.md confirmed visual truth, and `.impeccable/surfaces/` durable task strategy. Complete [init.md](init.md) first when PRODUCT.md is missing. Missing DESIGN.md does not route back to init.
|
||||
|
||||
This playbook is task-scoped. PRODUCT.md owns durable product facts and DESIGN.md owns durable visual invariants; the direction for one page or feature belongs in the current task, not in either document.
|
||||
## 1. Name the intent
|
||||
|
||||
## Choose the authority
|
||||
- **Greenfield:** no coherent visual implementation.
|
||||
- **Local extension:** a section, feature, component, or state inside an established surface and world.
|
||||
- **New surface:** a whole page, route, screen, flow, or standalone experience inside an established world.
|
||||
- **Expression expansion:** an established brand entering an unresolved whole-surface family or app boundary.
|
||||
- **Redesign/rebrand:** replace the world while preserving unchanged product truth, content, function, native affordances, constraints, and brand commitments.
|
||||
- **Refinement:** leave this flow for the scoped command; preserve the world and scope.
|
||||
|
||||
Classify the work before inventing anything:
|
||||
A plain “redesign this page/site” authorizes replacement. “Redesign this within the current brand/system” means extension or refinement. Ask once only when the wording is genuinely ambiguous.
|
||||
|
||||
- **Extend**: an incumbent system exists and the task adds or improves a surface. Preserve its lineage, semantics, and affordances.
|
||||
- **Surface redesign**: the current identity remains, but this surface may change its topology, hierarchy, and expression.
|
||||
- **New identity**: nothing committed exists, or the user explicitly authorized a rebrand.
|
||||
## 2. Resolve visual authority
|
||||
|
||||
When the evidence is mixed, preserve. Novelty is not permission to erase authored decisions.
|
||||
Read DESIGN.md and representative code, tokens, components, and assets. Choose one path:
|
||||
|
||||
## Find the concept
|
||||
### A. Explicit redesign
|
||||
|
||||
Name the subject, audience, page job, and visitor mode from SKILL.md. Then identify the product's unique mechanism: what it does, proves, or enables that a neighboring product cannot truthfully claim.
|
||||
The old DESIGN.md and implementation are not authority. Keep only unrevoked product facts, content, function, native expectations, constraints, and brand commitments. Establish a replacement world.
|
||||
|
||||
Derive the concept from that mechanism through one primary transformation: information topology, evidence, temporal behavior, or spatial mapping. The transformation must change how the surface is organized or behaves, not merely how it is decorated. This produces stranger and more defensible work than imitating a culturally specific document or object. Borrowing a literal cultural form is allowed only when it is genuinely native to the product and audience, and never as costume.
|
||||
### B. DESIGN.md covers this kind of surface
|
||||
|
||||
For **Operate** and **Read**, start with the task and information structure. Native controls remain native controls; expression comes from hierarchy, density, rhythm, state, and the system around them. For **Persuade** and **Experience** creating a new identity, explore more freely, but keep the product legible and the primary action obvious.
|
||||
Use its invariants and normative tokens. Skip world-building and discover the surface.
|
||||
|
||||
Run `node .claude/skills/impeccable/scripts/concept-seed.mjs` only for Persuade or Experience new-identity work when two or more directions remain equally credible. It is an entropy source, not an authority: never let the draw overrule the strongest fit. When color is genuinely unconstrained, `node .claude/skills/impeccable/scripts/palette.mjs` may break a reflex palette; subject evidence and incumbent color still win.
|
||||
### C. A coherent implementation exists but DESIGN.md does not
|
||||
|
||||
## State the direction
|
||||
Code, assets, tokens, type, and component behavior are incumbent authority. Run [document.md](document.md) in scan mode and confirm extracted invariants before writing DESIGN.md. Do not offer replacement worlds unless the user asked for a redesign.
|
||||
|
||||
Before code, write a task-scoped direction contract of at most 120 words in your reasoning:
|
||||
### D. The brand exists, but a whole-surface family is unresolved
|
||||
|
||||
- the thesis this surface owns;
|
||||
- the structural or behavioral transformation;
|
||||
- what authority is preserved;
|
||||
- the first viewport's composition and primary action;
|
||||
- the signature element the surface will be remembered by.
|
||||
Preserve logo, color/type assets, voice, recognizable component/motion traits, and constraints. Ask what must carry and where expression may expand. Offer two or three compatible ranges, not replacement identities, and merge the choice into DESIGN.md. Use a child-app DESIGN.md when the range is local.
|
||||
|
||||
Do not embed this contract as a comment in the production artifact or turn it into a second design system. In an attended substantial build, confirm it once. In an unattended run, record it and continue.
|
||||
A section, feature, component, or state inside a coherent existing surface stays on B or C. Its surrounding surface is authority even when DESIGN.md is incomplete.
|
||||
|
||||
## Build once, commit fully
|
||||
### E. No confirmed visual authority exists
|
||||
|
||||
Plan one compact token system and one layout source: the concept or the content's real structure. Build the strongest coherent direction once. Commitment means the transformation governs the whole surface; it does not mean every control must be rebuilt as a metaphor.
|
||||
Establish a world. Scaffolds, framework defaults, and stray utilities are not identity.
|
||||
|
||||
Make the first viewport demonstrate the product's mechanism. Pace long surfaces through contrast in density and scale, and cut sections that only repeat claims. Briefs that depend on imagery ship real, verified imagery. Preserve semantic HTML, familiar interaction behavior, accessibility, and the project's technical conventions.
|
||||
## 3. Discover the requested surface
|
||||
|
||||
## Finish proportionally
|
||||
Name this surface's audience, job, visitor mode, real content, primary action/task, evidence, constraints, and memorable moment. PRODUCT.md supplies truth and DESIGN.md the world; neither decides narrative or composition.
|
||||
|
||||
Inspect desktop and mobile, write one honest critique against the brief and direction, patch material defects, then run the detector once. Repeat only when a real defect remains. A separate reviewer is optional when the harness already provides one and the extra cost is earned by the risk; it is not a default step and its presence is not evidence of quality.
|
||||
Ask one attended round of at most three material questions without repeating durable facts. CTA hierarchy, proof sequence, content gaps, and interaction outcomes belong here, not PRODUCT.md. For a fully specified narrow request, state the interpretation and invite correction.
|
||||
|
||||
When `shape` has already completed its discovery interview, reuse those confirmed answers and do not ask this round again.
|
||||
|
||||
Classify the scope before ideation. A section, feature, component, or state that must join an existing page is a local extension. A page, route, screen, flow, or standalone experience may be a new surface. Do not inflate local work into a surface concept merely because it benefits from a novel layout.
|
||||
|
||||
## 4. Shape or select the direction
|
||||
|
||||
Do not select a new world and its first surface concept in separate tournaments. That creates a safe global choice followed by a more interesting local choice whose “lineage” exists only in prose.
|
||||
|
||||
### Local extension inside stable authority: shape, do not seed
|
||||
|
||||
For a local extension on path B or C, inherit both the visual world and the surrounding surface's direction. Resolve only the decisions the addition actually introduces: purpose, content, hierarchy, state or interaction, and how it joins the existing sequence. Use short, related question rounds when those decisions are still open. Do not run `concept-seed.mjs`, generate competing surface metaphors, or offer alternate visual worlds. The result may still have an authored, surprising layout; its novelty must come from the material and the established grammar, not a new identity thesis.
|
||||
|
||||
If a local request reveals a genuine gap in the brand system, name that gap and ask before treating it as path D. Do not silently turn a case-study section or feature into an expression-expansion exercise.
|
||||
|
||||
### A, D, or E: choose a coupled world and first expression
|
||||
|
||||
For a replacement world, unresolved brand expansion, or no authority, make one coupled decision:
|
||||
|
||||
1. **Ground.** Use PRODUCT.md, incumbent commitments that still bind, and the surface discovery above. Name what this surface uniquely does, proves, or enables.
|
||||
2. **Derive pairs.** Generate five to seven grounded directions. Each candidate joins a durable visual system (identity thesis, information/layout grammar, material and type behavior, color strategy, imagery, motion, reusable signature) to a concrete expression for this surface (topology, sequence, focal moment, and implementation consequence). Do not rank yet.
|
||||
3. **Break the ranking rut once.** Run `node .claude/skills/impeccable/scripts/concept-seed.mjs --scope direction`. Promote the assigned grounded pair and weigh its challengers only when they can become both a coherent system and a strong solution to this task.
|
||||
4. **Test coupling and breadth.** Reject a pair if its surface could swap into another candidate unchanged, or if its world is merely the surface motif repeated. Test each survivor on the requested surface plus navigation, quiet and dense content, interaction/state, and one unlike future surface. Compare it with both the category habit and predictable contrarian response.
|
||||
5. **Offer coupled choices.** Present two or three materially different pairs without recommendation cues. For each, show the world rules, this surface's expression, cross-surface consequence, and risk. Ask what is closest, should combine, or feels wrong; rejection is allowed.
|
||||
6. **Resolve once.** The user selects or revises the pair. Extract the durable rules into DESIGN.md and the task-specific strategy into the surface brief; do not reopen either half independently.
|
||||
|
||||
Without an answer mechanism, use the assigned grounded pair only if it survives product fit, coupling, and breadth; mark assumptions. This is fallback, not user choice.
|
||||
|
||||
### B or C, whole surface only: choose a direction inside stable authority
|
||||
|
||||
The visual world supplies the vocabulary; the task concept supplies the sentence.
|
||||
|
||||
1. Derive five to seven structural candidates from the content, mechanism, audience, and confirmed authority. Translate its relationships and behavior, not just its styling.
|
||||
2. Run `node .claude/skills/impeccable/scripts/concept-seed.mjs --scope surface` only when a whole page, route, screen, flow, or standalone experience calls for high-concept exploration. Otherwise shape the strongest grounded structure directly. Never run it for a local extension.
|
||||
3. Name the habitual arrangement and predictable contrarian response. Judge candidates skin-blind: topology, sequence, or interaction must remain different after names and styling disappear.
|
||||
4. When materially different whole-surface choices would help, present two or three neutral options with thesis, sequence, focal moment, signature, implementation consequence, and concrete inherited world rules. Let the user select or revise before code.
|
||||
|
||||
Without an answer mechanism, use the promoted candidate when a roll ran; otherwise use the strongest grounded structure. It must survive both tests.
|
||||
|
||||
For a substantial high-fidelity surface with native image generation, load [codex.md](codex.md) after selection. Probes stay inside the selected direction. For `shape`, stop after selection and continue in [shape.md](shape.md).
|
||||
|
||||
### Write or update DESIGN.md
|
||||
|
||||
For A or E, write or replace DESIGN.md at the resolved project/app boundary using the [format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md). For D, merge only the approved expansion range. Record the chosen durable rules and add:
|
||||
|
||||
`<!-- STATUS: DIRECTIONAL SEED; exact tokens remain provisional until the first implementation pass. -->`
|
||||
|
||||
Do not fabricate YAML tokens; add exact values only after the user, assets, or implementation establishes them. The selected pair authorizes its world and first expression together without another confirmation. A local extension does not change DESIGN.md unless the user approves a durable system addition.
|
||||
|
||||
## 5. Persist the surface brief
|
||||
|
||||
Once the primary target or route is known, persist durable surface-level product/UX strategy separately from PRODUCT.md and DESIGN.md. Prefer a clone-stable source file; map routes and alternate entries as related targets. For a local extension, update the parent surface's record only when the work establishes durable product strategy; do not create a component-level brief by reflex. Read any record first:
|
||||
|
||||
`node .claude/skills/impeccable/scripts/surface-brief.mjs read <primary-target>`
|
||||
|
||||
Exit 0: preserve still-valid decisions and change only what the user changed. For redesign, retain valid product strategy, content, function, and open decisions; replace visual direction and contract. Exit 2: no brief. After the contract, write with `node .claude/skills/impeccable/scripts/surface-brief.mjs write <primary-target> <body-file> [related-target ...]`.
|
||||
|
||||
The body is concise and contains:
|
||||
|
||||
```markdown
|
||||
# Surface brief: [name]
|
||||
|
||||
## Scope
|
||||
[Primary/related route or artifact, visitor mode, and what this surface owns.]
|
||||
|
||||
## Product strategy
|
||||
[Surface-specific audience and job, desired outcome, primary/secondary action or task, content and proof sequence, factual constraints, and explicitly open decisions.]
|
||||
|
||||
## Selected direction
|
||||
[Reference to the applicable DESIGN.md world or expression range, selected surface concept, focal moment, narrative/interaction sequence, and implementation consequence.]
|
||||
|
||||
## Direction contract
|
||||
[The six contract blocks below.]
|
||||
|
||||
## Open decisions
|
||||
[Only unresolved items that later work must not silently invent. Omit when empty.]
|
||||
```
|
||||
|
||||
Commit `.impeccable/surfaces/<target-slug>.md` as stable later-work context. Exclude global truth, exact tokens, transient notes, and work logs.
|
||||
|
||||
## 6. Write the direction contract for a whole surface
|
||||
|
||||
If a competent default could satisfy the concept, sharpen its focal moment until one product-specific move changes implementation. Difficulty must clarify the product, not add spectacle.
|
||||
|
||||
Before code, write a direction contract of at most 150 words in an opening HTML or framework comment. The first 200 characters must name `DIRECTION CONTRACT`.
|
||||
|
||||
- `UNIQUE`: the task thesis tied to the product mechanism;
|
||||
- `NOT-TEMPLATE`: the category-default arrangement this structure refuses;
|
||||
- `OWN-WORLD`: the confirmed DESIGN.md invariants, tokens, and materials it uses;
|
||||
- `STORY`: what the visitor understands, believes, and does;
|
||||
- `FIRST VIEWPORT`: exact composition, hierarchy, action, and where the concept exceeds competent convention;
|
||||
- `FORM`: chosen structure or behavior, signature, implementation consequence, and seed key.
|
||||
|
||||
The contract is task-scoped, inspectable, and subordinate to the user's choice. Put the same six blocks in the surface brief and artifact comment.
|
||||
|
||||
A local extension skips this contract unless the user explicitly wants it to become a distinct authored moment. Use the shaped decisions as the implementation plan instead.
|
||||
|
||||
## 7. Plan, build, and commit
|
||||
|
||||
Plan from the selected direction or local shape and real content, never a category skeleton. In redesign, remove inherited visual tokens.
|
||||
|
||||
Load only needed specialist references. Focal interaction or authored animation reads [animate.md](animate.md), even without the `animate` command.
|
||||
|
||||
Build the strongest coherent direction once. Its grammar governs navigation, actions, controls, content, and transitions without disguising affordances. Give the focal form the scale that gives it force; do not trap it inside a standard hero panel.
|
||||
|
||||
**Make the opening a thesis.** Demonstrate the mechanism immediately; leave an idea, interaction, or evidence, not merely mood.
|
||||
|
||||
**Commit before correcting.** Land the hard move at full strength before refining it. In unattended work, safety is the known risk.
|
||||
|
||||
**Commit at page scale.** Let color, material, image, or type own a region when the world calls for it. Scattered signature decoration is not commitment.
|
||||
|
||||
**Pace the whole surface.** Vary density, scale, image, motion, and quiet inside one grammar. Cut repeated claims; prove the mechanism with real artifact, interaction, data, transformation, or content.
|
||||
|
||||
**Author motion as material.** Motion expresses the world and task. Premium moments go beyond repeated transform/opacity through earned focus, depth, masks, continuity, light, or material change. Bound expensive effects, test in-browser, keep content visible by default, and design reduced motion.
|
||||
|
||||
Preserve semantics, affordances, accessibility, performance, responsiveness, and project conventions. Operate/Read express through topology, hierarchy, density, rhythm, and state; Persuade/Experience may earn drama.
|
||||
|
||||
## 8. Solidify the visual record
|
||||
|
||||
After first implementation of a new/replacement world or approved expansion, refresh DESIGN.md from the build:
|
||||
|
||||
- replace provisional direction with the exact type, color roles, tokens, spacing/radii, components, states, and motion that survived;
|
||||
- add normative YAML tokens only for values the implementation actually uses;
|
||||
- remove the directional-seed status once the record and implementation agree;
|
||||
- preserve broader world invariants and expression ranges;
|
||||
- do not promote the task's story, hero composition, or one-off motif into a global rule unless it is intentionally reusable.
|
||||
|
||||
Ordinary extension does not rewrite DESIGN.md; only approved durable changes do.
|
||||
|
||||
## 9. Finish like a studio
|
||||
|
||||
Inspect desktop and mobile; critique against the brief, DESIGN.md, and the applicable shape, concept, or contract; patch material defects; recheck skin-blind. Follow the quality guidance supplied by `context.mjs` and hooks. Context requests a manual scan only when no automatic detector is active; never add another detector pass. Fix real gaps and classify false positives until none remain. Add a reviewer only when risk earns it.
|
||||
|
||||
@@ -4,7 +4,7 @@ When design SERVES the product: app UIs, admin dashboards, settings panels, data
|
||||
|
||||
## The product slop test
|
||||
|
||||
Not "would someone say AI made this." Familiarity is often a feature here. The test is: would a user fluent in the category's best tools (Linear, Figma, Notion, Raycast, Stripe come to mind) sit down and trust this interface, or pause at every subtly-off component?
|
||||
Familiarity is often a feature here. The test is whether a category-fluent user can trust the interface immediately or must pause at every subtly-off component.
|
||||
|
||||
Product UI's failure mode isn't flatness, it's strangeness without purpose: over-decorated buttons, mismatched form controls, gratuitous motion, display fonts where labels should be, invented affordances for standard tasks. The bar is earned familiarity. The tool should disappear into the task.
|
||||
|
||||
@@ -41,7 +41,7 @@ Every interactive component has: default, hover, focus, active, disabled, loadin
|
||||
- Motion conveys state, not decoration. State change, feedback, loading, reveal: nothing else.
|
||||
- No orchestrated page-load sequences. Product loads into a task; users don't want to watch it load.
|
||||
|
||||
## Product bans (on top of the shared absolute bans)
|
||||
## Product constraints
|
||||
|
||||
- Decorative motion that doesn't convey state.
|
||||
- Inconsistent component vocabulary across screens. If the "save" button looks different in two places, one is wrong.
|
||||
@@ -54,7 +54,7 @@ Every interactive component has: default, hover, focus, active, disabled, loadin
|
||||
|
||||
Product can afford things brand surfaces can't.
|
||||
|
||||
- System fonts and familiar sans defaults (Inter, SF Pro, system-ui stacks).
|
||||
- System fonts and familiar sans defaults.
|
||||
- Standard navigation patterns: top bar + side nav, breadcrumbs, tabs, command palettes.
|
||||
- Density. Tables with many rows, panels with many labels, dense information when users need it.
|
||||
- Consistency over surprise. The same visual vocabulary screen to screen is a virtue; delight is saved for moments, not pages.
|
||||
|
||||
@@ -1,241 +1,98 @@
|
||||
> **Additional context needed**: quality bar (MVP vs flagship).
|
||||
> **Additional context needed**: quality bar and shipping constraints.
|
||||
|
||||
Perform a meticulous final pass to catch all the small details that separate good work from great work. The difference between shipped and polished.
|
||||
Polish is refinement, never concealed redesign. Preserve the incumbent visual world, content, behavior, and everything outside scope. If the concept itself is wrong, say so and recommend redesign or `bolder` instead of smuggling in a replacement.
|
||||
|
||||
Detector and automated QA output are defect evidence only. A clean script result is never proof that the design is strong; gather browser evidence and inspect the real interaction path.
|
||||
A detector result is defect evidence, not proof of quality. Inspect the rendered experience and real interaction path.
|
||||
|
||||
## Design System Discovery
|
||||
## 1. Establish the system
|
||||
|
||||
Aligning the feature to the design system is **not optional**. Polish without alignment is decoration on top of drift, and it makes the next person's job harder. Discovery comes before any other polish work.
|
||||
Read DESIGN.md and representative tokens, shared components, patterns, and neighboring flows. If no formal system exists, use coherent project conventions.
|
||||
|
||||
1. **Find the design system**: Search for design system documentation, component libraries, style guides, or token definitions. Study the core patterns: design principles, target audience, color tokens, spacing scale, typography styles, component API, motion conventions.
|
||||
2. **Note the conventions**: How are shared components imported? What spacing scale is used? Which colors come from tokens vs hard-coded values? What motion and interaction patterns are established? What flow shapes are used for comparable actions (modal vs full-page, inline vs route, save-on-blur vs explicit submit)?
|
||||
3. **Identify drift, then name the root cause**: For every deviation, classify it as a **missing token** (the value should exist in the system but doesn't), a **one-off implementation** (a shared component already exists but wasn't used), or a **conceptual misalignment** (the feature's flow, IA, or hierarchy doesn't match neighboring features). The fix differs by category: patch the value, swap to the shared component, or rework the flow. Fixing the symptom without naming the cause is how drift compounds.
|
||||
Classify each drift before fixing it:
|
||||
|
||||
If a design system exists, polish **must** align the feature with it. If none exists, polish against the conventions visible in the codebase. **If anything about the system is ambiguous, ask. Never guess at design system principles.**
|
||||
- **missing token:** the system needs a reusable value;
|
||||
- **one-off implementation:** an existing shared component or pattern should replace it;
|
||||
- **conceptual mismatch:** the flow, information architecture, or hierarchy differs from comparable product areas;
|
||||
- **local defect:** the implementation is simply incomplete or inconsistent.
|
||||
|
||||
## Pre-Polish Assessment
|
||||
Fix the cause at the narrowest correct level. Ask when a binding system principle cannot be inferred.
|
||||
|
||||
Understand the current state and goals before touching anything:
|
||||
## 2. Gather the evidence
|
||||
|
||||
1. **Review completeness**:
|
||||
- Is it functionally complete?
|
||||
- Are there known issues to preserve (mark with TODOs)?
|
||||
- What's the quality bar? (MVP vs flagship feature?)
|
||||
- When does it ship? (How much time for polish?)
|
||||
Use the feature yourself at representative desktop and mobile sizes. Determine:
|
||||
|
||||
2. **Think experience-first**: Who actually uses this, and what's the best possible experience for them? Effective design beats decorative polish; a feature that looks beautiful but fights the user's flow is not polished. Walk the path from their perspective before opening DevTools.
|
||||
- whether the path is functionally complete;
|
||||
- the intended quality bar and time available;
|
||||
- known constraints or deliberately unfinished work;
|
||||
- the states, content lengths, roles, and input methods users will actually encounter.
|
||||
|
||||
3. **Identify polish areas**:
|
||||
- Visual inconsistencies
|
||||
- Spacing and alignment issues
|
||||
- Interaction state gaps
|
||||
- Copy inconsistencies
|
||||
- Edge cases and error states
|
||||
- Loading and transition smoothness
|
||||
- Information architecture and flow drift (does this feature reveal complexity the way neighboring features do?)
|
||||
If a prior critique exists, use it as one input:
|
||||
|
||||
4. **Pull in any prior critique** (optional signal): If `/impeccable critique` has been run on the same target, its priority issues are a useful prior for what to address first. Resolve the target to a file path or URL, then:
|
||||
```bash
|
||||
slug=$(node .claude/skills/impeccable/scripts/critique-storage.mjs slug "<resolved>")
|
||||
node .claude/skills/impeccable/scripts/critique-storage.mjs latest "$slug"
|
||||
```
|
||||
Exit 0 with body = found; fold the P0/P1 items into your polish list and mention the snapshot path so the user sees what you read. Exit 2 = no snapshot, continue without it. The critique is one input among many. Do your own pass either way.
|
||||
```bash
|
||||
slug=$(node .claude/skills/impeccable/scripts/critique-storage.mjs slug "<resolved target>")
|
||||
node .claude/skills/impeccable/scripts/critique-storage.mjs latest "$slug"
|
||||
```
|
||||
|
||||
5. **Triage cosmetic vs functional**: Classify each issue as **cosmetic** (looks off, doesn't impede the user) or **functional** (breaks, blocks, or confuses the experience). When polish time is tight, functional issues ship first; cosmetic ones can land in a follow-up. Quality should be consistent; never perfect one corner while leaving another rough.
|
||||
Exit 0 returns the latest snapshot; incorporate relevant P0/P1 findings and name the snapshot read. Exit 2 means none exists. Perform an independent pass either way.
|
||||
|
||||
**CRITICAL**: Polish is the last step, not the first. Don't polish work that's not functionally complete.
|
||||
## 3. Triage
|
||||
|
||||
## Polish Systematically
|
||||
Separate functional defects from cosmetic ones and fix in this order:
|
||||
|
||||
Work through these dimensions methodically:
|
||||
1. broken or blocked tasks, data loss, misleading state, and inaccessible paths;
|
||||
2. missing loading, empty, error, success, disabled, and permission states;
|
||||
3. flow, hierarchy, responsive, and design-system drift;
|
||||
4. visual and motion inconsistencies;
|
||||
5. code and asset cleanup.
|
||||
|
||||
### Visual Alignment & Spacing
|
||||
Do not perfect one corner while leaving the rest below the same quality bar.
|
||||
|
||||
- **Pixel-perfect alignment**: Everything lines up to grid
|
||||
- **Consistent spacing**: All gaps use spacing scale (no random 13px gaps)
|
||||
- **Optical alignment**: Adjust for visual weight (icons may need offset for optical centering)
|
||||
- **Responsive consistency**: Spacing and alignment work at all breakpoints
|
||||
- **Grid adherence**: Elements snap to baseline grid
|
||||
## 4. Polish the whole path
|
||||
|
||||
**Check**:
|
||||
- Enable grid overlay and verify alignment
|
||||
- Check spacing with browser inspector
|
||||
- Test at multiple viewport sizes
|
||||
- Look for elements that "feel" off
|
||||
### Flow and hierarchy
|
||||
|
||||
### Information Architecture & Flow
|
||||
- Match neighboring mental models, terminology, disclosure, routing, save behavior, and optimistic or pessimistic patterns.
|
||||
- Make the primary task and current state obvious without flattening every element to equal weight.
|
||||
- Ensure arrival, transition, empty, and recovery paths connect instead of behaving as isolated screens.
|
||||
|
||||
Visual polish on a misshapen flow is wasted work. Match the *shape* of the experience to the system, not just the surface.
|
||||
### Layout and type
|
||||
|
||||
- **Progressive disclosure**: Match how much is revealed when, compared to neighboring features. A settings page exposing 40 fields when the rest of the app reveals 5 at a time is drift, even if every field is perfectly styled.
|
||||
- **Established user flows**: Multi-step actions follow the same shape as comparable flows elsewhere: modal vs full-page, inline edit vs separate route, save-on-blur vs explicit submit, optimistic vs pessimistic updates.
|
||||
- **Hierarchy & complexity**: The same conceptual weight gets the same visual weight throughout. Primary actions don't become tertiary in one corner of the product, and tertiary actions don't shout.
|
||||
- **Empty, loading, and arrival transitions**: How content arrives, updates, and leaves matches how it does in adjacent features.
|
||||
- **Naming and mental model**: The feature uses the same nouns and verbs as the rest of the system. A "Workspace" here shouldn't be a "Project" three screens away.
|
||||
- Align to the project's grid and spacing scale; fix optical as well as mathematical alignment.
|
||||
- Group related content tightly and separate distinct groups generously.
|
||||
- Keep same-role typography consistent; test measure, wrapping, localization expansion, zoom, and font loading.
|
||||
- Verify every supported viewport rather than correcting only the current screenshot.
|
||||
|
||||
### Typography Refinement
|
||||
### Color, imagery, and icons
|
||||
|
||||
- **Hierarchy consistency**: Same elements use same sizes/weights throughout
|
||||
- **Line length**: 45-75 characters for body text
|
||||
- **Line height**: Appropriate for font size and context
|
||||
- **Widows & orphans**: No single words on last line
|
||||
- **Hyphenation**: Appropriate for language and column width
|
||||
- **Kerning**: Adjust letter spacing where needed (especially headlines)
|
||||
- **Font loading**: No FOUT/FOIT flashes
|
||||
- Use semantic tokens and stable color meanings across themes.
|
||||
- Verify text, control, and focus contrast in every state.
|
||||
- Keep icon families, stroke/weight, sizing, and optical alignment coherent.
|
||||
- Prevent image layout shift; use correct aspect ratios, responsive sources, and useful alt text.
|
||||
|
||||
### Color & Contrast
|
||||
### Interaction and state
|
||||
|
||||
- **Contrast ratios**: All text meets WCAG standards
|
||||
- **Consistent token usage**: No hard-coded colors, all use design tokens
|
||||
- **Theme consistency**: Works in all theme variants
|
||||
- **Color meaning**: Same colors mean same things throughout
|
||||
- **Accessible focus**: Focus indicators visible with sufficient contrast
|
||||
- **Gray on color**: Never put gray text on colored backgrounds; use a shade of that color or transparency
|
||||
- Every control needs appropriate default, hover, focus, active, disabled, loading, error, and success behavior.
|
||||
- Preserve visible keyboard focus, logical tab order, labels, and platform-appropriate touch targets.
|
||||
- Keep motion coherent, interruptible, performant, and reduced-motion aware. Do not add animation merely to make polish visible.
|
||||
- Validate long, missing, localized, offline, slow, and permission-limited content where the product can encounter it.
|
||||
|
||||
### Interaction States
|
||||
### Content and code
|
||||
|
||||
Every interactive element needs all states:
|
||||
- Keep terminology, capitalization, punctuation, and factual copy consistent. Ask before changing claims.
|
||||
- Remove debug output, dead code, unused imports, obsolete styles, and polish-created duplication.
|
||||
- Replace custom implementations with shared components where the system owns the pattern.
|
||||
- Promote genuinely reusable values to tokens; do not create a system abstraction for one local exception.
|
||||
|
||||
- **Default**: Resting state
|
||||
- **Hover**: Subtle feedback (color, scale, shadow)
|
||||
- **Focus**: Keyboard focus indicator (never remove without replacement)
|
||||
- **Active**: Click/tap feedback
|
||||
- **Disabled**: Clearly non-interactive
|
||||
- **Loading**: Async action feedback
|
||||
- **Error**: Validation or error state
|
||||
- **Success**: Successful completion
|
||||
## 5. Verify and finish
|
||||
|
||||
**Missing states create confusion and broken experiences**.
|
||||
Walk the complete path again with mouse, keyboard, and touch where applicable. Check:
|
||||
|
||||
### Micro-interactions & Transitions
|
||||
- mobile, intermediate, and wide layouts;
|
||||
- loading, empty, error, success, disabled, long-content, and missing-content states;
|
||||
- zoom, contrast, focus, semantics, screen-reader names, and reduced motion;
|
||||
- console errors, layout shift, interaction latency, image loading, and supported browsers;
|
||||
- agreement with DESIGN.md, neighboring features, and the user's scope.
|
||||
|
||||
- **Smooth transitions**: All state changes animated appropriately (150-300ms)
|
||||
- **Consistent easing**: Use ease-out-quart/quint/expo for natural deceleration. Never bounce or elastic; they feel dated.
|
||||
- **No jank**: Smooth animations; use atmospheric blur/filter/mask/shadow effects when they add polish, but bound expensive paint areas and avoid casual layout-property animation
|
||||
- **Appropriate motion**: Motion serves purpose, not decoration
|
||||
- **Reduced motion**: Respects `prefers-reduced-motion`
|
||||
Follow the quality guidance supplied by `context.mjs` and hooks, then run any other relevant QA commands. Context requests a manual scan only when no automatic detector is active; never add another detector pass. Fix real defects and document only narrow intentional exceptions. A clean scan does not replace visual judgment.
|
||||
|
||||
### Content & Copy
|
||||
|
||||
- **Consistent terminology**: Same things called same names throughout
|
||||
- **Consistent capitalization**: Title Case vs Sentence case applied consistently
|
||||
- **Grammar & spelling**: No typos
|
||||
- **Appropriate length**: Not too wordy, not too terse
|
||||
- **Punctuation consistency**: Periods on sentences, not on labels (unless all labels have them)
|
||||
|
||||
### Icons & Images
|
||||
|
||||
- **Consistent style**: All icons from same family or matching style
|
||||
- **Appropriate sizing**: Icons sized consistently for context
|
||||
- **Proper alignment**: Icons align with adjacent text optically
|
||||
- **Alt text**: All images have descriptive alt text
|
||||
- **Loading states**: Images don't cause layout shift, proper aspect ratios
|
||||
- **Retina support**: 2x assets for high-DPI screens
|
||||
|
||||
### Forms & Inputs
|
||||
|
||||
- **Label consistency**: All inputs properly labeled
|
||||
- **Required indicators**: Clear and consistent
|
||||
- **Error messages**: Helpful and consistent
|
||||
- **Tab order**: Logical keyboard navigation
|
||||
- **Auto-focus**: Appropriate (don't overuse)
|
||||
- **Validation timing**: Consistent (on blur vs on submit)
|
||||
|
||||
### Edge Cases & Error States
|
||||
|
||||
- **Loading states**: All async actions have loading feedback
|
||||
- **Empty states**: Helpful empty states, not just blank space
|
||||
- **Error states**: Clear error messages with recovery paths
|
||||
- **Success states**: Confirmation of successful actions
|
||||
- **Long content**: Handles very long names, descriptions, etc.
|
||||
- **No content**: Handles missing data gracefully
|
||||
- **Offline**: Appropriate offline handling (if applicable)
|
||||
|
||||
### Responsiveness
|
||||
|
||||
- **All breakpoints**: Test mobile, tablet, desktop
|
||||
- **Touch targets**: 44x44px minimum on touch devices
|
||||
- **Readable text**: No text smaller than 14px on mobile
|
||||
- **No horizontal scroll**: Content fits viewport
|
||||
- **Appropriate reflow**: Content adapts logically
|
||||
|
||||
### Performance
|
||||
|
||||
- **Fast initial load**: Optimize critical path
|
||||
- **No layout shift**: Elements don't jump after load (CLS)
|
||||
- **Smooth interactions**: No lag or jank
|
||||
- **Optimized images**: Appropriate formats and sizes
|
||||
- **Lazy loading**: Off-screen content loads lazily
|
||||
|
||||
### Code Quality
|
||||
|
||||
- **Remove console logs**: No debug logging in production
|
||||
- **Remove commented code**: Clean up dead code
|
||||
- **Remove unused imports**: Clean up unused dependencies
|
||||
- **Consistent naming**: Variables and functions follow conventions
|
||||
- **Type safety**: No TypeScript `any` or ignored errors
|
||||
- **Accessibility**: Proper ARIA labels and semantic HTML
|
||||
|
||||
## Polish Checklist
|
||||
|
||||
Go through systematically:
|
||||
|
||||
- [ ] Aligned to the design system (drift named and resolved by root cause)
|
||||
- [ ] Information architecture and flow shape match neighboring features
|
||||
- [ ] Visual alignment perfect at all breakpoints
|
||||
- [ ] Spacing uses design tokens consistently
|
||||
- [ ] Typography hierarchy consistent
|
||||
- [ ] All interactive states implemented
|
||||
- [ ] All transitions smooth (60fps)
|
||||
- [ ] Copy is consistent and polished
|
||||
- [ ] Icons are consistent and properly sized
|
||||
- [ ] All forms properly labeled and validated
|
||||
- [ ] Error states are helpful
|
||||
- [ ] Loading states are clear
|
||||
- [ ] Empty states are welcoming
|
||||
- [ ] Touch targets are 44x44px minimum
|
||||
- [ ] Contrast ratios meet WCAG AA
|
||||
- [ ] Keyboard navigation works
|
||||
- [ ] Focus indicators visible
|
||||
- [ ] No console errors or warnings
|
||||
- [ ] No layout shift on load
|
||||
- [ ] Works in all supported browsers
|
||||
- [ ] Respects reduced motion preference
|
||||
- [ ] Code is clean (no TODOs, console.logs, commented code)
|
||||
|
||||
**IMPORTANT**: Polish is about details. Zoom in. Squint at it. Use it yourself. The little things add up.
|
||||
|
||||
Sweat the details. Zoom in until the alignment is right and the spacing reads as deliberate. Then ship.
|
||||
|
||||
**NEVER**:
|
||||
- Polish before it's functionally complete
|
||||
- Polish without aligning to the design system; that's decoration on drift
|
||||
- Guess at design system principles instead of asking when something is ambiguous
|
||||
- Spend hours on polish if it ships in 30 minutes (triage)
|
||||
- Introduce bugs while polishing (test thoroughly)
|
||||
- Ignore systematic issues (if spacing is off everywhere, fix the system, not just one screen)
|
||||
- Perfect one thing while leaving others rough (consistent quality level)
|
||||
- Create new one-off components when design system equivalents exist
|
||||
- Hard-code values that should use design tokens
|
||||
- Introduce new patterns or flows that diverge from established ones
|
||||
|
||||
## Final Verification
|
||||
|
||||
Before marking as done:
|
||||
|
||||
- **Use it yourself**: Actually interact with the feature.
|
||||
- **Test on real devices**: Not just browser DevTools.
|
||||
- **Ask someone else to review**: Fresh eyes catch things.
|
||||
- **Compare to design**: Match intended design.
|
||||
- **Check all states**: Don't just test happy path.
|
||||
- **Treat automation carefully**: Run detector or QA commands when they are available and relevant, fix their defects, but never cite a clean result as proof that the work is polished.
|
||||
|
||||
## Clean Up
|
||||
|
||||
After polishing, ensure code quality:
|
||||
|
||||
- **Replace custom implementations**: If the design system provides a component you reimplemented, switch to the shared version.
|
||||
- **Remove orphaned code**: Delete unused styles, components, or files made obsolete by polish.
|
||||
- **Consolidate tokens**: If you introduced new values, check whether they should be tokens.
|
||||
- **Verify DRYness**: Look for duplication introduced during polishing and consolidate.
|
||||
Finish with a source diff: remove accidental churn, orphaned code, redundant values, and temporary artifacts. Ship only when the feature is functionally complete and consistently finished across the path.
|
||||
|
||||
@@ -2,7 +2,7 @@ Quiet design is harder than bold design. Subtlety needs precision. Reduce visual
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: "quieter" means more restrained palette, more whitespace, more typographic air. Drama is reduced, not eliminated; the POV stays intact.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Reason over the signals; there is no score to obey:
|
||||
- `critique.latest` with a low `score` or non-zero `p0` / `p1` → `polish` (it reads that snapshot as its backlog), or re-run `critique` if the snapshot looks stale.
|
||||
- `git.changedFiles` pointing at one surface → scope `audit` or `polish` to those files specifically, naming them.
|
||||
- `devServer.running` true → `live` is available for in-browser iteration; if false, don't lead with `live`. **`live` and the bundled `detect.mjs` are web-only.** If `setup.platform` is `ios`, `android`, or `adaptive`, don't lead with either; the browser overlay and the HTML rule engine don't apply to native app code.
|
||||
- Otherwise group by intent exactly as init's "Recommend starting points" step does (build new / improve what's there / iterate visually), tailored to `setup.register`.
|
||||
- Otherwise group by intent (build new / improve what's there / iterate visually), tailored to the current surface and `setup.platform`.
|
||||
|
||||
**If `scan.targets` is non-empty and `setup.platform` is not `ios`/`android`/`adaptive`, run `node .claude/skills/impeccable/scripts/detect.mjs --json <scan.targets joined by spaces>` once** (the bundled detector over local files: no network, no npx; it reads HTML/CSS, so skip it for native projects). `scan.via` tells you what they are: `git-changes` (the markup/style files in your dirty tree, the most relevant set), `source-dir` (e.g. `src`, `app`), `html`, or `root`. Fold the hits into your picks: many quality / contrast hits → `audit` or `polish`; a specific slop family → the matching command (gradient text or eyebrows → `quieter` / `typeset`, flat or gray palette → `colorize`, and so on). It's a real, current signal that beats guessing. If detect errors or the tree is large and slow, skip it and recommend the user run `audit` themselves; never block the suggestion on it.
|
||||
|
||||
|
||||
@@ -1,167 +1,61 @@
|
||||
Shape the UX and UI for a feature before any code is written. This command produces a **design brief**: a structured artifact that guides implementation through discovery, not guesswork.
|
||||
# Shape
|
||||
|
||||
**Scope**: Design planning only. This command does NOT write code. It produces the thinking that makes code good.
|
||||
Discover what should be made and how it should work, then return a confirmed design brief without code.
|
||||
|
||||
**Output**: A design brief that can be handed off to /impeccable craft, or directly to /impeccable for freeform implementation. When visual direction probes are used, the images are supporting artifacts, not the primary output.
|
||||
**Product gate:** when context reports that PRODUCT.md is missing, load and complete [init.md](init.md) before Phase 1. Do not substitute shape questions for the product interview. Once PRODUCT.md exists, return here; product context does not replace task discovery.
|
||||
|
||||
## Philosophy
|
||||
## Phase 1: Discovery interview
|
||||
|
||||
Most AI-generated UIs fail not because of bad code, but because of skipped thinking. They jump to "here's a card grid" without asking "what is the user trying to accomplish?" This command inverts that: understand deeply first, so implementation is precise.
|
||||
Do not write code or choose visual direction yet.
|
||||
|
||||
## Phase 1: Discovery Interview
|
||||
### Cadence
|
||||
|
||||
**Do NOT write any code or make any design decisions during this phase.** Your only job is to understand the feature deeply enough to make excellent design decisions later.
|
||||
- Use the structured question tool when available; otherwise ask and stop.
|
||||
- Ask two or three related questions per round, then wait. One round is the default; add a second only when the answers expose a material gap.
|
||||
- Do not dump a questionnaire, repeat settled facts, or turn obvious facts into menus. Assert the likely reading and invite correction.
|
||||
- A sparse prompt requires at least one answer round. A precise prompt may need only a compact confirmation.
|
||||
|
||||
**Unattended runs:** when no user can respond (a one-shot task, an automated run, or an explicit instruction not to ask questions), answer the interview questions yourself from the brief, record the answers as the design brief, and continue without pausing at any confirmation gate in this file. The thinking is still required; only the waiting is waived.
|
||||
### Round 1: purpose, people, and outcome
|
||||
|
||||
This is a required interaction, not optional guidance. Ask these questions in conversation, adapting based on answers. Don't dump them all at once; have a natural dialogue. STOP and call the AskUserQuestion tool to clarify.
|
||||
Choose the two or three questions that most change the result:
|
||||
|
||||
### Interview cadence
|
||||
- What is this surface or feature for, and what problem must it solve?
|
||||
- Who specifically reaches it, in what situation and state of mind?
|
||||
- What is the primary thing they must understand or do? What would success look like?
|
||||
- What is uniquely true here that a neighboring product or generic template could not claim?
|
||||
|
||||
Discovery includes at least one user-answer round unless PRODUCT.md, DESIGN.md, or an already-confirmed brief directly answers the needed inputs. With a sparse prompt, do **not** synthesize a complete brief for confirmation on the first response.
|
||||
### Round 2: material, behavior, and boundaries
|
||||
|
||||
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop.
|
||||
- Ask **2-3 questions per round**, then wait for answers.
|
||||
- Treat PRODUCT.md and DESIGN.md as anchors; they reduce repeated questions but do **not** replace shape for craft. Shape is task-specific.
|
||||
- One round is the default. Add a second only if the first answers leave material gaps. Don't run a second round just to feel thorough.
|
||||
- Round 1 should clarify purpose, audience/context, content/scope, and (for brand) visual direction.
|
||||
- Round 2, when needed, fills in whatever's still genuinely missing.
|
||||
Run only for material unresolved decisions:
|
||||
|
||||
**Assert-then-confirm, not menu-with-escape.** When PRODUCT.md and the user's prompt make one option obvious, name it and ask the user to confirm or override. Don't enumerate "Restrained / Committed / Or something else?" as a real choice; "This reads as Restrained, confirm?" beats a four-option menu when the answer is already clear.
|
||||
- What real content, evidence, data, and assets must the experience carry? What are realistic minimum, typical, and maximum ranges?
|
||||
- Which states and transitions matter: first-run, empty, loading, error, success, permissions, overflow, or expert use?
|
||||
- What is the intended fidelity, breadth, and interactivity: exploration, production-ready screen, full flow, or broader surface?
|
||||
- What must remain untouched? What would make the result feel wrong even if it looked polished?
|
||||
- Which platform, framework, performance, accessibility, localization, or delivery constraints are binding?
|
||||
|
||||
### Purpose & Context
|
||||
- What is this feature for? What problem does it solve?
|
||||
- Who specifically will use it? (Not "users"; be specific: role, context, frequency)
|
||||
- What does success look like? How will you know this feature is working?
|
||||
- What's the user's state of mind when they reach this feature? (Rushed? Exploring? Anxious? Focused?)
|
||||
Never ask for CSS values or canned aesthetic lanes. New-work owns visual-world and concept choices.
|
||||
|
||||
### Content & Data
|
||||
- What content or data does this feature display or collect?
|
||||
- What are the realistic ranges? (Minimum, typical, maximum, e.g., 0 items, 5 items, 500 items)
|
||||
- What are the edge cases? (Empty state, error state, first-time use, power user)
|
||||
- Is any content dynamic? What changes and how often?
|
||||
- What visual assets are real content here? Note required images, product shots, illustrations, maps, textures, diagrams, generated objects, or existing project assets.
|
||||
## Phase 2: Resolve the design direction
|
||||
|
||||
### Design Direction
|
||||
For new surfaces, brand expansion, or replacement, follow [new-work.md](new-work.md) through visual authority, any world workshop, and concept choice. Reuse discovery, then return before its contract, persistence, or implementation. Inside an established world, use its concept process only when composition or interaction remains materially open.
|
||||
|
||||
Force a visual decision on three fronts. Skip anything PRODUCT.md or DESIGN.md already answers; ask only what's missing.
|
||||
## Phase 3: Write the brief
|
||||
|
||||
- **Color strategy for this surface.** Pick one: Restrained / Committed / Full palette / Drenched. Can override the project default if the surface earns it (e.g. a drenched hero inside an otherwise Restrained product).
|
||||
- **Theme via scene sentence.** Write one sentence of physical context for this surface: who uses it, where, under what ambient light, in what mood. The sentence forces dark vs light. If it doesn't, add detail until it does.
|
||||
- **Two or three named anchor references.** Specific products, brands, objects. Not adjectives like "modern" or "clean."
|
||||
Write the smallest useful brief:
|
||||
|
||||
### Scope
|
||||
1. **Job and audience:** who arrives, their context, need, and visitor mode.
|
||||
2. **Outcome and proof:** primary task/action, success, real evidence, and product-specific truth.
|
||||
3. **Selected direction:** visual authority, structural/interaction thesis, sequence, focal moment, and implementation consequence.
|
||||
4. **Scope and boundaries:** fidelity, breadth, interactivity, named target, what remains untouched, and explicit anti-goals.
|
||||
5. **States and ranges:** realistic content/data ranges and material states.
|
||||
6. **Interaction and layout:** hierarchy, topology, responsiveness, affordances, feedback, and transitions; intent, not CSS.
|
||||
7. **Constraints and open decisions:** platform, delivery, accessibility, localization, reusable components, and choices a builder must not invent.
|
||||
|
||||
Always ask. Sketch quality and shipped quality are different outputs; don't guess between them.
|
||||
Use three to five bullets when the task is settled; use the full structure only for ambiguous, multi-screen, or standalone planning. Do not restate the conversation.
|
||||
|
||||
- **Fidelity.** Sketch / mid-fi / high-fi / production-ready?
|
||||
- **Breadth.** One screen / a flow / a whole surface?
|
||||
- **Interactivity.** Static visual / interactive prototype / shipped-quality component?
|
||||
- **Time intent.** Quick exploration, or polish until it ships?
|
||||
## Confirm and stop
|
||||
|
||||
Scope answers are task-scoped. Don't write them to PRODUCT.md or DESIGN.md; carry them through the design brief only.
|
||||
Present the brief for explicit confirmation or one correction round, then stop: shape never writes code or a direction contract.
|
||||
|
||||
### Constraints
|
||||
- Are there technical constraints? (Framework, performance budget, browser support)
|
||||
- Are there content constraints? (Localization, dynamic text length, user-generated content)
|
||||
- Mobile/responsive requirements?
|
||||
- Accessibility requirements beyond WCAG AA?
|
||||
|
||||
### Anti-Goals
|
||||
- What should this NOT be? What would be a wrong direction?
|
||||
- What's the biggest risk of getting this wrong?
|
||||
|
||||
## Phase 1.5: Visual Direction Probe (Capability-Gated)
|
||||
|
||||
After the discovery interview, generate a small set of visual direction probes **before** writing the final brief when all of these are true:
|
||||
|
||||
- The work is **net-new** or directionally ambiguous enough that visual exploration will clarify the brief.
|
||||
- The requested fidelity is **mid-fi, high-fi, or production-ready**. Skip for sketch-only planning.
|
||||
- The current harness gives you native image generation (Codex's `image_gen`, an equivalent MCP tool, or similar). Don't ask the user to install APIs or tooling.
|
||||
|
||||
When those conditions are met, this step is mandatory. If image generation isn't natively available, do not ask the user to install APIs or tooling. State in one line that the image step is skipped because the harness lacks native image generation, then proceed. The one-line announcement is required, not optional; it forces a conscious decision instead of letting the step quietly evaporate.
|
||||
|
||||
Use probes to explore visual lanes, not to replace the brief.
|
||||
|
||||
Do not skip probes because the final UI will be semantic, editable, code-native, responsive, or accessible. Those are implementation requirements, not reasons to avoid visual exploration.
|
||||
|
||||
### What to generate
|
||||
|
||||
Generate **2 to 4** distinct direction probes based on the discovery answers, especially:
|
||||
|
||||
- Color strategy
|
||||
- Theme scene sentence
|
||||
- Named anchor references
|
||||
- Scope and fidelity
|
||||
|
||||
The probes should differ in primary visual direction (hierarchy, topology, density, typographic voice, or color strategy), not just palette tweaks.
|
||||
|
||||
### How to use the probes
|
||||
|
||||
- Treat them as **direction tests**, not final designs.
|
||||
- Use them to pressure-test whether the brief is pointing at the right lane.
|
||||
- Ask the user which direction feels closest, what feels off, and what should carry forward.
|
||||
- If the probes reveal a mismatch, revise the brief inputs before finalizing the brief.
|
||||
|
||||
### Important limits
|
||||
|
||||
- Do **not** skip discovery because image generation is available.
|
||||
- Do **not** treat generated imagery as final UX specification, final copy, or final accessibility behavior.
|
||||
- Do **not** use this step for minor refinements of existing work. It's for shaping a new surface or clarifying a big directional choice.
|
||||
|
||||
If image generation isn't natively available, announce the skip in one line and proceed to the design brief.
|
||||
|
||||
## Phase 2: Design Brief
|
||||
|
||||
After the interview and any required probes, present a brief and **end your response**. The user must confirm before any implementation runs. Do not present a brief and then continue to code in the same response, even if the brief feels obvious to you. The user's confirmation is the gate.
|
||||
|
||||
**Choose the brief shape based on how clear the answers are:**
|
||||
|
||||
- **Compact form (3-5 bullets)** when discovery was crisp and the original prompt + PRODUCT.md already pinned scope, content, and direction. State what you're building, the visual lane, and end with one or two specific questions or a clear "confirm or override?" prompt. This is the default for typical craft requests with a clear prompt.
|
||||
- **Full structured form (sections below)** when the task is genuinely ambiguous, multi-screen, or when the user asked for shape as a standalone step. Use this when the discipline of structure earns its weight.
|
||||
|
||||
Don't pad a clear brief into a long one to look thorough. A 70-line brief restating answers the user just gave is noise, not rigor. Equally, don't skip the confirmation pause to look efficient: the pause is the point.
|
||||
|
||||
Present the brief, then **stop and wait for explicit confirmation**. You are not the judge of whether the user already approved. Even when the brief feels obviously right, ask once and wait. The pause is what separates shape from premature implementation.
|
||||
|
||||
### Brief Structure
|
||||
|
||||
**1. Feature Summary** (2-3 sentences)
|
||||
What this is, who it's for, what it needs to accomplish.
|
||||
|
||||
**2. Primary User Action**
|
||||
The single most important thing a user should do or understand here.
|
||||
|
||||
**3. Design Direction**
|
||||
Color strategy (Restrained / Committed / Full palette / Drenched) + the theme scene sentence + 2–3 named anchor references. Reference PRODUCT.md and DESIGN.md where they already answer, and note any per-surface overrides.
|
||||
|
||||
If you ran the Visual Direction Probe step, name which probe direction won and what changed in the brief because of it.
|
||||
|
||||
**4. Scope**
|
||||
Fidelity, breadth, interactivity, and time intent from the Scope section of the interview. Task-scoped; these don't persist beyond the brief.
|
||||
|
||||
**5. Layout Strategy**
|
||||
High-level spatial approach: what gets emphasis, what's secondary, how information flows. Describe the visual hierarchy and rhythm, not specific CSS.
|
||||
|
||||
**6. Key States**
|
||||
List every state the feature needs: default, empty, loading, error, success, edge cases. For each, note what the user needs to see and feel.
|
||||
|
||||
**7. Interaction Model**
|
||||
How users interact with this feature. What happens on click, hover, scroll? What feedback do they get? What's the flow from entry to completion?
|
||||
|
||||
**8. Content Requirements**
|
||||
What copy, labels, empty state messages, error messages, and microcopy are needed. Note any dynamic content and its realistic ranges. For image-led surfaces, also list the required image/media roles and their likely source (project asset, generated raster, semantic SVG/CSS, canvas/WebGL, icon library, or accepted omission).
|
||||
|
||||
**9. Recommended References**
|
||||
Based on the brief, list which impeccable reference files would be most valuable during implementation (e.g., layout.md for complex layouts, animate.md for animated features, interaction-design.md for form-heavy features, typeset.md for typography-driven pages, colorize.md for color-led brands).
|
||||
|
||||
**10. Open Questions**
|
||||
Anything genuinely unresolved. Don't list "open questions" you've already recommended a default for; assert the default and move on. If you'd write `Recommend: X` next to a question, just decide X.
|
||||
|
||||
---
|
||||
|
||||
STOP and call the AskUserQuestion tool to clarify. Ask for explicit confirmation of the brief before finishing.
|
||||
|
||||
If the user disagrees with any part, revisit the relevant discovery questions. A shape run is incomplete until the user confirms direction.
|
||||
|
||||
Once confirmed, the brief is complete. The user can now hand it to /impeccable, or use it to guide any other implementation approach. (If the user wants the full discovery-then-build flow in one step, they should use /impeccable craft instead, which runs this command internally.)
|
||||
When no human or structured answer mechanism exists, mark assumptions plainly, return the brief, and stop.
|
||||
|
||||
@@ -1,301 +1,80 @@
|
||||
Typography carries most of the information on the page. Replace generic defaults (Inter, Roboto, system fallback at flat scale) with type that reflects the brand and scales with intentional contrast.
|
||||
Typography carries information, hierarchy, and voice. Improve it inside the established visual world; do not replace the identity unless the user asked to.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
New identity work: run the font selection procedure in [new-work.md](new-work.md). Fluid `clamp()` scale, ≥1.25 ratio between steps.
|
||||
- **Persuade + Experience:** display type may carry the voice. Use decisive contrast and responsive scale when the composition benefits.
|
||||
- **Operate + Read:** stability, scanability, and measure come first. A single well-tuned family and fixed role scale are often right.
|
||||
- **Native:** follow [ios.md](ios.md) or [android.md](android.md), including platform scaling and accessibility behavior.
|
||||
|
||||
Operate + Read: system fonts and familiar sans stacks are legitimate here. One well-tuned family typically carries the whole UI. Fixed `rem` scale, 1.125–1.2 ratio between more closely-spaced steps. Long-form Read content wants a steady reading measure and a quiet, stable scale, not display-scale drama.
|
||||
If typography replacement would create a new identity, route through [new-work.md](new-work.md) and update DESIGN.md. Otherwise preserve confirmed families and improve their use.
|
||||
|
||||
---
|
||||
## Two isolated assessments
|
||||
|
||||
## Two isolated assessments (required)
|
||||
When a sub-agent tool is available and permitted, run these independently; otherwise run them yourself in this order. Do not let detector findings anchor the design assessment.
|
||||
|
||||
Spawn two parallel sub-agents whenever a sub-agent/Task tool is exposed: one for the typography assessment, one for the mechanical pre-scan. If the harness needs explicit user permission for sub-agents, stop and ask before proceeding. Isolation is the point: detector output anchors visual judgment toward what the scan can see, so neither sub-agent gets the other's output. Each assessment runs in its own sub-agent; running either one in this context when a sub-agent tool exists is not permitted, even when it is faster; the fallback below is only for sessions with no sub-agent tool. Give each a self-contained prompt (target files, register, **DESIGN.md** content when present, and its instructions below); do not assume it can read this file.
|
||||
|
||||
**Sub-agent A (typography assessment)**: give it the full [Assess Current Typography](#assess-current-typography) checklist below, verbatim, in its prompt. It works through every item and returns per-item findings citing file, selector, or value.
|
||||
|
||||
**Sub-agent B (mechanical pre-scan)**: run the bundled detector scoped to type:
|
||||
1. **Typographic assessment:** inspect representative pages and styles. Answer every question below with a file, selector, or computed value:
|
||||
- **Authority and fit:** Which faces, weights, and roles are established? Do they fit the product and selected world, or are they unexamined defaults? Is every family necessary?
|
||||
- **Hierarchy:** Can heading, body, label, metadata, and data roles be distinguished at a glance? Are adjacent sizes or weights too close to carry different jobs?
|
||||
- **Scale and consistency:** Is there a deliberate role scale, or a collection of arbitrary values? Do repeated roles stay identical across screens and states?
|
||||
- **Reading:** Does body copy stay within a comfortable 45–75 character measure? Are line height, paragraph rhythm, contrast, and tracking tuned to the actual face, width, language, and surface?
|
||||
- **Stress:** What happens with long headings, localization expansion, zoom, narrow containers, missing weights, and font fallback?
|
||||
- **Delivery:** Are only used assets loaded? Do fallback metrics, loading strategy, and variable-font settings avoid invisible text and disruptive reflow?
|
||||
2. **Mechanical scan:** run:
|
||||
|
||||
```bash
|
||||
node .claude/skills/impeccable/scripts/detect.mjs --json --scope type [target files or dirs]
|
||||
```
|
||||
|
||||
A missing `node` on PATH is not permission to skip: hunt for a runtime (`command -v node`, nvm or Homebrew paths, the harness's own bundled node) and run it by full path. If none exists, halt the scan and report that Node must be installed (the parent relays this to the user); do **not** substitute grep for the detector or proceed unscanned. The scan checks literal font sizes against the **DESIGN.md** ramp but abstains on `em`, `%`, `clamp()`, and line-heights, so also grep `font-size\s*:`, `fontSize`, `text-\[`, `leading-\[` and judge those hits against the spec. Return the findings JSON plus the grep verdicts.
|
||||
Also inspect dynamic or arbitrary font values the detector cannot interpret. Synthesize both assessments before editing, noting what each caught alone. A clean scan is a floor, not proof of good typography.
|
||||
|
||||
**If no sub-agent tool is exposed (or the user declined)**: run both yourself, assessment first, pre-scan second, so the deterministic findings can't anchor the visual judgment. Keep that order even when the scan feels quicker to start with.
|
||||
## Set the system
|
||||
|
||||
**Synthesize** once both are done: merge into a single findings list, noting where they agree and what each caught alone. Fix every finding, or list it as a deliberate exception for the user to accept. A clean scan is a floor, not a verdict: a generic font stack at a flat scale passes every detector rule, which is exactly what the assessment exists to catch. State in your final summary which path ran (parallel sub-agents or single-context fallback).
|
||||
Before editing, state:
|
||||
|
||||
---
|
||||
- the roles the interface needs;
|
||||
- the intended contrast between those roles;
|
||||
- the reading measure and density;
|
||||
- which existing faces and weights are authoritative;
|
||||
- any performance, localization, or accessibility constraints.
|
||||
|
||||
## Assess Current Typography
|
||||
Use the fewest roles and families that make the hierarchy unmistakable. Combine size, weight, space, and tone deliberately instead of asking size alone to do all the work. Role names and tokens should describe purpose rather than values.
|
||||
|
||||
This checklist is sub-agent A's brief (on the fallback path, work through it yourself before the pre-scan). Analyze what's weak or generic about the current type:
|
||||
## Apply
|
||||
|
||||
1. **Font choices**:
|
||||
- Are we using invisible defaults? (Inter, Roboto, Arial, Open Sans, system defaults)
|
||||
- Does the font match the brand personality? (A playful brand shouldn't use a corporate typeface)
|
||||
- Are there too many font families? (More than 2-3 is almost always a mess)
|
||||
- Keep body copy comfortably readable and zoomable. Use 1rem / 16px as the ordinary web body floor unless a dense role, platform convention, or user setting justifies otherwise.
|
||||
- Keep prose in the 45–75ch range. Tune line height inversely with measure: wider lines generally need more leading.
|
||||
- Compensate light text on dark surfaces on all three perceptual axes: slightly more line height, a touch more tracking, and one step more weight when the face needs it.
|
||||
- Tune line height to the face, width, language, and contrast, not a universal ratio.
|
||||
- Keep repeated roles consistent across screens and states.
|
||||
- Use numeric, tabular, code, and label features when their content benefits.
|
||||
- Load only used font assets and weights. Provide metric-compatible fallbacks and avoid blocking text.
|
||||
- Let marketing display type respond to available space when useful; keep dense product and reading surfaces spatially predictable.
|
||||
- Preserve browser zoom, user font settings, Dynamic Type, and platform text scaling.
|
||||
- Use paragraph spacing or first-line indentation as the primary paragraph rhythm; combining both usually double-marks the boundary.
|
||||
|
||||
2. **Hierarchy**:
|
||||
- Can you tell headings from body from captions at a glance?
|
||||
- Are font sizes too close together? (14px, 15px, 16px = muddy hierarchy)
|
||||
- Are weight contrasts strong enough? (Medium vs Regular is barely visible)
|
||||
Do not make type decorative at the expense of comprehension, or introduce a second family without a clear role it alone can perform.
|
||||
|
||||
3. **Sizing & scale**:
|
||||
- Is there a consistent type scale, or are sizes arbitrary?
|
||||
- Does body text meet minimum readability? (16px+)
|
||||
- Is the sizing strategy appropriate for the context? (Fixed `rem` scales for app UIs and long-form reading, where a steady measure beats display scale; fluid `clamp()` for marketing-page headings)
|
||||
## Verify
|
||||
|
||||
4. **Readability**:
|
||||
- Are line lengths comfortable? (45-75 characters ideal)
|
||||
- Is line-height appropriate for the font and context?
|
||||
- Is there enough contrast between text and background?
|
||||
- Primary, secondary, body, and metadata roles are recognizable without reading the copy.
|
||||
- Long text remains comfortable across relevant widths and languages.
|
||||
- The typography belongs to the product and its established world.
|
||||
- Loading does not create disruptive reflow or invisible text.
|
||||
- Zoom, text scaling, focus, contrast, and reduced viewport paths remain usable.
|
||||
- The final mechanical scan has no unexplained findings.
|
||||
|
||||
5. **Consistency**:
|
||||
- Are the same elements styled the same way throughout?
|
||||
- Are font weights used consistently? (Not bold in one section, semibold in another for the same role)
|
||||
- Is letter-spacing intentional or default everywhere?
|
||||
Answer each item with rendered or source evidence, then rerun the scan. Do not substitute a bare “yes” for verification.
|
||||
|
||||
**CRITICAL**: The goal isn't to make text "fancier." It's to make it clearer, more readable, and more intentional. Good typography is invisible; bad typography is distracting.
|
||||
|
||||
## Plan Typography Improvements
|
||||
|
||||
Consult the [Reference Material](#reference-material) section below for detailed guidance on scales, pairing, and loading strategies.
|
||||
|
||||
Create a systematic plan:
|
||||
|
||||
- **Font selection**: Do fonts need replacing? What fits the brand/context?
|
||||
- **Type scale**: Establish a modular scale (e.g., 1.25 ratio) with clear hierarchy
|
||||
- **Weight strategy**: Which weights serve which roles? (Regular for body, Semibold for labels, Bold for headings, or whatever fits)
|
||||
- **Spacing**: Line-heights, letter-spacing, and margins between typographic elements
|
||||
|
||||
## Improve Typography Systematically
|
||||
|
||||
### Font Selection
|
||||
|
||||
If fonts need replacing:
|
||||
- Choose fonts that reflect the brand personality
|
||||
- Pair with genuine contrast (serif + sans, geometric + humanist), or use a single family in multiple weights
|
||||
- Ensure web font loading doesn't cause layout shift (`font-display: swap`, metric-matched fallbacks)
|
||||
|
||||
### Establish Hierarchy
|
||||
|
||||
Build a clear type scale:
|
||||
- **5 sizes cover most needs**: caption, secondary, body, subheading, heading
|
||||
- **Use a consistent ratio** between levels (1.25, 1.333, or 1.5)
|
||||
- **Combine dimensions**: Size + weight + color + space for strong hierarchy. Don't rely on size alone
|
||||
- **App UIs**: Use a fixed `rem`-based type scale, optionally adjusted at 1-2 breakpoints. Fluid sizing undermines the spatial predictability that dense, container-based layouts need
|
||||
- **Marketing / content pages**: Use fluid sizing via `clamp(min, preferred, max)` for headings and display text. Keep body text fixed
|
||||
|
||||
### Fix Readability
|
||||
|
||||
- Set `max-width` on text containers using `ch` units (`max-width: 65ch`)
|
||||
- Adjust line-height per context: tighter for headings (1.1-1.2), looser for body (1.5-1.7)
|
||||
- Increase line-height slightly for light-on-dark text
|
||||
- Ensure body text is at least 16px / 1rem
|
||||
|
||||
### Refine Details
|
||||
|
||||
- Use `tabular-nums` for data tables and numbers that should align
|
||||
- Apply proper `letter-spacing`: slightly open for small caps and uppercase, default or tight for large display text
|
||||
- Use semantic token names (`--text-body`, `--text-heading`), not value names (`--font-16`)
|
||||
- Set `font-kerning: normal` and consider OpenType features where appropriate
|
||||
|
||||
### Weight Consistency
|
||||
|
||||
- Define clear roles for each weight and stick to them
|
||||
- Don't use more than 3-4 weights (Regular, Medium, Semibold, Bold is plenty)
|
||||
- Load only the weights you actually use (each weight adds to page load)
|
||||
|
||||
**NEVER**:
|
||||
- Use more than 2-3 font families
|
||||
- Pick sizes arbitrarily; commit to a scale
|
||||
- Set body text below 16px
|
||||
- Use decorative/display fonts for body text
|
||||
- Disable browser zoom (`user-scalable=no`)
|
||||
- Use `px` for font sizes; use `rem` to respect user settings
|
||||
- Default to Inter/Roboto/Open Sans when personality matters
|
||||
- Pair fonts that are similar but not identical (two geometric sans-serifs)
|
||||
|
||||
## Verify Typography Improvements
|
||||
|
||||
- **Hierarchy**: Can you identify heading vs body vs caption instantly?
|
||||
- **Readability**: Is body text comfortable to read in long passages?
|
||||
- **Consistency**: Are same-role elements styled identically throughout?
|
||||
- **Personality**: Does the typography reflect the brand?
|
||||
- **Performance**: Are web fonts loading efficiently without layout shift?
|
||||
- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%?
|
||||
|
||||
Answer each item above by citing the file, selector, or value that satisfies it; never a bare yes. Then re-run the pre-scan and fix until the count of unresolved items and unaccepted findings is zero.
|
||||
|
||||
When the type carries the hierarchy on its own, hand off to `/impeccable polish` for the final pass.
|
||||
When the hierarchy holds, hand off to `/impeccable polish`.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
Each variant MUST declare a `scale` param controlling the hierarchy ratio. Express all font sizes in the variant's scoped CSS through `calc(var(--p-scale, 1) * <base>)` or, better, scale the type ramp via `clamp(min, calc(var(--p-scale, 1) * Npx), max)`. Users slide from subdued to commanding.
|
||||
Every variant declares a coarse `scale` parameter and authors its type ramp against `var(--p-scale, 1)`.
|
||||
|
||||
```json
|
||||
{"id":"scale","kind":"range","min":0.85,"max":1.3,"step":0.05,"default":1,"label":"Scale"}
|
||||
```
|
||||
|
||||
Where the variant riffs on a specific pairing, expose the pairing choice as a `steps` param (e.g. "serif display + sans body" vs. "mono display + sans body" vs. "all-sans"). Each branch routes through `:scope[data-p-pairing="X"]` selectors in scoped CSS.
|
||||
|
||||
See `reference/live.md` for the full params contract.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `typography.md` and live inline now so the typeset flow has its deep typography reference in one place. `bolder.md` also references this section.
|
||||
|
||||
### Typography
|
||||
|
||||
#### Classic Typography Principles
|
||||
|
||||
##### Vertical Rhythm
|
||||
|
||||
Your line-height should be the base unit for ALL vertical spacing. If body text has `line-height: 1.5` on `16px` type (= 24px), spacing values should be multiples of 24px. This creates subconscious harmony; text and space share a mathematical foundation.
|
||||
|
||||
##### Modular Scale & Hierarchy
|
||||
|
||||
The common mistake: too many font sizes that are too close together (14px, 15px, 16px, 18px...). This creates muddy hierarchy.
|
||||
|
||||
**Use fewer sizes with more contrast.** A 5-size system covers most needs:
|
||||
|
||||
| Role | Typical Ratio | Use Case |
|
||||
|------|---------------|----------|
|
||||
| xs | 0.75rem | Captions, legal |
|
||||
| sm | 0.875rem | Secondary UI, metadata |
|
||||
| base | 1rem | Body text |
|
||||
| lg | 1.25-1.5rem | Subheadings, lead text |
|
||||
| xl+ | 2-4rem | Headlines, hero text |
|
||||
|
||||
Popular ratios: 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth). Pick one and commit.
|
||||
|
||||
##### Readability & Measure
|
||||
|
||||
Use `ch` units for character-based measure (`max-width: 65ch`). Line-height scales inversely with line length: narrow columns need tighter leading, wide columns need more.
|
||||
|
||||
**Non-obvious**: Light text on dark backgrounds needs compensation on three axes, not just one. Bump line-height by 0.05–0.1, add a touch of letter-spacing (0.01–0.02em), and optionally step the body weight up one notch (regular → medium). The perceived weight drops across all three; fix all three.
|
||||
|
||||
**Paragraph rhythm**: Pick either space between paragraphs OR first-line indentation. Never both. Digital usually wants space; editorial/long-form can justify indent-only.
|
||||
|
||||
#### Font Selection & Pairing
|
||||
|
||||
The tactical selection procedure and the reflex-reject list live in [new-work.md](new-work.md) (loaded for new identity work). The rest of this section covers the adjacent knowledge: anti-reflex corrections, system font use, and pairing rules.
|
||||
|
||||
##### Anti-reflexes worth defending against
|
||||
|
||||
- A technical/utilitarian brief does NOT need a serif "for warmth." Most tech tools should look like tech tools.
|
||||
- An editorial/premium brief does NOT need the same expressive serif everyone is using right now. Premium can be Swiss-modern, can be neo-grotesque, can be a literal monospace, can be a quiet humanist sans.
|
||||
- A children's product does NOT need a rounded display font. Kids' books use real type.
|
||||
- A "modern" brief does NOT need a geometric sans. The most modern thing you can do is not use the font everyone else is using.
|
||||
|
||||
**System fonts are underrated**: `-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui` looks native, loads instantly, and is highly readable. Consider this for apps where performance > personality.
|
||||
|
||||
##### Pairing Principles
|
||||
|
||||
**The non-obvious truth**: You often don't need a second font. One well-chosen font family in multiple weights creates cleaner hierarchy than two competing typefaces. Only add a second font when you need genuine contrast (e.g., display headlines + body serif).
|
||||
|
||||
When pairing, contrast on multiple axes:
|
||||
- Serif + Sans (structure contrast)
|
||||
- Geometric + Humanist (personality contrast)
|
||||
- Condensed display + Wide body (proportion contrast)
|
||||
|
||||
##### Web Font Loading
|
||||
|
||||
The layout shift problem: fonts load late, text reflows, and users see content jump. Here's the fix:
|
||||
|
||||
```css
|
||||
/* 1. Use font-display: swap for visibility */
|
||||
@font-face {
|
||||
font-family: 'CustomFont';
|
||||
src: url('font.woff2') format('woff2');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* 2. Match fallback metrics to minimize shift */
|
||||
@font-face {
|
||||
font-family: 'CustomFont-Fallback';
|
||||
src: local('Arial');
|
||||
size-adjust: 105%; /* Scale to match x-height */
|
||||
ascent-override: 90%; /* Match ascender height */
|
||||
descent-override: 20%; /* Match descender depth */
|
||||
line-gap-override: 10%; /* Match line spacing */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'CustomFont', 'CustomFont-Fallback', sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
Tools like [Fontaine](https://github.com/unjs/fontaine) calculate these overrides automatically.
|
||||
|
||||
**`swap` vs `optional`**: `swap` shows fallback text immediately and FOUT-swaps when the web font arrives. `optional` uses the fallback if the web font misses a small load budget (~100ms) and avoids the shift entirely. Pick `optional` when zero layout shift matters more than seeing the branded font on slow networks.
|
||||
|
||||
**Preload the critical weight only**: typically the regular-weight body font used above the fold. Preloading every weight costs more bandwidth than it saves.
|
||||
|
||||
**Variable fonts for 3+ weights or styles**: a single variable font file is usually smaller than three static weight files, gives fractional weight control, and pairs well with `font-optical-sizing: auto`. For 1–2 weights, static is fine.
|
||||
|
||||
#### Modern Web Typography
|
||||
|
||||
##### Fluid Type
|
||||
|
||||
Fluid typography via `clamp(min, preferred, max)` scales text smoothly with the viewport. The middle value (e.g., `5vw + 1rem`) controls scaling rate (higher vw = faster scaling). Add a rem offset so it doesn't collapse to 0 on small screens.
|
||||
|
||||
**Use fluid type for**: Headings and display text on marketing/content pages where text dominates the layout and needs to breathe across viewport sizes.
|
||||
|
||||
**Use fixed `rem` scales for**: App UIs, dashboards, and data-dense interfaces. No major app design system (Material, Polaris, Primer, Carbon) uses fluid type in product UI; fixed scales with optional breakpoint adjustments give the spatial predictability that container-based layouts need. Body text should also be fixed even on marketing pages, since the size difference across viewports is too small to warrant it.
|
||||
|
||||
**Bound your clamp()**: keep `max-size ≤ ~2.5 × min-size`. Wider ratios break the browser's zoom and reflow behaviour and make large viewports feel like the page is shouting.
|
||||
|
||||
**Scale container width and font-size together** so effective character measure stays in the 45–75ch band at every viewport. A heading that widens faster than its container drifts out of the comfortable measure at the top end.
|
||||
|
||||
##### OpenType Features
|
||||
|
||||
Most developers don't know these exist. Use them for polish:
|
||||
|
||||
```css
|
||||
/* Proper fractions */
|
||||
.recipe-amount { font-variant-numeric: diagonal-fractions; }
|
||||
|
||||
/* Small caps for abbreviations */
|
||||
abbr { font-variant-caps: all-small-caps; }
|
||||
|
||||
/* Disable ligatures in code */
|
||||
code { font-variant-ligatures: none; }
|
||||
|
||||
/* Enable kerning (usually on by default, but be explicit) */
|
||||
body { font-kerning: normal; }
|
||||
```
|
||||
|
||||
Check what features your font supports at [Wakamai Fondue](https://wakamaifondue.com/).
|
||||
|
||||
##### Rendering polish
|
||||
|
||||
```css
|
||||
/* Variable fonts: pick the right optical-size master automatically */
|
||||
body { font-optical-sizing: auto; }
|
||||
```
|
||||
|
||||
**ALL-CAPS tracking**: capitals sit too close at default spacing. Add 5–12% letter-spacing (`letter-spacing: 0.05em` to `0.12em`) to short all-caps labels, eyebrows, and small headings. Real small caps (via `font-variant-caps`) need the same treatment, slightly gentler.
|
||||
|
||||
#### Typography System Architecture
|
||||
|
||||
Name tokens semantically (`--text-body`, `--text-heading`), not by value (`--font-size-16`). Include font stacks, size scale, weights, line-heights, and letter-spacing in your token system.
|
||||
|
||||
#### Accessibility Considerations
|
||||
|
||||
Beyond contrast ratios (which are well-documented), consider:
|
||||
|
||||
- **Never disable zoom**: `user-scalable=no` breaks accessibility. If your layout breaks at 200% zoom, fix the layout.
|
||||
- **Use rem/em for font sizes**: This respects user browser settings. Never `px` for body text.
|
||||
- **Minimum 16px body text**: Smaller than this strains eyes and fails WCAG on mobile.
|
||||
- **Adequate touch targets**: Text links need padding or line-height that creates 44px+ tap targets.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: More than 2-3 font families per project. Skipping fallback font definitions. Ignoring font loading performance (FOUT/FOIT). Using decorative fonts for body text.
|
||||
Add at most one pairing or weight parameter when it represents a real system choice. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"craft": {
|
||||
"description": "Full confirmed-brief-then-build flow. Runs multi-round shape discovery first, resolves visual probe and north-star mock gates when available, then builds and visually iterates. Use when building a new feature end-to-end.",
|
||||
"description": "Deprecated compatibility alias for an ordinary Impeccable new-work request. It adds no behavior; natural build and redesign requests use the same flow.",
|
||||
"argumentHint": "[feature description]"
|
||||
},
|
||||
"init": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Concept-seed picker: the dice half of the new-work concept procedure.
|
||||
* External concept seed: the dice half of new-work's coupled-direction and
|
||||
* established-world surface procedures.
|
||||
*
|
||||
* The model derives a grounded shortlist of candidate FORMS from the
|
||||
* audience's world and the subject's cultural home (see
|
||||
@@ -12,10 +13,9 @@
|
||||
*
|
||||
* This script rolls them from outside, the same trick that made the
|
||||
* palette seed work:
|
||||
* - BUILD INDEX (2-5): which entry of the model's own resonance-ordered
|
||||
* shortlist to build. The dice never choose an ungrounded ingredient;
|
||||
* they only refuse the argmax rut. (Index 1 is excluded: that's the
|
||||
* concept every run would ship anyway.)
|
||||
* - PROMOTED INDEX: which entry of the model's own resonance-ordered
|
||||
* shortlist must be taken seriously beside its favorites. The dice never
|
||||
* choose an ungrounded ingredient; they only refuse the argmax rut.
|
||||
* - CHALLENGERS (3): outside forms from concept-ingredients.json, weighed
|
||||
* against the derived candidates on exactly two axes — audience
|
||||
* identification and product clarity. They win only when they beat the
|
||||
@@ -23,8 +23,8 @@
|
||||
* material and win over thin categories, which is the intended shape.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/concept-seed.mjs # roll at random
|
||||
* node scripts/concept-seed.mjs --from <key> # deterministic (hash key)
|
||||
* node scripts/concept-seed.mjs --scope direction
|
||||
* node scripts/concept-seed.mjs --scope surface --from <key>
|
||||
*
|
||||
* Env vars:
|
||||
* IMPECCABLE_CONCEPT_SEED — same as --from; for reproducible eval runs.
|
||||
@@ -40,6 +40,12 @@ const pool = JSON.parse(readFileSync(join(here, 'concept-ingredients.json'), 'ut
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const fromIdx = args.indexOf('--from');
|
||||
const scopeIdx = args.indexOf('--scope');
|
||||
const scope = scopeIdx !== -1 ? args[scopeIdx + 1] : 'surface';
|
||||
if (scope !== 'surface' && scope !== 'direction') {
|
||||
process.stderr.write('concept-seed: --scope must be direction or surface\n');
|
||||
process.exit(1);
|
||||
}
|
||||
// When no key is supplied, generate one and print it: a user reporting a
|
||||
// bad outcome can hand us the key and we replay the exact roll.
|
||||
const key = fromIdx !== -1
|
||||
@@ -47,7 +53,7 @@ const key = fromIdx !== -1
|
||||
: (process.env.IMPECCABLE_CONCEPT_SEED || crypto.randomBytes(4).toString('hex'));
|
||||
|
||||
function hashUnit(k, salt) {
|
||||
const h = crypto.createHash('sha256').update(`${salt}:${k}`).digest();
|
||||
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${k}`).digest();
|
||||
return h.readUInt32BE(0) / 0xffffffff;
|
||||
}
|
||||
const unit = (salt) => hashUnit(key, salt);
|
||||
@@ -67,22 +73,48 @@ for (let i = 0; picks.length < 3 && i < 60; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write(`CONCEPT SEED (key: ${key}; rerun with --from ${key} to reproduce this roll)
|
||||
BUILD INDEX: ${buildIndex}
|
||||
After ordering your derived candidates by resonance, build the page whose
|
||||
form comes from candidate number ${buildIndex}, exactly as if it had ranked
|
||||
first: full commitment. Your top-ranked candidate is what every run in this
|
||||
category would ship; the assignment exists to refuse that rut, not to
|
||||
punish it.
|
||||
CHALLENGERS (weigh against your derived candidates on the same two axes,
|
||||
audience identification and product clarity; a challenger wins only when
|
||||
it beats the grounded list on both):
|
||||
const promotedInstruction = scope === 'direction'
|
||||
? `After ordering the grounded coupled directions by product fit, promote
|
||||
candidate ${buildIndex} into the serious shortlist. Each candidate must join
|
||||
a durable visual system to a concrete expression for the requested first
|
||||
surface; select or revise that pair as one decision. It must survive the
|
||||
current task plus navigation, quiet and dense content, interaction and state,
|
||||
and a substantially different future surface.`
|
||||
: `After ordering the task's grounded structural candidates by resonance,
|
||||
promote candidate ${buildIndex} into the serious shortlist. In an attended
|
||||
run, present it beside the strongest materially different candidates and
|
||||
let the user select or revise the surface concept. In a truly unattended
|
||||
run, use it when it survives audience identification and product clarity.`;
|
||||
|
||||
const challengerInstruction = scope === 'direction'
|
||||
? `A challenger enters only when it can supply both reusable identity grammar
|
||||
and a strong first-surface structure, not a one-page costume or a style pasted
|
||||
onto an unrelated layout. Weigh audience identification, product clarity,
|
||||
current-surface force, and cross-surface system breadth.`
|
||||
: `A challenger wins only when it beats the grounded list on both audience
|
||||
identification and product clarity. It may change task topology or
|
||||
interaction, but never the committed visual identity.`;
|
||||
|
||||
const authorityInstruction = scope === 'direction'
|
||||
? `PRODUCT.md and explicit incumbent brand commitments constrain every coupled
|
||||
direction. The seed never chooses exact colors, fonts, tokens, or a user
|
||||
preference, and it never permits the world and first surface to be selected
|
||||
independently.`
|
||||
: `PRODUCT.md and DESIGN.md constrain every surface candidate's identity
|
||||
vocabulary; they do not cancel task-level composition. The seed never
|
||||
authorizes a new palette, type system, material world, or unfamiliar control
|
||||
behavior.`;
|
||||
|
||||
process.stdout.write(`${scope.toUpperCase()} CONCEPT SEED (key: ${key}; rerun with --scope ${scope} --from ${key} to reproduce this roll)
|
||||
PROMOTED INDEX: ${buildIndex}
|
||||
${promotedInstruction}
|
||||
The promotion exists to refuse the model's ranking rut, not to outrank the
|
||||
user or the brief.
|
||||
CHALLENGERS:
|
||||
1. ${picks[0]}
|
||||
2. ${picks[1]}
|
||||
3. ${picks[2]}
|
||||
If a challenger wins, it replaces the assigned candidate. If the surface is
|
||||
an existing world whose incumbent carries a deliberate, ownable idea, the
|
||||
incumbent IS the chosen candidate: intensify its lineage and ignore the
|
||||
roll entirely. The same override applies when the user, PRODUCT.md, or
|
||||
DESIGN.md pins a direction: pinned direction beats the roll, always.
|
||||
${challengerInstruction}
|
||||
${authorityInstruction}
|
||||
A user- or brief-pinned decision beats the roll, always.
|
||||
`);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* output is always valid JSON.
|
||||
*
|
||||
* Signals:
|
||||
* - setup: PRODUCT.md / DESIGN.md presence, register, whether code exists
|
||||
* - setup: PRODUCT.md / DESIGN.md presence and whether code exists
|
||||
* - critique: the latest cached critique score (.impeccable/critique)
|
||||
* - git: branch + files changed vs the default branch (a scope hint)
|
||||
* - devServer: whether a local dev server answers on a common port (gates live)
|
||||
@@ -21,7 +21,7 @@ import net from 'node:net';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { loadContext, extractRegister, extractPlatform } from './context.mjs';
|
||||
import { loadContext, extractPlatform } from './context.mjs';
|
||||
import { getCritiqueDir } from './lib/impeccable-paths.mjs';
|
||||
|
||||
/** Is there code here at all, or just context files / an empty repo? */
|
||||
@@ -196,7 +196,6 @@ export async function gatherSignals(cwd = process.cwd()) {
|
||||
hasDesign: ctx.hasDesign,
|
||||
designPath: ctx.designPath,
|
||||
hasCode: hasCode(cwd),
|
||||
register: extractRegister(ctx.product),
|
||||
platform: extractPlatform(ctx.product),
|
||||
},
|
||||
critique: { latest: latestCritique(cwd) },
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* Context loader: prints PRODUCT.md (and DESIGN.md if present) as one
|
||||
* markdown block on stdout, or prints a `NO_PRODUCT_MD:` message when no
|
||||
* Context loader: prints PRODUCT.md, DESIGN.md when present, the matching
|
||||
* persisted surface brief when one can be resolved, and native-platform
|
||||
* guidance selected from PRODUCT.md. It prints a
|
||||
* `NO_PRODUCT_MD:` message when no
|
||||
* PRODUCT.md is found anywhere. The skill keys off that message to branch:
|
||||
* from-scratch build commands (init / teach / craft / shape) and clear
|
||||
* from-scratch build requests (plus init / teach / shape) and clear
|
||||
* build/shape intent divert into the init flow, while scoped commands proceed
|
||||
* using the existing code as context.
|
||||
*
|
||||
@@ -23,10 +25,13 @@ import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { parseTargetOptions } from './lib/target-args.mjs';
|
||||
import { IMPECCABLE_COMMAND } from './lib/provider.mjs';
|
||||
import { IMPECCABLE_COMMAND, IMPECCABLE_PROVIDER_ID } from './lib/provider.mjs';
|
||||
import { renderLlmOnlySlopReview } from './lib/slop-review.mjs';
|
||||
import { resolveSurfaceBrief } from './lib/surface-briefs.mjs';
|
||||
|
||||
const PRODUCT_NAMES = ['PRODUCT.md', 'Product.md', 'product.md'];
|
||||
const DESIGN_NAMES = ['DESIGN.md', 'Design.md', 'design.md'];
|
||||
const SKILL_REFERENCE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'reference');
|
||||
const FALLBACK_DIRS = ['.agents/context', 'docs'];
|
||||
const MONOREPO_MARKER_FILES = ['pnpm-workspace.yaml', 'turbo.json', 'nx.json', 'lerna.json'];
|
||||
const MONOREPO_FALLBACK_PROJECT_DIRS = ['apps', 'packages'];
|
||||
@@ -41,6 +46,8 @@ const WORKSPACE_DISCOVERY_IGNORED_DIRS = new Set([
|
||||
'.turbo',
|
||||
'.cache',
|
||||
'coverage',
|
||||
'vendor',
|
||||
'vendors',
|
||||
]);
|
||||
const VISUAL_SOURCE_DIRS = ['src', 'app', 'pages', 'components', 'site', 'public', 'styles'];
|
||||
const STYLE_EXTENSIONS = new Set(['.css', '.scss', '.sass', '.less', '.styl']);
|
||||
@@ -73,6 +80,12 @@ export function loadContext(cwd = process.cwd(), options = {}) {
|
||||
const designPath = resolved.designPath;
|
||||
const product = productPath ? safeRead(productPath) : null;
|
||||
const design = designPath ? safeRead(designPath) : null;
|
||||
const platform = extractPlatform(product);
|
||||
const surfaceResolution = resolveSurfaceBrief(
|
||||
resolved.projectRoot,
|
||||
hasTargetOption(options) ? options.targetPath : null,
|
||||
);
|
||||
const surfaceBrief = surfaceResolution.brief;
|
||||
return {
|
||||
hasProduct: !!product,
|
||||
product,
|
||||
@@ -83,7 +96,18 @@ export function loadContext(cwd = process.cwd(), options = {}) {
|
||||
contextDir: resolved.contextDir,
|
||||
productContextDir: productPath ? path.dirname(productPath) : null,
|
||||
designContextDir: designPath ? path.dirname(designPath) : null,
|
||||
hasSurfaceBrief: !!surfaceBrief,
|
||||
surfaceBrief: surfaceBrief?.text ?? null,
|
||||
surfaceBriefPath: surfaceBrief?.path ? path.relative(absCwd, surfaceBrief.path) : null,
|
||||
surfaceBriefReason: surfaceResolution.reason,
|
||||
surfaceBriefCandidates: surfaceResolution.candidates.map((brief) => ({
|
||||
slug: brief.slug,
|
||||
path: path.relative(absCwd, brief.path),
|
||||
primaryTarget: brief.primaryTarget,
|
||||
relatedTargets: brief.relatedTargets,
|
||||
})),
|
||||
hasVisualImplementation: hasVisualImplementation(resolved.projectRoot),
|
||||
platform,
|
||||
projectRoot: resolved.projectRoot,
|
||||
repoRoot: resolved.repoRoot,
|
||||
isMonorepo: resolved.isMonorepo,
|
||||
@@ -696,6 +720,19 @@ function safeRead(p) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadNativePlatformReferences(platform) {
|
||||
const names = platform === 'adaptive'
|
||||
? ['ios', 'android']
|
||||
: platform === 'ios' || platform === 'android'
|
||||
? [platform]
|
||||
: [];
|
||||
return names.flatMap((name) => {
|
||||
const filePath = path.join(SKILL_REFERENCE_DIR, `${name}.md`);
|
||||
const content = safeRead(filePath);
|
||||
return content ? [{ name, filePath, content }] : [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Best-effort evidence that the project already has an incumbent visual
|
||||
* implementation. DESIGN.md is documentation, not the only source of design
|
||||
@@ -719,9 +756,11 @@ export function hasVisualImplementation(projectRoot) {
|
||||
let styledComponents = 0;
|
||||
|
||||
const inspectFile = (filePath) => {
|
||||
if (scannedFiles++ >= VISUAL_SCAN_FILE_LIMIT) return false;
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
if (!STYLE_EXTENSIONS.has(ext) && !UI_EXTENSIONS.has(ext)) return false;
|
||||
const base = path.basename(filePath).toLowerCase();
|
||||
if (/\.min\.[a-z]+$/.test(base)) return false;
|
||||
if (scannedFiles++ >= VISUAL_SCAN_FILE_LIMIT) return false;
|
||||
let body;
|
||||
try {
|
||||
body = fs.readFileSync(filePath, 'utf-8').slice(0, 64 * 1024);
|
||||
@@ -729,18 +768,28 @@ export function hasVisualImplementation(projectRoot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const base = path.basename(filePath).toLowerCase();
|
||||
const evidence = body
|
||||
.replace(/\/\*[\s\S]*?\*\//g, '')
|
||||
.replace(/<!--[\s\S]*?-->/g, '')
|
||||
.replace(/^\s*\/\/.*$/gm, '');
|
||||
if (STYLE_EXTENSIONS.has(ext)) {
|
||||
const customProperties = body.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const visualDeclarations = body.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
if (/\b(?:tokens?|theme|design-system)\b/.test(base) && body.trim().length > 80) return true;
|
||||
const customProperties = evidence.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const visualDeclarations = evidence.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
if (/\b(?:tokens?|theme|design-system)\b/.test(base) && evidence.trim().length > 80) return true;
|
||||
if (customProperties >= 3 || visualDeclarations >= 5) return true;
|
||||
}
|
||||
|
||||
if ((ext === '.html' || ext === '.htm') && body.length > 600 && /<style\b|<link[^>]+stylesheet/i.test(body)) {
|
||||
if ((ext === '.html' || ext === '.htm') && evidence.length > 600 && /<style\b|<link[^>]+stylesheet/i.test(evidence)) {
|
||||
return true;
|
||||
}
|
||||
if (!['.html', '.htm'].includes(ext) && body.length > 300 && /class(?:Name)?\s*=|style\s*=|styled\(|css`/i.test(body)) {
|
||||
if (!['.html', '.htm'].includes(ext) && evidence.length > 300) {
|
||||
const embeddedCustomProperties = evidence.match(/--[a-z0-9_-]+\s*:/gi)?.length ?? 0;
|
||||
const embeddedVisualDeclarations = evidence.match(/\b(?:color|background(?:-color)?|border(?:-color)?|font-family)\s*:/gi)?.length ?? 0;
|
||||
const classTokens = [...evidence.matchAll(/class(?:Name)?\s*=\s*["'`]([^"'`]+)["'`]/gi)]
|
||||
.reduce((count, match) => count + match[1].trim().split(/\s+/).length, 0);
|
||||
if ((embeddedCustomProperties >= 3 && embeddedVisualDeclarations >= 3) || embeddedVisualDeclarations >= 5 || classTokens >= 12) return true;
|
||||
}
|
||||
if (!['.html', '.htm'].includes(ext) && evidence.length > 300 && /class(?:Name)?\s*=|style\s*=|styled\(|css`/i.test(evidence)) {
|
||||
styledComponents += 1;
|
||||
if (styledComponents >= 3) return true;
|
||||
}
|
||||
@@ -781,9 +830,9 @@ function escapeRegExp(value) {
|
||||
|
||||
/**
|
||||
* Read the first non-empty line under a bare `## <heading>` section of
|
||||
* PRODUCT.md (e.g. `## Register`, `## Platform`). Returns null when the
|
||||
* PRODUCT.md (for example `## Platform`). Returns null when the
|
||||
* section is absent. The heading match is exact (`\s*$`) so near-miss
|
||||
* headings like `## Register guidelines` don't shadow the real field.
|
||||
* near-miss headings don't shadow the real field.
|
||||
*/
|
||||
export function extractSectionValue(product, heading) {
|
||||
if (!product) return null;
|
||||
@@ -802,16 +851,6 @@ export function extractSectionValue(product, heading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the register (`brand` or `product`) out of PRODUCT.md by looking
|
||||
* for a `## Register` section and reading the first non-empty line that
|
||||
* follows it. Returns null when the file is legacy / register-less.
|
||||
*/
|
||||
export function extractRegister(product) {
|
||||
const word = (extractSectionValue(product, 'Register') || '').toLowerCase();
|
||||
return word === 'brand' || word === 'product' ? word : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the platform (`web`, `ios`, `android`, or `adaptive`) out of PRODUCT.md
|
||||
* by looking for a `## Platform` section and reading the first non-empty line
|
||||
@@ -985,30 +1024,35 @@ async function cli() {
|
||||
const parts = ctx.hasVisualImplementation
|
||||
? [
|
||||
'NO_PRODUCT_MD: This project has no PRODUCT.md yet, but it does have an incumbent visual implementation. ' +
|
||||
'For `init` or `teach`, load reference/init.md and create PRODUCT.md. For `craft`, `shape`, or other work ' +
|
||||
'against the existing product, read its CSS, tokens, components, and assets first and proceed without blocking; ' +
|
||||
`offer \`${IMPECCABLE_COMMAND} init\` as a follow-up. Only treat the work as greenfield when the user explicitly ` +
|
||||
'asks to discard or replace the current identity.',
|
||||
'EXISTING_VISUAL_SYSTEM: Code and assets are the incumbent design authority. Missing DESIGN.md is a documentation ' +
|
||||
'gap, not permission to invent a replacement identity. Preserve and extend the implementation unless the user ' +
|
||||
'explicitly requests a rebrand, or inspection proves the detected files contain no coherent visual decisions.',
|
||||
'For `init`, `teach`, `shape`, or any request to create a new surface or replacement visual world, load reference/init.md and create PRODUCT.md with the user first. ' +
|
||||
'After init writes PRODUCT.md, reference/new-work.md preserves and documents the incumbent system for an ' +
|
||||
'extension or replaces it with the user for a redesign/rebrand. Other ' +
|
||||
'narrow refinement commands may read the CSS, tokens, components, and assets and proceed without blocking, then ' +
|
||||
`offer \`${IMPECCABLE_COMMAND} init\` as a follow-up.`,
|
||||
'BUILD_INIT_REQUIRED: Before shape or any new-surface/redesign flow, init must capture PRODUCT.md with the human or structured ' +
|
||||
'simulated user. Init writes product truth only; reference/new-work.md owns every visual decision.',
|
||||
'SCOPED_EXISTING_ALLOWED: Narrow refinement commands may use the incumbent implementation as authority without ' +
|
||||
'blocking on context setup; they must preserve it and offer init afterward.',
|
||||
'EXISTING_VISUAL_SYSTEM: For refinement or extension, code and assets are incumbent design authority and missing ' +
|
||||
'DESIGN.md is a documentation gap. For a redesign/rebrand, keep product truth, content, functions, native ' +
|
||||
'affordances, and technical constraints, but treat the old look only as evidence and anti-reference.',
|
||||
]
|
||||
: [
|
||||
'NO_PRODUCT_MD: This project has no PRODUCT.md yet. ' +
|
||||
'For `init`, `teach`, `craft`, `shape`, ' +
|
||||
'For `init`, `teach`, `shape`, ' +
|
||||
'or wording that clearly maps to a from-scratch build/shape flow, load ' +
|
||||
'reference/init.md and write PRODUCT.md first, unless no user can ' +
|
||||
'respond (a one-shot or automated run, or the user said not to ask): ' +
|
||||
'then write a one-paragraph understanding of the product, audience, ' +
|
||||
'and the page\'s job from the brief, and continue. For any other ' +
|
||||
'reference/init.md, complete its human or structured simulated-user interview, and write PRODUCT.md before ' +
|
||||
'designing. If no answer mechanism truly exists, init may infer only from the explicit brief and must label its ' +
|
||||
'assumptions. It never writes DESIGN.md. For any other ' +
|
||||
'(scoped) command against existing code, proceed using the code as ' +
|
||||
`context and offer \`${IMPECCABLE_COMMAND} init\` as a suggestion (do not block).`,
|
||||
'NEW_WORK: No committed design context was found. If this task produces ' +
|
||||
'new design (a build from scratch, or a redesign that discards the ' +
|
||||
'current look), you MUST read reference/new-work.md before making any ' +
|
||||
'design decision. Scoped fixes to existing code do not need it.',
|
||||
'PRODUCT_INIT_REQUIRED: No product context or visual authority was found. New builds and redesigns ' +
|
||||
'must finish reference/init.md for PRODUCT.md, then reference/new-work.md establishes the world and surface. Scoped ' +
|
||||
'fixes to existing code do not need the new-surface flow.',
|
||||
];
|
||||
appendSurfaceBriefContext(parts, ctx);
|
||||
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
|
||||
appendHookFallback(parts, ctx);
|
||||
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
|
||||
parts.push(buildMissingTargetDirective());
|
||||
}
|
||||
@@ -1020,37 +1064,29 @@ async function cli() {
|
||||
if (ctx.hasDesign) {
|
||||
parts.push(`# DESIGN.md\n\n${ctx.design.trim()}`);
|
||||
}
|
||||
appendSurfaceBriefContext(parts, ctx);
|
||||
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
|
||||
appendHookFallback(parts, ctx);
|
||||
if (shouldWarnMissingTarget(ctx, targetProvided, targetExists)) {
|
||||
parts.push(buildMissingTargetDirective());
|
||||
}
|
||||
const register = extractRegister(ctx.product);
|
||||
// The register field survives as a family hint (brand = Persuade/Experience,
|
||||
// product = Operate/Read); SKILL.md's mode section carries the essentials
|
||||
// inline, so no register-file read is mandated here. What IS mandated:
|
||||
// the new-work playbook when no committed design system exists yet.
|
||||
if (!ctx.hasDesign) {
|
||||
parts.push(ctx.hasVisualImplementation
|
||||
? 'EXISTING_VISUAL_SYSTEM: PRODUCT.md exists and DESIGN.md is missing, but code contains incumbent visual decisions. ' +
|
||||
'Treat CSS, tokens, components, and assets as design authority. Do not route to new identity work merely because the ' +
|
||||
'document is absent; preserve and extend the implementation unless the user explicitly asks to discard it.'
|
||||
: 'NEW_WORK: PRODUCT.md exists but no DESIGN.md or incumbent visual implementation was found. If this task produces ' +
|
||||
'new design or a redesign that discards the current look, you MUST read reference/new-work.md before making any ' +
|
||||
'design decision. Scoped fixes to existing code do not need it.');
|
||||
? 'INCUMBENT_WORLD_UNDOCUMENTED: PRODUCT.md exists and DESIGN.md is missing, but code contains incumbent visual decisions. ' +
|
||||
'For shape or a new-surface/redesign request, load reference/new-work.md: an extension documents and preserves the code-defined world; ' +
|
||||
'a redesign replaces it with the user and uses the old look only as evidence and anti-reference. Narrow refinement ' +
|
||||
'commands may proceed using the implementation directly.'
|
||||
: 'WORLD_DISCOVERY_REQUIRED: PRODUCT.md exists but no DESIGN.md or incumbent visual implementation was found. ' +
|
||||
'For a new build or redesign, load reference/new-work.md and establish the visual world with the human or structured ' +
|
||||
'simulated user before developing the task concept. Scoped fixes to existing code do not need this flow.');
|
||||
}
|
||||
if (register) {
|
||||
parts.push(`REGISTER: \`${register}\` (family hint: brand = Persuade/Experience surfaces, product = Operate/Read). Derive the visitor's mode per SKILL.md.`);
|
||||
}
|
||||
const platform = extractPlatform(ctx.product);
|
||||
const nativeRefs =
|
||||
platform === 'adaptive' ? ['ios', 'android'] : platform === 'ios' || platform === 'android' ? [platform] : [];
|
||||
if (nativeRefs.length) {
|
||||
const refList = nativeRefs.map(p => `\`reference/${p}.md\``).join(' and ');
|
||||
const label = platform === 'adaptive' ? '`adaptive` (both iOS and Android)' : `\`${platform}\``;
|
||||
const platformReferences = loadNativePlatformReferences(ctx.platform);
|
||||
for (const reference of platformReferences) {
|
||||
parts.push(
|
||||
`NEXT STEP: This project targets ${label}. Also read ${refList} for native conventions, in addition to SKILL.md's mode guidance.`,
|
||||
`# NATIVE PLATFORM REFERENCE: ${reference.name.toUpperCase()} (reference/${reference.name}.md)\n\n${reference.content.trim()}`,
|
||||
);
|
||||
} else if (!platform) {
|
||||
}
|
||||
if (!ctx.platform) {
|
||||
// A `## Platform` section that names something we don't recognize (a
|
||||
// toolchain like `flutter`, a typo) would otherwise silently fall back to
|
||||
// web — the wrong default exactly when the user tried to say "native".
|
||||
@@ -1078,6 +1114,72 @@ function pathExistsForTarget(cwd, targetPath) {
|
||||
return fs.existsSync(abs);
|
||||
}
|
||||
|
||||
const HOOK_MANIFESTS_BY_PROVIDER = Object.freeze({
|
||||
'claude-code': ['.claude/settings.local.json', '.claude/settings.json'],
|
||||
codex: ['.codex/hooks.json'],
|
||||
agents: ['.codex/hooks.json'],
|
||||
cursor: ['.cursor/hooks.json'],
|
||||
github: ['.github/hooks/impeccable.json'],
|
||||
});
|
||||
|
||||
function truthyEnv(value) {
|
||||
return typeof value === 'string' && /^(1|true|yes|on)$/i.test(value.trim());
|
||||
}
|
||||
|
||||
function valueHasHookMarker(value) {
|
||||
if (typeof value === 'string') {
|
||||
return value.includes('skills/impeccable/scripts/hook.mjs')
|
||||
|| value.includes('skills/impeccable/scripts/hook-before-edit.mjs');
|
||||
}
|
||||
if (Array.isArray(value)) return value.some(valueHasHookMarker);
|
||||
if (value && typeof value === 'object') return Object.values(value).some(valueHasHookMarker);
|
||||
return false;
|
||||
}
|
||||
|
||||
function hookEnabledAt(root) {
|
||||
if (truthyEnv(process.env.IMPECCABLE_HOOK_DISABLED)) return false;
|
||||
let enabled = true;
|
||||
for (const name of ['.impeccable/config.json', '.impeccable/config.local.json']) {
|
||||
const raw = readJson(path.join(root, name));
|
||||
if (raw?.hook && Object.prototype.hasOwnProperty.call(raw.hook, 'enabled')) {
|
||||
enabled = raw.hook.enabled !== false;
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
const STOP_REVIEW_PROVIDERS = new Set(['claude-code', 'codex', 'agents']);
|
||||
|
||||
function automaticHookMode(ctx) {
|
||||
if (ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive') {
|
||||
return 'none';
|
||||
}
|
||||
const activeRoot = path.resolve(ctx.projectRoot || process.cwd());
|
||||
if (!hookEnabledAt(activeRoot)) return 'none';
|
||||
const manifests = HOOK_MANIFESTS_BY_PROVIDER[IMPECCABLE_PROVIDER_ID] || [];
|
||||
const roots = [...new Set([process.cwd(), ctx.projectRoot, ctx.repoRoot].filter(Boolean).map((root) => path.resolve(root)))];
|
||||
for (const root of roots) {
|
||||
for (const rel of manifests) {
|
||||
const raw = readJson(path.join(root, rel));
|
||||
if (raw?.hooks && valueHasHookMarker(raw.hooks)) {
|
||||
return STOP_REVIEW_PROVIDERS.has(IMPECCABLE_PROVIDER_ID) ? 'stop' : 'per-edit';
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'none';
|
||||
}
|
||||
|
||||
function appendHookFallback(parts, ctx) {
|
||||
const hookMode = automaticHookMode(ctx);
|
||||
if (hookMode === 'stop') return;
|
||||
const native = ctx.platform === 'ios' || ctx.platform === 'android' || ctx.platform === 'adaptive';
|
||||
parts.push(renderLlmOnlySlopReview({
|
||||
automaticDetector: hookMode === 'per-edit',
|
||||
manualDetector: hookMode === 'none' && !native,
|
||||
scriptsPath: path.dirname(fileURLToPath(import.meta.url)),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildResolvedContextDirective(ctx, options, { targetExists = null } = {}) {
|
||||
const targetPath = hasTargetOption(options) ? options.targetPath : null;
|
||||
return `RESOLVED_CONTEXT:\n${JSON.stringify({
|
||||
@@ -1087,10 +1189,29 @@ function buildResolvedContextDirective(ctx, options, { targetExists = null } = {
|
||||
repoRoot: ctx.repoRoot,
|
||||
productPath: ctx.productPath,
|
||||
designPath: ctx.designPath,
|
||||
surfaceBriefPath: ctx.surfaceBriefPath,
|
||||
surfaceBriefReason: ctx.surfaceBriefReason,
|
||||
surfaceBriefCandidates: ctx.surfaceBriefCandidates,
|
||||
hasVisualImplementation: ctx.hasVisualImplementation,
|
||||
platform: ctx.platform,
|
||||
}, null, 2)}`;
|
||||
}
|
||||
|
||||
function appendSurfaceBriefContext(parts, ctx) {
|
||||
if (ctx.hasSurfaceBrief && ctx.surfaceBrief) {
|
||||
parts.push(`# SURFACE BRIEF (${ctx.surfaceBriefPath})\n\n${ctx.surfaceBrief.trim()}`);
|
||||
return;
|
||||
}
|
||||
if (!ctx.surfaceBriefCandidates?.length) return;
|
||||
const helper = path.join(path.dirname(fileURLToPath(import.meta.url)), 'surface-brief.mjs');
|
||||
parts.push(
|
||||
'SURFACE_CONTEXT_AVAILABLE: Persisted surface briefs exist, but none was selected unambiguously for this invocation. ' +
|
||||
'Resolve the requested surface to its concrete primary or related source path, then run ' +
|
||||
`\`node ${helper} read <path>\` once before changing that surface. Candidates:\n` +
|
||||
JSON.stringify(ctx.surfaceBriefCandidates, null, 2),
|
||||
);
|
||||
}
|
||||
|
||||
function shouldWarnMissingTarget(ctx, targetProvided, targetExists = null) {
|
||||
if (ctx.isMonorepo && targetProvided && targetExists === false) return true;
|
||||
return !!(
|
||||
|
||||
@@ -29,8 +29,9 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { getCritiqueDir } from './lib/impeccable-paths.mjs';
|
||||
import { slugFromTarget } from './lib/target-slug.mjs';
|
||||
|
||||
const SLUG_MAX = 50;
|
||||
export { slugFromTarget } from './lib/target-slug.mjs';
|
||||
|
||||
/**
|
||||
* Mechanically derive a slug from a resolved target. Returns null if the
|
||||
@@ -40,46 +41,6 @@ const SLUG_MAX = 50;
|
||||
* concrete artifact before calling this — we never slug a natural-language
|
||||
* phrase.
|
||||
*/
|
||||
export function slugFromTarget(resolved, { cwd = process.cwd() } = {}) {
|
||||
if (!resolved || typeof resolved !== 'string') return null;
|
||||
const trimmed = resolved.trim();
|
||||
if (!trimmed) return null;
|
||||
|
||||
// URL
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
let url;
|
||||
try { url = new URL(trimmed); } catch { return null; }
|
||||
const hostPath = `${url.hostname}${url.pathname}`;
|
||||
return kebab(hostPath);
|
||||
}
|
||||
|
||||
// File path. Make it project-relative so two devs critiquing the same
|
||||
// checkout get the same slug regardless of where their repo is cloned.
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
|
||||
let rel = path.relative(cwd, abs);
|
||||
// If the target is outside cwd, fall back to the basename so we still
|
||||
// produce a stable slug (vs the absolute path, which would include
|
||||
// home dirs / usernames).
|
||||
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
rel = path.basename(abs);
|
||||
}
|
||||
if (!rel || rel === '.' || rel === '') return null;
|
||||
return kebab(rel);
|
||||
}
|
||||
|
||||
function kebab(s) {
|
||||
const slug = s
|
||||
.toLowerCase()
|
||||
.replace(/[/\\.]+/g, '-')
|
||||
.replace(/[^a-z0-9-]+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
if (!slug) return null;
|
||||
// Cap from the tail — the tail (filename) is more identifying than the
|
||||
// top-level directory.
|
||||
return slug.length <= SLUG_MAX ? slug : slug.slice(slug.length - SLUG_MAX).replace(/^-/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename-safe UTC ISO timestamp: hyphens for separators, trailing Z.
|
||||
* Plain colons aren't allowed on Windows filesystems.
|
||||
|
||||
@@ -312,17 +312,6 @@ const ANTIPATTERNS = [
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'numbered-section-markers',
|
||||
category: 'slop',
|
||||
scopes: ['layout'],
|
||||
severity: 'advisory',
|
||||
name: 'Numbered section markers (01 / 02 / 03)',
|
||||
description:
|
||||
'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'em-dash-overuse',
|
||||
category: 'slop',
|
||||
|
||||
@@ -280,22 +280,6 @@ const REGEX_ANALYZERS = [
|
||||
if (count === 0) return [];
|
||||
return [finding('marketing-buzzword', filePath, `${count} buzzword phrase${count === 1 ? '' : 's'}: "${firstSample}"`)];
|
||||
},
|
||||
// Numbered section markers (01 / 02 / 03 ...)
|
||||
(content, filePath) => {
|
||||
const text = stripHtmlToText(content);
|
||||
const re = /\b(0[1-9]|1[0-2])\b/g;
|
||||
const seen = new Set();
|
||||
let m;
|
||||
while ((m = re.exec(text)) !== null) seen.add(m[1]);
|
||||
if (seen.size < 3) return [];
|
||||
const sorted = [...seen].sort();
|
||||
let sequential = 0;
|
||||
for (let i = 1; i < sorted.length; i++) {
|
||||
if (parseInt(sorted[i], 10) === parseInt(sorted[i - 1], 10) + 1) sequential++;
|
||||
}
|
||||
if (sequential < 2) return [];
|
||||
return [finding('numbered-section-markers', filePath, `Sequence: ${sorted.slice(0, 6).join(', ')}`)];
|
||||
},
|
||||
// Aphoristic cadence: manufactured-contrast + short-rebuttal
|
||||
(content, filePath) => {
|
||||
const text = stripHtmlToText(content);
|
||||
@@ -430,21 +414,20 @@ function runRegexMatchers(lines, filePath, lineOffset = 0, blockContext = null,
|
||||
}
|
||||
|
||||
/** Page-level analyzers that scan rendered text content (em-dash use,
|
||||
* buzzword phrases, numbered section markers, aphoristic cadence).
|
||||
* buzzword phrases, aphoristic cadence).
|
||||
* These are detector-agnostic — they work on any HTML/text source
|
||||
* and don't need a parsed DOM. Exported so detectHtml can call them
|
||||
* for `.html` files (which otherwise skip the regex engine). */
|
||||
const TEXT_CONTENT_ANALYZER_IDS = [
|
||||
'em-dash-overuse',
|
||||
'marketing-buzzword',
|
||||
'numbered-section-markers',
|
||||
'aphoristic-cadence',
|
||||
];
|
||||
|
||||
function runTextContentAnalyzers(content, filePath, options = {}) {
|
||||
const profile = options?.profile;
|
||||
if (!shouldRunPageAnalyzers(content, filePath)) return [];
|
||||
// The 4 text-content analyzers are at indices 3-6 in REGEX_ANALYZERS.
|
||||
// The 3 text-content analyzers are at indices 3-5 in REGEX_ANALYZERS.
|
||||
const findings = [];
|
||||
for (let i = 0; i < TEXT_CONTENT_ANALYZER_IDS.length; i++) {
|
||||
const analyzer = REGEX_ANALYZERS[3 + i];
|
||||
@@ -535,7 +518,6 @@ function detectText(content, filePath, options = {}) {
|
||||
'monotonous-spacing',
|
||||
'em-dash-overuse',
|
||||
'marketing-buzzword',
|
||||
'numbered-section-markers',
|
||||
'aphoristic-cadence',
|
||||
'dark-glow',
|
||||
];
|
||||
|
||||
@@ -210,17 +210,6 @@ const ANTIPATTERNS = [
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'numbered-section-markers',
|
||||
category: 'slop',
|
||||
scopes: ['layout'],
|
||||
severity: 'advisory',
|
||||
name: 'Numbered section markers (01 / 02 / 03)',
|
||||
description:
|
||||
'Numbered display markers as section labels (01, 02, 03) are the AI editorial scaffold one tier deeper than tracked eyebrow chips. If you find yourself reaching for them, choose a different section cadence.',
|
||||
skillSection: 'Layout & Space',
|
||||
skillGuideline: 'numbered section markers',
|
||||
},
|
||||
{
|
||||
id: 'em-dash-overuse',
|
||||
category: 'slop',
|
||||
|
||||
@@ -352,27 +352,57 @@ function isAccentColor(cssColor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function resolveHeroHeadingSizePx(value) {
|
||||
const input = String(value || '').trim().toLowerCase();
|
||||
if (!input) return 0;
|
||||
|
||||
const simpleLengthPx = (token) => {
|
||||
const match = /^(-?\d*\.?\d+)\s*(px|rem|em|%)?$/.exec(String(token || '').trim());
|
||||
if (!match) return null;
|
||||
const amount = Number(match[1]);
|
||||
if (!Number.isFinite(amount)) return null;
|
||||
if (match[2] === 'rem' || match[2] === 'em') return amount * 16;
|
||||
if (match[2] === '%') return amount * 0.16;
|
||||
return amount;
|
||||
};
|
||||
|
||||
const direct = simpleLengthPx(input);
|
||||
if (direct !== null) return direct;
|
||||
|
||||
// Static CSS engines cannot resolve viewport units, but clamp's min/max
|
||||
// bounds still tell us whether the heading can ever reach hero scale.
|
||||
const clamp = /^clamp\((.*)\)$/.exec(input);
|
||||
if (clamp) {
|
||||
const parts = clamp[1].split(',');
|
||||
if (parts.length === 3) {
|
||||
const bounds = [simpleLengthPx(parts[0]), simpleLengthPx(parts[2])]
|
||||
.filter((candidate) => candidate !== null);
|
||||
if (bounds.length > 0) return Math.max(...bounds);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sibling-relationship rule. Anchor on a hero-scale h1, look at the
|
||||
// previousElementSibling, and gate on EITHER the classic tracked-
|
||||
// uppercase eyebrow OR the modern accent-colored bold eyebrow.
|
||||
function checkHeroEyebrow(opts) {
|
||||
const {
|
||||
headingTag, headingText, headingFontSize,
|
||||
headingInApplicationContext,
|
||||
siblingTag, siblingText, siblingTextTransform,
|
||||
siblingFontSize, siblingLetterSpacing,
|
||||
siblingFontWeight, siblingColor,
|
||||
siblingHasAccentDashPseudo,
|
||||
} = opts;
|
||||
if (headingTag !== 'h1') return [];
|
||||
// We previously gated on headingFontSize >= 48 to anchor "hero scale".
|
||||
// But modern hero h1s use clamp() / vw / var(--text-*), none of which
|
||||
// jsdom can resolve — the computed value comes back as "2em" or
|
||||
// "var(--text-9xl)" and parseFloat returns 2 or NaN. The gate fails
|
||||
// on virtually every Tailwind v4 / framework build. The other gates
|
||||
// (sibling text 2-60 chars, font-size ≤ 14px, accent-bold OR
|
||||
// tracked-caps) are tight enough to avoid false positives on non-
|
||||
// hero h1s — a tiny tan label directly above any h1 is the
|
||||
// antipattern regardless of how big the h1 ends up.
|
||||
// This is specifically a marketing-hero cliché, not a ban on compact
|
||||
// context labels in product UI (for example, a station name inside a tab
|
||||
// panel). Browser-computed sizes are reliable; the static adapter also
|
||||
// resolves ordinary px/rem/em and clamp() bounds before reaching here.
|
||||
if (headingInApplicationContext) return [];
|
||||
if (!(headingFontSize >= 48)) return [];
|
||||
if (!siblingTag) return [];
|
||||
// An h2 above an h1 is a different anti-pattern (heading hierarchy / dual
|
||||
// headings) — never an eyebrow.
|
||||
@@ -1938,6 +1968,7 @@ function checkElementHeroEyebrowDOM(el) {
|
||||
headingTag: tag,
|
||||
headingText: el.textContent || '',
|
||||
headingFontSize: parseFloat(headStyle.fontSize) || 0,
|
||||
headingInApplicationContext: !!el.closest('[role="tabpanel"], [role="dialog"], [role="application"], dialog'),
|
||||
siblingTag: sibling.tagName.toLowerCase(),
|
||||
siblingText: sibling.textContent || '',
|
||||
siblingTextTransform: sibStyle.textTransform || '',
|
||||
@@ -3367,7 +3398,8 @@ function checkElementHeroEyebrow(el, style, tag, window, customPropMap) {
|
||||
return checkHeroEyebrow({
|
||||
headingTag: tag,
|
||||
headingText: el.textContent || '',
|
||||
headingFontSize: parseFloat(headingFontSizeRaw) || 0,
|
||||
headingFontSize: resolveHeroHeadingSizePx(headingFontSizeRaw),
|
||||
headingInApplicationContext: !!el.closest?.('[role="tabpanel"], [role="dialog"], [role="application"], dialog'),
|
||||
siblingTag: sibling.tagName.toLowerCase(),
|
||||
siblingText: sibling.textContent || '',
|
||||
siblingTextTransform: sibStyle.textTransform || '',
|
||||
|
||||
@@ -46,6 +46,7 @@ import path from 'node:path';
|
||||
import { pathToFileURL, fileURLToPath } from 'node:url';
|
||||
import { extractPlatform, loadContext } from './context.mjs';
|
||||
import { IMPECCABLE_COMMAND } from './lib/provider.mjs';
|
||||
import { renderStopSlopReview } from './lib/slop-review.mjs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -1868,22 +1869,42 @@ export const CONTRACT_MAX_CHARS = 1800;
|
||||
// Cap contract sections per Stop emission so many touched artifacts cannot
|
||||
// stack an unbounded message.
|
||||
export const CONTRACT_AUDIT_MAX_FILES = 3;
|
||||
export const CONTRACT_EXTS = new Set(['.html', '.htm', '.astro', '.svelte', '.vue', '.jsx', '.tsx']);
|
||||
export const CONTRACT_REQUIRED_FIELDS = ['UNIQUE', 'NOT-TEMPLATE', 'OWN-WORLD', 'STORY', 'FIRST VIEWPORT', 'FORM'];
|
||||
|
||||
/**
|
||||
* Extract the artifact's own direction-contract comment: the first HTML
|
||||
* comment in the head of the file, when its opening chars identify it as a
|
||||
* contract/concept block. Returns the trimmed, length-capped body, or null
|
||||
* when the file carries none (no comment, unclosed comment, marker missing,
|
||||
* or the comment starts past the head window).
|
||||
* Extract the artifact's own direction-contract comment from the head of an
|
||||
* HTML or component file. Supports HTML-family comments and JSX block
|
||||
* comments so the contract works in the Astro/Svelte/Vue/React scaffolds the
|
||||
* skill actually builds. Returns the trimmed, length-capped body, or null
|
||||
* when the file carries no valid contract block.
|
||||
*/
|
||||
export function extractDirectionContract(content) {
|
||||
if (typeof content !== 'string' || !content) return null;
|
||||
const head = content.slice(0, CONTRACT_HEAD_CHARS);
|
||||
const m = /<!--([\s\S]*?)-->/.exec(head);
|
||||
if (!m) return null;
|
||||
const body = m[1].trim();
|
||||
if (!body || !/contract|concept/i.test(body.slice(0, CONTRACT_MARKER_CHARS))) return null;
|
||||
return body.slice(0, CONTRACT_MAX_CHARS);
|
||||
const candidates = [];
|
||||
for (const pattern of [/<!--([\s\S]*?)-->/g, /\{\/\*([\s\S]*?)\*\/\}/g]) {
|
||||
for (const match of head.matchAll(pattern)) {
|
||||
const index = match.index ?? 0;
|
||||
const linePrefix = head.slice(head.lastIndexOf('\n', index - 1) + 1, index).trim();
|
||||
if (linePrefix.startsWith('//')) continue;
|
||||
candidates.push({ index, body: match[1].trim() });
|
||||
}
|
||||
}
|
||||
candidates.sort((a, b) => a.index - b.index);
|
||||
for (const candidate of candidates) {
|
||||
if (!candidate.body || !/direction\s+contract|concept\s+contract/i.test(candidate.body.slice(0, CONTRACT_MARKER_CHARS))) continue;
|
||||
return candidate.body.slice(0, CONTRACT_MAX_CHARS);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function missingDirectionContractFields(contract) {
|
||||
const body = typeof contract === 'string' ? contract : '';
|
||||
return CONTRACT_REQUIRED_FIELDS.filter((field) => {
|
||||
const label = field.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\s+/g, '\\s+');
|
||||
return !new RegExp(`\\b${label}\\s*:`, 'i').test(body);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1899,7 +1920,11 @@ export function renderContractAudit(entries, opts = {}) {
|
||||
const shown = entries.slice(0, CONTRACT_AUDIT_MAX_FILES);
|
||||
const blocks = shown.map(({ filePath, contract }) => {
|
||||
const display = relativize(filePath, cwd);
|
||||
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}`;
|
||||
const missing = missingDirectionContractFields(contract);
|
||||
const integrity = missing.length > 0
|
||||
? `\n\nContract integrity defect: missing ${missing.join(', ')}. Repair the contract and the implementation together.`
|
||||
: '';
|
||||
return `${display} opens with this direction contract, written when the direction was decided:\n\n${contract}${integrity}`;
|
||||
});
|
||||
return [
|
||||
`${ENVELOPE_PREFIX} Direction-contract audit. Before finishing, audit the rendered page against the contract it opens with, promise by promise.`,
|
||||
@@ -1984,9 +2009,22 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
return result({ skipped: 'native-platform', platform, durationMs: Date.now() - started });
|
||||
}
|
||||
|
||||
const session = ensureSession(cache, sessionId);
|
||||
const needsSlopReview = session.llmSlopReviewed !== true;
|
||||
|
||||
const det = detector || await loadDetector();
|
||||
if (!det || typeof det.detectText !== 'function') {
|
||||
return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
|
||||
if (!needsSlopReview) return result({ skipped: 'detector-missing', durationMs: Date.now() - started });
|
||||
session.llmSlopReviewed = true;
|
||||
session.updatedAt = Date.now();
|
||||
persistCache(projectCwd, cache);
|
||||
const text = renderStopSlopReview();
|
||||
return {
|
||||
exitCode: 0,
|
||||
stdout: payload(text, 'Stop', harness),
|
||||
emission: { kind: 'stop-llm-slop-review', llmSlopReview: true },
|
||||
audit: { ...audit, emitted: true, detectorMissing: true, llmSlopReview: true, chars: text.length, durationMs: Date.now() - started },
|
||||
};
|
||||
}
|
||||
const scanOptions = designSystemOptions(config, det, projectCwd);
|
||||
|
||||
@@ -2013,10 +2051,11 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
? configuredExt.engine === 'html'
|
||||
: (ext === '.html' || ext === '.htm');
|
||||
|
||||
// Direction-contract audit: HTML artifacts only, at most once per file
|
||||
// Direction-contract audit: HTML and component artifacts, at most once per file
|
||||
// per session. The flag lives on the same session cache entry the
|
||||
// finding dedupe uses, so a second Stop fire stays quiet about it.
|
||||
if (useHtmlEngine) {
|
||||
const contractCapable = useHtmlEngine || CONTRACT_EXTS.has(ext);
|
||||
if (contractCapable) {
|
||||
const fileEntry = ensureFile(cache, sessionId, filePath);
|
||||
if (!fileEntry.contractAudited) {
|
||||
const contract = extractDirectionContract(content);
|
||||
@@ -2046,10 +2085,15 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
}
|
||||
audit.scannedFiles = scanned;
|
||||
|
||||
if (freshGroups.length === 0 && contractEntries.length === 0) {
|
||||
if (freshGroups.length === 0 && contractEntries.length === 0 && !needsSlopReview) {
|
||||
return result({ emitted: false, skipped: 'stop-clean', durationMs: Date.now() - started });
|
||||
}
|
||||
|
||||
if (needsSlopReview) {
|
||||
session.llmSlopReviewed = true;
|
||||
session.updatedAt = Date.now();
|
||||
}
|
||||
|
||||
// Fresh findings and first-time contract audits earn the cache write;
|
||||
// both mark this batch as surfaced so the next Stop fire is silent
|
||||
// unless new issues appear.
|
||||
@@ -2064,6 +2108,9 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
if (contractEntries.length > 0) {
|
||||
parts.push(renderContractAudit(contractEntries, { cwd: projectCwd }));
|
||||
}
|
||||
if (needsSlopReview) {
|
||||
parts.push(renderStopSlopReview());
|
||||
}
|
||||
const text = appendDesignSystemNote(parts.join('\n\n'), scanOptions);
|
||||
return {
|
||||
exitCode: 0,
|
||||
@@ -2074,6 +2121,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
...(contractEntries.length > 0
|
||||
? { contractFiles: contractEntries.map((entry) => entry.filePath) }
|
||||
: {}),
|
||||
...(needsSlopReview ? { llmSlopReview: true } : {}),
|
||||
},
|
||||
audit: {
|
||||
...audit,
|
||||
@@ -2081,6 +2129,7 @@ export async function runStopHook({ stdinJson, env = {}, cwd = process.cwd(), no
|
||||
freshFiles: freshGroups.length,
|
||||
freshFindings: freshGroups.reduce((sum, group) => sum + group.findings.length, 0),
|
||||
...(contractEntries.length > 0 ? { contractAudits: contractEntries.length } : {}),
|
||||
...(needsSlopReview ? { llmSlopReview: true } : {}),
|
||||
chars: text.length,
|
||||
durationMs: Date.now() - started,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Source scripts default to slash commands. The provider build replaces only
|
||||
// this exact declaration, avoiding heuristic rewrites across executable code.
|
||||
export const IMPECCABLE_COMMAND_PREFIX = "/";
|
||||
export const IMPECCABLE_PROVIDER_ID = "claude-code";
|
||||
export const IMPECCABLE_COMMAND = `${IMPECCABLE_COMMAND_PREFIX}impeccable`;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
export const LLM_ONLY_SLOP_ITEMS = Object.freeze([
|
||||
'Monospace used merely to signal “technical” or “developer.”',
|
||||
'Light or dark mode chosen by category habit rather than the actual use scene.',
|
||||
'Everything wrapped in cards, or identical icon-heading-text cards repeated as the page structure.',
|
||||
'Hero-metric scaffolds: one oversized number, a small label, supporting stats, and an accent treatment.',
|
||||
'Decorative glassmorphism, meaningless sparklines, or generic rounded rectangles with drop shadows.',
|
||||
'A modal chosen by reflex when the task does not require interruption or protected focus.',
|
||||
]);
|
||||
|
||||
export function renderLlmOnlySlopReview({ manualDetector = false, automaticDetector = false, scriptsPath = null } = {}) {
|
||||
const lines = [
|
||||
automaticDetector
|
||||
? 'AI_SLOP_REVIEW_REQUIRED: The automatic detector covers mechanical rules, but this harness has no reliable late review. Before finishing changed UI, inspect the authored result for detector-blind model reflexes:'
|
||||
: 'AI_SLOP_REVIEW_REQUIRED: The automatic Impeccable design hook is not available for this session. Before finishing changed UI, inspect the authored result for detector-blind model reflexes:',
|
||||
...LLM_ONLY_SLOP_ITEMS.map((item) => `- ${item}`),
|
||||
'Fix reflexes, not intentional choices required by the brief or established visual authority.',
|
||||
];
|
||||
if (manualDetector && scriptsPath) {
|
||||
lines.push(`Then run the mechanical detector once over the changed web UI: \`node ${scriptsPath}/detect.mjs --json <changed targets>\`. Do not run it earlier during concept selection.`);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
export function renderStopSlopReview() {
|
||||
return [
|
||||
'[impeccable@1] Detector-blind AI-slop review. The mechanical pass is complete; now inspect the rendered result for model reflexes it cannot reliably detect:',
|
||||
...LLM_ONLY_SLOP_ITEMS.map((item) => `- ${item}`),
|
||||
'Fix reflexes, not intentional choices required by the brief or established visual authority. Do not rerun the detector; this is the authored judgment layer.',
|
||||
].join('\n');
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { slugFromTarget } from './target-slug.mjs';
|
||||
|
||||
export const SURFACE_BRIEF_VERSION = 1;
|
||||
|
||||
export function getSurfaceBriefDir(projectRoot) {
|
||||
return path.join(projectRoot, '.impeccable', 'surfaces');
|
||||
}
|
||||
|
||||
export function normalizeSurfaceTarget(target, { projectRoot = process.cwd() } = {}) {
|
||||
if (!target || typeof target !== 'string' || !target.trim()) return null;
|
||||
const trimmed = target.trim();
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
try {
|
||||
const url = new URL(trimmed);
|
||||
url.hash = '';
|
||||
url.search = '';
|
||||
return url.toString().replace(/\/$/, '') || url.origin;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (/^route:/i.test(trimmed)) {
|
||||
const route = trimmed.slice(trimmed.indexOf(':') + 1).trim();
|
||||
if (!route.startsWith('/') || route.includes('..')) return null;
|
||||
const normalizedRoute = route.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
|
||||
return `route:${normalizedRoute}`;
|
||||
}
|
||||
if (trimmed === '/') return 'route:/';
|
||||
if (trimmed.startsWith('/')) {
|
||||
const absolute = path.resolve(trimmed);
|
||||
const relativeToProject = path.relative(projectRoot, absolute);
|
||||
const isProjectFile = relativeToProject && !relativeToProject.startsWith('..') && !path.isAbsolute(relativeToProject);
|
||||
if (!isProjectFile && !fs.existsSync(absolute) && !trimmed.includes('..')) {
|
||||
const normalizedRoute = trimmed.split(/[?#]/, 1)[0].replace(/\/{2,}/g, '/').replace(/\/$/, '') || '/';
|
||||
return `route:${normalizedRoute}`;
|
||||
}
|
||||
}
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
|
||||
const rel = path.relative(projectRoot, abs);
|
||||
if (!rel || rel === '.' || rel.startsWith('..') || path.isAbsolute(rel)) return null;
|
||||
return rel.split(path.sep).join('/');
|
||||
}
|
||||
|
||||
export function surfaceBriefPathForTarget(target, { projectRoot = process.cwd() } = {}) {
|
||||
const normalized = normalizeSurfaceTarget(target, { projectRoot });
|
||||
if (!normalized) return null;
|
||||
const slugInput = normalized.startsWith('route:') ? `route${normalized.slice('route:'.length)}` : normalized;
|
||||
const slug = slugFromTarget(slugInput, { cwd: projectRoot });
|
||||
return slug ? path.join(getSurfaceBriefDir(projectRoot), `${slug}.md`) : null;
|
||||
}
|
||||
|
||||
export function parseSurfaceBrief(text, filePath = null) {
|
||||
const match = String(text || '').match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
||||
const meta = {};
|
||||
if (match) {
|
||||
for (const line of match[1].split(/\r?\n/)) {
|
||||
const colon = line.indexOf(':');
|
||||
if (colon < 0) continue;
|
||||
const key = line.slice(0, colon).trim();
|
||||
const raw = line.slice(colon + 1).trim();
|
||||
if (!key) continue;
|
||||
if (/^(?:\[|\{|\")/.test(raw) || /^(?:true|false|null|-?\d+(?:\.\d+)?)$/.test(raw)) {
|
||||
try { meta[key] = JSON.parse(raw); continue; } catch { /* keep string */ }
|
||||
}
|
||||
meta[key] = raw.replace(/^['"]|['"]$/g, '');
|
||||
}
|
||||
}
|
||||
const primaryTarget = typeof meta.primary_target === 'string' ? meta.primary_target : null;
|
||||
const relatedTargets = Array.isArray(meta.related_targets)
|
||||
? meta.related_targets.filter((value) => typeof value === 'string')
|
||||
: [];
|
||||
return {
|
||||
path: filePath,
|
||||
text: String(text || ''),
|
||||
body: match ? String(text || '').slice(match[0].length).trim() : String(text || '').trim(),
|
||||
meta,
|
||||
slug: typeof meta.slug === 'string' ? meta.slug : filePath ? path.basename(filePath, '.md') : null,
|
||||
primaryTarget,
|
||||
relatedTargets,
|
||||
targets: [primaryTarget, ...relatedTargets].filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
export function listSurfaceBriefs(projectRoot = process.cwd()) {
|
||||
const dir = getSurfaceBriefDir(projectRoot);
|
||||
let names;
|
||||
try {
|
||||
names = fs.readdirSync(dir).filter((name) => name.endsWith('.md')).sort();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
return names.flatMap((name) => {
|
||||
const filePath = path.join(dir, name);
|
||||
try {
|
||||
return [parseSurfaceBrief(fs.readFileSync(filePath, 'utf-8'), filePath)];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveSurfaceBrief(projectRoot = process.cwd(), target = null) {
|
||||
const briefs = listSurfaceBriefs(projectRoot);
|
||||
if (!target) {
|
||||
return {
|
||||
brief: briefs.length === 1 ? briefs[0] : null,
|
||||
candidates: briefs,
|
||||
reason: briefs.length === 1 ? 'only-brief' : briefs.length > 1 ? 'ambiguous' : 'none',
|
||||
};
|
||||
}
|
||||
|
||||
const normalized = normalizeSurfaceTarget(target, { projectRoot });
|
||||
if (!normalized) return { brief: null, candidates: briefs, reason: 'invalid-target' };
|
||||
const exactPath = surfaceBriefPathForTarget(normalized, { projectRoot });
|
||||
const exact = briefs.find((brief) => brief.path === exactPath && (!brief.targets.length || brief.targets.includes(normalized)));
|
||||
if (exact) return { brief: exact, candidates: briefs, reason: 'slug' };
|
||||
const mapped = briefs.filter((brief) => brief.targets.includes(normalized));
|
||||
return {
|
||||
brief: mapped.length === 1 ? mapped[0] : null,
|
||||
candidates: mapped.length > 1 ? mapped : briefs,
|
||||
reason: mapped.length === 1 ? 'mapping' : mapped.length > 1 ? 'ambiguous-target' : 'not-found',
|
||||
};
|
||||
}
|
||||
|
||||
export function writeSurfaceBrief({
|
||||
projectRoot = process.cwd(),
|
||||
primaryTarget,
|
||||
relatedTargets = [],
|
||||
body,
|
||||
}) {
|
||||
const normalizedPrimary = normalizeSurfaceTarget(primaryTarget, { projectRoot });
|
||||
if (!normalizedPrimary) throw new Error('surface brief requires a concrete project-relative primary target or URL');
|
||||
const normalizedRelated = [...new Set(relatedTargets
|
||||
.map((target) => normalizeSurfaceTarget(target, { projectRoot }))
|
||||
.filter((target) => target && target !== normalizedPrimary))];
|
||||
const slug = slugFromTarget(normalizedPrimary, { cwd: projectRoot });
|
||||
const filePath = surfaceBriefPathForTarget(normalizedPrimary, { projectRoot });
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
const frontmatter = [
|
||||
'---',
|
||||
`version: ${SURFACE_BRIEF_VERSION}`,
|
||||
`slug: ${JSON.stringify(slug)}`,
|
||||
`primary_target: ${JSON.stringify(normalizedPrimary)}`,
|
||||
`related_targets: ${JSON.stringify(normalizedRelated)}`,
|
||||
'---',
|
||||
].join('\n');
|
||||
fs.writeFileSync(filePath, `${frontmatter}\n\n${String(body || '').trim()}\n`, 'utf-8');
|
||||
return filePath;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import path from 'node:path';
|
||||
|
||||
const SLUG_MAX = 50;
|
||||
|
||||
/** Derive one clone-stable slug from a concrete file path or URL. */
|
||||
export function slugFromTarget(resolved, { cwd = process.cwd() } = {}) {
|
||||
if (!resolved || typeof resolved !== 'string') return null;
|
||||
const trimmed = resolved.trim();
|
||||
if (!trimmed) return null;
|
||||
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
let url;
|
||||
try { url = new URL(trimmed); } catch { return null; }
|
||||
return kebab(`${url.hostname}${url.pathname}`);
|
||||
}
|
||||
|
||||
const abs = path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
|
||||
let rel = path.relative(cwd, abs);
|
||||
if (rel.startsWith('..') || path.isAbsolute(rel)) rel = path.basename(abs);
|
||||
if (!rel || rel === '.') return null;
|
||||
return kebab(rel);
|
||||
}
|
||||
|
||||
export function kebab(value) {
|
||||
const slug = String(value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[/\\.]+/g, '-')
|
||||
.replace(/[^a-z0-9-]+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
if (!slug) return null;
|
||||
return slug.length <= SLUG_MAX ? slug : slug.slice(slug.length - SLUG_MAX).replace(/^-/, '');
|
||||
}
|
||||
@@ -2592,7 +2592,7 @@
|
||||
minWidth: '16px', height: '16px', padding: '0 4px',
|
||||
borderRadius: '999px',
|
||||
background: tuneOpen ? C.brand : BP.hairline,
|
||||
color: tuneOpen ? 'oklch(98% 0 0)' : 'inherit',
|
||||
color: tuneOpen ? C.ink : 'inherit',
|
||||
fontFamily: MONO, fontSize: '9.5px', fontWeight: '600',
|
||||
lineHeight: '1',
|
||||
boxSizing: 'border-box',
|
||||
@@ -3131,7 +3131,7 @@
|
||||
position: 'absolute', top: '2px',
|
||||
left: initial ? '18px' : '2px',
|
||||
width: '16px', height: '16px', borderRadius: '50%',
|
||||
background: 'oklch(98% 0 0)',
|
||||
background: C.ink,
|
||||
transition: 'left 0.18s ' + EASE,
|
||||
boxShadow: '0 1px 2px oklch(0% 0 0 / 0.2)',
|
||||
});
|
||||
@@ -3165,7 +3165,7 @@
|
||||
const b = el('button', {
|
||||
padding: '5px 4px', border: 'none', borderRadius: '3px',
|
||||
background: active ? C.brand : 'transparent',
|
||||
color: active ? 'oklch(98% 0 0)' : P.text,
|
||||
color: active ? C.ink : P.text,
|
||||
fontFamily: FONT, fontSize: '10.5px', fontWeight: '500',
|
||||
cursor: 'pointer', whiteSpace: 'nowrap',
|
||||
transition: 'background 0.1s ease, color 0.1s ease',
|
||||
@@ -3178,7 +3178,7 @@
|
||||
segBtns.forEach(({ btn, val }) => {
|
||||
const on = val === o.value;
|
||||
btn.style.background = on ? C.brand : 'transparent';
|
||||
btn.style.color = on ? 'oklch(98% 0 0)' : P.text;
|
||||
btn.style.color = on ? C.ink : P.text;
|
||||
});
|
||||
applyParamValue(variantEl, p, o.value);
|
||||
queueCheckpoint('param_changed');
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
import { resolveProjectRoot } from './context.mjs';
|
||||
import {
|
||||
listSurfaceBriefs,
|
||||
resolveSurfaceBrief,
|
||||
surfaceBriefPathForTarget,
|
||||
writeSurfaceBrief,
|
||||
} from './lib/surface-briefs.mjs';
|
||||
|
||||
function summary(brief, projectRoot) {
|
||||
return {
|
||||
slug: brief.slug,
|
||||
path: path.relative(projectRoot, brief.path).split(path.sep).join('/'),
|
||||
primaryTarget: brief.primaryTarget,
|
||||
relatedTargets: brief.relatedTargets,
|
||||
};
|
||||
}
|
||||
|
||||
function main(argv) {
|
||||
const [command, target, bodyFile, ...relatedTargets] = argv;
|
||||
const projectRoot = resolveProjectRoot(process.cwd(), target ? { targetPath: target } : {});
|
||||
if (command === 'path') {
|
||||
const filePath = surfaceBriefPathForTarget(target, { projectRoot });
|
||||
if (!filePath) throw new Error('surface brief path requires a concrete target');
|
||||
process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
|
||||
return;
|
||||
}
|
||||
if (command === 'list') {
|
||||
process.stdout.write(`${JSON.stringify(listSurfaceBriefs(projectRoot).map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
|
||||
return;
|
||||
}
|
||||
if (command === 'read') {
|
||||
const result = resolveSurfaceBrief(projectRoot, target || null);
|
||||
if (result.brief) {
|
||||
process.stdout.write(result.brief.text);
|
||||
return;
|
||||
}
|
||||
if (result.candidates.length) process.stderr.write(`${JSON.stringify(result.candidates.map((brief) => summary(brief, projectRoot)), null, 2)}\n`);
|
||||
process.exit(2);
|
||||
}
|
||||
if (command === 'write') {
|
||||
if (!target || !bodyFile) throw new Error('usage: surface-brief.mjs write <primary-target> <body-file>');
|
||||
const filePath = writeSurfaceBrief({
|
||||
projectRoot,
|
||||
primaryTarget: target,
|
||||
relatedTargets,
|
||||
body: fs.readFileSync(bodyFile, 'utf-8'),
|
||||
});
|
||||
process.stdout.write(`${path.relative(process.cwd(), filePath) || filePath}\n`);
|
||||
return;
|
||||
}
|
||||
throw new Error('usage: surface-brief.mjs <path|list|read|write> [target] [body-file] [related-target ...]');
|
||||
}
|
||||
|
||||
function isMainModule() {
|
||||
if (!process.argv[1]) return false;
|
||||
try {
|
||||
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1]);
|
||||
} catch {
|
||||
return import.meta.url === pathToFileURL(process.argv[1]).href;
|
||||
}
|
||||
}
|
||||
|
||||
if (isMainModule()) {
|
||||
try {
|
||||
main(process.argv.slice(2));
|
||||
} catch (error) {
|
||||
process.stderr.write(`${error?.message || error}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,59 @@
|
||||
---
|
||||
name: impeccable
|
||||
description: Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.
|
||||
version: 4.0.0-alpha.9
|
||||
version: 4.0.0-alpha.10
|
||||
license: Apache 2.0
|
||||
---
|
||||
|
||||
Designs and iterates production-grade frontend interfaces. Real working code, committed design choices, exceptional craft.
|
||||
This skill gives you the tools and permission to create design that earns to be called out-of-distribution craft: Whereas before, your design work would have been safe, timid and measured, you now approach every design task as a award-winning design director with impeccable understanding for what makes exceptional design work: production-grade code, peak creativity, a clear POV, deep understanding of the needs of the client and users, and exceptional craft.
|
||||
|
||||
Approach every design task as the design lead at a small studio known for giving every client a visual identity that could not be mistaken for anyone else's. The client has already rejected work that felt templated; they are paying for a point of view. the model is capable of extraordinary work. Don't hold back.
|
||||
Core principles:
|
||||
- Go all out. No hedging, no shortcuts. The deliverable must be complete (except assets the user must provide).
|
||||
- Dream big and bold. Distinct, beautiful, outstanding and highly inspiring work.
|
||||
- Iterate with tools available to you (e.g. visual understanding, browser screenshots) until you think this meets the bar.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Run `node .cursor/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). It prints the project's context and its directives; follow what it prints. Once its output is in the conversation, never rerun it on a later turn.
|
||||
2. `craft` and `shape` are build-path exceptions: the new-work gate below owns their flow, and on unattended runs its checkpoints resolve without pausing. For any other invoked sub-command (`audit`, `polish`, `live`, ...), immediately read **`reference/<command>.md`** after `context.mjs` (the `.native` variant from the Commands table when the platform is `ios`/`android`/`adaptive`) and follow it. This read is a hard gate: do not inspect the target, run command-specific scripts, or edit files until the reference is loaded.
|
||||
3. Read at least one project file (CSS / tokens / theme / a representative component) to learn what world you're in. If PRODUCT.md's `## Platform` is `ios` or `android`, also read `reference/<platform>.md` (`adaptive` reads both).
|
||||
1. Run `node .cursor/skills/impeccable/scripts/context.mjs` once per session (if the runtime shows this skill's loaded base directory, run `node <skill-base-dir>/scripts/context.mjs`; keep cwd at the user's project). Pass a named source file or route as `--target <path>`. It loads PRODUCT.md, DESIGN.md, the matching surface brief, and native-platform guidance when applicable; follow its directives and do not rerun it.
|
||||
2. Before acting, load the one playbook that owns the request: the Commands table's reference for an explicit or clearly implied sub-command, or [reference/new-work.md](reference/new-work.md) for a new surface or replacement visual world. Then inspect the target and at least one representative source of incumbent visual truth (tokens, theme, CSS, component, or asset) before editing.
|
||||
|
||||
## How to design
|
||||
|
||||
**The brief wins.** Where the brief pins down a direction (a named aesthetic, an era, a place, a material, a specific font or palette), follow it exactly, including when it asks for a look this skill warns is saturated. Redirecting a pinned direction toward your own taste is a failure, not a save.
|
||||
|
||||
**Existing worlds are sacred.** Most of impeccable's work happens inside a site or app that already exists. When the surface has a committed design system (real tokens, deliberately chosen faces, a palette the brand owns), work inside that world: extend it, sharpen it, leave it unmistakably the same brand, and never degrade a working page's performance. Inventing parallel colors, fonts, or styles on an existing surface is a defect, not creativity. A scoped refinement keeps the named scope's content and media footprint unless the brief explicitly changes them; build the added emphasis by recomposing what is already there through hierarchy, proportion, rhythm, and the system's own motifs.
|
||||
|
||||
**New identity work reads the playbook first.** When nothing committed exists (greenfield, or a codebase with no real tokens or chosen faces), or the user explicitly asks for a redesign that discards the current look, you MUST read [reference/new-work.md](reference/new-work.md) before making any design decision. Missing DESIGN.md alone does not make work greenfield: code, tokens, chosen type, components, and assets are incumbent design authority. Preserve and extend them unless the user asked to replace them. Producing a genuinely new identity without the playbook yields the generic default this skill exists to prevent. Scoped fixes inside an existing world don't need it; the craft floor below governs them. `context.mjs` prints the appropriate authority directive.
|
||||
- **The brief wins.** Honor pinned aesthetics, eras, materials, fonts, and palettes even when they conflict with a saturated-pattern warning. Redirecting a clear brief toward your taste is failure.
|
||||
- **Refinement preserves; redesign replaces.** Refinement keeps the incumbent identity, behavior, copy, and everything outside scope. Ask before replacing factual copy or adding claims. Redesign keeps product truth, content, function, native affordances, and constraints, but treats the old look as evidence and anti-reference; choose a replacement world in new-work and replace DESIGN.md. Never split the difference into polish on the discarded look.
|
||||
- **Visual authority is evidence, not a filename.** Missing DESIGN.md alone does not make a project greenfield; new-work decides whether to preserve, expand, or replace the incumbent world.
|
||||
|
||||
## Modes
|
||||
|
||||
Name the visitor's mode before designing; the page's grammar follows from it, and most ruined pages are one mode wearing another mode's grammar. **The mode belongs to the surface, not the subject**: a landing page for a dense technical tool is still Persuade, with Persuade's full permission to be striking; a docs page for a fashion house is still Read. Deciding a page can be plain because its subject is workmanlike is the same category error in reverse. The brief and the surface decide the mode; PRODUCT.md's `register` field survives only as a family hint (`brand` covers Persuade and Experience, `product` covers Operate and Read). Depth beyond the paragraphs below: [reference/new-work.md](reference/new-work.md) when inventing identity, [reference/operate.md](reference/operate.md) for substantial Operate and Read work.
|
||||
Choose the mode from the requested surface, not the product, and persist it only in that surface brief. A tool's landing page is still Persuade; a fashion house's documentation is still Read. See [new-work.md](reference/new-work.md) for new surfaces and [operate.md](reference/operate.md) for deeper Operate/Read guidance.
|
||||
|
||||
**Persuade** (the surface exists to win someone over; design IS the product). The deliverable is an impression that stops the scroll, earns the click, converts. Spans every genre; don't collapse them into one look. On new surfaces, briefs that imply imagery must ship real, verified imagery; a colored rectangle where a photo belongs reads as incomplete. New Persuade surfaces take their typeface procedure and reject list from [reference/new-work.md](reference/new-work.md).
|
||||
|
||||
**Operate** (the surface is a tool someone works in; design SERVES the task). A person getting something done: scanability and consistency outrank expressiveness. These surfaces earn trust by feeling native to their platform: system font stacks and workhorse UI faces are legitimate and often correct here (the Persuade reject list does not apply). The brand lives in the details: focus states, empty states, microcopy, one owned accent. The usage scene is part of the spec: an interface read outdoors, in motion, or at a glance must survive its real ambient light, and the theme follows the scene, not the category's habit.
|
||||
|
||||
**Read** (the surface exists to be understood; long-form, reference, guidance). The deliverable is comprehension, and comprehension is earned twice: a structure the reader can hold in their head with nothing standing between them and the answer, and a reading experience good enough to stay in, through typographic quality and whatever visual or interactive support genuinely helps the reader follow. The brand lives in type, spacing, and small accents.
|
||||
|
||||
**Experience** (the surface presents a body of work; the page IS the work). The artifact leads, the interface recedes, and the visitor meets the work itself in the first viewport at every screen size. Boldness here means trusting the work.
|
||||
- **Persuade:** win someone over; design is the product. Earn attention and action. Ship real imagery when the brief needs it; follow the committed world, not category habit.
|
||||
- **Operate:** help someone do work. Scanability, consistency, native expectations, and the real usage scene outrank expression. Brand lives in precise details.
|
||||
- **Read:** make something understood. Structure for comprehension, then make the reading experience worth staying in.
|
||||
- **Experience:** present a body of work. Let the artifact lead from the first viewport; the interface recedes.
|
||||
|
||||
## Craft floor
|
||||
|
||||
Build to this floor without announcing it. The design detector (the project hook, `node .cursor/skills/impeccable/scripts/detect.mjs --json <file>`, or `audit`) verifies most of it mechanically; resolve every finding before finalizing. Fix real defects, but use context judgment rather than distorting intentional design to appease a false positive. Classify any intentional exception explicitly and use the hook system's narrowest appropriate waiver when it must persist.
|
||||
Build to this floor without announcing it.
|
||||
|
||||
- Contrast: body text ≥4.5:1 against its background (placeholders too); large text ≥3:1. 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.
|
||||
- Shadows describe real light: an offset and a soft blur. A zero-offset colored halo is decoration announcing itself.
|
||||
- Spacing has rhythm: generous separations, tight groupings; cramped padding reads as broken; the space above a heading exceeds the space below it. Verify computed spacing, not intended spacing.
|
||||
- Type: body line length 65-75ch; display clamp() max ≤6rem; letter-spacing ≥-0.04em; `text-wrap: balance` on headings; modular scale ≥1.25 between steps; light-on-dark adds 0.05-0.1 line-height. Pair faces on a contrast axis, never two similar-but-not-identical ones; one family with committed weight contrast beats a timid pair. Test headings at every breakpoint; overflow means reduce the clamp or rewrite the copy.
|
||||
- Motion is part of the build: one orchestrated moment beats scattered effects; ease-out exponential curves; reveals enhance an already-visible default (content gated on a class-triggered transition ships blank in hidden tabs and headless renderers). Responsive down to mobile and visible keyboard focus are part of the floor.
|
||||
- Ship real content (no placeholders, dead links, or fake controls) and cover the interaction states people will actually hit (hover, focus, disabled, loading, error, empty).
|
||||
- Copy is design material: name things the way the page's own people speak, make every control say what it does, and make every error say what happened and what to do next.
|
||||
- Before finishing, re-read the brief: every requirement it names must exist on the page, findable in seconds. A beautiful page missing an asked-for feature is unfinished.
|
||||
- **Contrast:** body and placeholder text ≥4.5:1; large text ≥3:1. On colored surfaces, tint secondary text from that hue or the foreground instead of using gray.
|
||||
- **Depth:** shadows describe light with offset and soft blur; zero-offset colored halos are decoration.
|
||||
- **Spacing:** tight groups, generous separation, no cramped containers; space above a heading exceeds space below. Verify computed values.
|
||||
- **Type:** body measure 65–75ch; display max 6rem and tracking floor -0.04em; balance headings; use clear scale/weight contrast; test overflow at every breakpoint.
|
||||
- **Motion:** author one coherent moment instead of scattered effects. Use exponential ease-out and an already-visible default. Premium motion is not transform/opacity alone: it may add focus, depth, masks, light, or material change through blur/filter, backdrop-filter, clip-path/masks, or shadow when smooth. Always provide reduced motion.
|
||||
- **Shipping:** real content, working controls, responsive composition, keyboard focus, and the states users hit: hover, disabled, loading, error, and empty.
|
||||
- **Copy:** use the product's language; controls name their action, errors name the problem and recovery.
|
||||
- **Coverage:** every brief requirement must exist and be findable within seconds.
|
||||
|
||||
Before finishing changed UI, follow the quality guidance supplied by `context.mjs` and hooks. Context requests a manual scan only when no automatic detector is active; never add a second detector pass.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Category | Description | Reference |
|
||||
|---|---|---|---|
|
||||
| `craft [feature]` | Build | The standard build flow with attended checkpoints | [reference/new-work.md](reference/new-work.md) |
|
||||
| `craft [feature]` | Build | Deprecated alias for an ordinary new-work request | [reference/craft.md](reference/craft.md) |
|
||||
| `shape [feature]` | Build | Plan UX/UI before writing code | [reference/shape.md](reference/shape.md) |
|
||||
| `init` | Build | Set up project context: PRODUCT.md, DESIGN.md, live config, next steps | [reference/init.md](reference/init.md) |
|
||||
| `init` | Build | Capture durable product context in PRODUCT.md | [reference/init.md](reference/init.md) |
|
||||
| `document` | Build | Generate DESIGN.md from existing project code | [reference/document.md](reference/document.md) |
|
||||
| `extract [target]` | Build | Pull reusable tokens and components into design system | [reference/extract.md](reference/extract.md) |
|
||||
| `critique [target]` | Evaluate | UX design review with heuristic scoring | [reference/critique.md](reference/critique.md) |
|
||||
@@ -76,7 +75,14 @@ Build to this floor without announcing it. The design detector (the project hook
|
||||
| `optimize [target]` | Fix | Diagnose and fix UI performance | [reference/optimize.md](reference/optimize.md) |
|
||||
| `live` | Iterate | Visual variant mode: pick elements in the browser, generate alternatives | [reference/live.md](reference/live.md) |
|
||||
|
||||
Routing: **no argument** → read [reference/routing.md](reference/routing.md) and present the context-aware menu (never auto-run a command). **First word matches a command** (or `pin` / `unpin` / `hooks`) → load its reference (native variant on native platforms) and follow it; everything after the command name is the target. **Intent clearly maps to one command** ("fix the spacing" → `layout`, "rewrite this error" → `clarify`) → same; if two fit, ask once. **Otherwise** → general design invocation: apply Setup and this file's guidance; builds flow through the new-work gate above, whose playbook carries the direction checkpoint and the finishing pass. `teach` routes to `init`, and `craft` routes to the standard build flow with attended checkpoints. If setup diverted into `init` for a build request, finish init, refresh context, then resume.
|
||||
Routing:
|
||||
|
||||
- **No argument:** read [routing.md](reference/routing.md) and present its context-aware menu; never auto-run a command.
|
||||
- **Explicit or clearly implied command:** load its reference (native variant on native platforms) and follow it. Ask once if two commands fit.
|
||||
- **Otherwise:** treat the request as general design work. Missing PRODUCT.md routes through init; new surfaces and replacement worlds use new-work.
|
||||
- `teach` aliases `init`. `craft` is a deprecated alias for ordinary new-work and adds nothing. `shape` owns task discovery, then enters new-work only for visual-world and surface-concept decisions.
|
||||
|
||||
After init writes PRODUCT.md, resume without rerunning `context.mjs`.
|
||||
|
||||
**Pin / Unpin:** `node .cursor/skills/impeccable/scripts/pin.mjs <pin|unpin> <command>` creates or removes a standalone `/<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native Android apps: Jetpack Compose, Android Views, React Native, Expo, Flutter shipping to Android hardware.
|
||||
|
||||
On native, register narrows. Material Design 3 governs structure, navigation, and interaction whatever the register; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
On native, the visitor mode narrows what expression may override. Material Design 3 governs structure, navigation, and interaction in every mode; brand expresses through Material's theming (color roles, type scale, shape, motion). A Material-everywhere cross-platform app that also ships to iPhone still owes iOS its OS guarantees on that hardware: safe-area insets, Reduce Motion, edge-swipe back.
|
||||
|
||||
## The Android slop test
|
||||
|
||||
|
||||
@@ -1,203 +1,88 @@
|
||||
> **Additional context needed**: performance constraints.
|
||||
|
||||
Add motion that conveys state, gives feedback, and clarifies hierarchy. Cut motion that exists only for decoration. Animation fatigue is a real cost; spend the budget on the moments that need it.
|
||||
Use motion to explain state, relationship, and hierarchy, or to create one authored moment the surface has earned. Decoration without purpose is animation debt.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: motion is part of the voice; one well-rehearsed entrance beats scattered micro-interactions. The saturated AI default is fade-and-rise reveals on every scrolled section; that's a tell, not a choreography. Reserve scroll-triggered motion for moments that earn it.
|
||||
- **Persuade + Experience:** motion may carry the voice. Prefer one rehearsed focal sequence to repeated section reveals.
|
||||
- **Operate + Read:** motion serves feedback, state, and continuity. Keep routine transitions fast and do not make users wait through page-load choreography.
|
||||
- **Native (`ios` / `android` / `adaptive`):** follow the Motion section of [ios.md](ios.md) or [android.md](android.md), including the platform's Reduce Motion behavior. Do not apply the web tooling below.
|
||||
|
||||
Operate + Read: 150–250 ms on most transitions. Motion conveys state: feedback, reveal, loading, transitions between views. No page-load choreography; users are in a task and won't wait for it.
|
||||
## Find the job
|
||||
|
||||
Native (`ios` / `android` / `adaptive`): implementation follows the Motion section of [ios.md](ios.md) / [android.md](android.md) (read it first if Setup hasn't already): system transitions and OS Reduce Motion, never the web tooling below.
|
||||
Inspect the existing motion language, interaction states, target devices, and performance budget. Find only the places where motion would:
|
||||
|
||||
---
|
||||
- acknowledge an action;
|
||||
- make a state change or spatial relationship legible;
|
||||
- preserve continuity through navigation or layout change;
|
||||
- direct attention at a meaningful moment;
|
||||
- embody the selected visual world.
|
||||
|
||||
## Assess Animation Opportunities
|
||||
Ask only when a material constraint cannot be inferred. Do not animate a static area merely because it exists.
|
||||
|
||||
Analyze where motion would improve the experience:
|
||||
## Set the motion thesis
|
||||
|
||||
1. **Identify static areas**:
|
||||
- **Missing feedback**: Actions without visual acknowledgment (button clicks, form submission, etc.)
|
||||
- **Jarring transitions**: Instant state changes that feel abrupt (show/hide, page loads, route changes)
|
||||
- **Unclear relationships**: Spatial or hierarchical relationships that aren't obvious
|
||||
- **Lack of delight**: Functional but joyless interactions
|
||||
- **Missed guidance**: Opportunities to direct attention or explain behavior
|
||||
Write a short plan before implementation:
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the personality? (Playful vs serious, energetic vs calm)
|
||||
- What's the performance budget? (Mobile-first? Complex page?)
|
||||
- Who's the audience? (Motion-sensitive users? Power users who want speed?)
|
||||
- What matters most? (One hero animation vs many micro-interactions?)
|
||||
- **Focal moment:** the one sequence or interaction that deserves authorship, if any.
|
||||
- **Continuity:** the state, layout, or navigation changes that need explanation.
|
||||
- **Feedback:** the controls and outcomes that need acknowledgment.
|
||||
- **Budget:** which effects may be expensive, how often they run, and the reduced-motion equivalent.
|
||||
|
||||
If any of these are unclear from the codebase, ask the user directly to clarify what you cannot infer.
|
||||
The focal moment must come from this product and surface concept. A generic fade-and-rise, hover lift, parallax layer, or scroll reveal is not a thesis.
|
||||
|
||||
**CRITICAL**: Respect `prefers-reduced-motion`. Always provide non-animated alternatives for users who need them.
|
||||
## Choose material by meaning
|
||||
|
||||
## Plan Animation Strategy
|
||||
Transform and opacity are reliable foundations, not the entire palette. Choose properties for what the transition communicates:
|
||||
|
||||
Create a purposeful animation plan:
|
||||
- **Continuity and relationship:** shared-element motion, FLIP-style transforms, view transitions, or deliberate spatial movement.
|
||||
- **Focus and depth:** bounded blur, filter, backdrop, light, or shadow changes.
|
||||
- **Reveal and composition:** masks, clip paths, cropping, or controlled occlusion.
|
||||
- **Material and energy:** color, gradient position, texture, distortion, or shader effects when the world and runtime support them.
|
||||
- **State and feedback:** the smallest change that makes cause and result unmistakable.
|
||||
|
||||
- **Feedback layer**: Which interactions need acknowledgment?
|
||||
- **Transition layer**: Which state changes need smoothing?
|
||||
- **Entrance moment**: The ONE entrance worth rehearsing, where the mode invites it. Not every surface wants one.
|
||||
- **Delight layer**: Where can we surprise and delight?
|
||||
Do not stack techniques for spectacle. One strong material idea, carried through the focal sequence and quiet supporting states, is usually enough.
|
||||
|
||||
**IMPORTANT**: One well-orchestrated experience beats scattered animations everywhere. Focus on high-impact moments.
|
||||
Sibling stagger is appropriate when a list appears as a list. Cap the total delay, and never reinterpret every scrolled section as a staggered list.
|
||||
|
||||
## Implement Animations
|
||||
## Timing and easing
|
||||
|
||||
Add motion systematically across these categories:
|
||||
Timing should express distance and consequence:
|
||||
|
||||
### Micro-interactions
|
||||
- **Button feedback**:
|
||||
- Hover: Subtle scale (1.02-1.05), color shift, shadow increase
|
||||
- Click: Quick scale down then up (0.95 → 1), ripple effect
|
||||
- Loading: Spinner or pulse state
|
||||
- **Form interactions**:
|
||||
- Input focus: Border color transition, slight scale or glow
|
||||
- Validation: Shake on error, check mark on success, smooth color transitions
|
||||
- **Toggle switches**: Smooth slide + color transition (200-300ms)
|
||||
- **Checkboxes/radio**: Check mark animation, ripple effect
|
||||
- **Like/favorite**: Scale + rotation, particle effects, color transition
|
||||
| Duration | Typical use |
|
||||
|---|---|
|
||||
| 100–150 ms | immediate feedback |
|
||||
| 150–300 ms | routine state change |
|
||||
| 300–500 ms | layout, overlay, or view transition |
|
||||
| 500–800 ms | a deliberately authored focal entrance |
|
||||
|
||||
### State Transitions
|
||||
- **Show/hide**: Fade + slide (not instant), appropriate timing (200-300ms)
|
||||
- **Expand/collapse**: Height transition with overflow handling, icon rotation
|
||||
- **Loading states**: Skeleton screen fades, spinner animations, progress bars
|
||||
- **Success/error**: Color transitions, icon animations, gentle scale pulse
|
||||
- **Enable/disable**: Opacity transitions, cursor changes
|
||||
Exit faster than entrance. Use natural deceleration such as `cubic-bezier(0.16, 1, 0.3, 1)` for confident arrivals; do not use bounce or elastic curves by reflex. Long feedback feels like latency.
|
||||
|
||||
### Entrance Animations
|
||||
- **The one entrance moment** (where the mode invites it): a committed entrance for primary content (scale, parallax, or a creative effect)
|
||||
- **Modal/drawer entry**: Smooth slide + fade, backdrop fade, focus management
|
||||
- **List rhythm**: Sibling stagger is legitimate for cards-in-a-grid or list-items-appearing. Whole-section fade-on-scroll is not a list and is not legitimate. Cap total stagger time: 10 items at 50ms each = 500ms total. For more items, reduce per-item delay or cap the staggered count.
|
||||
## Implement to the runtime
|
||||
|
||||
Use CSS custom properties for clean stagger: `animation-delay: calc(var(--i, 0) * 50ms)` with `style="--i: 0"`, `style="--i: 1"`, etc. on each item.
|
||||
- Use CSS transitions and keyframes for declarative state and bounded sequences.
|
||||
- Use Web Animations API or the project's existing motion library for interruption, sequencing, and dynamic values.
|
||||
- Use View Transitions or shared-element techniques when continuity across states is the point.
|
||||
- Use scroll-driven motion only when the scroll relationship itself carries meaning, with a robust fallback.
|
||||
- Do not add a dependency for an effect the existing stack can express cleanly.
|
||||
|
||||
### Navigation & Flow
|
||||
- **Page transitions**: Crossfade between routes, shared element transitions
|
||||
- **Tab switching**: Slide indicator, content fade/slide
|
||||
- **Carousel/slider**: Smooth transforms, snap points, momentum
|
||||
- **Scroll effects**: Parallax layers, sticky headers with state changes, scroll progress indicators
|
||||
Keep content visible in the default state so failed scripts do not hide the page. Avoid casually animating layout-driving properties such as `width`, `height`, `top`, `left`, and margins; use FLIP, transforms, or grid techniques when appropriate. Bound blur, filter, shadow, canvas, and shader work to isolated regions. Apply `will-change` only during known animation. Measure on target viewports and devices rather than assuming transform means fast.
|
||||
|
||||
### Feedback & Guidance
|
||||
- **Hover hints**: Tooltip fade-ins, cursor changes, element highlights
|
||||
- **Drag & drop**: Lift effect (shadow + scale), drop zone highlights, smooth repositioning
|
||||
- **Copy/paste**: Brief highlight flash on paste, "copied" confirmation
|
||||
- **Focus flow**: Highlight path through form or workflow
|
||||
## Accessibility and control
|
||||
|
||||
### Delight Moments
|
||||
- **Empty states**: Subtle floating animations on illustrations
|
||||
- **Completed actions**: Confetti, check mark flourish, success celebrations
|
||||
- **Easter eggs**: Hidden interactions for discovery
|
||||
- **Contextual animation**: Weather effects, time-of-day themes, seasonal touches
|
||||
Honor `prefers-reduced-motion` with an intentional alternative. Preserve state change and hierarchy while removing travel, parallax, flashing, or prolonged sequences. Do not replace every animation globally with `0.01ms` if that destroys useful feedback. Motion must never block focus, interaction, reading, or task completion.
|
||||
|
||||
## Technical Implementation
|
||||
Respect autoplay and sound preferences. Any nonessential loop must stop when offscreen or hidden.
|
||||
|
||||
Use appropriate techniques for each animation:
|
||||
## Verify
|
||||
|
||||
### Timing & Easing
|
||||
- The focal motion is specific to the selected world and surface.
|
||||
- Every supporting animation explains feedback, state, or relationship.
|
||||
- Interruption and repeated use behave correctly.
|
||||
- Desktop, mobile, keyboard, and reduced-motion paths remain usable.
|
||||
- Expensive effects stay smooth on the target device.
|
||||
- Removing an animation would lose meaning or authored character, not merely decoration.
|
||||
|
||||
**Duration: the 100/300/500 rule.** Timing matters more than easing for "feels right":
|
||||
|
||||
| Duration | Use Case | Examples |
|
||||
|----------|----------|----------|
|
||||
| **100–150ms** | Instant feedback | Button press, toggle, color change |
|
||||
| **200–300ms** | State changes | Menu open, tooltip, hover state |
|
||||
| **300–500ms** | Layout changes | Accordion, modal, drawer |
|
||||
| **500–800ms** | Entrance animations | Page load, hero reveal |
|
||||
|
||||
**Easing curves (use these, not CSS defaults):**
|
||||
```css
|
||||
/* Recommended: natural deceleration */
|
||||
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1); /* Smooth */
|
||||
--ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1); /* Slightly snappier */
|
||||
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); /* Confident, decisive */
|
||||
|
||||
/* AVOID: feel dated and tacky */
|
||||
/* bounce: cubic-bezier(0.34, 1.56, 0.64, 1); */
|
||||
/* elastic: cubic-bezier(0.68, -0.6, 0.32, 1.6); */
|
||||
```
|
||||
|
||||
**Exit animations are faster than entrances.** Use ~75% of enter duration.
|
||||
|
||||
### CSS Animations
|
||||
```css
|
||||
/* Prefer for simple, declarative animations */
|
||||
- transitions for state changes
|
||||
- @keyframes for complex sequences
|
||||
- transform and opacity for reliable movement
|
||||
- blur, filters, masks, clip paths, shadows, and color shifts for premium atmospheric effects when verified smooth
|
||||
```
|
||||
|
||||
### JavaScript Animation
|
||||
```javascript
|
||||
/* Use for complex, interactive animations */
|
||||
- Web Animations API for programmatic control
|
||||
- Framer Motion for React
|
||||
- GSAP for complex sequences
|
||||
```
|
||||
|
||||
### Motion Materials
|
||||
|
||||
Transform and opacity are reliable defaults, not the whole palette. Premium interfaces often need atmospheric properties. Match material to effect:
|
||||
|
||||
- **Transform / opacity**: movement, press feedback, simple reveals, list choreography
|
||||
- **Blur / filter / backdrop-filter**: focus pulls, depth, glass or lens effects, softened entrances
|
||||
- **Clip-path / masks**: wipes, reveals, editorial cropping, product-like transitions
|
||||
- **Shadow / glow / color filters**: energy, affordance, focus, warmth, active state
|
||||
- **Grid-template-rows or FLIP-style transforms**: expanding and reflowing layout without animating `height` directly
|
||||
|
||||
The hard rule isn't "transform and opacity only." It's: avoid animating layout-driving properties casually (`width`, `height`, `top`, `left`, margins), keep expensive effects bounded to small or isolated areas, and verify smoothness in-browser on target viewports.
|
||||
|
||||
### Performance
|
||||
- **Layout safety**: Avoid casual animation of layout-driving properties (`width`, `height`, `top`, `left`, margins)
|
||||
- **will-change**: Add sparingly for known expensive animations only (e.g. on `:hover` or an `.animating` class), never preemptively across the whole page
|
||||
- **Scroll triggers**: Use Intersection Observer instead of scroll event listeners; unobserve after the animation fires once
|
||||
- **Bound expensive effects**: Keep blur/filter/shadow areas small or isolated, use `contain` where appropriate
|
||||
- **Monitor FPS**: Ensure 60fps on target devices
|
||||
|
||||
### Perceived Performance
|
||||
|
||||
Nobody cares how fast your site *is*, only how fast it feels. The 80ms threshold: anything under ~80ms feels instant because our brains buffer sensory input for that long to synchronize perception. Target this for micro-interactions.
|
||||
|
||||
- **Preemptive start**: Begin transitions immediately while loading (iOS app zoom, skeleton UI). Users perceive work happening.
|
||||
- **Early completion**: Show content progressively, don't wait for everything (progressive images, streaming HTML, skeleton fade-ins).
|
||||
- **Optimistic UI**: Update the interface immediately, handle failures gracefully. Use for low-stakes actions (likes, follows). Avoid for payments or destructive operations.
|
||||
- **Easing affects perceived duration**: Ease-in (accelerating toward completion) makes tasks feel shorter because the peak-end effect weights final moments heavily. Ease-out feels satisfying for entrances.
|
||||
- **Caution**: Too-fast responses can decrease perceived value for complex operations (search, analysis). Sometimes a brief delay signals "real work" is happening.
|
||||
|
||||
### Accessibility
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**NEVER**:
|
||||
- Use bounce or elastic easing curves; they feel dated and draw attention to the animation itself
|
||||
- Animate layout properties casually (`width`, `height`, `top`, `left`, margins) when transform, FLIP, or grid-based techniques would work
|
||||
- Use durations over 500ms for feedback (it feels laggy)
|
||||
- Animate without purpose (every animation needs a reason)
|
||||
- Ignore `prefers-reduced-motion` (this is an accessibility violation)
|
||||
- Animate everything (animation fatigue makes interfaces feel exhausting)
|
||||
- Block interaction during animations unless intentional
|
||||
|
||||
## Verify Quality
|
||||
|
||||
Test animations thoroughly:
|
||||
|
||||
- **Smooth at 60fps**: No jank on target devices
|
||||
- **Feels natural**: Easing curves feel organic, not robotic
|
||||
- **Appropriate timing**: Not too fast (jarring) or too slow (laggy)
|
||||
- **Reduced motion works**: Animations disabled or simplified appropriately
|
||||
- **Doesn't block**: Users can interact during/after animations
|
||||
- **Adds value**: Makes interface clearer or more delightful
|
||||
|
||||
When the motion clarifies state instead of decorating it, hand off to `/impeccable polish` for the final pass.
|
||||
When motion earns its place, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -52,11 +52,11 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
|
||||
**Score 0-4**: 0=Desktop-only (breaks on mobile), 1=Major issues (some breakpoints, many failures), 2=Partial (works on mobile, rough edges), 3=Good (responsive, minor touch target or overflow issues), 4=Excellent (fluid, all viewports, proper touch targets)
|
||||
|
||||
### 5. Anti-Patterns (CRITICAL)
|
||||
### 5. Implementation Integrity (CRITICAL)
|
||||
|
||||
Check against ALL the **DON'T** guidelines from the parent impeccable skill (already loaded in this context). Look for AI slop tells (AI color palette, gradient text, glassmorphism, hero metrics, card grids, generic fonts) and general design anti-patterns (gray on color, nested cards, bounce easing, redundant copy).
|
||||
Run the bundled detector and verify each finding in context. Look for repeated implementation shortcuts, design-system drift, misleading or decorative content, and structure that is interchangeable with an unrelated product. Keep deterministic findings separate from visual judgment and call out false positives.
|
||||
|
||||
**Score 0-4**: 0=AI slop gallery (5+ tells), 1=Heavy AI aesthetic (3-4 tells), 2=Some tells (1-2 noticeable), 3=Mostly clean (subtle issues only), 4=No AI tells (distinctive, intentional design)
|
||||
**Score 0-4**: 0=systemic drift, 1=major repeated failures, 2=several verified issues, 3=minor isolated issues, 4=coherent and intentional
|
||||
|
||||
## Generate Report
|
||||
|
||||
@@ -68,13 +68,13 @@ Check against ALL the **DON'T** guidelines from the parent impeccable skill (alr
|
||||
| 2 | Performance | ? | |
|
||||
| 3 | Responsive Design | ? | |
|
||||
| 4 | Theming | ? | |
|
||||
| 5 | Anti-Patterns | ? | |
|
||||
| 5 | Implementation Integrity | ? | |
|
||||
| **Total** | | **??/20** | **[Rating band]** |
|
||||
|
||||
**Rating bands**: 18-20 Excellent (minor polish), 14-17 Good (address weak dimensions), 10-13 Acceptable (significant work needed), 6-9 Poor (major overhaul), 0-5 Critical (fundamental issues)
|
||||
|
||||
### Anti-Patterns Verdict
|
||||
**Start here.** Pass/fail: Does this look AI-generated? List specific tells. Be brutally honest.
|
||||
### Implementation Integrity Verdict
|
||||
**Start here.** Pass/fail: does the implementation express a coherent product-specific system? Cite verified evidence and detector findings.
|
||||
|
||||
### Executive Summary
|
||||
- Audit Health Score: **??/20** ([rating band])
|
||||
@@ -93,7 +93,7 @@ Tag every issue with **P0-P3 severity**:
|
||||
For each issue, document:
|
||||
- **[P?] Issue name**
|
||||
- **Location**: Component, file, line
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Anti-Pattern
|
||||
- **Category**: Accessibility / Performance / Theming / Responsive / Implementation Integrity
|
||||
- **Impact**: How it affects users
|
||||
- **WCAG/Standard**: Which standard it violates (if applicable)
|
||||
- **Recommendation**: How to fix it
|
||||
@@ -132,4 +132,3 @@ After presenting the summary, tell the user:
|
||||
- Skip positive findings (celebrate what works)
|
||||
- Forget to prioritize (everything can't be P0)
|
||||
- Report false positives without verification
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Run comprehensive checks across 5 dimensions. Score each dimension 0-4 using the
|
||||
- **Hard-coded colors**: raw hex instead of semantic system colors (iOS) / Material color roles (Android) / design tokens
|
||||
- **Broken dark appearance**: missing dark variants, poor contrast in dark, quick inverts
|
||||
- **Dynamic Color** (Android 12+): no static fallback scheme, or ignored where it fits
|
||||
- **Off-platform materials**: hand-rolled blur/glassmorphism instead of system materials or tonal elevation
|
||||
- **Off-platform materials**: hand-rolled visual materials where system materials or tonal elevation are expected
|
||||
|
||||
**Score 0-4**: 0=Hard-coded everything, 1=Minimal tokens, 2=Partial (tokens exist, inconsistently used), 3=Good (minor hard-coded values), 4=Excellent (semantic throughout, both appearances first-class)
|
||||
|
||||
@@ -48,7 +48,7 @@ Score against the loaded platform reference(s), including their slop tests. **Ch
|
||||
- **Off-platform navigation**: custom global nav, overloaded tab bars, iOS patterns on Android or vice versa
|
||||
- **Web-shaped controls**: HTML-style buttons, custom toggles, hover-dependent affordances
|
||||
- **Icon drift**: mixed icon sets instead of SF Symbols / Material Symbols
|
||||
- **AI tells**: the shared absolute bans still apply (AI palette, gradient text, hero metrics)
|
||||
- **System drift**: repeated shortcuts or decorative patterns that conflict with the product, platform, or established design system
|
||||
|
||||
**Score 0-4**: 0=Web port (nothing native), 1=Heavy violations (3-4 kinds), 2=Some (1-2 noticeable), 3=Mostly conformant (subtle issues), 4=Fully native (a fluent user trusts every screen)
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
## Why it reads flat
|
||||
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing, the specificity of the copy. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
A section usually reads flat for reasons its neighbors have already solved. Look at what the rest of the page does that this section does not: the display type at full strength, the structural devices that carry meaning, the signature motif, the density and pacing. A flat section is typically one that quietly opts out of the system's own strongest moves. The most reliable bolder pass brings the target up to the expressive level its neighbors already reach, in the system's own vocabulary rather than a new one.
|
||||
|
||||
## The amplification
|
||||
|
||||
- **Amplify what the system already owns.** Reuse its motif and its type scale at full strength, turned up for this section rather than invented for it. The bolder version should look more like the same brand, not less.
|
||||
- **Let the content carry the weight.** Flat copy makes a flat design, and no amount of size fixes a generic claim. Make every word specific enough to earn its place, and let the section's real evidence do the work that a decorative addition would otherwise fake.
|
||||
- **Keep content true.** Existing claims are part of the scope: preserve them unless the user supplies replacements. If real evidence is essential to the direction but absent, ask for it.
|
||||
- **Commit, then clarify.** Half-measures read as noise. Make the one decisive move completely, then quiet everything around it so the move is legible. If every element got louder, the section got flatter.
|
||||
- **Give it its own rhythm.** The target should read as a peak in the scroll, a shift in density or pace from what surrounds it, not simply more of the same.
|
||||
|
||||
|
||||
@@ -1,288 +1,94 @@
|
||||
> **Additional context needed**: audience technical level and users' mental state in context.
|
||||
> **Additional context needed**: audience knowledge and emotional state.
|
||||
|
||||
Find the unclear, confusing, or poorly written interface text and rewrite it. Vague copy creates support tickets and abandonment; specific copy gets users through the task.
|
||||
Rewrite unclear interface text so users understand what happened, what matters, and what to do next. Preserve factual meaning, product terminology, and brand voice.
|
||||
|
||||
## Audit the language
|
||||
|
||||
---
|
||||
Read the entire interaction path, not isolated strings. Identify:
|
||||
|
||||
## Assess Current Copy
|
||||
- ambiguous nouns, verbs, and actions;
|
||||
- internal jargon or assumed knowledge;
|
||||
- vague labels, outcomes, and system states;
|
||||
- missing consequences, recovery, or timing;
|
||||
- inconsistent terminology and capitalization;
|
||||
- redundant headings, intros, helper text, and confirmations;
|
||||
- text that breaks at realistic widths or in translation;
|
||||
- tone that ignores stress, risk, success, or urgency.
|
||||
|
||||
Identify what makes the text unclear or ineffective:
|
||||
Infer audience and task from product context and surrounding UI. Ask before changing factual claims, legal meaning, or a term that may be domain-specific.
|
||||
|
||||
1. **Find clarity problems**:
|
||||
- **Jargon**: Technical terms users won't understand
|
||||
- **Ambiguity**: Multiple interpretations possible
|
||||
- **Passive voice**: "Your file has been uploaded" vs "We uploaded your file"
|
||||
- **Length**: Too wordy or too terse
|
||||
- **Assumptions**: Assuming user knowledge they don't have
|
||||
- **Missing context**: Users don't know what to do or why
|
||||
- **Tone mismatch**: Too formal, too casual, or inappropriate for situation
|
||||
## Set the message hierarchy
|
||||
|
||||
2. **Understand the context**:
|
||||
- Who's the audience? (Technical? General? First-time users?)
|
||||
- What's the user's mental state? (Stressed during error? Confident during success?)
|
||||
- What's the action? (What do we want users to do?)
|
||||
- What's the constraint? (Character limits? Space limitations?)
|
||||
For each state, decide:
|
||||
|
||||
**CRITICAL**: Clear copy helps users succeed. Unclear copy creates frustration, errors, and support tickets.
|
||||
1. the one fact the user needs now;
|
||||
2. the action available next;
|
||||
3. supporting context that changes the decision;
|
||||
4. the appropriate tone for this moment.
|
||||
|
||||
## Plan Copy Improvements
|
||||
Say each idea once. If the heading already explains the state, the introduction should add new information or disappear.
|
||||
|
||||
Create a strategy for clearer communication:
|
||||
## Rewrite by function
|
||||
|
||||
- **Primary message**: What's the ONE thing users need to know?
|
||||
- **Action needed**: What should users do next (if anything)?
|
||||
- **Tone**: How should this feel? (Helpful? Apologetic? Encouraging?)
|
||||
- **Constraints**: Length limits, brand voice, localization considerations
|
||||
### Actions and navigation
|
||||
|
||||
**IMPORTANT**: Good UX writing is invisible. Users should understand immediately without noticing the words.
|
||||
Use a specific verb and object when the outcome is not already obvious. Labels should describe what will happen, not the gesture used to trigger it. Keep the same noun and verb for the same concept throughout the product.
|
||||
|
||||
## Improve Copy Systematically
|
||||
For destructive actions, name the object and consequence. Prefer undo over confirmation when recovery is safe. When confirmation is necessary, name the action on both the message and button instead of using `Yes`, `No`, `OK`, or `Submit`.
|
||||
|
||||
Refine text across these common areas:
|
||||
### Forms
|
||||
|
||||
### Error Messages
|
||||
**Bad**: "Error 403: Forbidden"
|
||||
**Good**: "You don't have permission to view this page. Contact your admin for access."
|
||||
Use persistent labels; placeholders are examples, not labels. Put format and eligibility requirements before submission. Explain why information is requested only when it is not obvious. Required and optional treatment should be consistent.
|
||||
|
||||
**Bad**: "Invalid input"
|
||||
**Good**: "Email addresses need an @ symbol. Try: name@example.com"
|
||||
Validation says what needs attention and how to correct it without blaming the user. Keep related instructions near the field and announce errors accessibly.
|
||||
|
||||
**Principles**:
|
||||
- Explain what went wrong in plain language
|
||||
- Suggest how to fix it
|
||||
- Don't blame the user
|
||||
- Include examples when helpful
|
||||
- Link to help/support if applicable
|
||||
|
||||
### Form Labels & Instructions
|
||||
**Bad**: "DOB (MM/DD/YYYY)"
|
||||
**Good**: "Date of birth" (with placeholder showing format)
|
||||
|
||||
**Bad**: "Enter value here"
|
||||
**Good**: "Your email address" or "Company name"
|
||||
|
||||
**Principles**:
|
||||
- Use clear, specific labels (not generic placeholders)
|
||||
- Show format expectations with examples
|
||||
- Explain why you're asking (when not obvious)
|
||||
- Put instructions before the field, not after
|
||||
- Keep required field indicators clear
|
||||
|
||||
### Button & CTA Text
|
||||
**Bad**: "Click here" | "Submit" | "OK"
|
||||
**Good**: "Create account" | "Save changes" | "Got it, thanks"
|
||||
### Errors and permissions
|
||||
|
||||
**Principles**:
|
||||
- Describe the action specifically
|
||||
- Use active voice (verb + noun)
|
||||
- Match user's mental model
|
||||
- Be specific ("Save" is better than "OK")
|
||||
An actionable error answers:
|
||||
|
||||
### Help Text & Tooltips
|
||||
**Bad**: "This is the username field"
|
||||
**Good**: "Choose a username. You can change this later in Settings."
|
||||
1. what failed;
|
||||
2. why, when known and useful;
|
||||
3. how to recover or what alternative remains.
|
||||
|
||||
**Principles**:
|
||||
- Add value (don't just repeat the label)
|
||||
- Answer the implicit question ("What is this?" or "Why do you need this?")
|
||||
- Keep it brief but complete
|
||||
- Link to detailed docs if needed
|
||||
Do not expose internal codes as the primary message. Do not promise a cause or resolution the system cannot know. Treat privacy, payment, deletion, access loss, and blocked work seriously; warmth is welcome, jokes are not.
|
||||
|
||||
### Empty States
|
||||
**Bad**: "No items"
|
||||
**Good**: "No projects yet. Create your first project to get started."
|
||||
### Loading, empty, and success states
|
||||
|
||||
**Principles**:
|
||||
- Explain why it's empty (if not obvious)
|
||||
- Show next action clearly
|
||||
- Make it welcoming, not dead-end
|
||||
Loading text names the real operation and sets an honest expectation when the wait is meaningful. Show determinate progress when available; never invent progress.
|
||||
|
||||
### Success Messages
|
||||
**Bad**: "Success"
|
||||
**Good**: "Settings saved! Your changes will take effect immediately."
|
||||
An empty state distinguishes first use, no results, filters, permissions, and failure. Explain the state and provide the next useful action.
|
||||
|
||||
**Principles**:
|
||||
- Confirm what happened
|
||||
- Explain what happens next (if relevant)
|
||||
- Be brief but complete
|
||||
- Match the user's emotional moment (celebrate big wins)
|
||||
|
||||
### Loading States
|
||||
**Bad**: "Loading..." (for 30+ seconds)
|
||||
**Good**: "Analyzing your data... this usually takes 30-60 seconds"
|
||||
|
||||
**Principles**:
|
||||
- Set expectations (how long?)
|
||||
- Explain what's happening (when it's not obvious)
|
||||
- Show progress when possible
|
||||
- Offer escape hatch if appropriate ("Cancel")
|
||||
Success confirms the completed outcome and mentions the next consequence only when it changes what the user should do. Routine success should be brief.
|
||||
|
||||
### Confirmation Dialogs
|
||||
**Bad**: "Are you sure?"
|
||||
**Good**: "Delete 'Project Alpha'? This can't be undone."
|
||||
### Help and instructional text
|
||||
|
||||
**Principles**:
|
||||
- State the specific action
|
||||
- Explain consequences (especially for destructive actions)
|
||||
- Use clear button labels ("Delete project" not "Yes")
|
||||
- Don't overuse confirmations (only for risky actions)
|
||||
Helper text answers an implicit question instead of restating the control. Use progressive disclosure for uncommon detail. Link text must make sense out of context; icon-only controls need accessible names.
|
||||
|
||||
### Navigation & Wayfinding
|
||||
**Bad**: Generic labels like "Items" | "Things" | "Stuff"
|
||||
**Good**: Specific labels like "Your projects" | "Team members" | "Settings"
|
||||
## Voice, accessibility, and localization
|
||||
|
||||
**Principles**:
|
||||
- Be specific and descriptive
|
||||
- Use language users understand (not internal jargon)
|
||||
- Make hierarchy clear
|
||||
- Consider information scent (breadcrumbs, current location)
|
||||
Voice stays consistent; tone adapts to the moment. Use plain language without flattening terminology the audience genuinely knows.
|
||||
|
||||
## Apply Clarity Principles
|
||||
- Write complete translatable messages rather than concatenated fragments.
|
||||
- Keep variables and numbers structured so translators can reorder them.
|
||||
- Allow expansion instead of abbreviating prematurely.
|
||||
- Make alt text convey the image's information; use empty alt for decoration.
|
||||
- Keep screen-reader names aligned with visible labels and outcomes.
|
||||
- Do not rely on punctuation, color, or iconography to carry the message alone.
|
||||
|
||||
Every piece of copy should follow these rules:
|
||||
Maintain a short terminology glossary when inconsistency spans the product. Do not vary words for literary effect in an interface.
|
||||
|
||||
1. **Be specific**: "Enter email" not "Enter value"
|
||||
2. **Be concise**: Cut unnecessary words (but don't sacrifice clarity)
|
||||
3. **Be active**: "Save changes" not "Changes will be saved"
|
||||
4. **Be human**: "Oops, something went wrong" not "System error encountered"
|
||||
5. **Tell users what to do**, not just what happened
|
||||
6. **Be consistent**: Use same terms throughout (don't vary for variety)
|
||||
## Verify
|
||||
|
||||
**NEVER**:
|
||||
- Use jargon without explanation
|
||||
- Blame users ("You made an error" → "This field is required")
|
||||
- Be vague ("Something went wrong" without explanation)
|
||||
- Use passive voice unnecessarily
|
||||
- Write overly long explanations (be concise)
|
||||
- Use humor for errors (be empathetic instead)
|
||||
- Assume technical knowledge
|
||||
- Vary terminology (pick one term and stick with it)
|
||||
- Repeat information (headers restating intros, redundant explanations)
|
||||
- Use placeholders as the only labels (they disappear when users type)
|
||||
Read the flow in context and test:
|
||||
|
||||
## Verify Improvements
|
||||
- comprehension without hidden product knowledge;
|
||||
- actionability at errors, empty states, and decision points;
|
||||
- factual accuracy and consistent terminology;
|
||||
- scanability at target widths and 200% zoom;
|
||||
- long names, localization expansion, pluralization, and dynamic values;
|
||||
- accessible names and announced state changes;
|
||||
- tone appropriate to consequence and emotional context.
|
||||
|
||||
Test that copy improvements work:
|
||||
The final copy is as short as it can be without removing meaning or recovery.
|
||||
|
||||
- **Comprehension**: Can users understand without context?
|
||||
- **Actionability**: Do users know what to do next?
|
||||
- **Brevity**: Is it as short as possible while remaining clear?
|
||||
- **Consistency**: Does it match terminology elsewhere?
|
||||
- **Tone**: Is it appropriate for the situation?
|
||||
|
||||
When the copy reads cleanly, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `ux-writing.md` and live inline now so the clarify flow has its deep UX-writing reference in one place.
|
||||
|
||||
### UX Writing
|
||||
|
||||
#### The Button Label Problem
|
||||
|
||||
**Never use "OK", "Submit", or "Yes/No".** These are lazy and ambiguous. Use specific verb + object patterns:
|
||||
|
||||
| Bad | Good | Why |
|
||||
|-----|------|-----|
|
||||
| OK | Save changes | Says what will happen |
|
||||
| Submit | Create account | Outcome-focused |
|
||||
| Yes | Delete message | Confirms the action |
|
||||
| Cancel | Keep editing | Clarifies what "cancel" means |
|
||||
| Click here | Download PDF | Describes the destination |
|
||||
|
||||
**For destructive actions**, name the destruction:
|
||||
- "Delete" not "Remove" (delete is permanent, remove implies recoverable)
|
||||
- "Delete 5 items" not "Delete selected" (show the count)
|
||||
|
||||
#### Error Messages: The Formula
|
||||
|
||||
Every error message should answer: (1) What happened? (2) Why? (3) How to fix it? Example: "Email address isn't valid. Please include an @ symbol." not "Invalid input".
|
||||
|
||||
##### Error Message Templates
|
||||
|
||||
| Situation | Template |
|
||||
|-----------|----------|
|
||||
| **Format error** | "[Field] needs to be [format]. Example: [example]" |
|
||||
| **Missing required** | "Please enter [what's missing]" |
|
||||
| **Permission denied** | "You don't have access to [thing]. [What to do instead]" |
|
||||
| **Network error** | "We couldn't reach [thing]. Check your connection and [action]." |
|
||||
| **Server error** | "Something went wrong on our end. We're looking into it. [Alternative action]" |
|
||||
|
||||
##### Don't Blame the User
|
||||
|
||||
Reframe errors: "Please enter a date in MM/DD/YYYY format" not "You entered an invalid date".
|
||||
|
||||
#### Empty States Are Opportunities
|
||||
|
||||
Empty states are onboarding moments: (1) Acknowledge briefly, (2) Explain the value of filling it, (3) Provide a clear action. "No projects yet. Create your first one to get started." not just "No items".
|
||||
|
||||
#### Voice vs Tone
|
||||
|
||||
**Voice** is your brand's personality, consistent everywhere.
|
||||
**Tone** adapts to the moment.
|
||||
|
||||
| Moment | Tone Shift |
|
||||
|--------|------------|
|
||||
| Success | Celebratory, brief: "Done! Your changes are live." |
|
||||
| Error | Empathetic, helpful: "That didn't work. Here's what to try..." |
|
||||
| Loading | Reassuring: "Saving your work..." |
|
||||
| Destructive confirm | Serious, clear: "Delete this project? This can't be undone." |
|
||||
|
||||
**Never use humor for errors.** Users are already frustrated. Be helpful, not cute.
|
||||
|
||||
#### Writing for Accessibility
|
||||
|
||||
**Link text** must have standalone meaning: "View pricing plans" not "Click here". **Alt text** describes information, not the image: "Revenue increased 40% in Q4" not "Chart". Use `alt=""` for decorative images. **Icon buttons** need `aria-label` for screen reader context.
|
||||
|
||||
#### Writing for Translation
|
||||
|
||||
##### Plan for Expansion
|
||||
|
||||
German text is ~30% longer than English. Allocate space:
|
||||
|
||||
| Language | Expansion |
|
||||
|----------|-----------|
|
||||
| German | +30% |
|
||||
| French | +20% |
|
||||
| Finnish | +30-40% |
|
||||
| Chinese | -30% (fewer chars, but same width) |
|
||||
|
||||
##### Translation-Friendly Patterns
|
||||
|
||||
Keep numbers separate ("New messages: 3" not "You have 3 new messages"). Use full sentences as single strings (word order varies by language). Avoid abbreviations ("5 minutes ago" not "5 mins ago"). Give translators context about where strings appear.
|
||||
|
||||
#### Consistency: The Terminology Problem
|
||||
|
||||
Pick one term and stick with it:
|
||||
|
||||
| Inconsistent | Consistent |
|
||||
|--------------|------------|
|
||||
| Delete / Remove / Trash | Delete |
|
||||
| Settings / Preferences / Options | Settings |
|
||||
| Sign in / Log in / Enter | Sign in |
|
||||
| Create / Add / New | Create |
|
||||
|
||||
Build a terminology glossary and enforce it. Variety creates confusion.
|
||||
|
||||
#### Avoid Redundant Copy
|
||||
|
||||
If the heading explains it, the intro is redundant. If the button is clear, don't explain it again. Say it once, say it well.
|
||||
|
||||
#### Loading States
|
||||
|
||||
Be specific: "Saving your draft..." not "Loading...". For long waits, set expectations ("This usually takes 30 seconds") or show progress.
|
||||
|
||||
#### Confirmation Dialogs: Use Sparingly
|
||||
|
||||
Most confirmation dialogs are design failures; consider undo instead. When you must confirm: name the action, explain consequences, use specific button labels ("Delete project" / "Keep project", not "Yes" / "No").
|
||||
|
||||
#### Form Instructions
|
||||
|
||||
Show format with placeholders, not instructions. For non-obvious fields, explain why you're asking.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Jargon without explanation. Blaming users ("You made an error" → "This field is required"). Vague errors ("Something went wrong"). Varying terminology for variety. Humor for errors.
|
||||
When the language reads cleanly, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,105 +1,38 @@
|
||||
# Codex: Visual Direction & Asset Production
|
||||
# Codex: Surface Probes & Asset Production
|
||||
|
||||
This file is loaded by `/impeccable craft` when the harness has native image generation (currently Codex via `image_gen`). Other harnesses skip it. It covers the two craft steps that depend on real image generation: landing the visual direction, and producing the raster assets the implementation will compose.
|
||||
Load this from [new-work.md](new-work.md) only when the harness has native image generation and a substantial, high-fidelity surface would benefit from seeing the shortlisted concept before code. PRODUCT.md and DESIGN.md are preconditions. New-work has already resolved the visual world; this file must not reopen it.
|
||||
|
||||
Read this *before* generating any images. The order matters, and the per-step user pauses are what keep generated imagery from drifting away from the brief.
|
||||
The purpose of a probe is to test composition, narrative, hierarchy, density, focal moment, signature use, and image requirements. It is not a second identity workshop. Keep DESIGN.md's palette, typography direction, material language, component character, imagery stance, and motion grammar fixed.
|
||||
|
||||
### Four stop points before code
|
||||
## Generate the smallest useful probe set
|
||||
|
||||
Steps A through D each end with the user. Do not advance past any of them on your own read of the situation.
|
||||
Generate one to three high-fidelity north-star comps using the native image-generation capability. Base them on the real content and the surface concepts already developed with the user.
|
||||
|
||||
1. **STOP after Step A questions.** Wait for answers.
|
||||
2. **STOP after Step B palette generation.** Wait for "confirm palette."
|
||||
3. **STOP after Step C mocks.** Wait for direction approval or delegation.
|
||||
4. **Only after Step D approves a direction** do you return to the build (new-work.md's plan, then code).
|
||||
- When the user shortlisted multiple concepts, show one clear expression of each.
|
||||
- When one concept is already selected, vary only the structural uncertainty that the image can resolve: topology, sequence, density, hierarchy, focal composition, or interaction framing.
|
||||
- Show enough beyond the opening moment to prove the concept can govern the whole requested surface.
|
||||
- Do not generate a palette artifact, ask new atmosphere questions, introduce a different type voice, or invent a new motif. If the committed world cannot support the concept, return to the concept shortlist rather than changing the world.
|
||||
|
||||
Prior shape approval does **not** satisfy any of these. Shape's "confirm or override" advances you into Step A; it is not a substitute for it.
|
||||
Treat each comp as a direction test, not a screenshot specification. Core UI text, responsive behavior, accessibility, semantics, and interaction states remain implementation responsibilities.
|
||||
|
||||
## Step A: Explore Directions with the User
|
||||
## One approval point
|
||||
|
||||
Before generating anything, run a brief direction conversation grounded in the shape brief.
|
||||
Show the probes together and ask what should carry forward, what feels false to the world, and whether the selected surface concept should be approved, combined, revised, or rejected. Then stop and wait. A structured simulated user counts as attended and receives the same question.
|
||||
|
||||
**Step A is required even when shape just produced a confirmed brief.** The shape questions and Step A questions cover different ground: shape pins purpose, content, scope; Step A pins palette, atmosphere, and named visual references for the comps you're about to generate. The only time you can skip Step A is when the user has already answered these exact palette/atmosphere/reference questions in the same session.
|
||||
Do not begin code until the user approves a direction or explicitly delegates the choice. If they delegate, choose using the task brief, PRODUCT.md, and DESIGN.md, and state the evidence. Approval refines the task concept; it does not modify DESIGN.md.
|
||||
|
||||
Ask **2-3 targeted questions** about visual lane, color strategy, atmosphere, and named anchor references. Don't enumerate generic menus; tie each question to the shape brief's answers. Example shape-grounded questions:
|
||||
After approval, summarize the composition and the parts of the comp that must not be literalized. Return to new-work.md and write the direction contract from the approved surface concept before code.
|
||||
|
||||
- "Brief says 'specimen-page restraint.' Are we closer to a quiet typographic page or a wider editorial spread with hero imagery?"
|
||||
- "Palette strategy from shape was 'Committed.' Which one color carries the surface (a brand-driven pick rather than a default warm-or-cool framing)? (And no, the answer isn't a cream/sand body bg; that's the saturated AI default.)"
|
||||
## Inventory implementation fidelity
|
||||
|
||||
**STOP and wait for answers.** These pin the palette before any pixel gets generated. Do not proceed to Step B until the user has responded.
|
||||
Before building, inventory the approved comp's major visible ingredients and choose an implementation medium for each: semantic HTML/CSS/SVG, existing project asset, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
## Step B: Generate the Brand Palette First
|
||||
Pay special attention to the dominant composition, signature use, image-native content, second-fold system, and any interaction the still image only implies. If the concept depends on a photograph, architectural scene, product object, portrait, or other raster-native material, do not silently replace it with generic CSS scenery.
|
||||
|
||||
Generate **one** palette artifact before any mocks. This is a small, focused image: typography pairing on the chosen background, primary + accent color swatches, one signature ornament or motif. Single image, single pass.
|
||||
Treat the comp as a north star, not something to trace. Do not rasterize core UI text or controls. Do not substitute a different visual driver after approval without asking.
|
||||
|
||||
Why palette first: mocks generated against a vague color sense produce noise that drowns out the structural decisions. A confirmed palette is the first concrete contract for everything downstream.
|
||||
## Produce only the assets the build needs
|
||||
|
||||
Show the palette to the user. Ask one question: "This is the palette I'm locking in for the mocks. Confirm, or call out what to shift?"
|
||||
When clean raster ingredients are required and a scoped subagent is available and authorized, use `impeccable_asset_producer`. Give it the approved comp, output paths, required dimensions and formats, transparency needs, crop notes, and what must remain semantic code. Otherwise produce the minimum required assets with the native image-generation capability in the current thread.
|
||||
|
||||
**STOP and wait for confirmation.** Do not generate mocks against an unconfirmed palette. "Probably good enough" is the wrong call here; the palette is the contract for everything downstream.
|
||||
|
||||
## Step C: Generate 1-3 Visual Mocks Against the Palette
|
||||
|
||||
Once the palette is confirmed, generate **1 to 3** high-fidelity north-star comps. Each mock must use the confirmed palette and typography. Mocks differ in *structural* direction (hierarchy, topology, density, composition), not in color or motif.
|
||||
|
||||
- Brand work: push visual identity, composition, mood, and signature motifs.
|
||||
- Product work: push hierarchy, topology, density, tone, grounded in realistic product structure.
|
||||
- Landing pages and long-form brand surfaces: show enough of the second fold to establish the system beyond the hero.
|
||||
|
||||
Use the `image_gen` tool directly (or via the imagegen skill when available). Don't ask the user to install anything.
|
||||
|
||||
## Step D: Approval Loop
|
||||
|
||||
Show the comps. Ask what carries forward. Iterate until **one direction is approved** or the user explicitly delegates.
|
||||
|
||||
**STOP and wait for the approval or the delegation.** Do not begin Step E or return to the build until a single direction is named. If the user delegates, pick the strongest direction and explain it from the brief, not personal taste.
|
||||
|
||||
Before moving to assets, summarize what to carry into code and what *not* to literalize from the mock. This is the handoff between visual exploration and semantic implementation.
|
||||
|
||||
## Step E: Mock Fidelity Inventory
|
||||
|
||||
Inventory the approved mock's major visible ingredients. For each, decide implementation: semantic HTML/CSS/SVG, generated raster, sourced raster, icon library, canvas/WebGL, or accepted omission.
|
||||
|
||||
Common ingredients to inventory:
|
||||
|
||||
- Hero silhouette and dominant composition
|
||||
- Signature motifs (planets, devices, portraits, charts, route lines, insets, badges, etc.)
|
||||
- Nav and primary-action treatment (when the surface has one)
|
||||
- Section sequence, especially the second fold
|
||||
- Image-native content the concept depends on
|
||||
- Typography, density, color/material treatment, motion cues
|
||||
|
||||
Treat the mock as a north star, not a screenshot to trace. Don't rasterize core UI text. But if the live result lacks the mock's major ingredients, the implementation is wrong.
|
||||
|
||||
If a photographic, architectural, product, or place-led mock becomes generic CSS scenery, decorative diagrams, bullets, or copy, stop and fix it. That's a broken implementation, not a harmless interpretation.
|
||||
|
||||
Don't substitute a different hero composition or visual driver post-approval without user sign-off.
|
||||
|
||||
## Step F: Asset Slicing via the Asset Producer
|
||||
|
||||
Raster ingredients identified in Step E need clean production assets. Use the bundled `impeccable_asset_producer` subagent rather than producing inline.
|
||||
|
||||
Spawn it as a scoped subagent. If you do not have explicit permission to use agents, stop and ask:
|
||||
|
||||
```text
|
||||
Asset production will work better as a scoped subagent job. Should I spawn the Impeccable asset producer subagent for this step?
|
||||
```
|
||||
|
||||
Pass to the agent:
|
||||
|
||||
- Approved mock path or screenshot reference
|
||||
- Crop paths or a contact sheet with crop ids
|
||||
- Output directory
|
||||
- Required dimensions, format, transparency needs
|
||||
- Avoid list
|
||||
- Notes on what should remain semantic HTML/CSS/SVG instead of raster
|
||||
|
||||
Attach image generation capability to the spawned agent when the harness supports it. Do **not** load image-generation reference material into the parent thread.
|
||||
|
||||
Inline asset production is allowed only if the user declines subagents, the harness cannot spawn the authorized agent, or the user explicitly asks for single-thread mode.
|
||||
|
||||
Prefer HTML/CSS/SVG/canvas when they can credibly reproduce an ingredient; reach for real, generated, or stock imagery when the mock or subject matter calls for actual visual content.
|
||||
|
||||
## After This File
|
||||
|
||||
Once Steps A through F are complete, return to the build: implement per new-work.md and SKILL.md's craft floor. The implementation builds against the confirmed palette, approved mock, and the assets the producer wrote.
|
||||
Return to [new-work.md](new-work.md) for the direction contract, implementation, and finishing pass.
|
||||
|
||||
@@ -1,257 +1,86 @@
|
||||
> **Additional context needed**: existing brand colors.
|
||||
|
||||
Replace timid grayscale or single-accent designs with a strategic palette: pick a color strategy, choose a hue family that fits the brand, then apply color with intent. More color ≠ better. Strategic color beats rainbow vomit.
|
||||
Introduce color as hierarchy, meaning, and atmosphere. Preserve confirmed brand and semantic conventions; do not replace a visual world under the guise of colorizing it.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: palette IS voice. Pick a color strategy first per SKILL.md (Restrained / Committed / Full palette / Drenched) and follow its dosage. Committed, Full palette, and Drenched deliberately exceed the ≤10% rule; that rule is Restrained only. Unexpected combinations are allowed; a dominant color can own the page when the chosen strategy calls for it.
|
||||
- **Persuade + Experience:** color may carry the voice and own large regions when the selected world calls for it.
|
||||
- **Operate + Read:** color primarily encodes action, selection, status, wayfinding, and reading hierarchy. Rarity gives an accent force.
|
||||
|
||||
Operate + Read: semantic-first and almost always Restrained. Accent color is reserved for primary action, current selection, and state indicators. Not decoration. Every color has a consistent meaning across every screen.
|
||||
## Audit before choosing
|
||||
|
||||
---
|
||||
Read DESIGN.md, tokens, assets, current themes, and representative states. Identify:
|
||||
|
||||
## Assess Color Opportunity
|
||||
- which colors are confirmed brand commitments;
|
||||
- current surface, text, action, and semantic roles;
|
||||
- places where grayscale obscures hierarchy or state;
|
||||
- contrast failures and color-only communication;
|
||||
- light/dark or data-visualization requirements;
|
||||
- whether the task asks for more color or a new identity.
|
||||
|
||||
Analyze the current state and identify opportunities:
|
||||
If a new identity is required, use [new-work.md](new-work.md). Ask only when a binding brand decision cannot be inferred.
|
||||
|
||||
1. **Understand current state**:
|
||||
- **Color absence**: Pure grayscale? Limited neutrals? One timid accent?
|
||||
- **Missed opportunities**: Where could color add meaning, hierarchy, or delight?
|
||||
- **Context**: What's appropriate for this domain and audience?
|
||||
- **Brand**: Are there existing brand colors we should use?
|
||||
## Choose a strategy
|
||||
|
||||
2. **Identify where color adds value**:
|
||||
- **Semantic meaning**: Success (green), error (red), warning (yellow/orange), info (blue)
|
||||
- **Hierarchy**: Drawing attention to important elements
|
||||
- **Categorization**: Different sections, types, or states
|
||||
- **Emotional tone**: Warmth, energy, trust, creativity
|
||||
- **Wayfinding**: Helping users navigate and understand structure
|
||||
- **Delight**: Moments of visual interest and personality
|
||||
Name the intended emotional temperature, dominant relationship, contrast range, and color dosage before editing. The strategy may be restrained or immersive; it must follow the brief and selected world rather than a fixed percentage rule.
|
||||
|
||||
If any of these are unclear from the codebase, ask the user directly to clarify what you cannot infer.
|
||||
Build roles, not a bag of swatches:
|
||||
|
||||
**CRITICAL**: More color ≠ better. Strategic color beats rainbow vomit every time. Every color should have a purpose.
|
||||
- canvas and elevated surfaces;
|
||||
- primary and secondary text;
|
||||
- action, focus, and selection;
|
||||
- borders and separators;
|
||||
- success, warning, error, and information;
|
||||
- data categories or scales when needed.
|
||||
|
||||
## Plan Color Strategy
|
||||
Use the project's existing color space. For a new web palette, prefer OKLCH because lightness and chroma can be adjusted predictably. Choose hue from product meaning and visual direction, never from a default category association.
|
||||
|
||||
Create a purposeful color introduction plan:
|
||||
## Apply at system scale
|
||||
|
||||
- **Color palette**: What colors match the brand/context? (Choose 2-4 colors max beyond neutrals)
|
||||
- **Dominant color**: Which color owns 60% of colored elements?
|
||||
- **Accent colors**: Which colors provide contrast and highlights? (30% and 10%)
|
||||
- **Application strategy**: Where does each color appear and why?
|
||||
- Let the strongest color own a deliberate region or role instead of scattering tiny accents.
|
||||
- Keep the primary action easy to find; do not spend its color on decoration.
|
||||
- Tint neutrals only when the brand hue genuinely creates cohesion. Neutral gray is valid when it serves the world.
|
||||
- On colored surfaces, derive secondary text from the foreground or surface hue rather than using washed-out generic gray.
|
||||
- Keep semantic meanings consistent, but respect platform and domain conventions instead of assuming fixed hues.
|
||||
- For data, use distinct lightness, chroma, shape, label, or pattern so color is not the only code.
|
||||
- In dark mode, design surface elevation and contrast explicitly; do not invert the light theme mechanically.
|
||||
- Define primitive values and semantic tokens when the project has a token system. Theme changes should normally remap semantic roles.
|
||||
|
||||
**IMPORTANT**: Color should enhance hierarchy and meaning, not create chaos. Less is more when it matters more.
|
||||
Decoration without a relationship to hierarchy, state, content, or the visual world is not a color strategy.
|
||||
|
||||
## Introduce Color Strategically
|
||||
## Contrast and perception
|
||||
|
||||
Add color systematically across these dimensions:
|
||||
Verify computed foreground/background pairs:
|
||||
|
||||
### Semantic Color
|
||||
- **State indicators**:
|
||||
- Success: Green tones (emerald, forest, mint)
|
||||
- Error: Red/pink tones (rose, crimson, coral)
|
||||
- Warning: Orange/amber tones
|
||||
- Info: Blue tones (sky, ocean, indigo)
|
||||
- Neutral: Gray/slate for inactive states
|
||||
| Content | WCAG AA minimum |
|
||||
|---|---|
|
||||
| body text | 4.5:1 |
|
||||
| large text | 3:1 |
|
||||
| controls, icons, focus indicators | 3:1 |
|
||||
|
||||
- **Status badges**: Colored backgrounds or borders for states (active, pending, completed, etc.)
|
||||
- **Progress indicators**: Colored bars, rings, or charts showing completion or health
|
||||
Do not rely on eyesight alone. Check interactive states, overlays, text on images, disabled content, and both themes. Simulate common vision deficiencies. Information conveyed by color also needs text, shape, iconography, or position.
|
||||
|
||||
### Accent Color Application
|
||||
- **Primary actions**: Color the most important buttons/CTAs
|
||||
- **Links**: Add color to clickable text (maintain accessibility)
|
||||
- **Icons**: Colorize key icons for recognition and personality
|
||||
- **Headers/titles**: Add color to section headers or key labels
|
||||
- **Hover states**: Introduce color on interaction
|
||||
When deriving OKLCH ramps, vary lightness and reduce chroma near white and black. Do not keep high chroma at extreme lightness merely to make the math uniform. Prefer explicit colors over chains of translucent overlays when alpha would make contrast context-dependent.
|
||||
|
||||
### Background & Surfaces
|
||||
- **Tinted backgrounds**: If you replace pure gray, tint toward the brand hue, not toward a generic-warm-or-cool pair. The default-warm-tint (`oklch(97% 0.01 60)` and its neighbors) is now the AI cream/sand giveaway. Be specific to the brand or stay neutral.
|
||||
- **Colored sections**: Use subtle background colors to separate areas
|
||||
- **Gradient backgrounds**: Add depth with subtle, intentional gradients (not generic purple-blue)
|
||||
- **Cards & surfaces**: Tint cards or surfaces toward the brand, not "for warmth" by reflex
|
||||
## Verify
|
||||
|
||||
**Use OKLCH for color**: It's perceptually uniform, meaning equal steps in lightness *look* equal. Great for generating harmonious scales.
|
||||
|
||||
### Data Visualization
|
||||
- **Charts & graphs**: Use color to encode categories or values
|
||||
- **Heatmaps**: Color intensity shows density or importance
|
||||
- **Comparison**: Color coding for different datasets or timeframes
|
||||
|
||||
### Borders & Accents
|
||||
- **Hairline borders**: 1px colored borders on full perimeter (not side-stripes; see the absolute ban on `border-left/right > 1px`)
|
||||
- **Underlines**: Color underlines for emphasis or active states
|
||||
- **Dividers**: Subtle colored dividers instead of gray lines
|
||||
- **Focus rings**: Colored focus indicators matching brand
|
||||
- **Surface tints**: A 4-8% background wash of the accent color instead of a stripe
|
||||
|
||||
**NEVER**: `border-left` or `border-right` greater than 1px as a colored accent stripe. This is one of the three absolute bans in the parent skill. If you want to mark a card as "active" or "warning", use a full hairline border, a background tint, a leading glyph, or a numbered prefix. Not a side stripe.
|
||||
|
||||
### Typography Color
|
||||
- **Colored headings**: Use brand colors for section headings (maintain contrast)
|
||||
- **Highlight text**: Color for emphasis or categories
|
||||
- **Labels & tags**: Small colored labels for metadata or categories
|
||||
|
||||
### Decorative Elements
|
||||
- **Illustrations**: Add colored illustrations or icons
|
||||
- **Shapes**: Geometric shapes in brand colors as background elements
|
||||
- **Gradients**: Colorful gradient overlays or mesh backgrounds
|
||||
- **Blobs/organic shapes**: Soft colored shapes for visual interest
|
||||
|
||||
## Balance & Refinement
|
||||
|
||||
Ensure color addition improves rather than overwhelms:
|
||||
|
||||
### Maintain Hierarchy
|
||||
- **Dominant color** (60%): Primary brand color or most used accent
|
||||
- **Secondary color** (30%): Supporting color for variety
|
||||
- **Accent color** (10%): High contrast for key moments
|
||||
- **Neutrals** (remaining): Gray/black/white for structure
|
||||
|
||||
### Accessibility
|
||||
- **Contrast ratios**: Ensure WCAG compliance (4.5:1 for text, 3:1 for UI components)
|
||||
- **Don't rely on color alone**: Use icons, labels, or patterns alongside color
|
||||
- **Test for color blindness**: Verify red/green combinations work for all users
|
||||
|
||||
### Cohesion
|
||||
- **Consistent palette**: Use colors from defined palette, not arbitrary choices
|
||||
- **Systematic application**: Same color meanings throughout (green always = success)
|
||||
- **Temperature consistency**: Warm palette stays warm, cool stays cool
|
||||
|
||||
**NEVER**:
|
||||
- Use every color in the rainbow (choose 2-4 colors beyond neutrals)
|
||||
- Apply color randomly without semantic meaning
|
||||
- Put gray text on colored backgrounds. It looks washed out; use a darker shade of the background color or transparency instead
|
||||
- Violate WCAG contrast requirements
|
||||
- Use color as the only indicator (accessibility issue)
|
||||
- Make everything colorful (defeats the purpose)
|
||||
- Default to purple-blue gradients (AI slop aesthetic)
|
||||
|
||||
## Verify Color Addition
|
||||
|
||||
Test that colorization improves the experience:
|
||||
|
||||
- **Better hierarchy**: Does color guide attention appropriately?
|
||||
- **Clearer meaning**: Does color help users understand states/categories?
|
||||
- **More engaging**: Does the interface feel warmer and more inviting?
|
||||
- **Still accessible**: Do all color combinations meet WCAG standards?
|
||||
- **Not overwhelming**: Is color balanced and purposeful?
|
||||
- Every color has a stable role or a world-specific atmospheric purpose.
|
||||
- Attention lands on the intended action, content, or state.
|
||||
- The palette works across quiet, dense, interactive, error, and empty states.
|
||||
- Light and dark themes are each composed, not mechanically inverted.
|
||||
- Contrast and non-color cues pass in all relevant states.
|
||||
- The result is recognizably this product, not a generic “colorful” treatment.
|
||||
|
||||
When the palette earns its place, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
## Live-mode signature params
|
||||
|
||||
When invoked from live mode, each variant MUST declare a `color-amount` param so the user can dial between a restrained accent and a drenched surface without regeneration. Author the variant's CSS against `var(--p-color-amount, 0.5)`, typically as the alpha multiplier on backgrounds, or as a scaling factor on the chroma axis in an OKLCH expression. 0 = neutral/monochrome, 1 = full saturation / dominant coverage.
|
||||
When invoked from live mode, every variant declares a `color-amount` parameter. Author CSS against `var(--p-color-amount, 0.5)` so the user can move from neutral to the variant's full color strategy without regeneration.
|
||||
|
||||
```json
|
||||
{"id":"color-amount","kind":"range","min":0,"max":1,"step":0.05,"default":0.5,"label":"Color amount"}
|
||||
```
|
||||
|
||||
Layer 1-2 variant-specific params on top: palette selection (`steps` with named options), temperature warmth, or tint vs. true color. See `reference/live.md` for the full params contract.
|
||||
|
||||
---
|
||||
|
||||
## Reference Material
|
||||
|
||||
The sections below were previously `color-and-contrast.md` and live inline now so the colorize flow has its deep color reference in one place.
|
||||
|
||||
### Color & Contrast
|
||||
|
||||
#### Color Spaces: Use OKLCH
|
||||
|
||||
**Stop using HSL.** Use OKLCH (or LCH) instead. It's perceptually uniform, meaning equal steps in lightness *look* equal, unlike HSL where 50% lightness in yellow looks bright while 50% in blue looks dark.
|
||||
|
||||
The OKLCH function takes three components: `oklch(lightness chroma hue)` where lightness is 0-100%, chroma is roughly 0-0.4, and hue is 0-360. To build a primary color and its lighter / darker variants, hold the chroma+hue roughly constant and vary the lightness, but **reduce chroma as you approach white or black**, because high chroma at extreme lightness looks garish.
|
||||
|
||||
The hue you pick is a brand decision and should not come from a default. Do not reach for blue (hue 250) or warm orange (hue 60) by reflex; those are the dominant AI-design defaults, not the right answer for any specific brand.
|
||||
|
||||
#### Building Functional Palettes
|
||||
|
||||
##### Tinted Neutrals
|
||||
|
||||
**Pure gray is dead.** A neutral with zero chroma feels lifeless next to a colored brand. Add a tiny chroma value (0.005-0.015) to all your neutrals, hued toward whatever your brand color is. The chroma is small enough not to read as "tinted" consciously, but it creates subconscious cohesion between brand color and UI surfaces.
|
||||
|
||||
The hue you tint toward should come from THIS project's brand, not from a "warm = friendly, cool = tech" formula. If your brand color is teal, your neutrals lean toward teal. If your brand color is amber, they lean toward amber. The point is cohesion with the SPECIFIC brand, not a stock palette.
|
||||
|
||||
**Avoid** the trap of always tinting toward warm orange or always tinting toward cool blue. Those are the two laziest defaults and they create their own monoculture across projects.
|
||||
|
||||
##### Palette Structure
|
||||
|
||||
A complete system needs:
|
||||
|
||||
| Role | Purpose | Example |
|
||||
|------|---------|---------|
|
||||
| **Primary** | Brand, CTAs, key actions | 1 color, 3-5 shades |
|
||||
| **Neutral** | Text, backgrounds, borders | 9-11 shade scale |
|
||||
| **Semantic** | Success, error, warning, info | 4 colors, 2-3 shades each |
|
||||
| **Surface** | Cards, modals, overlays | 2-3 elevation levels |
|
||||
|
||||
**Skip secondary/tertiary unless you need them.** Most apps work fine with one accent color. Adding more creates decision fatigue and visual noise.
|
||||
|
||||
##### The 60-30-10 Rule (Applied Correctly)
|
||||
|
||||
This rule is about **visual weight**, not pixel count:
|
||||
|
||||
- **60%**: Neutral backgrounds, white space, base surfaces
|
||||
- **30%**: Secondary colors: text, borders, inactive states
|
||||
- **10%**: Accent: CTAs, highlights, focus states
|
||||
|
||||
The common mistake: using the accent color everywhere because it's "the brand color." Accent colors work *because* they're rare. Overuse kills their power.
|
||||
|
||||
#### Contrast & Accessibility
|
||||
|
||||
##### WCAG Requirements
|
||||
|
||||
| Content Type | AA Minimum | AAA Target |
|
||||
|--------------|------------|------------|
|
||||
| Body text | 4.5:1 | 7:1 |
|
||||
| Large text (18px+ or 14px bold) | 3:1 | 4.5:1 |
|
||||
| UI components, icons | 3:1 | 4.5:1 |
|
||||
| Non-essential decorations | None | None |
|
||||
|
||||
##### Dangerous Color Combinations
|
||||
|
||||
These commonly fail contrast or cause readability issues:
|
||||
|
||||
- Light gray text on white (the #1 accessibility fail)
|
||||
- Red text on green background (or vice versa): 8% of men can't distinguish these
|
||||
- Blue text on red background (vibrates visually)
|
||||
- Yellow text on white (almost always fails)
|
||||
- Thin light text on images (unpredictable contrast)
|
||||
|
||||
##### Testing
|
||||
|
||||
Don't trust your eyes. Use tools:
|
||||
|
||||
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
||||
- Browser DevTools → Rendering → Emulate vision deficiencies
|
||||
- [Polypane](https://polypane.app/) for real-time testing
|
||||
|
||||
#### Theming: Light & Dark Mode
|
||||
|
||||
##### Dark Mode Is Not Inverted Light Mode
|
||||
|
||||
You can't just swap colors. Dark mode requires different design decisions:
|
||||
|
||||
| Light Mode | Dark Mode |
|
||||
|------------|-----------|
|
||||
| Shadows for depth | Lighter surfaces for depth (no shadows) |
|
||||
| Dark text on light | Light text on dark (reduce font weight) |
|
||||
| Vibrant accents | Desaturate accents slightly |
|
||||
| White backgrounds | Either pure black or a deep surface that fits the brand (a brand-tinted near-black at oklch 12-18% works too) |
|
||||
|
||||
In dark mode, depth comes from surface lightness, not shadow. Build a 3-step surface scale where higher elevations are lighter (e.g. 15% / 20% / 25% lightness). Use the SAME hue and chroma as your brand color (whatever it is for THIS project; do not reach for blue) and only vary the lightness. Reduce body text weight slightly (e.g. 350 instead of 400) because light text on dark reads as heavier than dark text on light.
|
||||
|
||||
##### Token Hierarchy
|
||||
|
||||
Use two layers: primitive tokens (`--blue-500`) and semantic tokens (`--color-primary: var(--blue-500)`). For dark mode, only redefine the semantic layer; primitives stay the same.
|
||||
|
||||
#### Alpha Is A Design Smell
|
||||
|
||||
Heavy use of transparency (rgba, hsla) usually means an incomplete palette. Alpha creates unpredictable contrast, performance overhead, and inconsistency. Define explicit overlay colors for each context instead. Exception: focus rings and interactive states where see-through is needed.
|
||||
|
||||
---
|
||||
|
||||
**Avoid**: Relying on color alone to convey information. Creating palettes without clear roles for each color. Skipping color blindness testing (8% of men affected).
|
||||
Add at most two variant-specific parameters, such as palette, temperature, or tint behavior. Follow [live.md](live.md)'s parameter contract.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Craft (deprecated alias)
|
||||
|
||||
`craft` is a deprecated alias for the standard build flow. Builds route through SKILL.md's new-work gate; [new-work.md](new-work.md) carries the direction checkpoint ("Decide, then build"), the identity playbook, and the finishing pass. Invoking `craft` explicitly forces the attended checkpoints: pause at the stated direction for confirmation, and follow [codex.md](codex.md)'s mock flow when the harness generates images. Nothing else differs from a plain build request.
|
||||
`craft` is a deprecated alias for an ordinary request to make new visual work. It adds no setup, interview, checkpoint, tool, or quality behavior. Apply SKILL.md's normal routing: create missing PRODUCT.md through [init.md](init.md), then follow [new-work.md](new-work.md) for visual authority, world and surface decisions, implementation, and finish.
|
||||
|
||||
Do not tell users they need to invoke `craft`. Natural requests such as “build this feature,” “make a landing page,” or “redesign this screen” use the same flow.
|
||||
|
||||
@@ -43,13 +43,13 @@ If browser automation is available, each assessment creates its own new tab. Nev
|
||||
Read relevant source files and visually inspect the live page when browser automation is available. Think like a design director.
|
||||
|
||||
Evaluate:
|
||||
- **AI slop**: Would someone believe "AI made this" immediately? Check all DON'T guidance from the parent Impeccable skill.
|
||||
- **Design specificity**: Is the composition, interaction, and visual language grounded in this product, or could an unrelated product use it unchanged? Make this judgment before seeing detector output.
|
||||
- **Holistic design**: hierarchy, IA, emotional fit, discoverability, composition, typography, color, accessibility, states, copy, and edge cases.
|
||||
- **Cognitive load**: consult the [Cognitive Load Assessment](#cognitive-load-assessment) section below; report checklist failures and decision points with >4 visible options.
|
||||
- **Emotional journey**: peak-end rule, emotional valleys, reassurance at high-stakes moments.
|
||||
- **Nielsen heuristics**: consult the [Heuristics Scoring Guide](#heuristics-scoring-guide) section below; score all 10 heuristics 0-4, marking any heuristic the mode-applicability rule allows as `n/a` instead of forcing a number.
|
||||
|
||||
Return: AI slop verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
Return: design-specificity verdict, heuristic scores, cognitive load, emotional journey, 2-3 strengths, 3-5 priority issues, persona red flags, minor observations, and provocative questions.
|
||||
|
||||
### Assessment B: Detector + Browser Evidence
|
||||
|
||||
@@ -115,11 +115,11 @@ Be honest with scores. A 4 means genuinely excellent. Most real interfaces score
|
||||
|
||||
**Mode applicability**: heuristics 7 (Flexibility and Efficiency) and 10 (Help and Documentation) may be scored `n/a` on Persuade and Experience surfaces (landing pages, campaigns, portfolios, bodies of work), as may any other heuristic that genuinely cannot apply to the surface under review. Write `n/a` in the Score cell with a one-line reason, and renormalize the total to the applicable maximum (e.g. **24/32** when two heuristics are n/a) so the rating band stays proportional. The persisted snapshot must record which heuristics were scored n/a.
|
||||
|
||||
#### Anti-Patterns Verdict
|
||||
#### Design Specificity Verdict
|
||||
|
||||
**Start here.** Does this look AI-generated?
|
||||
**Start here.** Does the result feel authored for this product, or category-interchangeable?
|
||||
|
||||
**LLM assessment**: Your own evaluation of AI slop tells. Cover overall aesthetic feel, layout sameness, generic composition, missed opportunities for personality.
|
||||
**LLM assessment**: Your unanchored evaluation of design specificity. Cover overall coherence, structural sameness, category-interchangeable choices, and missed opportunities for product character.
|
||||
|
||||
**Deterministic scan**: Summarize what the automated detector found, with counts and file locations. Note any additional issues the detector caught that you missed, and flag any false positives.
|
||||
|
||||
@@ -176,7 +176,7 @@ Once the report above is finalized, write it to `.impeccable/critique/` so the u
|
||||
|
||||
Skip this step if the Setup slug was null (vague or root-level target).
|
||||
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, anti-patterns verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
1. **Write the body to a temp file** so you can pipe it to the helper. Use the full critique report (heuristic table, design-specificity verdict, priority issues, persona red flags, minor observations, and questions), but stop before the "Ask the User" / "Recommended Actions" sections that come later.
|
||||
|
||||
2. **Pass the structured metadata** through `IMPECCABLE_CRITIQUE_META` (JSON), then run the write command:
|
||||
```bash
|
||||
|
||||
@@ -1,302 +1,70 @@
|
||||
> **Additional context needed**: what's appropriate for the domain (playful vs professional vs quirky vs elegant).
|
||||
> **Additional context needed**: the brand's emotional range.
|
||||
|
||||
Find the moments where personality and unexpected polish would turn a functional interface into one users remember and tell other people about. Add only where the moment earns it; delight everywhere reads as noise.
|
||||
Make the experience memorable at moments that earn it. Delight is not a layer of generic whimsy; it is product character revealed through a useful interaction, a humane response, or an unexpectedly considered detail.
|
||||
|
||||
---
|
||||
|
||||
## Register
|
||||
## Visitor mode
|
||||
|
||||
Persuade + Experience: delight can be distributed across copy voice, section transitions, discovery rewards, seasonal touches, personality across the whole surface.
|
||||
- **Persuade + Experience:** personality may run through voice, composition, motion, and discovery, provided the artifact remains the focus.
|
||||
- **Operate + Read:** concentrate delight at meaningful moments such as first use, completion, recovery, or mastery. Reliability carries everything else.
|
||||
|
||||
Operate + Read: delight at specific moments, not pages. Completion, first-time actions, error recovery, milestone crossings. Reliability and consistency carry the rest of the experience; delight pushed everywhere reads as noise.
|
||||
## Find the opportunity
|
||||
|
||||
---
|
||||
Inspect the target, DESIGN.md, product voice, repeated-use frequency, and emotional context. Look for:
|
||||
|
||||
## Assess Delight Opportunities
|
||||
- effort worth acknowledging;
|
||||
- waiting that can become informative;
|
||||
- an empty or first-use state that can orient;
|
||||
- an error or recovery moment that needs empathy;
|
||||
- an interaction whose physical or verbal response could express the brand;
|
||||
- a useful capability people might enjoy discovering.
|
||||
|
||||
Identify where delight would enhance (not distract from) the experience:
|
||||
Do not manufacture a celebration for an ordinary click. Ask only when the brand's emotional range or the stakes cannot be inferred.
|
||||
|
||||
1. **Find natural delight moments**:
|
||||
- **Success states**: Completed actions (save, send, publish)
|
||||
- **Empty states**: First-time experiences, onboarding
|
||||
- **Loading states**: Waiting periods that could be entertaining
|
||||
- **Achievements**: Milestones, streaks, completions
|
||||
- **Interactions**: Hover states, clicks, drags
|
||||
- **Errors**: Softening frustrating moments
|
||||
- **Easter eggs**: Hidden discoveries for curious users
|
||||
## Define one delight thesis
|
||||
|
||||
2. **Understand the context**:
|
||||
- What's the brand personality? (Playful? Professional? Quirky? Elegant?)
|
||||
- Who's the audience? (Tech-savvy? Creative? Corporate?)
|
||||
- What's the emotional context? (Accomplishment? Exploration? Frustration?)
|
||||
- What's appropriate? (Banking app ≠ gaming app)
|
||||
State in one sentence what the user should feel and why that feeling belongs to this product. Then choose the smallest system that can deliver it:
|
||||
|
||||
3. **Define delight strategy**:
|
||||
- **Subtle sophistication**: Refined micro-interactions (luxury brands)
|
||||
- **Playful personality**: Whimsical illustrations and copy (consumer apps)
|
||||
- **Helpful surprises**: Anticipating needs before users ask (productivity tools)
|
||||
- **Sensory richness**: Satisfying sounds, smooth animations (creative tools)
|
||||
- a distinctive response to a meaningful action;
|
||||
- product-specific language that clarifies while carrying voice;
|
||||
- an interaction or transition with a recognizable material behavior;
|
||||
- an illustration, sound, haptic, or environmental detail grounded in the product world;
|
||||
- a discovery reward that reveals real utility.
|
||||
|
||||
If any of these are unclear from the codebase, ask the user directly to clarify what you cannot infer.
|
||||
Derive the treatment from product mechanism and visual world, not a stock catalog.
|
||||
|
||||
**CRITICAL**: Delight should enhance usability, never obscure it. If users notice the delight more than accomplishing their goal, you've gone too far.
|
||||
## Build for the emotional moment
|
||||
|
||||
## Delight Principles
|
||||
- **Success:** match the response to the effort and consequence. Major milestones can expand; routine saves should simply feel certain.
|
||||
- **Waiting:** show truthful progress, useful context, or product-specific activity. Never fake work or delay completion to stage a flourish.
|
||||
- **Empty and first use:** make the next action clear before adding personality.
|
||||
- **Error and recovery:** lead with the problem and recovery. Warmth may reduce stress; jokes must not trivialize loss, money, privacy, or blocked work.
|
||||
- **Repeated interaction:** keep the response satisfying after the hundredth use. Variation is useful only when it remains coherent and predictable enough to trust.
|
||||
- **Discovery:** reward curiosity without hiding required functionality.
|
||||
|
||||
Follow these guidelines:
|
||||
Copy must use the product's language. Generic whimsy is worse than neutral clarity.
|
||||
|
||||
### Delight Amplifies, Never Blocks
|
||||
- Delight moments should be quick (< 1 second)
|
||||
- Never delay core functionality for delight
|
||||
- Make delight skippable or subtle
|
||||
- Respect user's time and task focus
|
||||
## Protect the experience
|
||||
|
||||
### Surprise and Discovery
|
||||
- Hide delightful details for users to discover
|
||||
- Reward exploration and curiosity
|
||||
- Don't announce every delight moment
|
||||
- Let users share discoveries with others
|
||||
Delight must not:
|
||||
|
||||
### Appropriate to Context
|
||||
- Match delight to emotional moment (celebrate success, empathize with errors)
|
||||
- Respect the user's state (don't be playful during critical errors)
|
||||
- Match brand personality and audience expectations
|
||||
- Cultural sensitivity (what's delightful varies by culture)
|
||||
- delay, block, or obscure the primary task;
|
||||
- override platform conventions or accessibility;
|
||||
- add unrequested factual claims;
|
||||
- play sound without consent or ignore mute settings;
|
||||
- become mandatory, unskippable, or exhausting on repeat;
|
||||
- add a dependency or asset cost disproportionate to the moment.
|
||||
|
||||
### Compound Over Time
|
||||
- Delight should remain fresh with repeated use
|
||||
- Vary responses (not same animation every time)
|
||||
- Reveal deeper layers with continued use
|
||||
- Build anticipation through patterns
|
||||
For authored motion, load [animate.md](animate.md). Respect reduced motion, screen readers, keyboard use, touch, localization, and cultural context. Nonessential loops stop when hidden. Make celebration intensity proportional to frequency and consequence.
|
||||
|
||||
## Delight Techniques
|
||||
## Verify
|
||||
|
||||
Add personality and joy through these methods:
|
||||
- The moment is specific enough that a neighboring product could not use it unchanged.
|
||||
- It improves comprehension, confidence, motivation, or emotional recovery.
|
||||
- The interface remains fast and obvious without the flourish.
|
||||
- Repetition does not turn charm into friction.
|
||||
- Reduced-motion, muted, keyboard, touch, and localized paths work.
|
||||
- The result feels like the selected world, not a generic “delight” treatment.
|
||||
|
||||
### Micro-interactions & Animation
|
||||
|
||||
**Button delight**:
|
||||
```css
|
||||
/* Satisfying button press */
|
||||
.button {
|
||||
transition: transform 0.1s, box-shadow 0.1s;
|
||||
}
|
||||
.button:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Ripple effect on click */
|
||||
/* Smooth lift on hover */
|
||||
.button:hover {
|
||||
transform: translateY(-2px);
|
||||
transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1); /* ease-out-quart */
|
||||
}
|
||||
```
|
||||
|
||||
**Loading delight**:
|
||||
- Playful loading animations (not just spinners)
|
||||
- Personality in loading messages (write product-specific ones, not generic AI filler)
|
||||
- Progress indication with encouraging messages
|
||||
- Skeleton screens with subtle animations
|
||||
|
||||
**Success animations**:
|
||||
- Checkmark draw animation
|
||||
- Confetti burst for major achievements
|
||||
- Gentle scale + fade for confirmation
|
||||
- Satisfying sound effects (subtle)
|
||||
|
||||
**Hover surprises**:
|
||||
- Icons that animate on hover
|
||||
- Color shifts or glow effects
|
||||
- Tooltip reveals with personality
|
||||
- Cursor changes (custom cursors for branded experiences)
|
||||
|
||||
### Personality in Copy
|
||||
|
||||
**Playful error messages**:
|
||||
```
|
||||
"Error 404"
|
||||
"This page is playing hide and seek. (And winning)"
|
||||
|
||||
"Connection failed"
|
||||
"Looks like the internet took a coffee break. Want to retry?"
|
||||
```
|
||||
|
||||
**Encouraging empty states**:
|
||||
```
|
||||
"No projects"
|
||||
"Your canvas awaits. Create something amazing."
|
||||
|
||||
"No saved articles"
|
||||
"Nothing on the nightstand yet. Save a story for later."
|
||||
```
|
||||
|
||||
**Playful labels & tooltips**:
|
||||
```
|
||||
"Delete"
|
||||
"Send to void" (for playful brand)
|
||||
|
||||
"Help"
|
||||
"Rescue me" (tooltip)
|
||||
```
|
||||
|
||||
**IMPORTANT**: Match copy personality to brand. Banks shouldn't be wacky, but they can be warm.
|
||||
|
||||
### Illustrations & Visual Personality
|
||||
|
||||
**Custom illustrations**:
|
||||
- Empty state illustrations (not stock icons)
|
||||
- Error state illustrations (friendly monsters, quirky characters)
|
||||
- Loading state illustrations (animated characters)
|
||||
- Success state illustrations (celebrations)
|
||||
|
||||
**Icon personality**:
|
||||
- Custom icon set matching brand personality
|
||||
- Animated icons (subtle motion on hover/click)
|
||||
- Illustrative icons (more detailed than generic)
|
||||
- Consistent style across all icons
|
||||
|
||||
**Background effects**:
|
||||
- Subtle particle effects
|
||||
- Gradient mesh backgrounds
|
||||
- Geometric patterns
|
||||
- Parallax depth
|
||||
- Time-of-day themes (morning vs night)
|
||||
|
||||
### Satisfying Interactions
|
||||
|
||||
**Drag and drop delight**:
|
||||
- Lift effect on drag (shadow, scale)
|
||||
- Snap animation when dropped
|
||||
- Satisfying placement sound
|
||||
- Undo toast ("Dropped in wrong place? [Undo]")
|
||||
|
||||
**Toggle switches**:
|
||||
- Smooth slide with spring physics
|
||||
- Color transition
|
||||
- Haptic feedback on mobile
|
||||
- Optional sound effect
|
||||
|
||||
**Progress & achievements** (Operate surfaces with recurring tasks only; gamification on editorial, portfolio, or one-visit surfaces reads as noise):
|
||||
- Streak counters with celebratory milestones
|
||||
- Progress bars that "celebrate" at 100%
|
||||
- Badge unlocks with animation
|
||||
- Playful stats ("You're on fire! 5 days in a row")
|
||||
|
||||
**Form interactions**:
|
||||
- Input fields that animate on focus
|
||||
- Checkboxes with a satisfying scale pulse when checked
|
||||
- Success state that celebrates valid input
|
||||
- Auto-grow textareas
|
||||
|
||||
### Sound Design
|
||||
|
||||
**Subtle audio cues** (when appropriate):
|
||||
- Notification sounds (distinctive but not annoying)
|
||||
- Success sounds (satisfying "ding")
|
||||
- Error sounds (empathetic, not harsh)
|
||||
- Typing sounds for chat/messaging
|
||||
- Ambient background audio (very subtle)
|
||||
|
||||
**IMPORTANT**:
|
||||
- Respect system sound settings
|
||||
- Provide mute option
|
||||
- Keep volumes quiet (subtle cues, not alarms)
|
||||
- Don't play on every interaction (sound fatigue is real)
|
||||
|
||||
### Easter Eggs & Hidden Delights
|
||||
|
||||
**Discovery rewards**:
|
||||
- Konami code unlocks special theme
|
||||
- Hidden keyboard shortcuts (Cmd+K for special features)
|
||||
- Hover reveals on logos or illustrations
|
||||
- Alt text jokes on images (for screen reader users too!)
|
||||
- A view-source or console colophon (a note on the typefaces, a thank-you, a hiring line)
|
||||
|
||||
**Seasonal touches**:
|
||||
- Holiday themes (subtle, tasteful)
|
||||
- Seasonal color shifts
|
||||
- Weather-based variations
|
||||
- Time-based changes (dark at night, light during day)
|
||||
|
||||
**Contextual personality**:
|
||||
- Different messages based on time of day
|
||||
- Responses to specific user actions
|
||||
- Randomized variations (not same every time)
|
||||
- Progressive reveals with continued use
|
||||
|
||||
### Loading & Waiting States
|
||||
|
||||
**Make waiting engaging**:
|
||||
- Interesting loading messages that rotate
|
||||
- Progress bars with personality
|
||||
- Mini-games during long loads
|
||||
- Fun facts or tips while waiting
|
||||
- Countdown with encouraging messages
|
||||
|
||||
```
|
||||
Loading messages: write ones specific to your product, not generic AI filler:
|
||||
- "Syncing with your team's changes..."
|
||||
- "Fetching this week's issue..."
|
||||
- "Developing your photos..."
|
||||
- "Checking tomorrow's tide tables..."
|
||||
```
|
||||
|
||||
**WARNING**: Avoid cliched loading messages like "Herding pixels", "Teaching robots to dance", "Consulting the magic 8-ball", "Counting backwards from infinity". These are AI-slop copy, instantly recognizable as machine-generated. Write messages that are specific to what your product actually does.
|
||||
|
||||
### Celebration Moments
|
||||
|
||||
**Success celebrations**:
|
||||
- Confetti for major milestones
|
||||
- Animated checkmarks for completions
|
||||
- Progress bar celebrations at 100%
|
||||
- "Achievement unlocked" style notifications
|
||||
- Personalized messages ("You published your 10th article!")
|
||||
|
||||
**Milestone recognition** (same scoping as Progress & achievements: Operate surfaces with recurring tasks):
|
||||
- First-time actions get special treatment
|
||||
- Streak tracking and celebration
|
||||
- Progress toward goals
|
||||
- Anniversary celebrations
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
**Animation libraries**:
|
||||
- Framer Motion (React)
|
||||
- GSAP (universal)
|
||||
- Lottie (After Effects animations)
|
||||
- Canvas confetti (party effects)
|
||||
|
||||
**Sound libraries**:
|
||||
- Howler.js (audio management)
|
||||
- Use-sound (React hook)
|
||||
|
||||
**Physics libraries**:
|
||||
- React Spring (spring physics)
|
||||
- Popmotion (animation primitives)
|
||||
|
||||
**IMPORTANT**: File size matters. Compress images, optimize animations, lazy load delight features.
|
||||
|
||||
**NEVER**:
|
||||
- Delay core functionality for delight
|
||||
- Force users through delightful moments (make skippable)
|
||||
- Use delight to hide poor UX
|
||||
- Overdo it (less is more)
|
||||
- Ignore accessibility (animate responsibly, provide alternatives)
|
||||
- Make every interaction delightful (special moments should be special)
|
||||
- Sacrifice performance for delight
|
||||
- Be inappropriate for context (read the room)
|
||||
|
||||
## Verify Delight Quality
|
||||
|
||||
Test that delight actually delights:
|
||||
|
||||
- **User reactions**: Do users smile? Share screenshots?
|
||||
- **Doesn't annoy**: Still pleasant after 100th time?
|
||||
- **Doesn't block**: Can users opt out or skip?
|
||||
- **Performant**: No jank, no slowdown
|
||||
- **Appropriate**: Matches brand and context
|
||||
- **Accessible**: Works with reduced motion, screen readers
|
||||
|
||||
When the moments feel earned, hand off to `/impeccable polish` for the final pass.
|
||||
When the personality feels earned, hand off to `/impeccable polish` for the final pass.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Generate a `DESIGN.md` file at the project root that captures the current visual design system, so AI agents generating new screens stay on-brand.
|
||||
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): YAML frontmatter carrying machine-readable design tokens, followed by a markdown body with exactly six sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but **do not reorder them and do not rename them**. Section headers must match the spec character-for-character so the file stays parseable by other DESIGN.md-aware tools (Stitch itself, awesome-design-md, skill-rest, etc.).
|
||||
DESIGN.md follows the [official DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md): optional YAML frontmatter carrying machine-readable design tokens, followed by up to eight markdown sections in a fixed order. **Tokens are normative; prose provides context for how to apply them.** Sections may be omitted when not relevant, but those present stay in the specified order. Use the canonical headings below so the file remains portable across DESIGN.md-aware tools.
|
||||
|
||||
## The frontmatter: token schema
|
||||
|
||||
@@ -43,26 +43,28 @@ components:
|
||||
Rules that matter:
|
||||
|
||||
- **Token refs** use `{path.to.token}` (e.g. `{colors.primary}`, `{rounded.md}`). Components may reference primitives; primitives may not reference each other.
|
||||
- **Stitch validates colors as hex sRGB only** (`#RGB` / `#RGBA` / `#RRGGBB` / `#RRGGBBAA`); OKLCH/HSL/P3 trigger a linter warning, not a hard error. YAML accepts the string either way and our own parser is format-agnostic. Choose based on project posture: (a) if the project has an "OKLCH-only" doctrine or uses Display-P3 values that don't round-trip through sRGB, put OKLCH directly in the frontmatter and accept the Stitch linter warning; (b) if the project wants strict Stitch compliance or plans to use their Tailwind/DTCG export pipeline, put hex in the frontmatter and keep OKLCH in prose as the canonical reference. Never split the source of truth without explicit reason.
|
||||
- **Colors accept any valid CSS color string.** Hex is the recommended default for portability, but preserve an incumbent `rgb()`, `hsl()`, `oklch()`, wide-gamut, or mixed-color value when it is the project's normative source. Never split the source of truth without explicit reason.
|
||||
- **Component sub-tokens** are limited to 8 props: `backgroundColor`, `textColor`, `typography`, `rounded`, `padding`, `size`, `height`, `width`. Shadows, motion, focus rings, backdrop-filter: none of those fit. Carry them in the sidecar (Step 4b).
|
||||
- **Scale keys are open-ended.** Use whatever names the project already uses (`oxblood-deep`, `surface-container-low`). Don't rename to Material defaults.
|
||||
- **Variants are naming convention, not schema.** `button-primary` / `button-primary-hover` / `button-primary-active` as sibling keys.
|
||||
|
||||
## The markdown body: six sections (exact order)
|
||||
## The markdown body: eight sections (canonical order)
|
||||
|
||||
1. `## Overview`
|
||||
2. `## Colors`
|
||||
3. `## Typography`
|
||||
4. `## Elevation`
|
||||
5. `## Components`
|
||||
6. `## Do's and Don'ts`
|
||||
4. `## Layout`
|
||||
5. `## Elevation & Depth`
|
||||
6. `## Shapes`
|
||||
7. `## Components`
|
||||
8. `## Do's and Don'ts`
|
||||
|
||||
Optional evocative subtitles are allowed in the form `## 2. Colors: The [Name] Palette` (Stitch's own outputs do this), but the literal word in each header (Overview, Colors, Typography, Elevation, Components, Do's and Don'ts) must be present. Do NOT add extra top-level sections (Layout Principles, Responsive Behavior, Motion, Agent Prompt Guide). Fold that content into the six spec sections where it naturally belongs.
|
||||
Omit irrelevant sections rather than filling them with invented rules. Put responsive layout in Layout, depth in Elevation & Depth, radius and form language in Shapes, and per-component behavior in Components. Unknown sections are preserved by the format, but new visual guidance should use the canonical structure whenever it fits.
|
||||
|
||||
## When to run
|
||||
|
||||
- The user just ran `/impeccable init` and needs the visual side documented.
|
||||
- The skill noticed no `DESIGN.md` exists and nudged the user to create one.
|
||||
- New-work found a coherent incumbent visual system but no `DESIGN.md`.
|
||||
- The first implementation of a new world is complete and its provisional decisions need to be carbonized.
|
||||
- An existing `DESIGN.md` is stale (the design has drifted).
|
||||
- Before a large redesign, to capture the current state as a reference.
|
||||
|
||||
@@ -71,9 +73,9 @@ If a `DESIGN.md` already exists, **do not silently overwrite it**. Show the user
|
||||
## Two paths
|
||||
|
||||
- **Scan mode** (default): the project has design tokens, components, or rendered output. Extract, then confirm descriptive language. Use when there's code to analyze.
|
||||
- **Seed mode**: the project is pre-implementation (fresh init, nothing built yet). Interview for five high-level answers, write a minimal DESIGN.md marked `<!-- SEED -->`. Re-run in scan mode once there's code.
|
||||
- **Seed mode**: the project is pre-implementation. Ensure PRODUCT.md exists, then reuse new-work's visual-world workshop and write its directional DESIGN.md seed. Re-run in scan mode once there's code.
|
||||
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` forces seed mode regardless of code presence.
|
||||
Decide by scanning first (Scan mode Step 1). If the scan finds no tokens, no component files, and no rendered site, offer seed mode; don't silently switch. `/impeccable document --seed` requests new-work's world workshop, but it does not authorize replacing coherent code: when an incumbent system exists, offer scan mode or route an explicit identity-replacement request through new-work.
|
||||
|
||||
## Scan mode (approach C: auto-extract, then confirm descriptive language)
|
||||
|
||||
@@ -97,7 +99,8 @@ Build a structured draft from the discovered tokens. For each token class:
|
||||
- **Typography**: Map observed sizes and weights to the Material hierarchy (display / headline / title / body / label). Note font-family stacks and the scale ratio.
|
||||
- **Elevation**: Catalogue the shadow vocabulary. If the project is flat and uses tonal layering instead, that's a valid answer; state it explicitly.
|
||||
- **Components**: For each common component (button, card, input, chip, list item, tooltip, nav), extract shape (radius), color assignment, hover/focus treatment, internal padding.
|
||||
- **Spacing + layout**: Fold into Overview or relevant Components. The spec does NOT have a Layout section.
|
||||
- **Layout + spacing**: Extract grid, container, breakpoint, rhythm, and density behavior into Layout.
|
||||
- **Shapes**: Extract radius, corner, border, clipping, and recurring form behavior into Shapes.
|
||||
|
||||
### Step 2b: Stage the frontmatter
|
||||
|
||||
@@ -112,19 +115,19 @@ Skip anything the project doesn't have. Empty scale keys or fabricated tokens po
|
||||
|
||||
### Step 3: Ask the user for qualitative language
|
||||
|
||||
The following require creative input that cannot be auto-extracted. Group them into one `AskUserQuestion` interaction:
|
||||
The following require creative input that cannot be auto-extracted. Ask them in two structured rounds of no more than three questions each (or the harness's lower limit), waiting between rounds:
|
||||
|
||||
- **Creative North Star**: a single named metaphor for the whole system ("The Editorial Sanctuary", "The Golden State Curator", "The Lab Notebook"). Offer 2-3 options that honor PRODUCT.md's brand personality.
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, anti-references (what the system should not feel like).
|
||||
- **Overview voice**: mood adjectives, aesthetic philosophy in 2-3 sentences, and any confirmed visual anti-reference.
|
||||
- **Color character** (for auto-extracted colors): descriptive names ("Deep Muted Teal-Navy", not "blue-800"). Suggest 2-3 options per key color based on hue/saturation.
|
||||
- **Elevation philosophy**: flat/layered/lifted. If shadows exist, is their role ambient or structural?
|
||||
- **Component philosophy**: the feel of buttons, cards, inputs in one phrase ("tactile and confident" vs. "refined and restrained").
|
||||
|
||||
Quote a line from PRODUCT.md when possible so the user sees their own strategic language carry forward.
|
||||
Carry a line from PRODUCT.md only when it is a durable brand commitment that actually constrains the visual system. Page strategy and surface concepts do not belong here.
|
||||
|
||||
### Step 4: Write DESIGN.md
|
||||
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the structure below. Headers must match character-for-character. Optional evocative subtitles (e.g. `## 2. Colors: The Coastal Palette`) are allowed.
|
||||
The file opens with the YAML frontmatter staged in Step 2b (schema documented at the top of this reference), then the markdown body using the canonical structure below.
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -136,13 +139,13 @@ colors:
|
||||
|
||||
# Design System: [Project Title]
|
||||
|
||||
## 1. Overview
|
||||
## Overview
|
||||
|
||||
**Creative North Star: "[Named metaphor in quotes]"**
|
||||
|
||||
[2-3 paragraph holistic description: personality, density, aesthetic philosophy. Start from the North Star and work outward. State what this system explicitly rejects (pulled from PRODUCT.md's anti-references). End with a short **Key Characteristics:** bullet list.]
|
||||
[2-3 paragraph holistic description: personality, density, and aesthetic philosophy. Start from the North Star and work outward. State only confirmed visual rejections. End with a short **Key Characteristics:** bullet list.]
|
||||
|
||||
## 2. Colors
|
||||
## Colors
|
||||
|
||||
[Describe the palette character in one sentence.]
|
||||
|
||||
@@ -162,7 +165,7 @@ colors:
|
||||
### Named Rules (optional, powerful)
|
||||
**The [Rule Name] Rule.** [Short, forceful prohibition or doctrine, e.g. "The One Voice Rule. The primary accent is used on ≤10% of any given screen. Its rarity is the point."]
|
||||
|
||||
## 3. Typography
|
||||
## Typography
|
||||
|
||||
**Display Font:** [Family] (with [fallback])
|
||||
**Body Font:** [Family] (with [fallback])
|
||||
@@ -180,7 +183,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [Short doctrine about type use.]
|
||||
|
||||
## 4. Elevation
|
||||
## Layout
|
||||
|
||||
[Describe the grid or spatial model, container behavior, density, responsive changes, and the spacing rhythm. Include exact values only when observed.]
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
[One paragraph: does this system use shadows, tonal layering, or a hybrid? If "no shadows", say so explicitly and describe how depth is conveyed instead.]
|
||||
|
||||
@@ -191,7 +198,11 @@ colors:
|
||||
### Named Rules (optional)
|
||||
**The [Rule Name] Rule.** [e.g. "The Flat-By-Default Rule. Surfaces are flat at rest. Shadows appear only as a response to state (hover, elevation, focus)."]
|
||||
|
||||
## 5. Components
|
||||
## Shapes
|
||||
|
||||
[Describe the form language: corner/radius strategy, borders, clipping, and any recurring silhouette or geometry.]
|
||||
|
||||
## Components
|
||||
|
||||
For each component, lead with a short character line, then specify shape, color assignment, states, and any distinctive behavior.
|
||||
|
||||
@@ -223,16 +234,16 @@ For each component, lead with a short character line, then specify shape, color
|
||||
### [Signature Component] (optional; if the project has a distinctive custom component worth documenting)
|
||||
[Description.]
|
||||
|
||||
## 6. Do's and Don'ts
|
||||
## Do's and Don'ts
|
||||
|
||||
Concrete, forceful guardrails. Lead each with "Do" or "Don't". Be specific: include exact colors, pixel values, and named anti-patterns the user mentioned in PRODUCT.md. **Every anti-reference in PRODUCT.md should show up here as a "Don't" with the same language**, so the visual spec carries the strategic line through. Quote PRODUCT.md directly where possible: if PRODUCT.md says *"avoid dark mode with purple gradients, neon accents, glassmorphism"*, the Don'ts here should repeat that by name.
|
||||
Concrete visual guardrails grounded in the incumbent implementation or the user's chosen world. Lead each with "Do" or "Don't" and include exact values only when established. Do not turn a task-specific concept or surface strategy into a system-wide prohibition.
|
||||
|
||||
### Do:
|
||||
- **Do** [specific prescription with exact values / named rule].
|
||||
- **Do** [...]
|
||||
|
||||
### Don't:
|
||||
- **Don't** [specific prohibition, e.g. "use border-left greater than 1px as a colored stripe"].
|
||||
- **Don't** [specific prohibition confirmed by the incumbent system or the user].
|
||||
- **Don't** [...]
|
||||
- **Don't** [...]
|
||||
```
|
||||
@@ -307,7 +318,7 @@ The `html` and `css` fields must be **self-contained, drop-in snippets** that re
|
||||
Aim for a tight set of **5-10 components** that best represent the visual system:
|
||||
|
||||
- **Canonical primitives (always include if the project has them):** button (each variant as a separate component entry), input/text field, navigation, chip/tag, card.
|
||||
- **Signature components (include if distinctive):** hero CTA, featured card, filter pill, a distinctive table or list-row treatment, any custom pattern the user mentioned as important in PRODUCT.md.
|
||||
- **Signature components (include if distinctive):** the recurring custom patterns that actually define the implemented system.
|
||||
- **Skip the rest.** Utility components, form building blocks, wrapper layouts: not worth documenting unless visually distinctive.
|
||||
|
||||
If the project has **no component library yet** (bare landing page, new project), synthesize canonical primitives from the tokens using best-practice defaults consistent with the DESIGN.md's rules. Every `.impeccable/design.json` has *something* to render, even on day zero.
|
||||
@@ -338,64 +349,40 @@ Your own write is the freshest source; subsequent commands in this session don't
|
||||
|
||||
## Seed mode
|
||||
|
||||
For projects with no visual system to extract yet. Produces a minimal scaffold, not a full spec.
|
||||
For projects with no visual system to extract yet. Produces a user-chosen visual-world scaffold, not a fabricated token spec.
|
||||
|
||||
### Step 1: Confirm seed mode
|
||||
### Step 1: Route through new-work's workshop
|
||||
|
||||
Before interviewing: "There's no existing visual system to scan. I'll ask five quick questions to seed a starter DESIGN.md. You can re-run `/impeccable document` once there's code, to capture the real tokens and components. OK?"
|
||||
PRODUCT.md is the prerequisite. If it is missing, load [init.md](init.md) and complete its product interview first. Do not create a visual identity without durable product context.
|
||||
|
||||
If the user prefers to skip, stop. No file.
|
||||
If PRODUCT.md exists, load [new-work.md](new-work.md) and resolve visual authority. Seed mode requires a concrete first surface: use the target the user named, or ask what they want to make first. Run **Select one direction** for A, D, or E so the visual world and its first expression are chosen as one pair. Stop after the directional DESIGN.md seed and surface brief; do not implement. A structured simulated user counts as the user and must get the same choice.
|
||||
|
||||
### Step 2: Five questions
|
||||
If new-work already completed the workshop in this session, use its chosen direction directly. Do not ask again.
|
||||
|
||||
Group into one `AskUserQuestion` interaction. Options must be concrete.
|
||||
### Step 2: Write seed DESIGN.md
|
||||
|
||||
1. **Color strategy.** Pick one:
|
||||
- Restrained: tinted neutrals + one accent ≤10%
|
||||
- Committed: one saturated color carries 30–60% of the surface
|
||||
- Full palette: 3–4 named color roles, each deliberate
|
||||
- Drenched: the surface IS the color
|
||||
|
||||
Then: one hue family or anchor reference ("deep teal", "mustard", "Klim #ff4500 orange").
|
||||
|
||||
2. **Typography direction.** Pick one (specific fonts come later):
|
||||
- Serif display + sans body
|
||||
- Single sans (warm / technical / geometric / humanist; pick a feel)
|
||||
- Display + mono
|
||||
- Mono-forward
|
||||
- Editorial script + sans
|
||||
|
||||
3. **Motion energy.** Pick one:
|
||||
- Restrained: state changes only
|
||||
- Responsive: feedback + transitions, no choreography
|
||||
- Choreographed: orchestrated entrances, scroll-driven sequences
|
||||
|
||||
4. **Three named references.** Brands, products, printed objects. Not adjectives.
|
||||
|
||||
5. **One anti-reference.** What it should NOT feel like. Also named.
|
||||
|
||||
### Step 3: Write seed DESIGN.md
|
||||
|
||||
Use the six-section spec from Scan mode. Populate what the interview answers; leave the rest as honest placeholders. The seed is a scaffold, not a fabricated spec.
|
||||
Use the canonical section order from Scan mode. Populate the selected workshop direction and leave unresolved implementation facts as honest placeholders. The seed commits a world and its invariants; it does not pretend implementation tokens already exist.
|
||||
|
||||
Lead the file with:
|
||||
|
||||
```markdown
|
||||
<!-- SEED: re-run /impeccable document once there's code to capture the actual tokens and components. -->
|
||||
<!-- SEED: established with the user before implementation; re-run /impeccable document once there's code to capture the actual tokens and components. -->
|
||||
```
|
||||
|
||||
Per-section guidance in seed mode:
|
||||
|
||||
- **Overview**: Creative North Star and philosophy phrased from the answers (color strategy + motion energy + references). Reference the user's anti-reference directly.
|
||||
- **Colors**: Color strategy as a Named Rule (e.g. *"The Drenched Rule. The surface IS the color."*). Hue family or anchor reference. No hex values; mark as `[to be resolved during implementation]`.
|
||||
- **Typography**: the direction the user picked (e.g. "Serif display + sans body"). No font names yet: `[font pairing to be chosen at implementation]`.
|
||||
- **Elevation**: inferred from motion energy. Restrained/Responsive → flat by default; Choreographed → layered. One sentence.
|
||||
- **Overview**: the chosen design thesis, layout behavior, material character, imagery stance, motion grammar, and reusable signature. Keep the selected first-surface expression in its surface brief; do not promote its composition into the global world.
|
||||
- **Colors**: the selected palette strategy and roles. Include values only when the user, an existing asset, or new-work's exploration established them; otherwise mark them `[to be resolved during implementation]`.
|
||||
- **Typography**: the selected type character and role relationship. Include font names only when established; otherwise mark the pairing `[to be resolved during implementation]`.
|
||||
- **Layout**: the selected spatial grammar and responsive behavior, without pretending exact measurements are settled.
|
||||
- **Elevation & Depth**: the selected material and depth behavior, stated as an invariant rather than inferred from a generic preset.
|
||||
- **Shapes**: the selected form and corner language.
|
||||
- **Components**: omit entirely; no components exist yet.
|
||||
- **Do's and Don'ts**: carry PRODUCT.md's anti-references directly plus the anti-reference named in Q5.
|
||||
- **Do's and Don'ts**: record the durable guardrails confirmed during the world choice, not task-local refusals.
|
||||
|
||||
Seed mode writes a minimal frontmatter with `name` and `description` only; no colors, typography, rounded, spacing, or components yet. Real tokens land on the next Scan-mode run. Skip the `.impeccable/design.json` sidecar in seed mode for the same reason: nothing to render.
|
||||
|
||||
### Step 4: Confirm
|
||||
### Step 3: Confirm
|
||||
|
||||
1. Show the seed DESIGN.md. Call out that it is a seed (the marker is the literal commitment).
|
||||
2. Tell the user: "Re-run `/impeccable document` once you have some code. That pass will extract real tokens and generate the sidecar."
|
||||
@@ -405,15 +392,15 @@ Your own write is the freshest source; no reload needed.
|
||||
## Style guidelines
|
||||
|
||||
- **Frontmatter first, prose second.** Tokens go in the YAML frontmatter; prose contextualizes them. Don't redefine a token value in two places; the frontmatter is normative.
|
||||
- **Cite PRODUCT.md anti-references by name** in the Do's and Don'ts section. If PRODUCT.md lists "SaaS landing-page clichés" or "generic AI tool marketing" as anti-references, the DESIGN.md Don'ts should repeat those phrases verbatim so the visual spec enforces the strategic line.
|
||||
- **Match the spec, don't invent new sections.** The six section names are fixed. If you have Layout/Motion/Responsive content to document, fold it into Overview (philosophy-level rules) or Components (per-component behavior).
|
||||
- **Carry only durable product constraints.** A binding logo, identity asset, accessibility need, or brand commitment from PRODUCT.md may constrain DESIGN.md. Surface strategy stays in its surface brief.
|
||||
- **Match the spec.** Use its eight canonical sections in order and omit any that are irrelevant. Put motion guidance with the world or component it affects rather than creating a token group the schema does not support.
|
||||
- **Descriptive > technical**: "Gently curved edges (8px radius)" > "rounded-lg". Include the technical value in parens, lead with the description.
|
||||
- **Functional > decorative**: for each token, explain WHERE and WHY it's used, not just WHAT it is.
|
||||
- **Exact values in parens**: hex codes, px/rem values, font weights; always the number in parens alongside the description.
|
||||
- **Use Named Rules**: `**The [Name] Rule.** [short doctrine]`. These are memorable, citable, and much stickier for AI consumers than bullet lists. Stitch's own outputs use them heavily ("The No-Line Rule", "The Ghost Border Fallback"). Aim for 1-3 per section.
|
||||
- **Be forceful**. The voice of a design director. "Prohibited", "forbidden", "never", "always", not "consider", "might", "prefer". Match PRODUCT.md's tone.
|
||||
- **Concrete anti-pattern tests**. Stitch writes things like *"If it looks like a 2014 app, the shadow is too dark and the blur is too small."* A one-sentence audit test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md**. The anti-references section of PRODUCT.md should directly inform the Do's and Don'ts section here. Quote or paraphrase.
|
||||
- **Be decisive where evidence is decisive.** Use hard language for actual invariants and softer language for provisional guidance.
|
||||
- **Use concrete audit tests only when they are grounded in the observed system or a confirmed user decision.** A one-sentence test beats a paragraph of principle.
|
||||
- **Reference PRODUCT.md selectively.** Product truth explains why the world fits; it does not supply page composition or a visual don't-list by default.
|
||||
- **Group colors by role**, not by hex-order or hue-order. Primary / Secondary / Tertiary / Neutral is the spec ordering.
|
||||
|
||||
## Pitfalls
|
||||
@@ -423,7 +410,7 @@ Your own write is the freshest source; no reload needed.
|
||||
- Don't invent components that don't exist. If the project only has buttons and cards, only document those.
|
||||
- Don't overwrite an existing DESIGN.md without asking.
|
||||
- Don't duplicate content from PRODUCT.md. DESIGN.md is strictly visual.
|
||||
- Don't add a "Layout Principles" or "Motion" or "Responsive Behavior" top-level section. The spec has six, not nine. Fold that content where it belongs.
|
||||
- Don't replace canonical sections with near-synonyms. Put layout and responsive behavior in `Layout`; put motion with the affected world or component.
|
||||
- Don't rename sections even slightly. "Colors" not "Color Palette & Roles". "Typography" not "Typography Rules". Tooling parsing depends on exact headers.
|
||||
- Don't duplicate token values between frontmatter and prose. If a color is in `colors.primary` as hex, the prose can name it and describe its role but should not reassert a different hex. The frontmatter is normative.
|
||||
- Don't invent frontmatter token groups outside Stitch's schema (no `motion:`, `breakpoints:`, `shadows:` at the top level). Stitch's Zod schema only accepts `colors`, `typography`, `rounded`, `spacing`, `components`. Anything else belongs in the sidecar's `extensions`.
|
||||
|
||||
@@ -4,7 +4,7 @@ Manage the **design detector hook** for the current project.
|
||||
|
||||
The hook runs the impeccable design detector on direct file edits to design-relevant files (`.tsx`, `.jsx`, `.html`, `.vue`, `.svelte`, `.astro`, `.css`, `.scss`, `.sass`, `.less`, `.ts`, `.js`). Claude Code, Codex, and GitHub Copilot use a post-tool-use hook and push a short system reminder into the agent's context after the edit; findings get a correction prompt, pending issues get a re-nudge, and clean UI-ish files get a short ack unless quiet mode is on (`hook.quiet` in config). Plain `.ts` and `.js` files are still scanned, but stay quiet unless the detector finds something. Cursor uses `preToolUse` to block bad proposed writes before they land and stays silent when it allows a clean write.
|
||||
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so Copilot keeps the full rule set per edit instead of deferring.
|
||||
The detector rules run in two tiers. The per-edit hook surfaces only the immediate tier: mechanical, unambiguous problems worth interrupting an edit for, such as broken images, overflowing or clipped content, contrast and legibility failures, gradient text, glow shadows, and design-system drift. Everything else (copy cadence, palette and typography taste, layout rhythm) is deferred to a deep pass on the `Stop` hook event, which runs the full rule set over every UI file touched in the session and surfaces the remaining findings once, deduplicated against what the per-edit pass already reported. That Stop message also asks for one authored review of detector-blind model reflexes. A session that touched no UI files stops silently. Set `hook.perEditRules` to `"all"` in `.impeccable/config.json` to restore the full rule set on every edit. The Stop deep pass is wired for Claude Code and Codex, which both dispatch a native `Stop` hook event. Cursor does not get one (its stop hook is not consistently dispatched; the pre-write gate covers it), and GitHub Copilot's stop-style events do not feed context back to the model, so they keep the full detector per edit while `context.mjs` supplies the detector-blind review. When no automatic hook is active, `context.mjs` instead supplies that review plus one manual detector command.
|
||||
|
||||
This command toggles the hook **per project** by editing `.impeccable/config.json` (the unified Impeccable config; hook runtime settings live under its `hook` key, and shared detector ignores live under `detector`). Per-developer overrides, including the install consent decision (`hook.consent`) the CLI records, live in the gitignored `.impeccable/config.local.json`. Set `hook.enabled: false` to turn the hook off, `hook.quiet: true` to silence the clean/pending acks, or `hook.auditLog` to a file path for an NDJSON log. The legacy `IMPECCABLE_HOOK_DISABLED`, `IMPECCABLE_HOOK_QUIET`, and `IMPECCABLE_HOOK_LOG` env vars are still honored and override these config values when set.
|
||||
|
||||
|
||||
@@ -1,224 +1,114 @@
|
||||
# Init Flow
|
||||
# Init flow
|
||||
|
||||
The setup command for a project. One codebase crawl feeds everything it writes:
|
||||
|
||||
- **PRODUCT.md** (strategic): root project file for register, target users, product purpose, brand personality, anti-references, strategic design principles. Answers "who/what/why".
|
||||
- **DESIGN.md** (visual): root project file for visual theme, color palette, typography, components, layout. Follows the [DESIGN.md format spec](https://raw.githubusercontent.com/google-labs-code/design.md/main/docs/spec.md). Answers "how it looks".
|
||||
- **`.impeccable/live/config.json`** (live mode): pre-configured so `/impeccable live` boots straight into variant mode with no first-time detour.
|
||||
|
||||
It closes by pointing the user at the best command to run next. Every other impeccable command reads PRODUCT.md and DESIGN.md before doing any work.
|
||||
`init` captures durable product truth in PRODUCT.md. It does not invent a visual world and does not write DESIGN.md; [new-work.md](new-work.md) creates or expands one, and [document.md](document.md) records an incumbent one. Existing runnable web projects may also receive `.impeccable/live/config.json`.
|
||||
|
||||
## Step 1: Load current state
|
||||
|
||||
Check what already exists. PRODUCT.md and DESIGN.md live at the project root, or under `.agents/context/` or `docs/` (case-insensitive). Read whichever are present with your native file tool. Also note whether `.impeccable/live/config.json` already exists (Step 6 leaves it untouched if so).
|
||||
Use the PRODUCT.md path resolved by context.mjs. Update it instead of creating a competing authority. In a child app inheriting root context, confirm shared versus app-specific scope before writing.
|
||||
|
||||
Decision tree:
|
||||
- **Neither file exists (empty project or no context yet)**: do Steps 2-4 (write PRODUCT.md), then decide on DESIGN.md based on whether there's code to analyze.
|
||||
- **PRODUCT.md exists, DESIGN.md missing**: skip to Step 5 and offer to run `/impeccable document` for DESIGN.md.
|
||||
- **PRODUCT.md exists but has no `## Register` section (legacy)**: add it. Infer a hypothesis from the codebase (see Step 2), confirm with the user, write the field.
|
||||
- **PRODUCT.md exists but has no `## Platform` section (legacy)**: add it the same way, but only when the project is native (`ios` / `android` / `adaptive`) or the user wants it explicit; a missing field already means `web`.
|
||||
- **Both exist**: ask the user directly to clarify what you cannot infer. Ask which file to refresh. Skip the one the user doesn't want changed.
|
||||
- **Just DESIGN.md exists (unusual)**: do Steps 2-4 to produce PRODUCT.md.
|
||||
- **No PRODUCT.md:** explore, interview, and write it.
|
||||
- **PRODUCT.md exists:** ask what product knowledge is stale or missing; do not reopen confirmed fields without a reason.
|
||||
- **Legacy PRODUCT.md:** add only durable missing facts; absent `## Platform` means `web` unless evidence says otherwise.
|
||||
- **Only DESIGN.md exists:** leave it untouched and create PRODUCT.md.
|
||||
- **Redesign/rebrand request:** preserve confirmed product truth unless the user changes it. Visual replacement happens later in new-work, not here.
|
||||
|
||||
Never silently overwrite an existing file. Always confirm first.
|
||||
Never silently overwrite an existing file or offer DESIGN.md during init. If another request invoked init, finish PRODUCT.md and resume it. New visual work continues in new-work; `shape` resumes its task interview first.
|
||||
|
||||
If init was invoked as a setup blocker by another command, such as `/impeccable craft landing page`, pause that command here. Complete init, then resume the original command. Your own writes are the freshest source; no reload needed. For craft, resume into shape next; init creates project context, but it is not a substitute for the task-specific shape interview and confirmed design brief.
|
||||
## Step 2: Explore the project
|
||||
|
||||
## Step 2: Explore the codebase
|
||||
Before asking, scan enough to avoid making the user repeat known facts: product docs and copy; package/config and app boundaries; features, workflows, routes, and roles; names, logos, legal/proof assets, and brand commitments; platform/accessibility signals; and the dev command/entry when live mode applies.
|
||||
|
||||
Before asking questions, thoroughly scan the project to discover what you can. This single crawl feeds PRODUCT.md, DESIGN.md, **and** the live-mode framework detection in Step 6, so be thorough once rather than re-scanning later:
|
||||
Treat repository evidence as a hypothesis, not user approval. Note visual maturity without documenting, extending, or replacing the world.
|
||||
|
||||
- **README and docs**: Project purpose, target audience, any stated goals
|
||||
- **Package.json / config files**: Tech stack, dependencies, existing design libraries, **and the framework** (Vite/SPA, Next.js, Nuxt, SvelteKit, Astro, multi-page static) plus the HTML entry the browser actually loads
|
||||
- **Existing components**: Current design patterns, spacing, typography in use
|
||||
- **Brand assets**: Logos, favicons, color values already defined
|
||||
- **Design tokens / CSS variables**: Existing color palettes, font stacks, spacing scales
|
||||
- **Any style guides or brand documentation**
|
||||
Form a platform hypothesis: `web`, `ios`, `android`, or `adaptive` (one product that genuinely adapts its design language per OS). Mobile web remains `web`; a native wrapper around a website does not make its design language native.
|
||||
|
||||
Also form a **register hypothesis** from what you find:
|
||||
## Step 3: Interview for product truth
|
||||
|
||||
- Brand signals: `/`, `/about`, `/pricing`, `/blog/*`, `/docs/*`, hero sections, big typography, scroll-driven sections, landing-page-shaped content.
|
||||
- Product signals: `/app/*`, `/dashboard`, `/settings`, `/(auth)`, forms, data tables, side/top nav, app-shell components.
|
||||
ask the user directly to clarify what you cannot infer. Ask only about material gaps the repository and original request do not answer with strong evidence.
|
||||
|
||||
Register is a hypothesis at this point, not a decision; Step 3 confirms it.
|
||||
Use the structured question tool when available; otherwise ask and wait. Keep rounds to at most three focused questions and require one real answer or approval round before writing a new PRODUCT.md. Confirm inferences.
|
||||
|
||||
Also form a **platform hypothesis**:
|
||||
Start with the unknowns that most change future product decisions:
|
||||
|
||||
- Native signals: React Native / Expo (`react-native`, `expo`), Flutter (`pubspec.yaml`, `flutter`), SwiftUI / UIKit (`.swift`, `.xcodeproj`, an `ios/` app target), Jetpack Compose / Android (`build.gradle`, an `android/` app module, `AndroidManifest.xml`). An `ios/` and/or `android/` directory that is a real app target, not just a Capacitor/Cordova wrapper around a website.
|
||||
- Web signals (the default): a web framework (Vite, Next, Nuxt, SvelteKit, Astro), an HTML entry, a CSS/Tailwind setup, no native app target.
|
||||
1. Who is the primary user, in what situation, and what job are they doing?
|
||||
2. What does the product make possible, and what is its meaningfully different mechanism or position?
|
||||
3. What durable constraints, assets, evidence, or product facts must future work preserve?
|
||||
|
||||
Values: `web` / `ios` / `android` / `adaptive` (one codebase, ships both, adapts per OS). Mobile web is still `web`. Like register, this is a hypothesis; Step 3 confirms it.
|
||||
Confirm ambiguous platform separately. Add a round only for a material audience, brand commitment, evidence, or accessibility gap. Record undecided facts instead of inventing them.
|
||||
|
||||
Note what you've learned and what remains unclear. Also note any rough edges worth a follow-up command (thin hierarchy, flat or gray palette, missing error/empty states, dull copy); Step 7 turns these into concrete recommendations without re-analyzing.
|
||||
Do not ask for an aesthetic direction, emotional feel, visual references, colors, typography, or style during init. If the user volunteers a binding visual constraint, record it without expanding it.
|
||||
|
||||
## Step 3: Ask strategic questions (for PRODUCT.md)
|
||||
### What belongs here
|
||||
|
||||
ask the user directly to clarify what you cannot infer. Ask about anything the codebase doesn't answer with strong, explicit evidence.
|
||||
- users, jobs, workflows, purpose, success, positioning, and operating context;
|
||||
- capabilities, constraints, terminology, evidence, platform, and accessibility;
|
||||
- confirmed voice, assets, and brand commitments.
|
||||
|
||||
### Interview mode, not confirmation mode
|
||||
### What does not belong here
|
||||
|
||||
If the repo is empty or the user's brief is sparse, run a short interview before proposing PRODUCT.md. Do **not** turn a one-sentence request into a complete inferred PRODUCT.md and ask for blanket confirmation.
|
||||
|
||||
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop: one question at a time, with lettered options where the crawl suggests likely answers, waiting for each answer before the next.
|
||||
- Keep skill vocabulary (register, belief ladder, anti-references) out of question text; ask for the thing in words the user would use. For the brand register, ask like a magazine editor profiling the brand: curious and narrative, drawing out the story, the feel, and what a visitor should come to believe.
|
||||
- Ask in focused rounds and wait for answers between them. Keep **one topic per question**; add rounds rather than fold several topics into one either-or choice. Options obey the same rule: an option answers only the question asked; never write a compound option that bundles a feeling with a business outcome or names an additional audience.
|
||||
- Use inferred answers as hypotheses or options, not as finished facts.
|
||||
- Complete at least one real user-answer round before drafting PRODUCT.md, unless every required answer is directly discoverable from repo docs.
|
||||
- Round 1 should establish register, platform, users, purpose, positioning, and desired outcome.
|
||||
- Round 2 should establish brand personality or references, anti-references, and accessibility needs, plus conversion & proof for Persuade surfaces.
|
||||
|
||||
### Minimum viable interview
|
||||
|
||||
Ask enough to complete PRODUCT.md. At minimum, cover register confirmation, **platform confirmation** (`web` / `ios` / `android` / `adaptive`), users, purpose, positioning, brand personality, anti-references, and accessibility needs (plus conversion & proof for Persuade surfaces) unless each answer is directly discoverable from repo context. Never let the template's default `web` stand unconfirmed for a native or cross-platform repo. After at least one interview round, you may propose inferred answers, but the user must confirm them before you write PRODUCT.md. Never synthesize PRODUCT.md from the original task prompt alone.
|
||||
|
||||
### Register (ask first; it shapes everything below)
|
||||
|
||||
Every design task serves one of four visitor modes (see SKILL.md's Registers): **Persuade** (marketing, landing, campaigns), **Experience** (portfolios, albums, bodies of work), **Operate** (app UI, admin, dashboards, tools), and **Read** (documentation, editorial, long-form). PRODUCT.md stores the two-value family that covers them: `brand` covers Persuade and Experience, `product` covers Operate and Read. The brief decides the exact mode per task; the stored register only sets the default family.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [brand / product] surface. Does that match your intent, or should we treat it differently?"*
|
||||
|
||||
If the signal is genuinely split (e.g. a product with a big marketing landing), ask the user directly to clarify what you cannot infer. Ask which register describes the **primary** surface. The register can be overridden per task later, but PRODUCT.md carries one default. Settle the default before drafting any register-dependent questions; never batch Persuade-only questions (Conversion & proof) into the same round as the question that decides the register.
|
||||
|
||||
### Platform (ask right after register)
|
||||
|
||||
Every project targets **web** (includes responsive mobile web), **ios**, **android**, or **adaptive** (one codebase, ships both, adapts per OS: Flutter, React Native, KMP). Platform picks the native rulebook: HIG for `ios`, Material 3 for `android`, both for `adaptive`, none for `web`.
|
||||
|
||||
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [web / ios / android / adaptive] project. Does that match?"* For cross-platform apps, decide by the **design language the app renders**, not the toolchain: one look on both platforms (Flutter's Material-everywhere default) takes that platform's value; genuine per-OS adaptation (Cupertino on iOS, Material on Android) is `adaptive`. When in doubt, `web`.
|
||||
|
||||
A monorepo shipping both a website and a native app gets a PRODUCT.md per app, each with its own `## Platform`; the root PRODUCT.md carries the primary surface's platform.
|
||||
|
||||
### Users & Purpose
|
||||
- Who uses this? What's their context when using it?
|
||||
- What job are they trying to get done?
|
||||
- What is this for? A purpose stated in README or docs is a hypothesis, not strong evidence; confirm it, don't transcribe it.
|
||||
- What does success look like?
|
||||
- If more than one kind of user is plausible, confirm a primary and secondary audience; don't manufacture a split that isn't there. An audience implied by another answer (a success metric, a CTA) is still unconfirmed; ask before writing it as secondary.
|
||||
- If the surface speaks to a different audience than the people who use the product, ask the user to name both.
|
||||
- For brand: what emotions should the interface evoke? (confidence, delight, calm, urgency) Ask this standalone; don't fold emotions into the success question.
|
||||
- For product: what workflow are they in? What's the primary task on any given screen?
|
||||
|
||||
### Positioning
|
||||
- In one line, what does this do that nothing else does? The single strategic claim every screen reinforces.
|
||||
|
||||
### Brand & Personality
|
||||
- How would you describe the brand personality in 3 words?
|
||||
- Reference sites or apps that capture the right feel? What specifically about them?
|
||||
- Push for specific named references with the *specific* thing about them that fits this brand, not generic "modern" adjectives or category-bucket lanes.
|
||||
- What should this explicitly NOT look like? Any anti-references?
|
||||
|
||||
### Conversion & proof (Persuade surfaces only)
|
||||
|
||||
Ask these only when the primary surface is a Persuade one (marketing, landing, campaigns). Experience and Read surfaces (portfolios, albums, long-form writing, documentation) get no CTA, belief-ladder, or proof questions even when the stored register is `brand`; skip this section and its PRODUCT.md counterpart.
|
||||
|
||||
- What's the primary CTA?
|
||||
- What's the secondary fallback, for visitors not ready for the primary?
|
||||
- The one line a visitor should remember after 10 seconds.
|
||||
- What must the visitor believe, in order, before taking the primary CTA? (The template's belief ladder.)
|
||||
- What proof is on hand? Ask the user to hand over any testimonials, case studies, press, or client/partner logos they already have. If you can receive files directly, collect them; otherwise create `.impeccable/assets/proof/` and ask the user to add files there. Reference supplied files by path; record text proof inline.
|
||||
|
||||
### Accessibility & Inclusion
|
||||
- Specific accessibility requirements? (WCAG level, known user needs)
|
||||
- Considerations for reduced motion, color blindness, or other accommodations?
|
||||
|
||||
Skip questions where the answer is already clear. **Do NOT ask about colors, fonts, radii, or visual styling here.** Those belong in DESIGN.md, not PRODUCT.md.
|
||||
- visual worlds, palettes, typography, components, or page concepts;
|
||||
- visitor mode, narrative, CTA/proof sequence, or other surface strategy;
|
||||
- invented testimonials, customers, benchmarks, pricing, licensing, or deployment claims;
|
||||
- a requirement to decide every optional field.
|
||||
|
||||
## Step 4: Write PRODUCT.md
|
||||
|
||||
Write PRODUCT.md only after the user has confirmed the strategic answers from Step 3. If an inferred answer is uncertain or unconfirmed, ask before writing. Confirmed means what the user actually said yes to; do not pad a confirmed answer with extras they never picked (additional anti-references, audiences, roadmap claims, a WCAG level), whether drawn from the crawl, another answer, or your own option text. If an extra belongs in the doc, ask about it first.
|
||||
|
||||
Synthesize into a strategic document:
|
||||
Write only confirmed facts and explicitly marked open decisions. Omit irrelevant sections rather than filling them with generic prose.
|
||||
|
||||
```markdown
|
||||
# Product
|
||||
|
||||
## Register
|
||||
|
||||
product
|
||||
|
||||
## Platform
|
||||
|
||||
web
|
||||
|
||||
## Users
|
||||
[Who they are, their context, the job to be done. Primary audience; a secondary audience or a surface-vs-user split only when they apply.]
|
||||
[Primary users, their situation, and job. Add other audiences only when confirmed.]
|
||||
|
||||
## Product Purpose
|
||||
[What this product does, why it exists, what success looks like]
|
||||
[What the product does, why it exists, and what success means.]
|
||||
|
||||
## Positioning
|
||||
[The single strategic claim every screen reinforces. Not a visual rule, not an anti-reference.]
|
||||
[The product mechanism or claim a neighboring product could not truthfully copy.]
|
||||
|
||||
## Conversion & proof
|
||||
[Persuade surfaces only (marketing, landing, campaigns). Omit this section entirely, heading included, for the product register and for Experience or Read surfaces such as portfolios, albums, or long-form writing.]
|
||||
- Primary and secondary CTA: [...]
|
||||
- The line a visitor remembers after 10 seconds: [...]
|
||||
- Belief ladder: [...]
|
||||
- Proof on hand: [testimonials, case studies, press, or logos, referenced by path]
|
||||
## Operating Context
|
||||
[Workflows, environments, tools, documents, materials, and rituals that are factual parts of using or evaluating the product.]
|
||||
|
||||
## Brand Personality
|
||||
[Voice, tone, 3-word personality, emotional goals]
|
||||
## Capabilities and Constraints
|
||||
[Confirmed functionality, technical constraints, terminology, and explicitly undecided product facts.]
|
||||
|
||||
## Anti-references
|
||||
[What this should NOT look like. Specific bad-example sites or patterns to avoid.]
|
||||
## Brand Commitments
|
||||
[Existing name, voice, assets, personality, identity constraints, and references the user explicitly made binding. Omit when none exist.]
|
||||
|
||||
## Design Principles
|
||||
[3-5 strategic principles derived from the conversation. Principles like "practice what you preach", "show, don't tell", "expert confidence". NOT visual rules like "use OKLCH" or "magenta accent".]
|
||||
## Evidence on Hand
|
||||
[Real content, data, demonstrations, testimonials, case studies, press, or assets, with paths where applicable. State absences that future work must not fabricate.]
|
||||
|
||||
## Product Principles
|
||||
[Three to five durable strategic principles derived from confirmed answers; no visual recipes.]
|
||||
|
||||
## Accessibility & Inclusion
|
||||
[WCAG level, known user needs, considerations]
|
||||
[Known user needs or required standard. Omit when no product-specific requirement was established.]
|
||||
```
|
||||
|
||||
Register is either `brand` or `product` as a bare value. No prose, no commentary. Platform is `web`, `ios`, `android`, or `adaptive`, also a bare value; omit the section only on legacy files you're leaving untouched, otherwise write `web` explicitly.
|
||||
Platform is the bare value `web`, `ios`, `android`, or `adaptive`. Preserve useful legacy headings. New files go at `PROJECT_ROOT/PRODUCT.md`; otherwise update the resolved file. Write it before any visual-world or surface-concept work.
|
||||
|
||||
Write fields as prose, and use bold sparingly: only where a word carries a decision, never as a label lead-in on every line.
|
||||
### Completion gate
|
||||
|
||||
Write to `PROJECT_ROOT/PRODUCT.md`. If `.impeccable.md` existed, the loader already renamed it; merge into that content rather than starting from scratch.
|
||||
Before loading new-work or resuming shape/build, verify that PRODUCT.md exists at the resolved path and contains the confirmed product record. If the file is absent, init is incomplete. Do not substitute interview notes, a planning packet, or later design prose for the file.
|
||||
|
||||
## Step 5: Decide on DESIGN.md
|
||||
## Step 5: Configure live mode when useful
|
||||
|
||||
Offer `/impeccable document` either way. Two paths:
|
||||
Skip native or non-runnable projects and leave existing config untouched. Otherwise follow [live.md](live.md)'s first-time setup. Any CSP source edit still requires its stated consent.
|
||||
|
||||
- **Code exists** (CSS tokens, components, a running site): "I can generate a DESIGN.md that captures your visual system (colors, typography, components) so variants stay on-brand. Want to do that now?"
|
||||
- **Pre-implementation** (empty project): "I can seed a starter DESIGN.md from five quick questions about color strategy, type direction, motion energy, and references. You can re-run once there's code, to capture the real tokens. Want to do that now?"
|
||||
## Step 6: Wrap up or resume
|
||||
|
||||
If the user agrees, delegate to `/impeccable document` (it auto-detects scan vs seed). Load its reference and follow that flow.
|
||||
Summarize captured and deliberately undecided facts. Do not offer DESIGN.md merely because it is missing.
|
||||
|
||||
If the user prefers to skip, mention they can run `/impeccable document` any time later.
|
||||
Recommend the next action from the actual project state:
|
||||
|
||||
## Step 6: Configure live mode (when code exists)
|
||||
- Empty or early project: ask naturally for the surface to be built, or use `/impeccable shape <surface>` when the user wants a confirmed brief without implementation. New-work will establish a visual world only when the requested work needs one.
|
||||
- Existing coherent interface without DESIGN.md: `/impeccable document` if the user wants the incumbent system recorded independently of a new build.
|
||||
- Existing surface needing work: name the most relevant scoped command.
|
||||
- Web project ready for visual iteration: `/impeccable live` when configured.
|
||||
|
||||
**Skip this step when the platform is native** (`ios` / `android` / `adaptive`): live mode drives a browser overlay. A hybrid wrapper or Expo web target serving HTML doesn't change that.
|
||||
|
||||
If the project has code with HTML entries and a dev server (the same "code exists" condition that puts `/impeccable document` in scan mode), pre-configure live mode now. You already identified the framework and the served HTML entry in Step 2, so this is nearly free, and it spares the user the first-time setup detour when they later run `/impeccable live`.
|
||||
|
||||
**Skip this step for empty / pre-implementation projects** (nothing to inject into yet). Tell the user live mode will configure itself the first time they run it once there's code.
|
||||
|
||||
**If `.impeccable/live/config.json` already exists, leave it untouched** and note that live mode is already configured.
|
||||
|
||||
Otherwise:
|
||||
|
||||
1. Write `.impeccable/live/config.json`. Choose `files` (the HTML entries the browser actually loads), `insertBefore`, and `commentSyntax` from the framework table in [live.md](live.md)'s **First-time setup** section, using the framework you found in Step 2. That table is canonical; do not restate it here. For multi-page static sites, prefer a glob (`["public/**/*.html"]`) over a literal list.
|
||||
2. Run `node .cursor/skills/impeccable/scripts/detect-csp.mjs`. If it reports a patchable shape (`append-arrays` / `append-string`), use the **consent prompt template** from live.md before editing any source file. On decline, skip the patch. For `middleware` / `meta-tag` shapes, surface the detected files and ask the user to add `http://localhost:8400` to `script-src` and `connect-src` manually. For `null`, there's nothing to do.
|
||||
3. Set `cspChecked: true` in the config once CSP is handled (patched, declined, manual, or not needed). The schema and per-shape patch details live in live.md's First-time setup; follow it rather than duplicating.
|
||||
|
||||
Writing the config file is harmless and needs no consent; only the CSP **source-file patch** requires a yes.
|
||||
|
||||
## Step 7: Recommend starting points, then wrap up
|
||||
|
||||
Summarize tersely:
|
||||
- Register captured (brand / product) and platform captured (web / ios / android / adaptive)
|
||||
- What was written (PRODUCT.md, DESIGN.md, live config, or a subset)
|
||||
- The 3-5 strategic principles from PRODUCT.md that will guide future work
|
||||
- If DESIGN.md or live config is pending, one line on how to set it up later
|
||||
|
||||
Then recommend the **best commands to run next**, drawn from what your Step 2 crawl already surfaced. Do not run a fresh analysis here; surface observations you already have. Tailor to register **and platform**, offer the 2-4 most relevant (not a menu dump), and give the exact command to type. Group by intent:
|
||||
|
||||
- **Build something new**: `/impeccable craft <feature>` (shape, then build end-to-end) or `/impeccable shape <feature>` (plan first). Lead with this for empty or early-stage projects.
|
||||
- **Improve what's there**: name the specific surface. `/impeccable critique <page>` for a scored UX review; `/impeccable audit <area>` for a11y / perf / responsive checks; `/impeccable polish <component>` for a pre-ship pass. When the crawl flagged a specific weakness, point the matching command at it: thin hierarchy or spacing → `layout`, flat or gray palette → `colorize`, missing error / empty states → `harden` or `onboard`, dull or unclear copy → `clarify`.
|
||||
- **Iterate visually** (web only): `/impeccable live` (configured in Step 6) to pick elements in the browser and generate variants in place. **Skip this group for native platforms.**
|
||||
|
||||
The full command menu is one bare `/impeccable` away; keep this list short and pointed.
|
||||
|
||||
If init was invoked as a blocker by another impeccable command (e.g. the user ran `/impeccable polish` with no PRODUCT.md), resume that original task now. Your own writes are the freshest source; no reload needed.
|
||||
|
||||
Optionally ask the user directly to clarify what you cannot infer. Ask whether they'd like a brief summary of PRODUCT.md appended to .cursorrules for easier agent reference. If yes, append a short **Design Context** pointer section there.
|
||||
If init was invoked by another request, resume without rerunning context.mjs; new-work owns later visual decisions.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
For native iOS / iPadOS apps: SwiftUI, UIKit, React Native, Expo, Flutter shipping to Apple hardware.
|
||||
|
||||
On native, register narrows. HIG conformance governs structure, navigation, and interaction whatever the register; brand expresses through the expressive layer the platform provides (tint, type, motion, content). Calm, Duolingo, and Spotify carry strong identity entirely inside HIG conventions.
|
||||
On native, the visitor mode narrows what expression may override. HIG conformance governs structure, navigation, and interaction in every mode; brand expresses through the layer the platform leaves open (tint, type, motion, content).
|
||||
|
||||
## The iOS slop test
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user