open-design/craft
Mohamed Abdallah 5da21e4054
feat(craft): animation-discipline module + opt-ins on mobile-app, mobile-onboarding, gamified-app (#515)
* feat(craft): add animation-discipline + opt-ins on mobile-app, mobile-onboarding, gamified-app

Animation discipline is the second behavioral craft module proposed in
#501 and explicitly invited in @mrcfps's post-merge comment on #502.

Differentiation from prior art (LottieFiles motion-design-skill, MIT,
96 stars): citation-grounded against primary sources rather than
asserted. Anchors:

- Tversky/Morrison/Bétrancourt 2002 (IJHCS) on the one demonstrated
  win-condition for animation
- Heer & Robertson TVCG 2007 on staging (with the actual durations
  they tested, not the laundered '300-1000ms' rule)
- Harrison/Yeo/Hudson CHI 2010 on perceived-duration scope (progress
  bars only, not skeletons)
- Doherty & Thadani IBM 1982 productivity numbers
- Material 3 motion tokens (M3 standard vs M2 legacy delta)
- IBM @carbon/motion durations
- Apple SwiftUI Animation API published defaults
- W3C View Transitions API + WCAG 2.2.2/2.3.3 calibration
- WebKit 2017 prefers-reduced-motion rationale

The 'common mistakes (lint these)' section busts five specific
folklore claims that don't survive primary-source check, including
the Doherty-400ms attribution and the M2-vs-M3 standard easing
confusion.

Three skills opt in via od.craft.requires:
  - mobile-app (animation-heavy mobile screens)
  - mobile-onboarding (multi-screen flow with transitions)
  - gamified-app (animations central to the format)

Refs #501.

* fix(craft): address review findings on animation-discipline

Six findings from @lefarcen's CHANGES_REQUESTED review on #515,
addressed in one pass. Reviewed by codex across three loops before
push.

P1 integration gaps:
- gamified-app and mobile-onboarding skills now require both
  state-coverage and animation-discipline (both render stateful UI
  with motion).
- craft/README.md silent-fallback example reframed as a
  planned-but-not-yet-vendored placeholder rather than a hard-coded
  next-to-ship slug. Note added pointing skill authors who arrive from
  older guidance at animation-discipline as the equivalent of the
  earlier 'motion' placeholder.

P2 reasoning completeness:
- > 500 ms duration row reframed: 'Reserved for cross-screen, staged,
  or platform-native transitions (e.g. M3 long2-extraLong4, Heer &
  Robertson 2007's per-stage recommendation)'. Surrounding paragraph
  rewritten with an enumerated category — 'Non-navigation
  microinteractions: hover, press, toggle, validation, chip selection,
  row expansion' — rather than the vague 'routine' term.
- New 'Flashing limits' subsection added in the Reduced motion
  section. WCAG 2.3.1 (Level A) three-flashes-in-any-one-second-period
  rule with the area/brightness threshold qualifier; WCAG 2.3.2 (AAA)
  unconditional rule. Photosensitive epilepsy framing.
- New 'Repeated and ambient motion' section added. Five rules covering
  iteration cap, WCAG 2.2.2 pause control after 5s, cancel-on-route,
  one-shot reward animations, and spinner timeout cross-referencing
  state-coverage.md.

File length now 154 lines (was 130, 80-110 craft target). Trade is
citation density and the new sections demanded by the integration
context (gamified/onboarding skills with looping motion).

Refs #501, #515.
2026-05-05 18:32:30 +08:00
..
animation-discipline.md feat(craft): animation-discipline module + opt-ins on mobile-app, mobile-onboarding, gamified-app (#515) 2026-05-05 18:32:30 +08:00
anti-ai-slop.md feat(craft): add brand-agnostic craft references + Refero-derived lint rules (#225) 2026-05-02 11:00:33 +08:00
color.md feat(craft): add brand-agnostic craft references + Refero-derived lint rules (#225) 2026-05-02 11:00:33 +08:00
README.md feat(craft): animation-discipline module + opt-ins on mobile-app, mobile-onboarding, gamified-app (#515) 2026-05-05 18:32:30 +08:00
state-coverage.md feat(craft): state-coverage module + opt-ins on dashboard, mobile-app, kanban-board (#502) 2026-05-05 16:31:05 +08:00
typography.md feat(craft): add brand-agnostic craft references + Refero-derived lint rules (#225) 2026-05-02 11:00:33 +08:00

Craft references

Brand-agnostic craft knowledge. Each file is a small, dense rulebook on one dimension of professional UI craft (typography, color, motion, …). Skills opt into the references they need; the daemon injects only the requested ones into the system prompt above the active skill body.

Why a third axis next to skills/ and design-systems/

Axis Scope Example
skills/ Artifact shape saas-landing, dashboard, pricing-page
design-systems/ Brand visual language (the 9-section DESIGN.md) linear-app, apple, notion
craft/ Universal craft knowledge — true regardless of brand letter-spacing rules, accent-overuse caps, anti-AI-slop

DESIGN.md tells the agent which colors and fonts a brand uses. craft/ tells the agent the universal rules a competent designer applies on top — e.g. ALL CAPS always needs ≥0.06em tracking, regardless of the brand.

How a skill opts in

Add an od.craft.requires array to the skill's front-matter. Only the listed sections are injected, so a skill that needs only typography pays no token cost for color/motion content.

od:
  craft:
    requires: [typography, color, anti-ai-slop]

Allowed values match the file names in this directory minus the .md extension. Unknown values are silently ignored (forward-compatible).

Why silent fallback instead of fail-fast?

A skeptical reader will ask: "If a skill requests a planned-but-not-yet-vendored section and the corresponding file doesn't exist yet, shouldn't we warn the user?" We chose forward-compatibility over fail-fast: a skill authored today can list a planned slug and start benefiting the moment the matching craft/<slug>.md is vendored in a follow-up PR, with no skill edit needed. The cost of a missed reference is a missing paragraph in the system prompt, not a broken skill — so the loud failure mode is not worth the friction.

Note for skill authors arriving from older guidance: an earlier draft used motion as the future-slug placeholder. The shipped equivalent today is animation-discipline. Use that one if your skill emits motion.

Enforcement levels

Craft files mix auto-checked rules and guidance.

  • Auto-checked. Rules wired into apps/daemon/src/lint-artifact.ts — currently the P0 list in anti-ai-slop.md (Tailwind-indigo accent, two-stop hero gradients, emoji-as-icons, etc.). The linter reports these as findings back to the UI (for P0/P1 badges) and to the agent (as a system reminder for self-correction). Artifact persistence is not currently hard-blocked on P0 hits.
  • Guidance. The rest. The agent reads the rules, reviewers apply them, the linter doesn't check them.

A purely behavioral craft file (state-coverage, animation-discipline) is guidance unless a specific rule is later promoted into lint-artifact.ts.

Files

File Section name When to require
typography.md typography Any skill that emits typed content (~all skills)
color.md color Any skill that emits styled output (~all skills)
anti-ai-slop.md anti-ai-slop Marketing pages, landing pages, decks
state-coverage.md state-coverage Any skill with stateful UI (dashboards, mobile apps, forms, list/table views)
animation-discipline.md animation-discipline Any skill that ships motion: mobile apps, multi-screen flows, gamified UI, transitions, microinteractions

Partial-stateful skills. A skill that's mostly static but contains an embedded form, data table, or query surface should opt in. State-coverage rules apply to the stateful component, not the whole page.

More sections (icons, craft-details) will be added in follow-up PRs as we wire the linter side.

Attribution

Craft content is adapted from the MIT-licensed refero_skill project (© Refero Design), with edits to fit Open Design's house style and link back to OD's design tokens (var(--accent) etc.) instead of generic Tailwind hex values.