@maccesar/aiskills 1.12.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +89 -9
  2. package/lib/cleanup.js +29 -0
  3. package/lib/commands/skills.js +110 -9
  4. package/lib/config.js +18 -9
  5. package/lib/installer.js +5 -3
  6. package/lib/symlink.js +45 -3
  7. package/lib/utils.js +41 -0
  8. package/package.json +2 -2
  9. package/skills/audit-codebase/SKILL.md +70 -0
  10. package/skills/audit-codebase/agents/openai.yaml +4 -0
  11. package/skills/audit-codebase/references/comprehensive-audit.md +220 -0
  12. package/skills/audit-codebase/references/report-format.md +119 -0
  13. package/skills/humaniza/SKILL.md +55 -4
  14. package/skills/humaniza/references/ai-patterns-es.md +40 -0
  15. package/skills/humaniza/references/checklist.md +9 -0
  16. package/skills/humaniza/references/examples.md +16 -0
  17. package/skills/humaniza/references/lexicon-es-mx.md +18 -0
  18. package/skills/humaniza/references/structures-es.md +132 -0
  19. package/skills/humaniza/scripts/check_ai_patterns.py +216 -0
  20. package/skills/refactoring-ui/SKILL.md +65 -29
  21. package/skills/refactoring-ui/references/05-motion.md +124 -0
  22. package/skills/refactoring-ui/references/06-dark-mode.md +117 -0
  23. package/skills/refactoring-ui/references/07-component-patterns.md +181 -0
  24. package/skills/session-log/SKILL.md +524 -0
  25. package/skills/session-log/evals/README.md +79 -0
  26. package/skills/session-log/evals/ab-ronda-1.md +115 -0
  27. package/skills/session-log/evals/ab-ronda-2.md +174 -0
  28. package/skills/session-log/evals/defecto-experimento.md +12 -0
  29. package/skills/session-log/evals/evals.json +147 -0
  30. package/skills/session-log/evals/trigger-eval.json +23 -0
  31. package/skills/session-log/references/file-layout.md +336 -0
  32. package/skills/session-log/references/verification.md +173 -0
  33. package/skills/stitch-showcase/SKILL.md +24 -232
  34. package/skills/stitch-showcase/references/07-theme-system.md +12 -0
  35. package/skills/stitch-showcase/references/08-type-detection.md +9 -1
  36. package/skills/stitch-showcase/references/10-component-standardization.md +25 -0
  37. package/skills/stitch-showcase/references/12-video-embedding.md +113 -0
  38. package/skills/stitch-showcase/references/13-language-detection.md +82 -0
  39. package/skills/stitch-showcase/references/14-troubleshooting-known-issues.md +122 -0
  40. package/skills/stitch-showcase/references/15-build-flags.md +71 -0
  41. package/skills/stitch-showcase/references/16-design-md-format.md +107 -0
  42. package/skills/stitch-showcase/references/index.html +25 -19
  43. package/skills/stitch-showcase/references/viewer.html +24 -12
  44. package/skills/stitch-showcase/scripts/__pycache__/build_showcase.cpython-314.pyc +0 -0
  45. package/skills/stitch-showcase/scripts/__pycache__/component_utils.cpython-314.pyc +0 -0
  46. package/skills/stitch-showcase/scripts/__pycache__/detect_components.cpython-314.pyc +0 -0
  47. package/skills/stitch-showcase/scripts/__pycache__/extract_catalog.cpython-314.pyc +0 -0
  48. package/skills/stitch-showcase/scripts/__pycache__/extract_text.cpython-314.pyc +0 -0
  49. package/skills/stitch-showcase/scripts/__pycache__/extract_zips.cpython-314.pyc +0 -0
  50. package/skills/stitch-showcase/scripts/__pycache__/parse_design_md.cpython-314.pyc +0 -0
  51. package/skills/stitch-showcase/scripts/__pycache__/slug_demangle.cpython-314.pyc +0 -0
  52. package/skills/stitch-showcase/scripts/build_showcase.py +150 -10
  53. package/skills/stitch-showcase/scripts/parse_design_md.py +145 -12
  54. package/skills/stitch-showcase/scripts/slug_demangle.py +209 -0
  55. package/skills/vscode-extension-dev/SKILL.md +90 -41
  56. package/skills/vscode-extension-dev/references/api-additional.md +168 -0
  57. package/skills/vscode-extension-dev/references/api-progress.md +55 -0
  58. package/skills/vscode-extension-dev/references/api-quickpick.md +75 -0
  59. package/skills/vscode-extension-dev/references/api-secretstorage.md +57 -0
  60. package/skills/vscode-extension-dev/references/api-statusbar.md +38 -0
  61. package/skills/vscode-extension-dev/references/api-treeview.md +78 -0
  62. package/skills/vscode-extension-dev/references/api-webview.md +149 -0
  63. package/skills/vscode-extension-dev/references/architecture.md +67 -0
  64. package/skills/vscode-extension-dev/references/debugger.md +179 -0
  65. package/skills/vscode-extension-dev/references/lsp.md +175 -0
  66. package/skills/vscode-extension-dev/references/notebooks.md +208 -0
  67. package/skills/vscode-extension-dev/references/testing.md +208 -0
  68. package/skills/vscode-extension-dev/references/api-patterns.md +0 -625
