Claude Skills UI 磨き込み、つまりエージェントにUIの仕上げを任せる使い方が定着してきた。「このコンポーネントを整えて」と言えば、角丸の入れ子からアニメーションの easing まで面倒を見てくれる——はずだ。
問題は、その手のスキルが複数あることにある。どれも「この値を使え」と言い切る形で書かれていて、しかも言い切る値が同じとは限らない。
今回は skills.sh に並んでいる2本を突き合わせた。emilkowalski/skills の emil-design-eng(sonner・vaul の作者、元Vercel・Linear)と、jakubkrehel/skills の better-ui(interfaces.dev)。どちらも UI の磨き込みを扱い、どちらもMITで、star は43.7kと7.5k。並べて読むと、同じ対象に別の数字を指定している箇所が3つ見つかった。
30秒でわかる
・押下時の縮小:emil は scale(0.97)(許容 0.95〜0.98)、better-ui は「常に 0.96、0.95未満は誇張」
・stagger の間隔:emil は 30〜80ms で「長いと遅く感じる」、better-ui は約100ms——相手の許容範囲の外側
・ease-out の曲線:別の cubic-bezier。Chromium で実走させると進捗が最大24.2ポイントずれる
・配り方が正反対。emil は1ファイル674行を全部読ませ、better-ui は112行の索引+6ファイルで必要分だけ読ませる(発火時の読み込み量は3.8倍の差)
・検証できる技術的主張3件はブラウザで実行して全部そのとおりだった。感覚の主張は切り分けて未検証とした
・1本だけ入れることはできない。14本と11本、まとめて入る
Claude Code の全体像はClaude Code|2026年版・インストールからCLAUDE.md・Hooks・本番運用までの実装手引きにまとめてある。本記事はその枝として、同じ役割のスキルを複数入れたときに何が起きるかを扱う。
Claude Skills UI 磨き込みの2本は何が違うのか
まず正体の確認から。両方とも skills.sh に掲載されているが、skills.sh 自体はこの環境の egress プロキシに遮断されているため、本記事は配布元の GitHub リポジトリと、実際の導入結果から計測している。掲載ページ上のインストール数やスターは取得できていない。
| emil-design-eng | better-ui | |
|---|---|---|
| 配布元 | emilkowalski/skills |
jakubkrehel/skills |
| 作者 | Emil Kowalski(sonner・vaul) | Jakub Krehel(interfaces.dev) |
| リポジトリの star | 43.7k | 7.5k |
| 同梱スキル数 | 14本 | 11本 |
| ライセンス | MIT | MIT |
| 構成 | SKILL.md 1ファイル | SKILL.md + 参照6ファイル |
| 行数 / バイト数 | 674行 / 27,123B | 112行 / 7,152B(全体 986行 / 35,629B) |
| 本文中のコード例 | 26個 | 0個(参照側に40個) |
| 当該スキルのコミット数 | 5 | 39 |
| 最終更新 | 2026-09-15 | 2026-08-29 |
| プラグイン配布 | なし | interfaces v1.6.3(marketplace.json) |
同じ分量の知識を、正反対の形で配っているのが見てとれる。
emil-design-eng は単一ファイルで、哲学から入る。冒頭は「センスは訓練で身につく(Taste is trained, not innate)」「見えない細部は積み重なる」「美しさはレバレッジ」の3節で、Paul Graham の「かろうじて聞こえる千の声が、すべて調和して歌う」が引かれる。そのうえで判断の枠組み(このUIはそもそもアニメーションすべきか → 目的は何か → どの easing か → どのくらい速く)に降りていき、最後にCSSの具体論まで続く。通し読みを前提にした教科書だ。
better-ui は索引だ。112行のSKILL.mdにはコードブロックが1個も無い。各節は2〜4行で原則だけを書き、実装は animations.md enter-exit.md icon-transitions.md icons.md performance.md surfaces.md の6ファイルに振る。さらに冒頭で担当範囲を切っている。
Text wrapping, font rendering, tabular numbers and text spacing belong to
better-typography. Hit areas, focus, keyboard support, ARIA and reduced motion belong tobetter-accessibility.
自分がやらないことを名指しで他のスキルへ委譲する構えで、11本のスキルが互いの守備範囲を宣言し合う設計になっている。
この差は読み込み量にそのまま出る。emil-design-eng は発火すると674行・27,123バイトが全部入る。better-ui は7,152バイトだけ入り、残りはモデルが必要と判断したときに開く。 全体では better-ui のほうが31%大きいのに、最初に読む量は3.8分の1になる。
better-ui の書き出しは、その設計を自分で宣言している。
Every duration, curve, scale and blur below is a specific value, not a range to approximate.
cubic-bezier(0.2, 0, 0, 1)is notcubic-bezier(0.4, 0, 0.2, 1), and0.96is not0.95. Use what is written.
近似するな、書いてある値を使え。 ここまで言い切るなら、その値を確かめる価値がある。
指定値が食い違う3箇所
突き合わせた結果、同じ対象に別の具体値を指定している箇所が3つ見つかった。いずれも「範囲が重なっている」のではなく、片方の推奨値が他方の許容範囲の外にある関係だ。
① 押下時の縮小
emil はこう書く。
Add
transform: scale(0.97)on:active. (中略) The scale should be subtle (0.95-0.98).
better-ui はこう書く。
A
scale(0.96)on click gives a button tactile feedback. Always0.96; anything below0.95feels exaggerated.
値そのものは 0.97 と 0.96 で近い。問題は書き方だ。emil は 0.95〜0.98 という幅を許し、better-ui は「常に 0.96」と言い切ったうえで冒頭で「0.96 は 0.95 ではない」と近似を禁じている。両方を読んだエージェントは、「0.97でよい」と「常に0.96」を同時に渡されることになる。
② stagger の間隔
emil は CSS の animation-delay を 0 / 50 / 100 / 150ms と刻む例を示したうえで、こう締める。
Keep stagger delays short (30-80ms between items). Long delays make the interface feel slow.
better-ui はこうだ。
Stagger with ~100ms delay between groups
100ms は emil の許容範囲 30〜80ms の外側にあり、emil はその領域を「インターフェースが遅く感じる」と明示的に否定している。ここは数字の好みではなく、評価が反転している。
ただし公平のために書くと、適用範囲が違う。better-ui は「頻度の低い段階的な登場(ページヒーローの初回読み込み、成功状態、空状態)に使え。行のホバーやキー入力や繰り返すタブ切り替えには絶対に使うな」と条件を付けている。emil 側にはその限定が無い。100ms が許されるのは「めったに起きない登場」に限る、という読み方はできる。
③ ease-out の曲線
ここが一番わかりやすい。両者とも「UIのための easing」を CSS 変数として定義している。
・emil:--ease-out: cubic-bezier(0.23, 1, 0.32, 1)(コメントは “Strong ease-out for UI interactions”)
・better-ui:cubic-bezier(0.2, 0, 0, 1)(アイコンのクロスフェードなどに指定)
数字の並びが違うだけに見えるが、曲線としては別物だ。三次ベジェとして進捗を計算すると、こうなる。
| 経過割合 | emil (0.23,1,0.32,1) | better-ui (0.2,0,0,1) | Material 標準 (0.4,0,0.2,1) |
|---|---|---|---|
| 10% | 0.398 | 0.156 | 0.026 |
| 20% | 0.682 | 0.500 | 0.134 |
| 30% | 0.843 | 0.688 | 0.367 |
| 50% | 0.966 | 0.878 | 0.776 |
| 70% | 0.995 | 0.963 | 0.938 |
| 90% | 1.000 | 0.996 | 0.994 |
最大の差は 0.242。アニメーションの1割が過ぎた時点で、emil の曲線は約4割まで進み、better-ui の曲線は1.5割しか進んでいない。
計算だけでは足りないので、実際のブラウザでも走らせた。Chromium 141 で 1000px を 1000ms かけて動かし、left の算出値を時間ごとに読む。実際に流し込んだCSSはこれだ。
.box { position: absolute; transition-property: left; transition-duration: 1000ms }
#emil { transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1) } /* emil */
#bui { transition-timing-function: cubic-bezier(0.2, 0, 0, 1) } /* better-ui */
#mat { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1) } /* Material 標準 */
| 経過 | emil | better-ui | Material 標準 |
|---|---|---|---|
| 100ms | 454.7px | 222.1px | 36.7px |
| 300ms | 861.0px | 710.9px | 412.8px |
| 500ms | 974.3px | 897.2px | 814.5px |
| 900ms | 1000.0px | 998.5px | 997.6px |
計算値よりやや進んでいるのは、サンプリングが厳密に100msちょうどではないためで、順序と桁は計算と一致した。終端はどれも揃うので、アニメーションが終わった画面だけ見ても違いに気づけない。差が出るのは前半だ。
ついでに better-ui の主張そのものも検算できた。「cubic-bezier(0.2, 0, 0, 1) は cubic-bezier(0.4, 0, 0.2, 1) ではない」——この2曲線の最大差は 0.366 で、主張は正しい。ただしそう言い切る当の better-ui も、emil の曲線との 0.242 の差には触れていない。自分の値を守ることと、他人が別の値を守っていることは別問題として残る。
哲学から実装まで通し"] B -->|"better-ui"| D["112行の索引だけ入る"] D --> E["必要な参照ファイルを開く
animations.md など6本"] C --> F{"同じ対象に別の値"} E --> F F --> G["押下時の縮小
0.97 と 常に0.96"] F --> H["stagger間隔
30-80ms と 約100ms"] F --> I["ease-out曲線
進捗が最大24.2pt差"] G --> J["どちらが採られるかは
本記事では未検証"] H --> J I --> J
ブラウザで決着がつく主張とつかない主張
食い違いの話とは別に、そもそも書いてあることは正しいのかも確かめた。両スキルには機械で検証できる技術的主張が混ざっている。Chromium 141 で実行した結果は3件とも主張どおりだった。
① scale() は子要素も拡大する(emil)
親に transform: scale(2) を当て、子の getBoundingClientRect() を測った。50×20 が 100×40、倍率ちょうど2.00。だから emil は「アイコンだけ拡大したいなら親ではなくアイコン自身に当てろ」と続ける。当たり前に見えるが、ボタン全体を :active で縮めるとラベルも一緒に縮む、という形で実際に効いてくる。
② @starting-style が使える(emil)
新しいCSS機能なので、実際に解釈されるかを確認した。@starting-style{ .x{opacity:0} } を挿すと CSSStartingStyleRule として解釈される。display:none から現れる要素に enter アニメーションを付ける用途で、JSなしで書ける。
③ transition: all ではなく変化するプロパティを名指しする(better-ui)
width と opacity と color を同時に変えたとき、transition: all 500ms では getAnimations() が 3本を返し、transition-property: opacity では 1本だけだった。60ms 時点の値を見ると、all 側は width が 27.98px、color が rgb(24, 0, 0) と途中なのに対し、個別指定側は 200px と rgb(255, 0, 0) へ即座に到達している。意図していないプロパティまで遅れて追従するのが目に見える。
一方で、決着がつかないものもある。「0.96 が正しく 0.95 は誇張に見える」「センスは訓練で身につく」——これらはブラウザで測れない。感覚の主張を感覚の主張として扱うのは大事で、本記事では未検証として切り分けた。両スキルの価値の大半はこちら側にあるとも言える。
スキル同士を clone して突き合わせる方法は、当サイトでアンチスロップ・スキル10本を全部cloneして実測比較|AIっぽい文章を消すSKILL.mdの中身でも使った。あのときは10本が「AIっぽさ」の定義でばらついていた。今回の2本は定義が揃っているぶん、値のレベルで衝突するという別の形になっている。
入れてみて分かった実務上の注意
実際に npx skills add で導入して気づいた点を書く。
1本だけ入れることはできない。 これが最初の落とし穴だった。
# 単体を指定してみる → 失敗する
npx skills@latest add emilkowalski/skills/emil-design-eng
# No skills found
# No valid skills found. Skills require a SKILL.md with name and description.
リポジトリ単位で入れるのが正しい。実際に両方を同じプロジェクトへ入れるとこうなる。
npx skills@latest add emilkowalski/skills # 14本
npx skills@latest add jakubkrehel/skills # 11本
ls .agents/skills | wc -l # → 25
実測では emilkowalski/skills が14本、jakubkrehel/skills が11本をまとめて導入した。emil-design-eng だけが欲しくても、アニメーション関連5本も Swift も Expo も一緒に来る。
両方入れても衝突はしない。 25本が名前の重複なく同居した(.agents/skills/ 配下に実体、.claude/skills/ にシンボリックリンク)。合計 844KB。導入ツールは skills-lock.json にスキルごとの computedHash を記録していて、中身の差し替えを後から検出できるようになっている。
導入の最後にこう出るのも引用しておく。
Done! Review skills before use; they run with full agent permissions.
スキルはエージェントの全権限で動く。中身を読んでから使え、というのは正しい警告だ。
常駐コストは説明文の長さで決まる。 スキルは本文が読まれなくても、frontmatter の name と description が毎ターン文脈に乗る。実測はこうだった。
| 本数 | frontmatter 合計 | 1本あたり平均 | 自動起動オフ | |
|---|---|---|---|---|
| emilkowalski/skills | 14 | 6,192B(約1,548tok) | 442B | 3本 |
| jakubkrehel/skills | 11 | 1,755B(約439tok) | 160B | 4本 |
| 両方 | 25 | 7,947B(約1,987tok) | 318B | 7本 |
※ トークン数は heuristic-jp-v1(CJK 1文字=1トークン / ASCII 4文字=1トークン)による近似。tiktoken の cl100k_base は BPE辞書の取得先が遮断されていて使えなかった
1本あたりの説明文が約2.8倍違う。emil 側は説明文が長く、そのぶん「いつ発火すべきか」をモデルが判断しやすい代わりに常駐が重い。jakub 側は短く、常駐は軽い。25本入れると毎ターン約2,000トークンが乗る計算で、これは無視できる量ではないが、破滅的でもない。
なお emilkowalski/skills 単体の内訳と常駐コストはemilkowalski/skills徹底解説|5本から13本に増えたセンスのSkill集を常駐コストまで実測で先に測っている。あのとき13本だったものが、break-ui の追加で14本になった。
更新の活きかたが違う。 emil-design-eng は 2026-03-16 の初出からコミット5回、直近の変更(2026-09-15)は講座への言及を消しただけで、中身は 2026-07-21 以降動いていない。対して better-ui はコミット39回で、しかもリポジトリ全体の最新コミット(2026-08-29)が better-ui の説明文更新だった。片方は完成したものとして置かれ、片方はまだ練られている。
配布の形も違う。jakubkrehel 側は .claude-plugin/marketplace.json と plugin.json(interfaces v1.6.3)を持つ Claude Code プラグインとしても配られ、opencode.json で OpenCode に、agents/openai.yaml で別系統にも対応している。emilkowalski 側にプラグインのマニフェストは無い。スキル配布の形式差はBuilderIO/skillsとは|24本の実体と/visual-editを実際に入れて配布版との差を実測でも扱ったが、同じ npx skills add で入るものが、裏では別の流通経路も持っているのは覚えておくといい。
Claude Skills UI 磨き込みをどう選ぶか
emil-design-eng が向く場面
・なぜそうするのかを一緒に学びたい場合。判断の枠組み(そもそもアニメーションすべきか→目的→easing→速さ)が言語化されていて、人間が読んでも得るものがある
・アニメーション寄りの作業。同梱の14本がアニメーション中心で、review-animations や improve-animations と組み合わせが効く
・読み込み量を気にしない場面。27,123バイトを毎回入れても困らない長さの作業
better-ui が向く場面
・値だけ欲しい場合。索引が112行しかなく、必要な参照だけ開くので無駄が少ない
・タイポグラフィやアクセシビリティも含めて面倒を見てほしい場合。11本が守備範囲を宣言し合っていて、担当外は明示的に別スキルへ渡される
・レビュー結果を機械的に扱いたい場合。深刻度(HIGH / MEDIUM / LOW)と Block / Approve の判定、path/to/file:line 形式の表が規定されている
両方入れる場合
衝突は起きないが、3箇所で別の値を渡されることは理解しておく。実務上の落としどころは、片方を「規範」としてプロジェクトの CLAUDE.md に明記し、もう片方は参考に留めることだろう。たとえば「押下時は 0.96、stagger は 80ms、easing は cubic-bezier(0.2,0,0,1)」のように自分の側で一本化して書いておけば、スキルが何を言っても最終的な値は揃う。
そして一番大事なことを最後に。この3箇所の食い違いは、どちらかが間違っているという話ではない。 終端はどちらも同じ場所に着く。0.96 と 0.97 の差を見分けられる人はほとんどいない。両者とも自分の経験から一貫した値を選んでいて、それぞれの中では筋が通っている。
問題は、エージェントに両方を渡すと一貫性が失われることだ。人間なら「今回はこっちの流儀で」と決められるが、スキルは文脈ごとに片方だけ発火する。同じプロジェクトの中でボタンによって 0.96 と 0.97 が混ざり、画面によって stagger が 50ms と 100ms に分かれる——磨き込みのスキルを入れたのに、磨き込みの一貫性が落ちるという逆説が起こりうる。
だから選ぶなら片方だ。どちらでもいい。決めて、書いておく。それが実測から出た結論になる。
参照ソース
・emilkowalski/skills(GitHub) — emil-design-eng の配布元。MIT・star 43.7k
・skills/emil-design-eng/SKILL.md — 674行の本体。引用はすべてここから
・jakubkrehel/skills(GitHub) — better-ui の配布元。MIT・star 7.5k
・skills/better-ui/SKILL.md — 112行の索引と6本の参照ファイル
計測値は data/measurements/runs/2026-10-06-claude-skills-ui-polish.json に記録した。環境は Ubuntu 24.04 / x86_64 / node v22.22.2 / Chromium 141.0.0.0。skills.sh の掲載ページはこの環境から到達できないため、インストール数などページ側の指標は未取得。エージェントに両スキルを同時に読ませたときの実際の選択挙動も未検証。