diff --git a/skills-external/design-motion-principles/references/demo-shell.html b/skills-external/design-motion-principles/references/demo-shell.html index 647755c..0914dd7 100644 --- a/skills-external/design-motion-principles/references/demo-shell.html +++ b/skills-external/design-motion-principles/references/demo-shell.html @@ -1,63 +1,77 @@ @@ -65,144 +79,197 @@ Demo Shell — design-motion-principles + + + -
-
↻ looping
-
Recommended motion title
-
300ms · ease-out
-
+
+ + + +
+
+ Recommended motion title + 300ms · ease-out +
+
+
+ + + +
+ ↻ +
+
+
- - (motion preview renders here per finding) - + a card, an icon, a row of items for stagger demos, a number, + a badge, etc.). All inner UI primitives use the stage tokens + (--st-fg / --st-bg / --st-line / --st-dim) — NEVER page tokens. --> +
+
+
Placeholder
+
+ + (motion preview renders here per finding) +
+
+
-
+ diff --git a/skills-external/design-motion-principles/references/output-format.md b/skills-external/design-motion-principles/references/output-format.md index 124d538..f0ea8c9 100644 --- a/skills-external/design-motion-principles/references/output-format.md +++ b/skills-external/design-motion-principles/references/output-format.md @@ -1,19 +1,28 @@ # Output Format -This file defines the audit's two output modes: +The audit produces one of two outputs: -- **HTML mode (default)** — a self-contained `.html` file written to the audited project's `motion-audits/` directory and opened in the user's default browser. Each Critical or Important finding gets an auto-looping CSS demo card beside it. -- **Terminal mode (flag-triggered)** — the decorated-markdown report rendered inline in the conversation. Use when the user passes `--terminal`, `--inline`, "show the full report inline," "skip the HTML," or any natural-language equivalent. No HTML file is written. +- **HTML mode (default)** — a self-contained `.html` file written to the audited project's `motion-audits/` directory and opened in the user's default browser. Each Critical or Important finding gets a live, looping CSS demo card beside it. +- **Terminal mode (flag-triggered)** — a decorated-markdown report rendered inline in the conversation. Use when the user passes `--terminal`, `--inline`, `--no-html`, "show the full report inline," or any natural-language equivalent. No HTML file is written. -The two modes contain the same audit content; only the rendering differs. Do not summarize — users want full per-lens perspectives. +Both modes carry the same audit content; only the rendering differs. Do not summarize — users want full per-lens perspectives. --- ## HTML mode +### Canonical references + +| File | Role | +|---|---| +| `references/report-template.html` | **Source of truth.** Full worked example (fictional "Tally" habit tracker, React + Framer Motion). Every section, every token, every pattern. When in doubt about layout, structure, or styling, READ this file. | +| `references/demo-shell.html` | Minimal isolated example of a single demo card with the per-finding slot pattern. Used as a per-finding template snippet. | + +The agent builds the report by reading these two files and adapting them to the audited project — same architecture, audit-specific content. + ### File structure -The HTML output is a single self-contained `.html` document with everything inlined — no external CSS, no external JS, no external fonts (fonts may degrade gracefully if a CDN reference is used). The file scaffolds: +Single self-contained `.html`. All CSS inlined. No external JS. Fonts loaded via Google Fonts CDN (Familjen Grotesk / Public Sans / Geist Mono) with full system-stack fallbacks so the file degrades gracefully offline. ``` @@ -22,310 +31,233 @@ The HTML output is a single self-contained `.html` document with everything inli {project-name} motion audit — {ISO date} + + + - + + - - - + + + + + + ``` -### Report's own motion posture +### Design system -The report itself has **no** entrance, scroll, or mount animations. No staggered reveals, no fade-in-on-scroll, no motion-on-mount outside the demo cards. The demo cards are the only animated elements in the document — anything else would reproduce the AI-slop patterns the skill audits against. +Neutral-default, dual-mode, severity-driven. -### Hero header +- **Neutrals.** Cool slate-graphite at hue 255, very low chroma (0.003–0.010). `--ink` is the page background; `--paper` is the foreground text. In light mode the two swap values via the `:root:has(#theme-light:checked)` override — every other token derives from these two and flips automatically. +- **Severity (FIXED, never adaptive).** Red `oklch(0.655 0.185 25)` (critical) · Amber `oklch(0.805 0.125 78)` (important) · Green `oklch(0.745 0.135 152)` (opportunity). Light-mode counterparts deepen L for contrast on white; hues stay constant. +- **Timing-budget ramp (FIXED).** Same hues as severity; used in section 02 only. Instant + responsive = green, deliberate = amber, sluggish = red. +- **Accent (NEUTRAL by default).** `--accent`, `--accent-soft`, `--accent-tint` alias to `--paper`, `--paper-dim`, and a low-alpha paper tint. The report has no chromatic primary color — severity is the only color in the document. An individual audit MAY repoint these three to a sampled brand color, but ONLY if the brand has at least ~40° hue clearance from each of the severity hues and is verified not to fall in the AI-cliché zone (neon cyan, purple-to-blue gradients). +- **Fonts.** Display = Familjen Grotesk, body = Public Sans, mono = Geist Mono. The mono carries timing values (`240ms · ease-out`) and all small labels — never substitute a more generic mono for the timing values. -Top of the document. Project name + ISO date + severity counts row + primary lens label. +### Dual theme -```html -
-

{project-name} motion audit

-

{ISO date}

-

- 🔴 Critical: {N} · - 🟡 Important: {N} · - 🟢 Opportunities: {N} -

-

Primary: {Designer Name} — {Perspective Handle}

-
+Pure-CSS toggle. Two radios (`#theme-dark` default-checked, `#theme-light`) live inside `.theme-switch` at the top of `.wrap`. `:root:has(#theme-light:checked)` overrides every theme-dependent token. No JS. Selector compatibility: `:has()` is Baseline 2023, supported by all modern browsers. + +The global toggle's visual control is a segmented `Dark / Light` pill, top-right of the page, styled to match the per-demo stage segmented control. + +### The report's motion posture + +**The report itself has no entrance, scroll, or mount animation.** No staggered reveals. No fade-in-on-scroll. No motion on mount outside the demo cards. The demo cards are the only animated elements in the document — anything else would reproduce the AI-slop patterns this skill audits against. + +The one allowed transition: `border-color 0.2s ease` on lens-table rows and finding-rows for hover feedback. That's it. + +### Sections (in render order) + +#### Global theme switch +First element inside `.wrap`, right-aligned segmented `Dark / Light` pill. + +#### Header +``` +.eyebrow ("MOTION AUDIT · DESIGN-MOTION-PRINCIPLES") +h1.title ({project name} — {one-line audit framing}) +p.lede ({1–2 sentence project description}) +.meta-row (what it is · stack) +.stats (Findings · Critical · Important · Opportunities — each is an anchor link to its rec table) ``` -The severity counts pair each emoji with a text label (`Critical: N`, not just `🔴 N`) so the severity signal is readable under red-green color vision deficiency. Each count is an anchor link to the corresponding section in the body — this is the navigation affordance for long audits with many findings. +Each severity count pairs the number with a text label so the signal is readable under red-green color vision deficiency. Each count is an anchor link (`#rec-crit`, `#rec-imp`, `#rec-opp`) to the corresponding recommendation table. -### Overall Assessment +#### Overall Assessment +One short paragraph in larger display type. Does this feel polished? Too much? Too little? What's working, what's not? Wraps in `
` with a `mono-label` "OVERALL" eyebrow. -One short paragraph in larger type. Does this feel polished? Too much? Too little? What's working, what's not? +#### 01 · Lens summary +3-row table, one row per practitioner. Columns: Lens (with name and weight chip) · Verdict (`Strong` / `Concern` / `Problem` / `Mixed` with a colored dot) · One-line read. Weight chips indicate `Primary` / `Secondary` / `Selective` per audit context. -```html -
-

{one-paragraph assessment}

-
+#### 02 · Where the timings land — duration-budget diagram +Motion-native analog of thumb-first's thumb-zone diagram. A horizontal SVG (`viewBox="0 0 660 300"`) plots Tally's animations as numbered dots on a 0–600ms scale with four zone bands: + +| Zone | Range | Color | +|---|---|---| +| Instant | 0–100ms | green (`--t-good`) | +| Responsive | 100–300ms | green (`--t-good`) | +| Deliberate | 300–500ms | amber (`--t-mid`) | +| Sluggish | 500ms+ | red (`--t-slow`) | + +Animations with NO transition are plotted as hollow dashed circles at `x=40` (= 0ms). The paired key list to the right carries the action names and durations. A "What's off" block below explains the misalignments. + +The SVG uses CSS-class-driven fills (via an inline ` + + +
+ + +
+ + +
+ + +
+
+ + +
+
Motion audit · design-motion-principles
+

Tally — what to slow down, speed up, and finish

+

+ A pass over Tally's core loop — check-off, tab switches, the add-habit sheet, and the streak milestones — + read through three motion practitioners' lenses, ordered by what users feel most and the order to fix it. +

+
+
What it isHabit & streak tracker, used in quick daily bursts
+
StackMobile web · React + Framer Motion
+
+
+
7
Findings
+ + + +
+
+ + +
+ Overall +

+ Tally has real motion personality — but it's uneven. The highest-frequency action, the check-off, + is the most over-animated; the add-habit sheet that should glide just snaps shut. Tighten the frequent + moments toward speed, finish the half-built transitions, then spend delight where it's earned: the streaks. +

+
+ + +
+
01
+

How each practitioner reads the motion

+

+ Three lenses, weighted for this context — a frequently-opened utility where most motion should get out of + the way, and a little should be memorable. The read is what each would push on hardest today. +

+ + + + + + + + + + + + + + + + + + + +
LensVerdictOne-line read
Restraint & Speed Emil KowalskiSecondaryConcernThe check-off and tab switches are over-animated for actions this frequent — durations run long.
Production Polish Jakub KrehelPrimaryProblemSeveral transitions are half-built: enters without exits, state changes that snap. Craft is uneven.
Experimentation & Delight Jhey TompkinsSelectiveStrongRestraint is mostly right. The open prize is making the streak milestones actually feel earned.
+
+ + +
+
02
+

Where the timings land

+

+ Duration is a budget. A 320ms sheet is correct — a large surface earns the time. A 600ms tab switch on an + action you fire dozens of times a session is the mistake. Each dot is one of Tally's animations, plotted + where it runs today. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 100 + 300 + 500 + 600ms + + + + + INSTANT + RESPONSIVE + DELIBERATE + SLUGGISH + + + + + 5 + + + + + 3 + + 7 + + 6 + + 4 + + 2 + + 1 + + + + + fire most often + + +
+

The animations

+
    +
  1. 1Tab switch600ms
  2. +
  3. 2Check-off (bounce)450ms
  4. +
  5. 3Card hover lift80ms
  6. +
  7. 4Add-habit sheet enter320ms
  8. +
  9. 5Streak counter changenone
  10. +
  11. 6Page route250ms
  12. +
  13. 7Toast200ms
  14. +
+ +
+
Instant / Responsive · 0–300ms — where almost everything belongs. Taps, toggles, tabs, hovers.
+
Deliberate · 300–500ms — earned by large surfaces: sheets, modals, full-screen routes.
+
Sluggish · 500ms+ — feels laggy. Reserve for rare, deliberately cinematic moments — or nothing.
+
+ +
+ What's off +

The two dots furthest right — tab switch (1) and check-off (2) — are the actions that fire most. Frequency and duration are inversely related: the more often it runs, the faster it should be. And the streak counter (5) has no transition at all.

+
+
+
+
+ + +
+
03
+
+

Jakub Krehel — Production Polish

+ Primary lens +
+

Problem

+ +
+ What's working well +
    +
  • ✓Page routes use a clean opacity + 8px translate at 250ms — the right shape and duration. routes/transition.tsx:14
  • +
  • ✓Toasts enter and exit symmetrically — the exit isn't an afterthought. ui/Toast.tsx:31
  • +
+
+ +
+ Issues to address +
+ + +
+
+
CriticalJakub
+