@@ -0,0 +1,132 @@
1
+ # Estructuras a evitar
2
+
3
+ Basado en el patrón detectado por Stop Slop, adaptado al español.
4
+
5
+ ## Contrastes binarios
6
+
7
+ Crean falso drama. Afirma el punto directo.
8
+
9
+ | Patrón | Problema |
10
+ |--------|----------|
11
+ | "No porque X, sino porque Y" / "No por X, sino por Y" | Giro telegrafiado |
12
+ | "X no es el problema. Y lo es." | Reformulación formulaica |
13
+ | "La respuesta no es X. Es Y." | Giro predecible |
14
+ | "No se trata de X, sino de Y" | Mecánico |
15
+ | "La pregunta no es X, sino Y" | Distracción retórica |
16
+ | "No es X, es Y" | Contraste mecánico |
17
+ | "No solo X, sino también Y" | Muletilla aditiva |
18
+ | "deja de ser X y empieza a ser Y" | Falso arco de transformación |
19
+ | "no significa X, sino Y" | Negación-seguida-de-afirmación |
20
+
21
+ **En lugar de:** Afirma Y directo. "El problema es Y." "Aquí importa Y." Suelta la negación.
22
+
23
+ ## Listado negativo
24
+
25
+ Enumerar lo que algo *no* es antes de decir lo que *sí* es. Striptease retórico.
26
+
27
+ | Patrón | Problema |
28
+ |--------|----------|
29
+ | "No es X... No es Y... Es Z." | Acumulación dramática con negación |
30
+ | "No fue X. No fue Y. Fue Z." | Misma estructura, pasado |
31
+
32
+ **En lugar de:** Di Z. El lector no necesita la pista de aterrizaje.
33
+
34
+ ## Fragmentación dramática
35
+
36
+ Fragmentos de oración para énfasis que leen a profundidad fabricada.
37
+
38
+ | Patrón | Problema |
39
+ |--------|----------|
40
+ | "[Sustantivo]. Eso es todo." / "[Sustantivo]. Eso es." | Simplicidad performativa |
41
+ | "X. Y. Y Z." | Drama staccato |
42
+ | "Esto activa algo. [Palabra]." | Revelación artificial |
43
+
44
+ **En lugar de:** Oraciones completas. Confía en el contenido, no en la presentación.
45
+
46
+ ## Setups retóricos
47
+
48
+ Anuncian perspicacia en lugar de entregarla.
49
+
50
+ | Patrón | Problema |
51
+ |--------|----------|
52
+ | "¿Qué tal si...?" / "¿Y si...?" | Postura socrática |
53
+ | "He aquí lo que quiero decir:" / "Esto es lo que quiero decir:" | Vista previa redundante |
54
+ | "Piénsalo." | Indicación condescendiente |
55
+ | "Y eso está bien." / "Y no pasa nada." | Permiso innecesario |
56
+ | "Imagina que..." | Falso gancho narrativo |
57
+
58
+ **En lugar de:** Di el punto directo. Deja que el lector saque conclusiones.
59
+
60
+ ## Agencia falsa
61
+
62
+ Darle a objetos inanimados verbos humanos. A la IA le encanta porque evita nombrar al actor.
63
+
64
+ | Patrón | Problema |
65
+ |--------|----------|
66
+ | "la queja se convierte en solución" | La queja no hizo nada. Alguien la resolvió. |
67
+ | "la decisión emerge" | Las decisiones no emergen. Alguien decide. |
68
+ | "la cultura cambia" | Las culturas no cambian solas. La gente cambia su comportamiento. |
69
+ | "la conversación avanza hacia" | Las conversaciones no avanzan solas. Alguien las dirige. |
70
+ | "los datos nos dicen" | Los datos están ahí. Alguien los lee y saca conclusiones. |
71
+ | "el mercado recompensa" | Los mercados no recompensan. Los compradores pagan por cosas. |
72
+ | "la plataforma permite" | La plataforma no permite nada. Alguien la construyó para eso. |
73
+ | "el sistema detecta" | El sistema no detecta nada. Alguien programó esa detección. |
74
+
75
+ **En lugar de:** Nombra al humano. "El equipo lo resolvió esa semana" gana a "la queja se convierte en solución".
76
+
77
+ ## Narrador desde la distancia
78
+
79
+ Flotando sobre la escena en vez de poner al lector en ella.
80
+
81
+ | Patrón | Problema |
82
+ |--------|----------|
83
+ | "Nadie diseñó esto." | Observación incorpórea |
84
+ | "Esto pasa porque..." | Voz de conferencista |
85
+ | "Por eso es que..." | Misma voz distante |
86
+ | "La gente tiende a..." | Sociólogo de sillón |
87
+ | "Uno tiende a pensar que..." | Generalización impersonal |
88
+ | "Se tiende a creer que..." | Distanciamiento innecesario |
89
+
90
+ **En lugar de:** Pon al lector en la escena. "Tú no te sientas un día y decides..." gana a "Nadie diseñó esto".
91
+
92
+ ## Voz pasiva
93
+
94
+ Cada oración necesita un sujeto haciendo algo. La voz pasiva esconde al actor.
95
+
96
+ | Patrón | Solución |
97
+ |--------|----------|
98
+ | "fue creado por" | Nombra quién lo creó |
99
+ | "se cree que" | Nombra quién lo cree |
100
+ | "se tomaron decisiones" | Nombra quién decidió |
101
+ | "se llegó a la conclusión" | Nombra quién concluyó |
102
+ | "fue implementado" | Nombra quién implementó |
103
+ | "ha sido reportado que" | Nombra quién reportó |
104
+
105
+ **En lugar de:** Encuentra al actor. Ponlo al frente de la oración.
106
+
107
+ ## Inicios de oración a evitar
108
+
109
+ | Patrón | Solución |
110
+ |--------|----------|
111
+ | Oraciones que empiezan con qué, cuándo, dónde, cómo, quién, por qué | Reestructura. Lidera con el sujeto o el verbo. |
112
+ | Párrafos que empiezan con "entonces", "así que" | Empieza con contenido |
113
+ | Oraciones que empiezan con "mira", "oye" | Elimínalas |
114
+
115
+ Los interrogativos (qué, cómo, por qué) como abridores se vuelven muleta. "Lo que hace difícil esto es..." cambia a "La dificultad es..." o mejor, nombra la dificultad específica.
116
+
117
+ ## Patrones de ritmo
118
+
119
+ | Patrón | Solución |
120
+ |--------|----------|
121
+ | Listas de tres elementos | Usa dos o uno |
122
+ | Preguntas respondidas inmediatamente | Deja que las preguntas respiren o elimínalas |
123
+ | Todo párrafo termina con golpe de efecto | Varía los finales |
124
+ | Rayas (—) en prosa narrativa | Elimínalas. Usa comas o puntos. |
125
+ | Fragmentación staccato | No apiles oraciones cortas sucesivas |
126
+ | "No siempre. No perfectamente." | Muletilla disfrazada de seguridad |
127
+
128
+ ## Vaguedad con extremos
129
+
130
+ | Patrón | Problema |
131
+ |--------|----------|
132
+ | Extremos vagos: todo, todos, siempre, nunca, nadie, absolutamente | Falsa autoridad. Usa datos específicos. |
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ check_ai_patterns.py — Deterministic scanner for AI-writing tics in Spanish.
4
+
5
+ Reads patterns from sibling `references/lexicon-es-mx.md` and reports every
6
+ hit found in the input text with line number, category, matched phrase, and
7
+ a replacement suggestion when the lexicon supplies one.
8
+
9
+ Usage:
10
+ python check_ai_patterns.py <text_file>
11
+ python check_ai_patterns.py < input.txt
12
+ cat input.txt | python check_ai_patterns.py
13
+
14
+ Stdlib only. Python 3.8+.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import re
20
+ import sys
21
+ from pathlib import Path
22
+ from typing import Iterator, NamedTuple
23
+
24
+
25
+ SCRIPT_DIR = Path(__file__).resolve().parent
26
+ LEXICON_PATH = SCRIPT_DIR.parent / "references" / "lexicon-es-mx.md"
27
+
28
+
29
+ class Hit(NamedTuple):
30
+ line_no: int
31
+ column: int
32
+ category: str
33
+ matched: str
34
+ suggestion: str # empty string if none
35
+
36
+
37
+ def _parse_section_header(line: str) -> str:
38
+ """Return the header text if line is `## ...`, else empty string."""
39
+ if line.startswith("## "):
40
+ return line[3:].strip().rstrip(":")
41
+ return ""
42
+
43
+
44
+ def _split_phrases(content: str) -> list[str]:
45
+ """
46
+ Split a comma-separated phrase block into individual phrases.
47
+ Strips whitespace and a trailing period.
48
+ """
49
+ cleaned = content.strip().rstrip(".")
50
+ return [p.strip() for p in cleaned.split(",") if p.strip()]
51
+
52
+
53
+ def _parse_replacement_line(line: str) -> tuple[str, str] | None:
54
+ """
55
+ Parse a lexicon line of the form `- phrase -> suggestion` or
56
+ `phrase -> suggestion`. Returns (phrase, suggestion) or None.
57
+ """
58
+ stripped = line.lstrip("-").strip()
59
+ if "->" not in stripped:
60
+ return None
61
+ left, _, right = stripped.partition("->")
62
+ phrase = left.strip()
63
+ suggestion = right.strip()
64
+ # Strip any inline parenthetical hint on the phrase side, e.g. `aplicar a (trabajo)`.
65
+ # We keep the visible form so the user can locate it, but build a search regex
66
+ # that ignores the hint. Here, we keep the phrase as-is and let the search
67
+ # tolerate the parenthetical by stripping it for matching only.
68
+ return phrase, suggestion
69
+
70
+
71
+ def load_lexicon(path: Path) -> dict[str, list[tuple[str, str]]]:
72
+ """
73
+ Parse the lexicon markdown file into a dict of:
74
+ category -> list of (phrase, suggestion) tuples.
75
+
76
+ Suggestion is an empty string when the lexicon offers none.
77
+ """
78
+ if not path.exists():
79
+ return {}
80
+
81
+ categories: dict[str, list[tuple[str, str]]] = {}
82
+ current_category = ""
83
+ current_inline_block: list[str] = []
84
+
85
+ def flush_inline_block() -> None:
86
+ if not current_category or not current_inline_block:
87
+ return
88
+ text = " ".join(current_inline_block)
89
+ phrases = _split_phrases(text)
90
+ for p in phrases:
91
+ categories.setdefault(current_category, []).append((p, ""))
92
+ current_inline_block.clear()
93
+
94
+ for raw_line in path.read_text(encoding="utf-8").splitlines():
95
+ line = raw_line.rstrip()
96
+
97
+ header = _parse_section_header(line)
98
+ if header:
99
+ flush_inline_block()
100
+ current_category = header
101
+ continue
102
+
103
+ if not current_category:
104
+ continue
105
+
106
+ if not line.strip():
107
+ flush_inline_block()
108
+ continue
109
+
110
+ replacement = _parse_replacement_line(line)
111
+ if replacement is not None:
112
+ phrase, suggestion = replacement
113
+ categories.setdefault(current_category, []).append((phrase, suggestion))
114
+ continue
115
+
116
+ if line.startswith("-"):
117
+ # Bullet item without `->`: treat as a plain phrase.
118
+ phrase = line.lstrip("-").strip()
119
+ if phrase:
120
+ categories.setdefault(current_category, []).append((phrase, ""))
121
+ continue
122
+
123
+ # Otherwise, this is part of an inline comma-separated block.
124
+ current_inline_block.append(line)
125
+
126
+ flush_inline_block()
127
+ return categories
128
+
129
+
130
+ def _compile_pattern(phrase: str) -> re.Pattern[str]:
131
+ """
132
+ Build a case-insensitive regex matching the phrase as a whole-word boundary,
133
+ tolerating an optional parenthetical hint (e.g. `aplicar a (trabajo)` matches
134
+ `aplicar a`).
135
+ """
136
+ bare = re.sub(r"\s*\([^)]*\)\s*", "", phrase).strip()
137
+ escaped = re.escape(bare)
138
+ # Allow optional whitespace inside multi-word phrases.
139
+ escaped = escaped.replace(r"\ ", r"\s+")
140
+ return re.compile(rf"(?<!\w){escaped}(?!\w)", re.IGNORECASE)
141
+
142
+
143
+ def scan_text(
144
+ text: str,
145
+ categories: dict[str, list[tuple[str, str]]],
146
+ ) -> Iterator[Hit]:
147
+ """Yield a Hit for every phrase match found in the text."""
148
+ compiled = [
149
+ (category, phrase, suggestion, _compile_pattern(phrase))
150
+ for category, items in categories.items()
151
+ for phrase, suggestion in items
152
+ ]
153
+
154
+ for line_no, line in enumerate(text.splitlines(), start=1):
155
+ for category, phrase, suggestion, pattern in compiled:
156
+ for match in pattern.finditer(line):
157
+ yield Hit(
158
+ line_no=line_no,
159
+ column=match.start() + 1,
160
+ category=category,
161
+ matched=match.group(0),
162
+ suggestion=suggestion,
163
+ )
164
+
165
+
166
+ def read_input() -> str:
167
+ if len(sys.argv) > 1:
168
+ arg = sys.argv[1]
169
+ if arg in ("-h", "--help"):
170
+ print(__doc__)
171
+ sys.exit(0)
172
+ return Path(arg).read_text(encoding="utf-8")
173
+ return sys.stdin.read()
174
+
175
+
176
+ def format_hit(hit: Hit) -> str:
177
+ location = f"line {hit.line_no}:{hit.column}"
178
+ body = f'[{hit.category}] "{hit.matched}"'
179
+ if hit.suggestion:
180
+ body += f" → {hit.suggestion}"
181
+ return f"{location} {body}"
182
+
183
+
184
+ def main() -> int:
185
+ categories = load_lexicon(LEXICON_PATH)
186
+ if not categories:
187
+ print(
188
+ f"WARNING: lexicon not found or empty at {LEXICON_PATH}",
189
+ file=sys.stderr,
190
+ )
191
+ return 2
192
+
193
+ text = read_input()
194
+ hits = list(scan_text(text, categories))
195
+
196
+ if not hits:
197
+ print("OK: no AI-writing tics detected.")
198
+ return 0
199
+
200
+ print(f"Found {len(hits)} potential AI-writing tic(s):\n")
201
+ for hit in hits:
202
+ print(format_hit(hit))
203
+
204
+ by_category: dict[str, int] = {}
205
+ for hit in hits:
206
+ by_category[hit.category] = by_category.get(hit.category, 0) + 1
207
+
208
+ print("\nSummary by category:")
209
+ for category, count in sorted(by_category.items(), key=lambda x: -x[1]):
210
+ print(f" {count:>3} {category}")
211
+
212
+ return 1
213
+
214
+
215
+ if __name__ == "__main__":
216
+ sys.exit(main())
@@ -1,32 +1,65 @@
1
1
  ---
