Skip to content

Establish design system + reduced-motion spinner (P0 a11y) - #4

Merged
guyghost merged 2 commits into
mainfrom
guyghost-impeccable-ui-init
Jul 29, 2026
Merged

Establish design system + reduced-motion spinner (P0 a11y)#4
guyghost merged 2 commits into
mainfrom
guyghost-impeccable-ui-init

Conversation

@guyghost

Copy link
Copy Markdown
Owner

Why

RightClick had no committed design system, so UI decisions were being made ad hoc and the accessibility baseline was unverified. This PR lands the design foundation (impeccable init) and the first polish pass surfaced by the subsequent critique + audit: a reduced-motion spinner — the P0 accessibility finding both evaluations converged on.

What changed

Design system (impeccable init)

  • PRODUCT.md + DESIGN.md capture the product register (a tool, not a brand site) and six non-negotiable UI rules for RightClick.
  • .impeccable/design.json is the machine-readable sidecar: OKLCH canonicals, tonal ramps, component tiles, and motion tokens that commit us to reduced-motion fallbacks.
  • AGENTS.md gains a Design Context pointer so future sessions honor token discipline and the "Operator's Console" north star before touching UI code.
  • .impeccable/critique/2026-07-28T11-22-39Z__src-ui.md persists the review snapshot (design 33/40, technical audit 15/20) that scoped the work below.

Reduced-motion spinner (P0 a11y)

  • Spinner gains a reduced_motion: bool field + with_reduced_motion() builder. When enabled, tick() and next_frame() become no-ops (frame frozen at its current index) and is_running() returns false, so render loops stop driving animation while still drawing a stable, style-consistent glyph.
  • UIConfig gains reduced_motion: bool with #[serde(default)] so existing config files deserialize unchanged.

Approach & non-obvious bits

  • No LLM in the state loop. This follows the project's mandatory Model → Review → Implement → Verify rule: the animated↔static transition is a pure boolean. The LLM produces nothing here; the model decides.
  • Glyph choice is style-consistent, not a new decision. Reduced-motion freezes the spinner's own first frame (e.g. for dots) rather than swapping in an unrelated icon, so the visual identity is preserved.
  • Serde backward-compat is asserted by a witness test — the pre-existing deserialization JSON (which omits the field) still loads and defaults to false.
  • The Spinner is currently a library component (exported, not yet instantiated in the live app), so this change is self-contained; wiring it into a live surface is deferred.

Verify

  • cargo test --lib spinner20/20 (6 new)
  • cargo test --lib config34/34 (2 new, incl. backward-compat witness)
  • cargo build + cargo fmt --check clean

Out of scope (flagged by the audit, each needs a design-identity decision)

  • Muted token #565f89 is 2.76:1 (WCAG FAIL). Verified correct fix is #868fba (5.41:1, AA) — but it touches the canonical palette across all themes.
  • Border token #414868 is 1.91:1 (FAIL, 3:1 non-text).
  • Color::from_str().unwrap_or() appears at 50+ call sites — fragile, worth centralizing.

Establishes the project's design system and lands the first
accessibility polish pass flagged by the impeccable critique/audit.

Design system (impeccable init):
- PRODUCT.md and DESIGN.md capture the product register (product, not
  brand) and six non-negotiable UI rules for RightClick.
- .impeccable/design.json is the machine-readable sidecar: OKLCH
  canonicals, tonal ramps, component tiles, and the motion tokens that
  commit us to reduced-motion fallbacks.
- AGENTS.md gains a Design Context pointer so future sessions honor the
  token discipline and the "Operator's Console" north star before
  touching UI code.
- .impeccable/critique/ snapshot records the 33/40 design review and
  15/20 technical audit that scoped the work below.

Reduced-motion spinner (P0 accessibility finding):
- Spinner gains a `reduced_motion: bool` field plus a
  `with_reduced_motion()` builder. When enabled, `tick()` and
  `next_frame()` are no-ops (frame frozen at its current index) and
  `is_running()` returns false, so render loops stop driving animation
  while still drawing a stable, style-consistent glyph.