The add-habit sheet enters, then snaps shut with no exit

+
+

WhatThe bottom sheet animates up on open (320ms, good), but on dismiss it's removed from the tree instantly — no exit. The component renders conditionally with no AnimatePresence wrapper, so Framer Motion never gets to play the exit.

+

Why it mattersA surface that glides in and vanishes reads as broken — the eye expects symmetry. It's the single most common "half-built motion" tell, and it's on the app's primary create flow.

+

Recommended motionWrap the sheet in AnimatePresence and mirror the enter: slide down + fade over 300ms with the same ease-out-quint. The demo shows the enter; the exit is its reverse.

+

screens/Habits/AddSheet.tsx:48

+
+
+
+ + + +
+
Sheet enter (mirror for exit)300ms · ease-out-quint
+
+
+ ↻ +
+
+
+
+
+
New habit
+
+ Drink water + Add +
+
+
+
+
+
+ + +
+
+
ImportantJakub
+

Streak counter jumps between values with no transition

+
+

WhatWhen a streak increments, the number is replaced in place — a hard swap. There's no transition on the value change, so the most rewarding number in the app updates with the least ceremony.

+

Why it mattersThe streak count is the payoff of the whole interaction. A snap makes a hard-won number feel like a re-render, not an achievement.

+

Recommended motionRoll the new value in: opacity + 10px translateY + a 5px blur that clears, 220ms. Subtle, but it tells the eye something changed and it's good.

+

components/StreakBadge.tsx:22

+
+
+
+ + + +
+
Number roll-in220ms · opacity + Y + blur
+
+
+ ↻ +
+
+
+
+
Current streak
+
7 days
+
+
+
+
+ +
+
+ +
+ Opportunities +
    +
  • 💡Habit cards lean on a drop shadow that's invisible on the dark theme — a 1px border would carry the elevation on both. components/HabitCard.tsx:9
  • +
+
+ +
+ Through Jakub's lens +

The vocabulary is right; the sentences are unfinished. Pair every enter with an exit, give the streak its moment, and Tally crosses from "animated" to "polished."

+
+
+ + +
+
04
+
+

Emil Kowalski — Restraint & Speed

+ Secondary lens +
+

Concern

+ +
+ What's working well +
    +
  • ✓Card hover lift is 80ms — instant, exactly right for a passive affordance. components/HabitCard.tsx:18
  • +
  • ✓No animation on keyboard-driven navigation — keyboard users aren't taxed with motion they didn't ask for.
  • +
+
+ +
+ Issues to address +
+ + +
+
+
CriticalEmil
+

Tab switches slide for 600ms — far too slow for the most frequent action

+
+

WhatThe four bottom tabs cross-slide the full panel width over 600ms with an ease-in-out. Tabs are the app's highest-frequency navigation; a 600ms slide means every switch holds the user behind an animation.

+

Why it mattersEmil's rule: the more often an action fires, the less it should animate. At this duration the motion stops being feedback and becomes a toll. ease-in-out also adds a slow start, compounding the lag.

+

Recommended motionDrop to a 180ms opacity crossfade with a 7px slide, ease-out. Better still: consider no slide at all — a fast crossfade is plenty of orientation for a tab.

+

navigation/TabView.tsx:63

+
+
+
+ + + +
+
Quick tab crossfade180ms · ease-out
+
+
+ ↻ +
+
+
+
+
Today
+
Morning walk
+
Read 10 pages
+
+
+
+
+ + +
+
+
ImportantEmil
+

Check-off pops from scale(0) with a spring bounce

+
+

WhatTicking a habit animates the checkmark from scale(0) with a bouncy spring (~450ms to settle). It's the app's core, most-repeated gesture, and it's the showiest animation in the product.

+

Why it mattersBounce on a high-frequency confirm gets tiring fast — the overshoot draws attention to motion the user has already mentally completed. Starting from scale(0) exaggerates the distance and the time.

+

Recommended motionScale 0.9 → 1 with opacity, 200ms ease-out, no overshoot. Confident and done before the finger lifts.

+

components/HabitCheck.tsx:27

