@ericrisco/rsc 3.1.3 → 3.3.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 (105) hide show
  1. package/README.md +8 -6
  2. package/manifest.json +43 -69
  3. package/package.json +6 -1
  4. package/scripts/design-upstream.js +92 -0
  5. package/scripts/doctor.js +0 -24
  6. package/scripts/lib/default-skill-floor.js +5 -1
  7. package/scripts/lib/domains.js +2 -2
  8. package/scripts/lib/recommend.js +1 -3
  9. package/scripts/lib/retired-skills.js +7 -1
  10. package/skills/ai-media/SKILL.md +2 -2
  11. package/skills/design/IMPECCABLE-LICENSE.txt +191 -0
  12. package/skills/design/SKILL.md +79 -328
  13. package/skills/design/THIRD_PARTY.md +26 -0
  14. package/skills/design/engine/LICENSE +21 -0
  15. package/skills/design/engine/RUN.md +515 -0
  16. package/skills/design/engine/UPSTREAM.json +4 -0
  17. package/skills/design/engine/assets/app.css +216 -0
  18. package/skills/design/engine/assets/base.css +105 -0
  19. package/skills/design/engine/assets/base.js +37 -0
  20. package/skills/design/engine/assets/charts.js +617 -0
  21. package/skills/design/engine/assets/scenes/stage.css +28 -0
  22. package/skills/design/engine/assets/scenes/stage.js +133 -0
  23. package/skills/design/engine/library/app.json +1327 -0
  24. package/skills/design/engine/library/directions.json +1078 -0
  25. package/skills/design/engine/library/heroes.json +1086 -0
  26. package/skills/design/engine/library/motions.json +92 -0
  27. package/skills/design/engine/library/palettes.json +1485 -0
  28. package/skills/design/engine/library/photos.json +7240 -0
  29. package/skills/design/engine/library/sections.json +4429 -0
  30. package/skills/design/engine/library/sites.json +8350 -0
  31. package/skills/design/engine/library/type.json +2024 -0
  32. package/skills/design/engine/references/app-screens.md +1199 -0
  33. package/skills/design/engine/references/colour.md +141 -0
  34. package/skills/design/engine/references/copy.md +177 -0
  35. package/skills/design/engine/references/critique.md +182 -0
  36. package/skills/design/engine/references/imagery.md +791 -0
  37. package/skills/design/engine/references/layout.md +292 -0
  38. package/skills/design/engine/references/motion.md +980 -0
  39. package/skills/design/engine/references/research.md +356 -0
  40. package/skills/design/engine/references/scenes.md +174 -0
  41. package/skills/design/engine/references/tells.md +115 -0
  42. package/skills/design/engine/references/type.md +170 -0
  43. package/skills/design/engine/scripts/assets.mjs +865 -0
  44. package/skills/design/engine/scripts/draw.mjs +584 -0
  45. package/skills/design/engine/scripts/inspect.mjs +303 -0
  46. package/skills/design/engine/scripts/lib/app-draw.mjs +203 -0
  47. package/skills/design/engine/scripts/lib/cdp.mjs +248 -0
  48. package/skills/design/engine/scripts/lib/probe.mjs +909 -0
  49. package/skills/design/engine/scripts/lib/rules.mjs +243 -0
  50. package/skills/design/engine/scripts/lint.mjs +119 -0
  51. package/skills/design/engine/scripts/scenes.mjs +124 -0
  52. package/skills/design/evals/cases.yaml +35 -46
  53. package/skills/design/references/design-md.md +49 -0
  54. package/skills/design/references/finish-review.md +46 -0
  55. package/skills/design/references/modes.md +51 -0
  56. package/skills/expo/SKILL.md +3 -4
  57. package/skills/marketing/references/landing-copy.md +2 -2
  58. package/skills/react/SKILL.md +2 -2
  59. package/skills/react-native/SKILL.md +3 -3
  60. package/skills/scroll-film/SKILL.md +220 -0
  61. package/skills/scroll-film/assets/page-template.html +128 -0
  62. package/skills/scroll-film/assets/scrub-engine.js +352 -0
  63. package/skills/scroll-film/evals/README.md +26 -0
  64. package/skills/scroll-film/evals/cases.yaml +81 -0
  65. package/skills/scroll-film/references/chain.md +218 -0
  66. package/skills/scroll-film/references/engine.md +132 -0
  67. package/skills/scroll-film/scripts/verify.sh +158 -0
  68. package/skills/swift-ios/SKILL.md +1 -1
  69. package/skills/ui-engineering/SKILL.md +3 -4
  70. package/skills/ui-engineering/evals/cases.yaml +2 -2
  71. package/skills/variant-explorer/SKILL.md +4 -4
  72. package/skills/variant-explorer/evals/cases.yaml +1 -1
  73. package/targets/clone-bootstrap.mjs +1 -1
  74. package/scripts/lib/design-identity.js +0 -117
  75. package/scripts/lib/starting-point.js +0 -314
  76. package/skills/design/evals/README.md +0 -53
  77. package/skills/design/references/ai-tells.md +0 -75
  78. package/skills/design/references/brand-grounding.md +0 -197
  79. package/skills/design/references/copywriting-frameworks.md +0 -138
  80. package/skills/design/references/design-systems.md +0 -49
  81. package/skills/design/references/inspiration-sources.md +0 -96
  82. package/skills/design/references/landing-anatomy-and-cro.md +0 -202
  83. package/skills/design/references/motion-and-interaction.md +0 -228
  84. package/skills/design/references/research-method.md +0 -154
  85. package/skills/design/references/signature-and-craft.md +0 -148
  86. package/skills/design/references/starting-point.md +0 -75
  87. package/skills/design/references/trends-2026.md +0 -80
  88. package/skills/design/references/visual-system.md +0 -237
  89. package/skills/design/scripts/verify.sh +0 -357
  90. package/skills/design-dna/PROMPT.md +0 -211
  91. package/skills/design-dna/SKILL.md +0 -162
  92. package/skills/design-dna/design-dna.schema.json +0 -230
  93. package/skills/design-dna/evals/README.md +0 -64
  94. package/skills/design-dna/evals/cases.yaml +0 -68
  95. package/skills/design-dna/references/method.md +0 -436
  96. package/skills/design-dna/scripts/emit.py +0 -164
  97. package/skills/design-dna/templates/PROMPT.md.tmpl +0 -42
  98. package/skills/design-dna/templates/SKILL.md.tmpl +0 -42
  99. package/skills/design-dna/templates/check.py.tmpl +0 -143
  100. package/skills/design-loop/SKILL.md +0 -160
  101. package/skills/design-loop/evals/README.md +0 -56
  102. package/skills/design-loop/evals/cases.yaml +0 -60
  103. package/skills/motion-craft/SKILL.md +0 -125
  104. package/skills/motion-craft/evals/cases.yaml +0 -38
  105. package/skills/motion-craft/scripts/verify.sh +0 -75