- UIConfig gains a `reduced_motion: bool` field with `#[serde(default)]`
  for backward-compatible deserialization of existing configs.

Follows the project's mandatory Model -> Review -> Implement -> Verify
flow: the transition is a pure boolean, no LLM in the loop, no
text-driven state change.

Verify: spinner 20/20 (6 new), config 34/34 (2 new), cargo build + fmt clean.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Establishes a committed design system for RightClick (human + machine-readable) and adds a reduced-motion mode to the Spinner component, plus a config flag to carry the preference through configuration.

Changes:

  • Added design foundation docs: PRODUCT.md, DESIGN.md, .impeccable/design.json, and a persisted critique snapshot.
  • Introduced Spinner::with_reduced_motion(bool) and a reduced_motion flag that freezes frame advancement and reports is_running() == false.
  • Added UIConfig.reduced_motion with #[serde(default)] and a backward-compat deserialization witness test.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/ui/spinner.rs Adds reduced-motion behavior to the spinner and covers it with unit tests.
src/core/models/config.rs Adds ui.reduced_motion config flag with serde defaults + tests for backward compatibility.
PRODUCT.md New product register and accessibility commitments (incl. reduced motion).
DESIGN.md New design system + UI rules and token references for consistent theming.
AGENTS.md Adds pointers for future agent sessions to follow the design system and token discipline.
.impeccable/design.json Machine-readable design system sidecar (colors, typography, motion tokens).
.impeccable/critique/2026-07-28T11-22-39Z__src-ui.md Captures the critique/audit snapshot motivating the reduced-motion work.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/core/models/config.rs Outdated
Comment thread src/ui/spinner.rs
Comment thread DESIGN.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f48db79dd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/ui/spinner.rs
Comment thread .impeccable/critique/2026-07-28T11-22-39Z__src-ui.md Outdated
Address 5 review comments on PR #4. No behavioral regression; pure
docs, token-consistency, and a convenience constructor.

- config.rs: reword UIConfig.reduced_motion doc to drop the misleading
  "progress animations" claim (progress.rs renders a static bar). Keep
  the PRODUCT.md / DESIGN.md references. Plain ASCII punctuation.
  (comment 3668817519)

- spinner.rs: update is_running() doc to state it returns true only when
  multi-frame AND reduced-motion is disabled (it reports active
  animation, not just frame count). No behavior change.
  (comment 3668817567)

- spinner.rs: add Spinner::from_ui_config(&UIConfig) convenience
  constructor so future live surfaces honor the reduced_motion
  preference automatically, without manually threading the builder.
  Investigation confirmed zero live Spinner construction sites today
  (library-only), so no consumer is wired in this PR; the constructor
  encodes the intended pattern for adopters. +1 test covering the config
  path (default animates, reduced_motion=true freezes).
  (comment 3668824555, P1)

- DESIGN.md: the Buttons section referenced an undefined
  {colors.button-hover-bg}. Replaced with the existing {colors.secondary}
  token (already defined as the rare hover accent), honoring the One
  Console Rule and the restrained palette. Verified all 17 {colors.*}
  references now resolve to a defined token.
  (comment 3668817607)

- .impeccable/critique snapshot: corrected inaccurate WCAG contrast
  figures (muted was wrongly marked ~4.5:1 pass; actual 2.76:1 FAIL).
  Added an ERRATUM block dated 2026-07-29 and corrected inline numbers
  for muted (2.76:1), placeholder (2.35:1), and border (1.91:1) on
  Default/Tokyo Night, with reviewer-cited Dracula/Nord values flagged
  for formal verification. Health score unchanged (33/40).
  (comment 3668824566, P2)

Verify: cargo build clean; spinner 21/21 (+1) + doctests 21/21;
config 35/35 (+1); cargo fmt --check clean; cargo clippy clean.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@guyghost
guyghost merged commit 9117dd0 into main Jul 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants