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つ見つかった。

同じ問題を解く2本のSkillが違う値を指定している。押下時の縮小は0.97と0.96で片方は常に0.96と近似を禁じる、stagger間隔は30から80msと約100msで100msは相手の許容範囲の外側、ease-out曲線は別のcubic-bezierで進捗が最大24.2ポイントずれる。発火時に読み込まれるバイト数はemil-design-engが27123で全体の100パーセント、better-uiが7152で全体の20パーセント
両スキルを `npx skills add` で実際に導入して計測。数値はいずれも 2026-10-06 の実測

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 to better-accessibility.

自分がやらないことを名指しで他のスキルへ委譲する構えで、11本のスキルが互いの守備範囲を宣言し合う設計になっている。

同じ分量を正反対の形で配っている。emil-design-engは1ファイルで674行27123バイトを一度に読みコード例26個を本文に直書きし哲学から判断基準から実装の順に通し読みする。better-uiは索引と6ファイルで本体は112行7152バイトだけ、本文にコード例0個で参照側に40個、担当外は別スキルへ明示的に委譲する
発火時に読むのは emil が全体の100%、better-ui は20%

この差は読み込み量にそのまま出る。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 not cubic-bezier(0.4, 0, 0.2, 1), and 0.96 is not 0.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. Always 0.96; anything below 0.95 feels 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 標準 */
1000pxと1000msを実際に走らせた結果。100ms時点でemilが454.7px・better-uiが222.1px・Material標準が36.7px、300ms時点でemilが861.0px・better-uiが710.9px・Material標準が412.8px、500ms時点でemilが974.3px・better-uiが897.2px・Material標準が814.5px、900ms時点でemilが1000.0px・better-uiが998.5pxで終端はどれも揃う
Chromium 141 で transition を実走させた実測。計算値と順序・桁が一致した
経過 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 の差には触れていない。自分の値を守ることと、他人が別の値を守っていることは別問題として残る。

graph TD A["UIを整えて、と頼む"] --> B{"どのSkillが発火するか"} B -->|"emil-design-eng"| C["674行が全部入る
哲学から実装まで通し"] 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は子も拡大し親にscale(2)で子が50x20から100x40になる、@starting-styleはCSSStartingStyleRuleとして有効、transition:allは3本走り個別指定は1本だけ、0.96が正しいは感覚の主張で機械では決まらない
技術的な主張は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 磨き込みをどう選ぶか

導入して数えた結果。両方入れたSkill数は25、食い違う具体値は3、発火時の読込量の倍率は3.8、1本だけ入れる手段は0
数値はいずれも 2026-10-06 の実測

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 の掲載ページはこの環境から到達できないため、インストール数などページ側の指標は未取得。エージェントに両スキルを同時に読ませたときの実際の選択挙動も未検証。