2
2
  name: refactoring-ui
3
- description: Design advisor for UI/UX work, drawing on principles from "Refactoring UI" by Adam Wathan & Steve Schoger. Use when the user asks for UI/UX design advice, design reviews, visual hierarchy improvements, color system help, typography guidance, spacing decisions, depth/shadow usage, image handling, or finishing touches on any interface.
4
- when_to_use: >
5
- - User asks "how do I make this look better?"
6
- - User asks about color palettes, type scales, or spacing systems
7
- - User asks about visual hierarchy or emphasis
8
- - User is designing a UI component, page, or layout
9
- - User wants a design review or critique
10
- - User asks about shadows, depth, or layering
11
- - User asks about handling images in UI
12
- - User asks about empty states, borders, or decorative elements
13
- source: "Inspired by 'Refactoring UI' by Adam Wathan & Steve Schoger — refactoringui.com"
14
- anti_hallucination_note: >
15
- Recommendations in this skill summarize design principles in the maintainer's own words.
16
- Do NOT invent ratios, scale values, or technical numbers that are not in the reference
17
- files. If a topic is not covered, say so explicitly rather than inventing advice.
3
+ description: 'Use when the user asks for UI/UX design advice, design reviews, visual hierarchy improvements, color system help, typography guidance, spacing decisions, depth/shadow usage, image handling, or finishing touches on any interface. Inspired by "Refactoring UI" by Adam Wathan & Steve Schoger. Triggers: "how do I make this look better?", color palettes, type scales, spacing systems, visual hierarchy, design reviews, shadows/depth, image handling, empty states, borders.'
18
4
  ---
