@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.
- package/README.md +89 -9
- package/lib/cleanup.js +29 -0
- package/lib/commands/skills.js +110 -9
- package/lib/config.js +18 -9
- package/lib/installer.js +5 -3
- package/lib/symlink.js +45 -3
- package/lib/utils.js +41 -0
- package/package.json +2 -2
- package/skills/audit-codebase/SKILL.md +70 -0
- package/skills/audit-codebase/agents/openai.yaml +4 -0
- package/skills/audit-codebase/references/comprehensive-audit.md +220 -0
- package/skills/audit-codebase/references/report-format.md +119 -0
- package/skills/humaniza/SKILL.md +55 -4
- package/skills/humaniza/references/ai-patterns-es.md +40 -0
- package/skills/humaniza/references/checklist.md +9 -0
- package/skills/humaniza/references/examples.md +16 -0
- package/skills/humaniza/references/lexicon-es-mx.md +18 -0
- package/skills/humaniza/references/structures-es.md +132 -0
- package/skills/humaniza/scripts/check_ai_patterns.py +216 -0
- package/skills/refactoring-ui/SKILL.md +65 -29
- package/skills/refactoring-ui/references/05-motion.md +124 -0
- package/skills/refactoring-ui/references/06-dark-mode.md +117 -0
- package/skills/refactoring-ui/references/07-component-patterns.md +181 -0
- package/skills/session-log/SKILL.md +524 -0
- package/skills/session-log/evals/README.md +79 -0
- package/skills/session-log/evals/ab-ronda-1.md +115 -0
- package/skills/session-log/evals/ab-ronda-2.md +174 -0
- package/skills/session-log/evals/defecto-experimento.md +12 -0
- package/skills/session-log/evals/evals.json +147 -0
- package/skills/session-log/evals/trigger-eval.json +23 -0
- package/skills/session-log/references/file-layout.md +336 -0
- package/skills/session-log/references/verification.md +173 -0
- package/skills/stitch-showcase/SKILL.md +24 -232
- package/skills/stitch-showcase/references/07-theme-system.md +12 -0
- package/skills/stitch-showcase/references/08-type-detection.md +9 -1
- package/skills/stitch-showcase/references/10-component-standardization.md +25 -0
- package/skills/stitch-showcase/references/12-video-embedding.md +113 -0
- package/skills/stitch-showcase/references/13-language-detection.md +82 -0
- package/skills/stitch-showcase/references/14-troubleshooting-known-issues.md +122 -0
- package/skills/stitch-showcase/references/15-build-flags.md +71 -0
- package/skills/stitch-showcase/references/16-design-md-format.md +107 -0
- package/skills/stitch-showcase/references/index.html +25 -19
- package/skills/stitch-showcase/references/viewer.html +24 -12
- package/skills/stitch-showcase/scripts/__pycache__/build_showcase.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/component_utils.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/detect_components.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_catalog.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_text.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_zips.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/parse_design_md.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/slug_demangle.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/build_showcase.py +150 -10
- package/skills/stitch-showcase/scripts/parse_design_md.py +145 -12
- package/skills/stitch-showcase/scripts/slug_demangle.py +209 -0
- package/skills/vscode-extension-dev/SKILL.md +90 -41
- package/skills/vscode-extension-dev/references/api-additional.md +168 -0
- package/skills/vscode-extension-dev/references/api-progress.md +55 -0
- package/skills/vscode-extension-dev/references/api-quickpick.md +75 -0
- package/skills/vscode-extension-dev/references/api-secretstorage.md +57 -0
- package/skills/vscode-extension-dev/references/api-statusbar.md +38 -0
- package/skills/vscode-extension-dev/references/api-treeview.md +78 -0
- package/skills/vscode-extension-dev/references/api-webview.md +149 -0
- package/skills/vscode-extension-dev/references/architecture.md +67 -0
- package/skills/vscode-extension-dev/references/debugger.md +179 -0
- package/skills/vscode-extension-dev/references/lsp.md +175 -0
- package/skills/vscode-extension-dev/references/notebooks.md +208 -0
- package/skills/vscode-extension-dev/references/testing.md +208 -0
- 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:
|
|
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
|
-
##
|
|
10
|
+
## Required workflow (read before responding)
|
|
25
11
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|