@@ -1,42 +0,0 @@
1
- ---
2
- name: __SLUG__
3
- description: "Use when building anything in the __NAME__ style: __ONE_LINE__ Fires on '__SLUG__', 'in the __NAME__ style', 'another one like <reference>', 'same look as before'. Captured from __MEDIUM__; drives any format. NOT inventing a new direction (that is `design`), NOT re-deriving this style (its record already exists in dna.json)."
4
- tags: [style, design-dna, __SLUG__]
5
- recommends: [design-dna, nextjs, marketing]
6
- origin: design-dna
7
- ---
8
-
9
- # __NAME__
10
-
11
- *__ONE_LINE__*
12
-
13
- Captured __CAPTURED__ from __MEDIUM__. Reference kept in `reference/`. Worked proof in `example/`.
14
-
15
- ## How to use this
16
-
17
- 1. Load **`PROMPT.md` only**, and attach `reference/__REF__`. Never paste `dna.json` into a prompt: it is the record, not the payload, and its size is exactly what breaks compliance.
18
- 2. Pick an archetype by name before writing a line. Structure first, or piece 8 will not sit beside piece 1 as a set.
19
- 3. Build. Web build goes to `../nextjs/SKILL.md`, words to `../marketing/SKILL.md`; the identity stays here.
20
- 4. Run the self-check. Name every test and its result:
21
-
22
- python3 scripts/check.py <output files or a rendered PNG>
23
-
24
- Non-zero exit means do not ship. Answer the MANUAL tests out loud.
25
-
26
- ## What this style is, in one screen
27
-
28
- __SUMMARY__
29
-
30
- ## Do not
31
-
32
- __BANS__
33
-
34
- ## Known drift risks
35
-
36
- __CONFIDENCE__
37
-
38
- These are the values that were inferred rather than measured. If output starts feeling off, re-measure these first.
39
-
40
- ## Maintenance
41
-
42
- Re-capture only when the reference itself changes. To extend the style, edit `dna.json`, then recompile `PROMPT.md` under the 2KB cap: adding a signature means deleting one. Method and rationale: `../design-dna/SKILL.md`.
@@ -1,143 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Auto tests for the __NAME__ style. Exits non-zero on any failure.
3
-
4
- python3 scripts/check.py <output.html|output.css|output.png> [more files...]
5
-
6
- Reads dna.json and runs every test marked "auto": true that carries a "probe".
7
- Tests without a probe are reported as MANUAL and never silently pass.
8
- A probe handed no artefact it can read is reported as SKIP with its reason -
9
- never as PASS or FAIL.
10
-
11
- Probe kinds
12
- -----------
13
- regex_absent {"kind":"regex_absent","pattern":"..."} fails if the pattern appears
14
- regex_count {"kind":"regex_count","pattern":"...","exactly":1} or "min"/"max"
15
- distinct_css {"kind":"distinct_css","property":"font-size","max":3} distinct declared values
16
- css_ratio {"kind":"css_ratio","property":"font-size","min":6.0} largest / smallest declared
17
- min_unit {"kind":"min_unit","property":"font-size","min_px":28} smallest declared value
18
- color_coverage {"kind":"color_coverage","hex":"#ff4d00","max_pct":8,
19
- "tolerance":24} needs an image file + Pillow
20
- """
21
- import json, os, re, sys
22
-
23
- HERE = os.path.dirname(os.path.abspath(__file__))
24
- DNA_PATH = os.path.join(HERE, "..", "dna.json")
25
- if not os.path.isfile(DNA_PATH):
26
- sys.exit("no dna.json beside this script, so there is nothing to check against.\n"
27
- "This style skill was scaffolded and never finished. Fix:\n"
28
- " write dna.json, then validate it with\n"
29
- " python3 ../design-dna/scripts/emit.py <slug> --validate")
30
- DNA = json.load(open(DNA_PATH))
31
-
32
- TEXT_EXT = {".html", ".htm", ".css", ".scss", ".jsx", ".tsx", ".svg", ".md", ".js", ".ts"}
33
- IMG_EXT = {".png", ".jpg", ".jpeg", ".webp"}
34
-
35
-
36
- def load(paths):
37
- text, images = "", []
38
- for p in paths:
39
- ext = os.path.splitext(p)[1].lower()
40
- if ext in IMG_EXT:
41
- images.append(p)
42
- elif ext in TEXT_EXT or os.path.isfile(p):
43
- text += "\n" + open(p, encoding="utf-8", errors="replace").read()
44
- return text, images
45
-
46
-
47
- def css_values(text, prop):
48
- out = []
49
- for raw in re.findall(rf"{re.escape(prop)}\s*:\s*([^;}}\"']+)", text, re.I):
50
- m = re.match(r"\s*(-?[\d.]+)\s*(px|rem|em|pt|%)?", raw)
51
- if not m:
52
- continue
53
- n = float(m.group(1))
54
- unit = (m.group(2) or "px").lower()
55
- out.append(n * 16 if unit in ("rem", "em") else n)
56
- return out
57
-
58
-
59
- def coverage(path, hex_target, tol):
60
- try:
61
- from PIL import Image
62
- except ImportError:
63
- return None, "Pillow not installed (pip install pillow)"
64
- tr, tg, tb = (int(hex_target.lstrip("#")[i:i + 2], 16) for i in (0, 2, 4))
65
- im = Image.open(path).convert("RGB")
66
- im.thumbnail((400, 400))
67
- px = list(im.get_flattened_data()) if hasattr(im, "get_flattened_data") else list(im.getdata())
68
- hit = sum(1 for r, g, b in px if abs(r - tr) <= tol and abs(g - tg) <= tol and abs(b - tb) <= tol)
69
- return 100.0 * hit / max(1, len(px)), None
70
-
71
-
72
- # Probes that read declared values. Handed no text they must SKIP: a regex over an empty
73
- # string is not a check, and calling it PASS or FAIL is the gate lying in one direction
74
- # or the other.
75
- TEXT_PROBES = ("regex_absent", "regex_count", "distinct_css", "css_ratio", "min_unit")
76
-
77
-
78
- def run(test, text, images):
79
- pr = test.get("probe")
80
- if not pr:
81
- return "MANUAL", "no probe declared"
82
- k = pr.get("kind")
83
- if k in TEXT_PROBES and not text.strip():
84
- return "SKIP", "no text artefact passed; this probe reads declarations, not pixels"
85
- if k == "regex_absent":
86
- hits = re.findall(pr["pattern"], text, re.I)
87
- return ("FAIL" if hits else "PASS"), f"{len(hits)} match(es)"
88
- if k == "regex_count":
89
- n = len(re.findall(pr["pattern"], text, re.I))
90
- ok = (n == pr["exactly"]) if "exactly" in pr else (pr.get("min", 0) <= n <= pr.get("max", 10 ** 9))
91
- return ("PASS" if ok else "FAIL"), f"found {n}"
92
- if k == "distinct_css":
93
- vals = sorted(set(css_values(text, pr["property"])))
94
- return ("PASS" if len(vals) <= pr["max"] else "FAIL"), f"{len(vals)} distinct: {vals}"
95
- if k == "css_ratio":
96
- vals = [v for v in css_values(text, pr["property"]) if v > 0]
97
- if not vals:
98
- return "SKIP", f"no {pr['property']} declarations found"
99
- r = max(vals) / min(vals)
100
- return ("PASS" if r >= pr["min"] else "FAIL"), f"ratio {r:.2f}:1"
101
- if k == "min_unit":
102
- vals = [v for v in css_values(text, pr["property"]) if v > 0]
103
- if not vals:
104
- return "SKIP", f"no {pr['property']} declarations found"
105
- return ("PASS" if min(vals) >= pr["min_px"] else "FAIL"), f"smallest {min(vals)}px"
106
- if k == "color_coverage":
107
- if not images:
108
- return "SKIP", "no image passed; render the output to PNG to check coverage"
109
- pct, err = coverage(images[0], pr["hex"], pr.get("tolerance", 24))
110
- if err:
111
- return "SKIP", err
112
- lo, hi = pr.get("min_pct", 0), pr.get("max_pct", 100)
113
- return ("PASS" if lo <= pct <= hi else "FAIL"), f"{pct:.1f}% of canvas"
114
- return "SKIP", f"unknown probe kind {k!r}"
115
-
116
-
117
- def main():
118
- if len(sys.argv) < 2:
119
- print(__doc__)
120
- return 2
121
- text, images = load(sys.argv[1:])
122
- failed = manual = 0
123
- print(f"design-dna check: {DNA['meta']['name']}\n")
124
- for t in DNA.get("tests", []):
125
- if not t.get("auto"):
126
- status, detail = "MANUAL", "human judgement"
127
- else:
128
- status, detail = run(t, text, images)
129
- failed += status == "FAIL"
130
- manual += status == "MANUAL"
131
- print(f" [{status:6}] {t['id']:28} {t['check']}")
132
- if detail:
133
- print(f" {detail}")
134
- if status == "FAIL":
135
- print(f" fail looks like: {t['fail_looks_like']}")
136
- print(f"\n{failed} failed, {manual} need human judgement.")
137
- if manual:
138
- print("Answer the MANUAL tests out loud before you call this done.")
139
- return 1 if failed else 0
140
-
141
-
142
- if __name__ == "__main__":
143
- sys.exit(main())
@@ -1,160 +0,0 @@
1
- ---
2
- name: design-loop
3
- description: "Use when something must be built well and there is a real reference it should beat: turn what makes the reference good into measured mechanisms, then run a builder and three fresh-context critics until all three pass. Fires on 'design loop', 'make it as good as <site>', 'it looks generic'. NOT keeping an already-won look (that is `design-dna`)."
4
- tags: [design, critique, loop, reference, quality, convergence]
5
- recommends: [design, design-dna, marketing, nextjs]
6
- origin: risco
7
- ---
8
-
9
- # Design Loop — the front door of the design area
10
-
11
- *A reference you can open, mechanisms you can check, and three judges who did not build the thing.*
12
-
13
- This is where a design request **enters**. It owns the method: the bar, the judges, the rounds. It
14
- does not own the visual system — `../design/SKILL.md` does, and this skill invokes it as the builder.
15
-
16
- **Why the method and not a rubric.** A rubric scored by whoever built the piece measures *intent*,
17
- because the builder knows what they were going for and so they see it there. And scores drift upward
18
- every round: a 7 that becomes an 8 with nothing changed is how a loop declares itself finished early.
19
- Binary verdicts from someone who did not build it are the fix for both.
20
-
21
- Four phases. Do not skip ahead, and do not start building during 1 to 3.
22
-
23
- ## Phase 1 — Interview
24
-
25
- Ask exactly these three, together, then stop and wait.
26
-
27
- 1. What are you building, and how long or how big?
28
- 2. Name something that already does this brilliantly — a site, a video, a doc, anything I can open.
29
- If nothing comes to mind, say skip.
30
- 3. Any files I should work from? Design system, brand doc, script, existing draft.
31
-
32
- **A vague bar is the number one reason this method fails.** If they name something vague ("Apple's
33
- website", "good SaaS design"), push once for the specific page or file: a critic with no concrete
34
- reference invents the comparison and approves everything on round one.
35
-
36
- On *skip*, propose three candidate bars, one line each on why, and wait. No answer → take the
37
- hardest one and say so. **Where they come from:** `../design/references/starting-point.md` — run its
38
- step 0 first, because a bar the project already owns outranks anything you would pick from outside,
39
- and proposing from memory is how this promise used to resolve to the AI-template median.
40
-
41
- **Where to go looking.** For a whole page to beat, and for the flows and single patterns behind it:
42
- `../design/references/inspiration-sources.md`. For a component idea rather than a whole reference:
43
- a gallery of real products. Browse for the technique, never to clone a
44
- competitor's exact grid — and come back with **a specific page you can open**, because a gallery
45
- is not a bar.
46
-
47
- ## Phase 2 — Preflight
48
-
49
- A check, not a question. Run it before any work and report in one block.
50
-
51
- - **Fetch the bar now.** Screenshot the URL or read the file. Blocked or missing → say so, ask for
52
- another. Never substitute a description from memory.
53
- - **Confirm you can render our output**: screenshots for a site, a filmstrip for animation, a PDF
54
- render for a doc.
55
- - **Name the generation tools the goal needs** (image, video, voice) and confirm they are connected.
56
- - **Confirm the input files exist**: design system, brand doc, script.
57
- - **Read the harness identity if it exists** — `02-DOCS/wiki/brand/`, reached from the root
58
- `CLAUDE.md` `## Brand & voice` section, the same place `design`, `marketing` and
59
- `presentations` read. A bar from outside cannot silently overrule the identity this project
60
- already committed to: if the reference contradicts it, say which rule conflicts and let the
61
- user decide which one wins. If no identity exists yet, say so — this run is what creates it.
62
-
63
- Then print what is working, what is missing, and **which critic goes blind** if something is
64
- missing. Never carry on quietly with a critic that cannot see — a verdict from a judge who cannot
65
- see the thing is worse than no verdict, because it looks like evidence.
66
-
67
- ## Phase 3 — Teardown
68
-
69
- Read the reference properly and write **5 to 7 mechanisms** to `bar.md`.
70
-
71
- Mechanisms, not adjectives. "Feels premium" is useless. These are useful:
72
-
73
- - headline is 5x body size, three type sizes total
74
- - one accent colour, used at most twice per screen
75
- - motion always resolves in one direction
76
- - nothing animates for under 400ms
77
- - whitespace above the fold is at least 40% of the frame
78
-
79
- Every line must be something a critic can check by looking. Show `bar.md` to the user before
80
- continuing — and where a mechanism contradicts the harness identity, mark the conflict rather
81
- than resolving it silently in favour of the reference.
82
-
83
- ## Phase 4 — Loop
84
-
85
- Split the goal into the smallest pieces that can be improved and judged on their own. You choose
86
- them. Keep it to three or four unless told otherwise: **every extra piece multiplies the run, and so
87
- does every extra round.**
88
-
89
- For each piece: fan out a builder, then three critics, each with fresh context and no knowledge of
90
- how the builder worked.
91
-
92
- - **Brief critic** — judges against the stated goal only. Does it do the thing? Ignore aesthetics.
93
- - **System critic** — judges against the project's design system only. Objective adherence.
94
- - **Craft critic** — judges against `bar.md` and rendered output only. Put ours next to the
95
- reference blind, labels stripped, say which is better, name the single biggest gap.
96
-
97
- Write each critic's brief yourself, adapted to this goal. Do not reuse generic wording across
98
- different goals.
99
-
100
- ### Rules
101
-
102
- - **Critics judge rendered output, never the code.** Reading the implementation makes a critic
103
- evaluate intent instead of result.
104
- - **Binary verdicts, not scores.** Scores drift upward every round.
105
- - **Critics are harsh, and harshness has a floor.** A critic has explicit permission to say a piece
106
- passes. A judge under standing orders to find fault will manufacture one, and then "all three must
107
- pass" is a door that recedes as you approach it.
108
- - **All three must pass.** Any fail goes back to the builder with the single biggest gap named — one,
109
- not a list.
110
- - **No fixed round count.** The exit is winning, or the user stopping the run, or the halt below.
111
-
112
- ### The halt — how this loop is allowed to end
113
-
114
- Fresh-context critics cannot see the gap history, so nothing arbitrates across rounds. Left alone,
115
- two incompatible gaps ("more air" / "more density") make the builder ping-pong forever, and the only
116
- brake is a human watching. Keep the gap history and use it:
117
-
118
- > **The same biggest gap named twice for the same piece halts that piece.** Put the two competing
119
- > demands side by side and ask the user to decide. Do not spend a third round on it.
120
-
121
- This is not a nicety. A loop whose declared exit is "all three pass" and which cannot detect that it
122
- will never get there is a gate that cannot close.
123
-
124
- ### Progress and cost
125
-
126
- Keep a live progress page: piece status, each critic's verdict, gap history, round count.
127
-
128
- There is **no reliable self-reported token cost, so do not show one.** Show round count and pieces
129
- instead. If the user names a ceiling, treat it as a checkpoint: pause and ask before passing it, and
130
- tell them plainly that the real brake is them watching and stopping the run.
131
-
132
- ## When the piece wins
133
-
134
- Hand the winner to `../design-dna/SKILL.md` to codify it: measured ratios, bans and tests that can
135
- fail, so piece eight still sits beside piece one as a set. Winning once and not writing down why is
136
- how the look drifts back to generic by the fifth piece.
137
-
138
- ## What breaks this
139
-
140
- | Symptom | Cause | Fix |
141
- |---|---|---|
142
- | Everything approved on round one | Vague bar | Push for the specific page or file |
143
- | Approvals that do not survive a second look | Builder judged its own work | Critics need fresh context |
144
- | Verdicts creep upward each round | Scores instead of binaries | Binary job, not a score |
145
- | Loop never exits | No halt on a repeated gap | Apply the halt above |
146
- | Loop exits with the piece still weak | Fixed round count | The exit is winning |
147
- | Obeys the letter, misses the point | Over-specifying | Every extra instruction is one fewer decision the model makes with its own judgment |
148
-
149
- ## Hand-offs
150
-
151
- - **The visual system, brand grounding, page composition** → `../design/SKILL.md`. It is the builder
152
- this loop invokes; it stays reachable directly when there is no bar to beat and no loop to run.
153
- - **Codifying the winner into a permanent identity** → `../design-dna/SKILL.md`.
154
- - **The words** → `../marketing/SKILL.md`. **The build** → `../nextjs/SKILL.md`.
155
- - **Motion craft** → `../motion-craft/SKILL.md`. **How the interface should be built** → `../ui-engineering/SKILL.md`.
156
- - **"Show me a few versions and I'll pick"** → `../variant-explorer/SKILL.md`. That is selection among
157
- variants; this is convergence against a bar.
158
- - **SDD gate.** This skill runs a method; it does not outrank the chain. If the request is a new
159
- feature or a non-trivial behaviour change in a real app, `../specify/SKILL.md` runs first, then
160
- `plan`, then the loop builds what was approved.
@@ -1,56 +0,0 @@
1
- # Eval harness — `design-loop` skill
2
-
3
- Agent-run eval, not a shell script. The cases in `cases.yaml` are fed to a Claude Code agent and
4
- graded by inspection. The "harness" is the procedure below plus a human (or a judge agent) checking
5
- outputs against the rubrics.
6
-
7
- ## What's under test
8
-
9
- 1. **Triggering** — does the loop fire when a goal comes with a real reference to beat, and stay
10
- quiet on the near-misses that belong to a sibling? The expensive confusions are `design` (visual
11
- system, no bar), `prototype` (variants picked by preference, no bar) and `design-dna` (the winner
12
- already exists).
13
- 2. **Capability** — when it fires, does it hold the three phases it is easiest to skip, and does its
14
- loop actually terminate?
15
-
16
- ## A. Triggering accuracy
17
-
18
- Run each `should_trigger` prompt in a session with the skill installed. It must activate. Run each
19
- `should_not_trigger` prompt: it must stay quiet and the named `route_to` sibling must be the one that
20
- answers.
21
-
22
- The two cases worth watching, because they are where the boundary really is:
23
-
24
- - *"Show me three versions and I'll pick"* → `prototype`. Selection is not convergence. The user is
25
- the judge and no bar exists.
26
- - *"Codify this into a reusable style"* → `design-dna`. Nothing left to converge; this is the
27
- downstream half.
28
-
29
- ## B. Capability
30
-
31
- The three scenarios are the three things this skill exists to do and the three it is cheapest to
32
- fake:
33
-
34
- 1. **The vague bar and the blind critic.** A bar of "Apple's website" must be pushed back on once,
35
- and a missing render capability must be declared as *which critic goes blind* — not absorbed
36
- silently. A critic that cannot see, still voting, is the failure this phase prevents.
37
- 2. **Termination.** The scenario hands it an oscillation: air, then density, then air again. The
38
- skill must halt the piece and surface the two competing demands. **This is the case that matters
39
- most**: everything else in the skill is judgement, but a loop that cannot detect it will never
40
- converge is a gate that cannot close, and the constitution's P2 forbids exactly that.
41
- 3. **Hand-off on winning.** Four more pages after a win must go through `design-dna`, not four more
42
- loops. Re-deriving a style you already won is how the set stops looking like a set.
43
-
44
- ## Grading
45
-
46
- A case passes when every `must_include` line is observably present in the agent's output or actions.
47
- Partial credit is not useful here: the mechanisms are the skill, and a run that keeps the prose but
48
- drops the halt has kept the part that costs nothing.
49
-
50
- ## Known limits of this eval
51
-
52
- - **Scores vs binaries** and **critics judging rendered output only** are properties of a real
53
- multi-round run. A single-turn eval can check that the skill *states* them; it cannot prove a
54
- four-round run honoured them. Verifying that needs a live run against a real reference.
55
- - The halt is checked from a described history, not a real one. It tests the rule, not the
56
- bookkeeping that feeds it.
@@ -1,60 +0,0 @@
1
- skill: design-loop
2
-
3
- should_trigger:
4
- - prompt: "Build me a landing page for our analytics product that's as good as linear.app — here's the URL."
5
- why: "Goal plus a named, openable reference to beat. This is the skill's core shape: a bar exists and the work must clear it."
6
- - prompt: "Our homepage looks generic. Loop it against stripe.com until it actually wins."
7
- why: "'Looks generic' plus a named bar plus explicit looping — three of the skill's stated triggers in one sentence."
8
- - prompt: "/design-loop"
9
- why: "Explicit invocation by name; the skill must run its own interview rather than asking what the user wants in free form."
10
- - prompt: "I want a pitch deck that holds up next to this one — attaching their PDF."
11
- why: "Non-obvious because the medium is not web. The method is medium-agnostic: a deck with an openable reference is the same loop, and the craft critic renders to PDF instead of screenshots."
12
- - prompt: "Run the critic loop on the pricing page and don't stop until it beats the reference."
13
- why: "Names the mechanism (critic loop) and the exit condition (beating the reference) rather than the outcome."
14
- - prompt: "Quiero que esta página le gane a la de vercel. Dale vueltas hasta que gane."
15
- why: "Non-English phrasing with no keyword overlap with the description; the trigger is the semantic shape — a reference to beat plus iteration until it wins."
16
- - prompt: "This animation feels cheap compared to the one on their site. Can you get it to that level?"
17
- why: "Non-obvious: reads like a motion request, but a named reference plus a quality gap is a bar to converge against. The loop owns convergence and hands the motion implementation to the craft siblings."
18
-
19
- should_not_trigger:
20
- - prompt: "This page came out great. Codify it into a reusable style so my next five pages match it."
21
- route_to: "design-dna"
22
- why: "The winner already exists; nothing left to converge. Capturing an identity is the downstream half of the pipe, not the loop."
23
- - prompt: "Pick a colour palette and type pairing for my product and give me the Tailwind tokens."
24
- route_to: "design"
25
- why: "Visual system work with no reference to beat and nothing to judge. `design` stays directly reachable exactly for this."
26
- - prompt: "Show me three versions of this button and I'll pick the one I like."
27
- route_to: "variant-explorer"
28
- why: "Selection among variants by human preference, not convergence against a measured bar. The user is the judge and there is no reference."
29
- - prompt: "Review the motion in this diff and tell me what's off."
30
- route_to: "motion-craft"
31
- why: "One diff, motion-specific, no reference and no build-then-judge rounds. The motion craft skill owns the complaint-to-cause mapping; reviewing is not looping."
32
- - prompt: "Write the hero headline and value prop for our developer-tool site."
33
- route_to: "marketing"
34
- why: "The words, not the bar. `voice` constrains copy in this pipe; it does not write it."
35
- - prompt: "Set up the Next.js App Router routing and server actions for these pages."
36
- route_to: "nextjs"
37
- why: "Pure build mechanics with no design judgement involved at all."
38
-
39
- capability:
40
- - scenario: "User asks: 'Make our homepage as good as Apple's website.' (Vague bar. The repo has a design system at design-system.md but no way to render output to screenshots.)"
41
- must_include:
42
- - "Pushes back ONCE for the specific page or file rather than accepting 'Apple's website' — names that a vague bar is the top failure mode because a critic with no concrete reference invents the comparison and approves everything on round one."
43
- - "Runs preflight BEFORE any work and reports it as one block: fetches the bar, checks render capability, checks input files."
44
- - "Explicitly names that the CRAFT critic goes blind because output cannot be rendered — does not quietly proceed with three critics when only two can see."
45
- - "Does not start building during the interview, preflight or teardown phases."
46
- - "Writes 5-7 mechanisms to bar.md as checkable measurements (ratios, coverage, percentages, absences) and shows them to the user before continuing; rejects adjectives like 'feels premium' as mechanisms."
47
- - "Uses binary verdicts, never numeric scores, and states that scores drift upward every round."
48
- - "Keeps critics on rendered output only, never the implementation, and gives each fresh context with no knowledge of how the builder worked."
49
- - scenario: "The loop is running on a hero section. Round 2's craft critic names 'not enough breathing room above the fold' as the biggest gap. Round 3's craft critic names 'the hero feels empty, needs more density' as the biggest gap. Round 4 would name 'not enough breathing room' again."
50
- must_include:
51
- - "HALTS that piece instead of starting another round — detects that the same biggest gap has been named twice for the same piece."
52
- - "Puts the two competing demands side by side (more air vs more density) and asks the user to decide, rather than picking one itself or averaging them."
53
- - "Does not present the halt as a failure of the loop; it is the declared exit for non-convergence."
54
- - "Shows round count and pieces rather than claiming a token cost, and states that no reliable self-reported token cost exists."
55
- - "Keeps the gap history that made the detection possible, as part of the live progress page."
56
- - scenario: "A piece has cleared all three critics and the user says 'perfect, now do the other four pages'."
57
- must_include:
58
- - "Hands the winner to design-dna to codify it into a permanent identity before building the remaining pieces, rather than re-running the loop from scratch four more times."
59
- - "Names why: winning once without writing down the mechanisms is how the look drifts back to generic by the fifth piece."
60
- - "Does not merge the won style with any other identity."
@@ -1,125 +0,0 @@
1
- ---
2
- name: motion-craft
3
- description: "Use when an interface moves and the movement has to feel right — durations and easing, what must never animate, fixing motion that reads sluggish, cheap or janky, and reduced-motion. Web and native. NOT the visual system (that is `design`), NOT the graded critique (that is `design-loop`)."
4
- tags: [motion, animation, interface, craft, frontend]
5
- recommends: [design]
6
- profiles: [full]
7
- origin: risco
8
- ---
9
-
10
- # Motion craft — movement that reads as intent
11
-
12
- Motion is not decoration laid over an interface. It is the interface **explaining what just
13
- happened**: what appeared, what it came from, what is still loading, what the user just did. When
14
- motion feels wrong the complaint is almost never "the curve is off" — it is "this feels cheap", or
15
- "slow", or "I don't know what happened". Those are the symptoms this skill exists to convert into
16
- decisions.
17
-
18
- ## The one rule
19
-
20
- **Every animation answers a question the user is already asking.** If you cannot name the question,
21
- delete the animation — it is costing time and attention and returning nothing.
22
-
23
- | The user is asking | The motion that answers it |
24
- | --- | --- |
25
- | "Where did this come from?" | It enters from its origin, not from nowhere |
26
- | "Is it working?" | Immediate feedback, under 100ms, even before the result |
27
- | "What did I just do?" | The changed thing moves; nothing else does |
28
- | "Where did it go?" | It exits toward where it can be found again |
29
- | nothing | **no animation** |
30
-
31
- That table is the whole method. Everything below is how to honour it without shipping something
32
- that janks.
33
-
34
- ## Duration: the only numbers worth memorising
35
-
36
- Movement is read as *slow* long before it is read as *long*. The usable range is narrower than most
37
- people expect, and the mistake is almost always **too slow**, not too fast.
38
-
39
- | What moves | Range | Why |
40
- | --- | --- | --- |
41
- | State on an element already on screen (hover, toggle, press) | 100–150ms | It must feel like a response, not an event |
42
- | Something entering or leaving in place (menu, tooltip, toast) | 150–250ms | Long enough to be seen, short enough not to be waited for |
43
- | A region rearranging (list reflow, panel) | 250–350ms | Bigger travel needs more time to stay legible |
44
- | A full view transition | 300–400ms | The ceiling. Past 400ms it is a wait, not a transition |
45
-
46
- Two rules that come from those numbers, not from taste:
47
-
48
- - **Exits are faster than entrances**, usually by about a third. The user has already decided; making
49
- them watch the decision leave is the single most common way an interface feels sluggish.
50
- - **Distance and duration scale together, sub-linearly.** Doubling the travel does not double the
51
- time. If a value grows past 400ms because the element crosses the screen, the layout is the
52
- problem, not the timing.
53
-
54
- ## Easing: three curves cover almost everything
55
-
56
- - **Entering, or responding to input** — start fast, settle slow (`ease-out` family). The user's
57
- attention is already there; arriving quickly and settling reads as responsive.
58
- - **Leaving** — start slow, accelerate away (`ease-in` family). It matches how the eye lets go.
59
- - **Moving between two on-screen positions** — accelerate and decelerate (`ease-in-out` family).
60
-
61
- **Linear is for one thing only: continuous, non-positional change** — a progress bar filling, a
62
- spinner rotating, a colour crossfade. Linear on anything that moves in space reads as mechanical,
63
- because nothing physical starts at full speed.
64
-
65
- Springs are worth reaching for when the motion should feel *physical* — dragging, dismissing,
66
- anything the user's finger or pointer is still in contact with. They are the wrong tool for
67
- appearing and disappearing, where a bounce reads as indecision.
68
-
69
- ## What must never animate
70
-
71
- This is where most jank comes from, and it is not a matter of degree.
72
-
73
- - **Never animate layout.** Width, height, top, left, margin, padding — each frame forces the engine
74
- to recompute geometry. Animate transform and opacity, which do not.
75
- - **Never `transition: all`.** It is the shortest path to animating layout by accident. List the
76
- properties.
77
- - **Never animate what the user is reading.** Text that moves while being read is illegible.
78
- - **Never block input on an animation.** The interface accepts the next action immediately, even
79
- mid-motion. An animation that must finish before the user may act has become a modal dialog.
80
- - **Never animate more than one thing per event.** If three things move when one changed, the user
81
- cannot tell which one mattered.
82
-
83
- ## Reduced motion is not an edge case
84
-
85
- A real share of people have vestibular conditions for which large movement is nauseating, and they
86
- have told their operating system so. Honouring it is not optional and it is not a fallback to
87
- nothing:
88
-
89
- - **Keep** the feedback: opacity changes, colour, instant state.
90
- - **Remove** the travel: no sliding across the screen, no scaling, no parallax, no auto-playing loops.
91
- - The interface must still say what happened — it just says it without moving.
92
-
93
- An implementation with no reduced-motion branch is unfinished, the same way an interface with no
94
- error state is unfinished.
95
-
96
- ## Diagnosing motion that feels wrong
97
-
98
- The complaint names the symptom; this maps it to a cause.
99
-
100
- | Complaint | Usually | Fix |
101
- | --- | --- | --- |
102
- | "Sluggish" | Duration too long, or the exit matches the entrance | Cut to the range above; make exits faster |
103
- | "Cheap" / "amateur" | Linear easing on positional movement, or bounce on entrances | Match curve to direction |
104
- | "Janky" / "stutters" | Animating layout properties | Move to transform and opacity |
105
- | "Distracting" | More than one thing moving per event | Animate only what changed |
106
- | "I don't know what happened" | Motion with no origin or destination | Move it from where it came from |
107
- | "Nice, but I'd turn it off" | No reduced-motion branch, or motion that repeats | Honour the setting; never loop what is not loading |
108
-
109
- ## Anti-patterns → STOP
110
-
111
- | If you're about to… | Reality / Fix |
112
- | --- | --- |
113
- | Add motion because the screen feels static | Static is not a defect. Motion with no question to answer is noise with a frame cost. |
114
- | Copy a duration from a design you liked | You copied the number without its distance and its context. Take the range, verify against the feel. |
115
- | Animate a list so every item cascades in | Stagger past ~4 items becomes a queue the user waits through. Cap it, or drop it. |
116
- | Use a spring for a menu appearing | A bounce on an entrance reads as indecision. Springs are for what the pointer is still touching. |
117
- | Ship motion without checking reduced-motion | It is not an edge case. Unchecked means unfinished. |
118
- | Reach here for the visual system | Type, colour, spacing and composition are `../design/SKILL.md`. This skill only moves what that one placed. |
119
-
120
- ## See Also
121
-
122
- - `../design/SKILL.md` — the visual system this motion serves.
123
- - `../design-loop/SKILL.md` — the graded critique that judges a finished screen, motion included.
124
- - `../design-dna/SKILL.md` — turning a look, motion rules included, into a reusable identity.
125
- - `../accessibility/SKILL.md` — the wider ground reduced-motion sits in.
@@ -1,38 +0,0 @@
1
- skill: motion-craft
2
-
3
- should_trigger:
4
- - prompt: "The menu animation feels sluggish, can you make it feel snappier?"
5
- why: "The canonical case: a complaint about feel, which this skill converts into a duration and an easing decision."
6
- - prompt: "What duration and easing should this dropdown use?"
7
- why: "Directly the numbers this skill owns, for an element entering in place."
8
- - prompt: "My list animation stutters when it reflows."
9
- why: "Jank is the symptom of animating layout properties, which is the one hard rule here."
10
- - prompt: "Añade una animación al abrir el panel, pero que no quede cutre."
11
- why: "Same ask in Spanish; the trigger is the intent, not the language."
12
- - prompt: "Does this respect prefers-reduced-motion? I don't think we handled it."
13
- why: "Reduced-motion is treated here as part of finishing the work, not as an edge case."
14
- - prompt: "Everything on the page moves at once when I click one button."
15
- why: "More than one thing moving per event is a named diagnosis in this skill."
16
-
17
- should_not_trigger:
18
- - prompt: "Design a landing page for my analytics SaaS — hero, pricing, the works."
19
- route_to: "design"
20
- why: "Type, colour, spacing and composition are the visual system, which this skill only moves once it exists."
21
- - prompt: "Review this checkout screen and tell me how good it actually is, with a grade."
22
- route_to: "design-loop"
23
- why: "Graded critique of a finished screen is the loop's job; this skill builds motion, it does not judge screens."
24
- - prompt: "This design came out great — turn it into a style I can reuse everywhere."
25
- route_to: "design-dna"
26
- why: "Codifying a look into a permanent identity is capture, not motion craft."
27
- - prompt: "Make the site keyboard navigable and fix the contrast failures."
28
- route_to: "accessibility"
29
- why: "Accessibility beyond reduced-motion is its own ground; only the motion half lives here."
30
- - prompt: "Our React app re-renders too much and the profiler shows wasted renders."
31
- route_to: "react"
32
- why: "A rendering performance problem is framework work, even when the symptom looks like stutter."
33
-
34
- capability:
35
- - prompt: "This modal slides in over 600ms with a linear curve and it feels cheap. Fix it and say why."
36
- why: "Exercises the two most common defects at once — too slow, and linear on positional movement — and demands the reasoning, not just new numbers."
37
- - prompt: "We animate width and height on the sidebar and it janks on mobile. What do we do instead?"
38
- why: "The layout-vs-compositor rule is the load-bearing piece of technical content here."