+
+
+
+ + + +
+
Calm check, no bounce200ms · ease-out
+
+
+ ↻ +
+
+
+
+
Drink water
+
+
+
+
+ +
+
+ +
+ Through Emil's lens +

Speed up everything the user touches constantly. The tab switch and the check-off should feel instant; their current durations are the difference between an app that feels fast and one that feels fussy.

+
+
+ + +
+
05
+
+

Jhey Tompkins — Experimentation & Delight

+ Selective lens +
+

Strong

+ +
+ What's working well +
    +
  • ✓Tally resists the urge to animate everything — restraint is the right default for a daily utility. Delight is rationed, which makes room for it to land where it counts.
  • +
+
+ +
+ Issues to address +
+ + +
+
+
ImportantJhey
+

Hitting a milestone streak passes by with no celebration

+
+

WhatCrossing a 7-, 30-, or 100-day streak looks identical to any other day — the number just increments. The one moment in the app that has genuinely earned a flourish gets none.

+

Why it mattersThis is where delight pays for itself. A milestone is rare, emotionally loaded, and shareable — exactly the place to spend motion the rest of the app withholds. Skipping it leaves the payoff flat.

+

Recommended motionOn a milestone only: a badge that scales 0.8 → 1 (260ms ease-out) with a short, one-shot sparkle burst. Fires once on the event — not a looping pulse.

+

components/StreakBadge.tsx:40

+
+
+
+ + + +
+
Milestone badge enter260ms · ease-out + sparkle
+
+
+ ↻ +
+
+
+
+
+ 7 + DAY +
+ + + + +
+
+
+
+ +
+
+ +
+ Opportunities +
    +
  • 💡The today-list could stagger its rows in on first paint — 30ms apart, opacity + 6px rise. One orchestrated load beats scattered micro-interactions. screens/Today.tsx:51
  • +
+
+ +
+ Through Jhey's lens +

Don't add more motion — add it in one right place. The streak milestone is the moment worth engineering; everywhere else, keeping your hands off the controls is the sophisticated move.

+
+
+ + +
+
06
+

In the order I'd fix them

+

+ Ordered by what users feel: critical (degrades the core loop on every use) → important + (real friction or a missed payoff) → opportunity (could enhance). +

+ +
+
Critical · must fix2
+ + + + + + +
IssueFileFix
Tab switch runs 600ms on the highest-frequency actionTabView.tsx:63180ms opacity crossfade + 7px slide, ease-out
Add-habit sheet has no exit — snaps shutAddSheet.tsx:48Wrap in AnimatePresence; mirror the 300ms enter on exit
+
+ +
+
Important · should fix3
+ + + + + + + +
IssueFileFix
Check-off pops from scale(0) with a bounceHabitCheck.tsx:27scale 0.9→1 + opacity, 200ms ease-out, no overshoot
Streak counter swaps with no transitionStreakBadge.tsx:22220ms opacity + translateY + blur roll-in
Milestone streaks have no celebration momentStreakBadge.tsx:40One-shot badge scale-in + sparkle, milestones only
+
+ +
+
Opportunities · could enhance2
+ + + + + + +
EnhancementWhereImpact
Habit-card elevation invisible on dark themeHabitCard.tsx:91px border carries elevation on both themes
Today-list could stagger in on first paintToday.tsx:5130ms stagger, opacity + 6px rise — one orchestrated load
+
+
+ + +
+
07
+

Which lens carried this audit

+
+ Referenced most +

Jakub Krehel — Production Polish

+

Tally's gaps are craft gaps, not taste gaps: enters without exits, state changes that snap. That's Jakub's territory — finishing what's been started — so his lens drove the ordering. Emil set the durations; Jhey marked the one place to spend.

+
    +
  • Lean EmilTreat every duration as a budget. Push tab, check, and toggle timings under 200ms and question any motion on a high-frequency action.
  • +
  • Lean JakubAudit every conditional render for a missing exit. Pair enters and exits, and give meaningful state changes a transition.
  • +
  • Lean JheyPick the single highest-emotion moment — the milestone — and over-invest there, with @property, springs, or scroll-driven touches.
  • +
+
+
+ + + +
+ +