19
5
 
20
6
  # Refactoring UI Skill
21
7
 
22
8
  Design advice grounded in the principles taught by Adam Wathan & Steve Schoger in their book *Refactoring UI*. **The book itself contains the original prose, illustrations, side-by-side examples, and case studies — buy it at https://refactoringui.com for the full material.** This skill provides reformulated guidance for use as an AI assistant reference.
23
9
 
24
- ## How to Use This Skill
10
+ ## Required workflow (read before responding)
25
11
 
26
- 1. Read the relevant reference file(s) before answering
27
- 2. Base advice on the reference content not training data or unrelated design systems
28
- 3. Speak in your own words; do not reproduce the book's prose, illustrations, or examples verbatim
29
- 4. Do not invent numbers, ratios, or specific technical rules that are not in the references
12
+ The SKILL.md alone is an **index** of references. The detail you need
13
+ to give accurate answers lives in the reference files. **Reading this
14
+ SKILL.md is not enough.**
15
+
16
+ ### Step 1 — Open the relevant reference files
17
+
18
+ | Task involves | Required reading |
19
+ |---|---|
20
+ | Color systems, typography, spacing scales — defining the system | [references/01-foundations.md](references/01-foundations.md) |
21
+ | Layout, white space, visual hierarchy, page-level structure | [references/02-page-mechanics.md](references/02-page-mechanics.md) |
22
+ | Color usage, HSL, greys, contrast, shadows, depth, images | [references/03-visual-treatment.md](references/03-visual-treatment.md) |
23
+ | Empty states, borders, accents, finishing touches | [references/04-polish.md](references/04-polish.md) |
24
+ | Motion, microinteractions, transitions, hover/press states, loading | [references/05-motion.md](references/05-motion.md) |
25
+ | Dark mode, multi-theme color tokens, theme toggle, contrast strategy | [references/06-dark-mode.md](references/06-dark-mode.md) |
26
+ | Modals, forms, tables — component-specific layout and behavior patterns | [references/07-component-patterns.md](references/07-component-patterns.md) |
27
+
28
+ ### Step 2 — Output contract
29
+
30
+ Every design recommendation, ratio, value, or rule you cite MUST be
31
+ backed by a citation in the form:
32
+
33
+ `[source: references/<file>.md]`
34
+
35
+ Example: *"Use weight and color, not just font size, to establish hierarchy [source: references/02-page-mechanics.md]"*
36
+
37
+ ### Step 3 — If you must answer from memory
38
+
39
+ If you write a claim without having read the reference that backs it,
40
+ prepend `FROM_MEMORY (unverified):` to that claim. Do not hide it.
41
+
42
+ ### Banned behaviors
43
+
44
+ - ❌ Inventing ratios, scale values, contrast numbers, or rules not in the references
45
+ - ❌ Reproducing the book's prose, illustrations, or examples verbatim — paraphrase only
46
+ - ❌ Mixing in advice from unrelated design systems (Material, HIG, Tailwind defaults) as if it were *Refactoring UI* doctrine
47
+ - ❌ Marking the answer complete without listing which reference files you read
48
+
49
+ ## When to use
50
+
51
+ - User asks "how do I make this look better?"
52
+ - User asks about color palettes, type scales, or spacing systems
53
+ - User asks about visual hierarchy or emphasis
54
+ - User is designing a UI component, page, or layout
55
+ - User wants a design review or critique
56
+ - User asks about shadows, depth, or layering
57
+ - User asks about handling images in UI
58
+ - User asks about empty states, borders, or decorative elements
59
+
60
+ ## Source
61
+
62
+ Inspired by 'Refactoring UI' by Adam Wathan & Steve Schoger — refactoringui.com
30
63
 
31
64
  ## Reference Files
32
65
 
@@ -36,18 +69,21 @@ Design advice grounded in the principles taught by Adam Wathan & Steve Schoger i
36
69
  | `references/02-page-mechanics.md` | Visual hierarchy, layout, white space, spacing scales, typography |
37
70
  | `references/03-visual-treatment.md` | Color systems (HSL, shades, greys, contrast), depth and shadows, image handling |
38
71
  | `references/04-polish.md` | Finishing touches: borders, accents, empty states, decorative defaults, design intuition |
72
+ | `references/05-motion.md` | Motion system (durations, easings), hover/press states, loading patterns, prefers-reduced-motion — **complementary** (not from RUI) |
73
+ | `references/06-dark-mode.md` | Dark mode color tokens, text contrast, shadow handling, images, theme toggle — **complementary** (extrapolates RUI's HSL principles) |
74
+ | `references/07-component-patterns.md` | Modals (focus, layout), forms (labels, validation), tables (density, alignment) — **complementary** (extends RUI principles to specific components) |
39
75
 
40
76
  ## Anti-Patterns to Watch For
41
77
 
42
- - Designing layouts/navs/shells before designing real features
43
- - Using font size as the only tool for hierarchy (ignoring weight and color)
44
- - Using opacity to create grey text on colored backgrounds
45
- - Starting with too little white space and adding it later
46
- - Using `em` for type scales (compounds when nested)
47
- - Using color as the only signal for a UI state
48
- - Designing with placeholder images instead of real content
49
- - Shrinking a logo down to use as a favicon
50
- - Using preprocessor `lighten()` / `darken()` to derive shades
78
+ - Designing layouts/navs/shells before designing real features [source: references/01-foundations.md]
79
+ - Using font size as the only tool for hierarchy (ignoring weight and color) [source: references/02-page-mechanics.md]
80
+ - Using opacity to create grey text on colored backgrounds [source: references/02-page-mechanics.md]
81
+ - Starting with too little white space and adding it later [source: references/02-page-mechanics.md]
82
+ - Using `em` for type scales (compounds when nested) [source: references/02-page-mechanics.md]
83
+ - Using color as the only signal for a UI state [source: references/03-visual-treatment.md]
84
+ - Designing with placeholder images instead of real content [source: references/03-visual-treatment.md]
85
+ - Shrinking a logo down to use as a favicon [source: references/03-visual-treatment.md]
86
+ - Using preprocessor `lighten()` / `darken()` to derive shades [source: references/03-visual-treatment.md]
51
87
 
52
88
  ## Attribution
53
89
 
@@ -0,0 +1,124 @@
1
+ # Motion: Microinteractions, Transitions, Hover
2
+
3
+ > **Scope note**: motion is **not** covered in *Refactoring UI* by Adam Wathan & Steve Schoger. This file is complementary guidance, written in the same spirit as the book — favor restraint, build from a small fixed system, and avoid effects that exist to draw attention to themselves. It does not paraphrase the book.
4
+
5
+ ---
6
+
7
+ ## The Restraint Principle Carries Over
8
+
9
+ The book's central idea — "make the right things stand out by quieting the rest" — applies directly to motion. Animation in a UI is for **communicating state changes**, not for entertainment.
10
+
11
+ - If the user wouldn't notice the animation is gone, it shouldn't be there
12
+ - If the animation shows that something happened (state change, success, error), keep it
13
+ - "Wow" animations are a tax on every interaction after the first
14
+
15
+ ## Pre-Build a Motion System
16
+
17
+ Like type/color/spacing scales, define a fixed menu of durations and easings up front. Pick from that menu instead of inventing per-component.
18
+
19
+ **Sample duration scale (in milliseconds):**
20
+
21
+ | Token | Duration | Use |
22
+ |---|---|---|
23
+ | `instant` | 0–80 | Press/active states. Should feel like no delay. |
24
+ | `fast` | 100–200 | Hover effects, small state changes (icons, toggles, focus rings) |
25
+ | `normal` | 200–400 | Modal/drawer entry, expand/collapse, page-level transitions |
26
+ | `slow` | 400–600 | Decorative reveals, onboarding sequences |
27
+ | `+1s` | ≥ 1000 | Almost always wrong in a working UI — reserve for very specific moments |
28
+
29
+ **Sample easing scale:**
30
+
31
+ | Token | Curve | Use |
32
+ |---|---|---|
33
+ | `enter` | `cubic-bezier(0, 0, 0.2, 1)` (ease-out) | Elements appearing — fast start, slow finish |
34
+ | `exit` | `cubic-bezier(0.4, 0, 1, 1)` (ease-in) | Elements leaving — slow start, fast finish (they "fall away") |
35
+ | `standard` | `cubic-bezier(0.4, 0, 0.2, 1)` (ease-in-out) | State changes that aren't directional |
36
+ | `linear` | linear | Loaders, progress, anything tied to real time |
37
+
38
+ ## Animate Cheap Properties
39
+
40
+ Only `transform` and `opacity` are GPU-composited and frame-stable. Animating other properties forces layout/paint per frame and stutters on mid-range hardware.
41
+
42
+ | Cheap | Expensive |
43
+ |---|---|
44
+ | `transform: translate(...)`, `scale(...)`, `rotate(...)` | `width`, `height`, `top`, `left`, `margin`, `padding` |
45
+ | `opacity` | `box-shadow` (animatable, but slow at large blur) |
46
+ | `filter: blur()` (sparingly) | `background-color` on large surfaces |
47
+
48
+ To slide a panel in: animate `transform: translateX(100%)` → `translateX(0)`, not `right: -400px` → `right: 0`.
49
+
50
+ ## Hover States
51
+
52
+ The book's principle (use color/weight/contrast for hierarchy, not just one tool) applies to hover too — combine signals subtly.
53
+
54
+ A solid hover combines two of:
55
+
56
+ - A small lightness shift on the background (1–2 steps on your shade scale)
57
+ - A border or shadow change
58
+ - An icon color change
59
+
60
+ Avoid:
61
+
62
+ - Scaling up the whole element (1.05×, 1.1×) — chunky and dated
63
+ - A bright glow — feels like 2008
64
+ - Animating font size on hover — text reflow is jarring
65
+
66
+ ```css
67
+ .button {
68
+ background: var(--brand-500);
69
+ transition: background-color 150ms cubic-bezier(0, 0, 0.2, 1);
70
+ }
71
+ .button:hover {
72
+ background: var(--brand-600);
73
+ }
74
+ ```
75
+
76
+ ## Press / Active States
77
+
78
+ Visual pressure should feel like the element was pushed *into* the page — the inverse of "raised."
79
+
80
+ - Shadow shrinks or disappears
81
+ - A tiny `transform: translateY(1px)` works for cards
82
+ - The hover background usually deepens one more step on press
83
+
84
+ Press states should feel **instant** — duration `instant` (0–80ms), not `fast`.
85
+
86
+ ## Loading
87
+
88
+ In order of preference:
89
+
90
+ 1. **Optimistic UI** — assume success, update immediately, roll back on error. No spinner.
91
+ 2. **Skeleton screen** — placeholder shapes matching the final layout. Communicates structure while content loads.
92
+ 3. **Inline progress** — a thin progress bar at the top of the affected region, or shimmer on a single field.
93
+ 4. **Spinner** — only when 1–3 don't fit. Add a "Cancel" if the operation is long.
94
+
95
+ Skeleton screens beat spinners because they reduce the perceived wait — the layout doesn't shift when content arrives.
96
+
97
+ If you must use a spinner, **only show it after ~150ms** of waiting. Most operations finish faster than that; a spinner that flashes in and out is worse than no spinner.
98
+
99
+ ## Respect `prefers-reduced-motion`
100
+
101
+ Some users disable motion at the OS level (motion sickness, vestibular disorders, focus). The browser exposes this preference:
102
+
103
+ ```css
104
+ @media (prefers-reduced-motion: reduce) {
105
+ * {
106
+ animation-duration: 0.01ms !important;
107
+ animation-iteration-count: 1 !important;
108
+ transition-duration: 0.01ms !important;
109
+ scroll-behavior: auto !important;
110
+ }
111
+ }
112
+ ```
113
+
114
+ Or, more deliberately, swap motion for an instant state change inside specific components. Never disable a state change entirely (the user still needs to see that something happened) — only the *animation between* states.
115
+
116
+ ## Anti-Patterns
117
+
118
+ - ❌ Animating layout-affecting properties (`width`, `top`, `margin`) — jank
119
+ - ❌ One-off durations per component — kills consistency
120
+ - ❌ Easing on a linear curve for entries — feels mechanical
121
+ - ❌ Spinners that appear under 150ms — flashy noise
122
+ - ❌ Decorative animations that fire on every page load — annoying by the second visit
123
+ - ❌ Ignoring `prefers-reduced-motion` — accessibility regression
124
+ - ❌ Long durations (>600ms) for state changes — feels sluggish