Silverpoint のデザインチェック(lint、インスペクタの デザインチェック、silverpoint score、エージェントのセルフチェック)は、10 個の組み込みルールを実行します。raw-color、off-grid、text-style、tiny-text、contrast、clipped、empty-mask、brand-drift、variable-alias、variable-expression です。カスタムリントルール を使うと、「ボタンの角丸は 8 か 12」「どの画面も幅 390」「アイコン名はケバブケース」といったチーム独自の決まりを同じチェックに加えられます。
contrast(error、修正なし)は、背後にあるもの、つまりそれを囲むフレームまたは長方形の最後の不透明な単色の塗りに対して見えにくいものを報告します。基準は、テキストで 4.5:1、24 pt 以上(太字なら 18.5 pt 以上)のテキストで 3:1、そして(WCAG 1.4.11、非テキストのコントラスト)アイコン、48 × 48 pt までのシェイプ、コントロールの枠線で 3:1 です。アイコンはその色で、シェイプはその塗りで(塗りがなければ線で。ブーリアンは 1 つのシェイプです)確認し、枠線とはフレームまたは長方形の 1 pt 以上の線のことです。枠線は、コントロールの塗りが背後に対して 3:1 に届かないときだけ確認されます。そのため、塗りのない入力欄やページと同じ色のカードは確認され、塗りのあるボタンは確認されません。区切り線は装飾なので、線は確認されません。コネクタとマスクも同様です。不透明度またはアルファが 0.1 以下のレイヤー、または decor という名前か、それで始まる名前(decor dot、Decorative。大文字小文字は問いません)のレイヤーは、中身も含めて装飾として扱われます。その中のアイコン、シェイプ、枠線は確認されませんが、テキストは確認されます。Silverpoint には無効状態がないので無効状態の例外はなく、キャンバスにはフォーカス状態もありません。フォーカスリングは線なので、focused バリアントのリングは枠線として確認されます。ノードの背後に単色のものが何もなければ、何も確認されません。グラデーションや画像の背景は確認されません。このルールはテーマのすべてのモードを、軸ごとに 1 つずつ(組み合わせの総当たりはせずに)確認します。キャンバスに加えて、各軸のほかのモードのうち、カラー変数に値があるものをそれぞれ 1 回描画し(ほかの軸はキャンバスの表示のまま)、そこでだけ見つかった問題は 1 回報告され、メッセージの末尾に (theme <axis>: <mode>) が付きます。たとえば contrast 1.4:1 of #334155 on #1E293B (theme mode: dark) です。詳細には対象の部分が示されます。テキストは contrast …、ほかは icon contrast …、shape contrast …、border contrast 1.2:1 of #E5E7EB on #FFFFFF です。
brand-drift は参考情報(info、修正なし)です。背景が Claude 自身のブランドのクリーム色のニュートラル(#FAF9F5、#F0EEE6、#E8E6DC)で、クレイやテラコッタの塗り(#D97757、#C6613F、#C15F3C)を含むトップレベルのフレームを、フレームごとに 1 回報告します。どちらもチャンネルごとに数値が少し違っても該当します。デザインシステムをリンクしているドキュメント(imports または packages)では報告しません。ユーザーがそのパレットを求めたり提供したりしたときは、エージェントが set_builtin_lint_rule {rule: "brand-drift", enabled: false} でオフにします。
variable-alias(warning、修正なし)は、デフォルトのテーマ、またはテーマの軸のいずれかの組み合わせで解決できない変数エイリアス("$other")を、ドキュメントのルートの変数ごとに 1 回報告します。対象は、循環(alias cycle a → b → a)、存在しない参照先(alias x → later (no such variable))、別の型への参照です。set_variables はすでに循環と型の不一致を拒否するので、実際に見つかるのは、まだ定義(またはリンク)されていない変数へのエイリアスと、このチェックより前に保存されたドキュメントです。
variable-expression(warning、修正なし)は、値の中に式("=$space * 2"。スキーマの「変数とテーマ」を参照)を持つ数値変数について、同じことを変数ごとに 1 回行います。対象は、パースできない式(expression error at column 8: …)、エイリアスと式をたどる循環(alias cycle a → b → a)、存在しない参照先(alias m → later (no such variable))、数値でない変数への参照、ゼロ除算(division by zero)、数値にならないほど大きな結果(result is not a finite number)で、デフォルトのテーマでも、どのテーマの組み合わせでも確認します。単純なエイリアスのチェーンがその先の式の中で切れている場合は variable-alias の担当のままなので、壊れた変数 1 つにつき問題は 1 つです。set_variables はパースできない式、循環、型の不一致を拒否します。それ以外は受け付けられ、ここで報告されます。
ルールは 宣言的な JSON です。ルールに書かれた内容がコードとして実行されることはありません。Silverpoint がそれを読み、検証し、自分のチェックを実行します。Silverpoint をビルドし直さずに、ルールを追加、変更、削除できます。
ルールは、ノードを選び(match)、それぞれについて成り立つべきことを示し(expect)、必要なら違反したノードの直し方を示します(fix)。ルールが出す問題にはどれも、ルールの ID、重大度、ルールの出どころが付くので、自分のルールと組み込みのルールを見分けられます。
ルールは 3 つのレイヤーから来ます(下から順に)。上のレイヤーは、同じルール ID を持つ下のレイヤーのルールを置き換えます。
| レイヤー | 場所 | 問題に表示される出どころ |
|---|---|---|
| user | ~/Library/Application Support/Silverpoint/Lint(または $SILVERPOINT_LINT_DIR のフォルダ)の *.json ファイル | user |
| library | ドキュメントがリンクしている各デザインシステムの lintRules | library:<alias> |
| document | ドキュメント自体に保存された lintRules | document |
つまり document > library > user です。チームのルールはファイル(document)やデザインシステム(library。そのライブラリをリンクしたドキュメントはライブラリのルールを受け取ります)と一緒に持ち運ばれ、個人のルールはフォルダに置かれてすべてのドキュメントに適用されます。
*.json ファイルはルールファイルで、形式は {"rules": [rule, ...]} です。ファイルは名前のバイト順に読まれます。lintRules リストとして、オフにした組み込みルールを disabledLintRules(ルール名のリスト)として持ちます。どちらも中身があるときだけ保存されるので、カスタムルールのないドキュメントは以前とバイト単位で同じです。docs/design-system-packages.md)は、同じ形式のルールファイルを lint/*.json に入れて配布できます。ドキュメントがパッケージをリンクしている間、それらは library レイヤーに入り、出どころは library:<alias>(ドキュメントがパッケージをリンクしているエイリアス)で、パッケージ内のライブラリの lintRules のあとに来ます。パッケージのリンクを外すとなくなります。検証に通らないルールファイルは、ファイル library:<alias>/<name>.json として報告されます。b.json: dup-id: skipped: a.json already defines the rule "dup-id" (the first file in byte order wins)silverpoint lint-rules は、優先されたルールの横に (overrides user) または (overrides library) を表示します。ドキュメントでは組み込みルールをオフにできます。エージェントに頼む(「このドキュメントは独自のスペーシングスケールを使うので、off-grid をオフにして」)か、set_builtin_lint_rule ツールを使います。ルール名はドキュメントの disabledLintRules に保存されるので、ファイルと一緒に持ち運ばれます。オフにした組み込みルールは実行されず、rules: ["off-grid"] を指定しても戻りません。カスタムルールはこの方法ではオフにできないので、置き換えるか削除してください。
{
"id": "button-radius",
"severity": "warning",
"message": "{name} radius {value} should be one of {expected}",
"match": { "type": "frame", "name": "Button*" },
"expect": [ { "check": "in", "property": "cornerRadius", "values": [8, 12] } ],
"fix": { "set": { "cornerRadius": 8 } }
}
| キー | |
|---|---|
id | 必須。ケバブケース(button-radius)。組み込みルールの名前は使えません。 |
severity | error、warning、info のいずれか。デフォルトは warning。 |
message | 問題の文面のテンプレート。メッセージを参照。省略可。 |
match | ルールが見るノード。省略可。省略するとすべてのノード。 |
expect | 必須。空でないチェックのリスト。チェックに通らないノードは問題を出します。 |
fix | 省略可。通らないノードの直し方。 |
description | 人向けのメモ。省略可。無視されます。 |
ほかのキーは問題になります(そうしないと、"mesage" のような打ち間違いが黙って何もしなくなるためです)。
match指定した条件はすべて成り立つ必要があります(AND で結ばれます)。どれも省略できます。
| キー | 選ぶもの |
|---|---|
type | ノードの種類("frame")またはそのリスト(["text", "icon"]):frame group rectangle ellipse polygon line path text icon ref boolean。 |
name | ノード名に対する glob。* は任意の文字列、? は 1 文字です。名前全体が一致する必要があり、大文字小文字を区別します。"Button*"。 |
topLevel | true:画面、つまり再利用可能なコンポーネントではない、ドキュメントの直接の子。false:それ以外のノード。 |
inside | {"kind": "component" | "frame" | "screen", "name": glob}。その種類の祖先を持つノード。必要なら名前も一致するもの。親だけでなく、どの祖先でも数えます。screen はコンポーネントではないトップレベルのフレームです。 |
has | プロパティ名またはそのリスト。ノードにそのすべてが設定されている(["fill"])。 |
lacks | プロパティ名またはそのリスト。ノードにそのどれも設定されていない。 |
expect各項目には check があります。ルールには複数のチェックを並べられ、通らなかったチェックはそれぞれ別の問題を出します。
ノードのプロパティを読むチェックは property を取ります。ドキュメントの JSON にあるノードのキー(width、height、cornerRadius、gap、padding、fontSize、opacity、layout、justifyContent など。strokeWidth は線の太さです)か、その リスト で、リストならそれぞれを個別に確認します。
check | フィールド | 通る条件 |
|---|---|---|
equals | property、value | プロパティが value と等しい。設定されていないプロパティは通りません。 |
in | property、values | プロパティが values のどれかと等しい。設定されていなければ通りません。 |
multipleOf | property、value | 数値が value の倍数(value > 0)。 |
range | property、min と max の一方または両方 | 数値が範囲内(両端を含む)。 |
colorVariable | property(fill または stroke、デフォルトは fill)、prefix または group(省略可) | プロパティのすべてのペイントがカラー変数($brand/primary)で、prefix("brand/")があればその名前がそれで始まる。group: "brand" は prefix: "brand/" と同じです。#FF0000 のような生の色は通らず、プレフィックス外の変数も通りません。グラデーションの分岐点も確認します。塗りや線がなければ通ります。 |
textStyle | oneOf(省略可) | テキストノードがテキストスタイルを使っていて、oneOf があればそのどれか。テキスト以外のノードは通ります。 |
name | regex | ノード名が正規表現に一致する(名前のどこかで一致すればよく、^ と $ で固定できます)。名前のないノードの名前は空文字列です。 |
children | min と max の一方または両方 | 子の数が範囲内。 |
値の読み方:
multipleOf と range は数値を確認します。設定されていないプロパティ、fit_content や fill_container のプロパティ、数値変数ではない変数のプロパティは、測るものがないので対象外です。数値変数("$space-md")は、デフォルトのテーマでの値として読みます。padding と cornerRadius には 4 辺があります。 multipleOf、range、in の集合では、4 辺すべてが満たすときだけ通ります。padding: [8, 8, 8, 12] は最後の辺のために 8 の倍数ではありません。equals も 4 辺を比べ、16 は [16, 16, 16, 16] の意味です。辺の値が異なるときは、メッセージに各辺が表示されます:[8, 8, 8, 12]。fontSize はノード自身のサイズで、ノードにサイズがなければリンクしたテキストスタイルのサイズです。equals と in はテキストの値も比べます("layout": "vertical")。fix修正は、組み込みの修正と同じバッチ操作(update)で表されるので、fix_lint やデザインチェックの すべて修正 は 1 回の取り消しステップとして適用します。
fix | 内容 |
|---|---|
{"set": {"cornerRadius": 8}} | 通らなかったノードにそのプロパティを設定します。id、type、children 以外のどのノードプロパティでも使えます。 |
{"link": "variable"} | colorVariable チェックが必要です。塗り(または線)を、チェックの prefix 内の変数のうち色がいちばん近いカラー変数にします。プレフィックス外の変数は、内側のいちばん近いものに置き換えます。修正されるのは単一の単純な単色だけで、合う変数がなければ何もしません。デザインシステムの変数も対象です。 |
{"link": "textStyle"} | textStyle チェックが必要です。フォントサイズがいちばん近いテキストスタイル(同じなら小さいほう)を、oneOf があればその中からリンクし、ノード自身のサイズを消します。 |
修正の内容を決められない問題は、修正なしで出されます。fix_lint はそれを残すので、自分で直してください。
message はテンプレートです。次のプレースホルダーが埋められます。
| プレースホルダー | 内容 |
|---|---|
{id} | ルールの ID |
{name} | ノードの名前 |
{type} | ノードの種類 |
{property} | 通らなかったプロパティ |
{value} | その値(設定されていなければ none) |
{expected} | チェックが求めたもの:in なら 8, 12、equals なら 390、範囲なら 12 to 24 / at least 12 / at most 24 |
波かっこで囲まれたそれ以外のものは、書いたまま残ります。message がなければ、文面は {name}: {property} is {value}, expected {expected} です。
カスタムの問題の行は [severity] <rule id> (<source>) <node id>: <message> となります。組み込みの問題の行には出どころは表示されません。
検証に通らないルールはスキップされ、報告されます。同じファイルのほかのルールや、ほかのすべてのファイルのルールは引き続き実行されます。Silverpoint がルールファイルのせいで失敗したりクラッシュしたりすることはありません。問題には、ファイル(team.json、document、library:<alias>)、ルールの ID(ない場合は -。たとえば有効な JSON でないとき)、理由が示されます。
broken.json: bad-sev: unknown severity "loud" (error, warning, info)
team.json: -: not valid JSON: ...
理由は次のとおりです。有効な JSON でない、ID がないか重複している、ID がケバブケースでないか組み込みルールの名前である、重大度・チェックの種類・match のキー・ルールのキー・プロパティが不明である、正規表現が正しくない、expect が空である、fix の形が違う(または link の修正に対応するチェックがない)、ルールがオブジェクトでない。
問題が表示される場所:デザインチェックのセクションでは問題の下に一覧され、lint は出力の末尾に加え、silverpoint score は stderr に出力し、silverpoint lint-rules は出力して終了コード 1 で終了します。
ベータにはまだ含まれていません。silverpoint コマンドラインツールはダウンロード版に入っていないため、この節はソースからビルドした場合の説明です。
silverpoint lint-rules [<file.silverpoint>] [--json] [--check <file.json>]
id<TAB>source[ (overrides X)][ (disabled)]<TAB>severity。ドキュメントを指定するとそのドキュメントとライブラリのルールを使い、指定しなければユーザーフォルダのルールを使います。<file>: <id|->: <reason> の形で stderr に出ます。終了コードは、問題がなければ 0、あれば 1 です(有効なルールは一覧されます)。--check <file.json> は 1 つのルールファイルを検証し、ok: N rules を出力します。ファイルに問題があるか読めないときは、問題を stderr に出して終了コード 1 で終了します。--json は、ルールと問題を 1 つの JSON オブジェクトとして出力します。silverpoint score と silverpoint call <file> lint もカスタムルールを実行します。score はそれらを lint.counts の中でそれぞれのルール ID で数え、各問題には source が付きます。
lint と fix_lint は、組み込みルールとカスタムルールを一緒に実行します。rules で、組み込みでもカスタムでも、一部の ID に絞れます。save_lint_rule {scope, rule, confirm} は、あなたが述べた決まり(「カードのパディングはすべて 16」)からルールの下書きを作ります。まず プレビュー します。ルール、それが有効かどうか、どの下のレイヤーを上書きするか、上のレイヤーに隠されるかどうか、今のドキュメントで出る問題です。確定するまで何も書き込まれません。アプリでは、エージェントが 保存 と 破棄 のあるカードにルールを表示します。MCP(と silverpoint call)では、confirm: true のときだけ書き込みます。scope: "document" は 1 回の取り消しステップとしてドキュメントに保存し、scope: "user" は <lint folder>/<id>.json に書き込みます。ユーザーフォルダのファイルがすでにその ID を定義しているときは、そのファイルをその場で書き換え(そのルールを置き換え、ほかのルールは残します)、プレビューにそのファイル名が表示されます。無効なルールはエラーになり、何も書き込まれません。set_builtin_lint_rule {rule, enabled} は、組み込みルールをドキュメントでオフまたはオンにします。1 回の取り消しステップです。次の 6 つは、チームが最初に求める決まりをカバーしています。どれも、そのままリントフォルダに置けるルールファイルです。
ボタンの角丸は 8 か 12。 名前のパターンでの一致、集合、8 を選ぶ修正。
{"rules": [
{
"id": "button-radius",
"severity": "warning",
"message": "{name} radius {value} should be one of {expected}",
"match": {"type": "frame", "name": "Button*"},
"expect": [{"check": "in", "property": "cornerRadius", "values": [8, 12]}],
"fix": {"set": {"cornerRadius": 8}}
}
]}
どの画面フレームも幅 390。 画面とはトップレベルのフレームです(コンポーネントを除く)。
{"rules": [
{
"id": "screen-width",
"severity": "error",
"message": "{name} is {value} wide; screens are {expected}",
"match": {"type": "frame", "topLevel": true},
"expect": [{"check": "equals", "property": "width", "value": 390}],
"fix": {"set": {"width": 390}}
}
]}
画面内に 12pt 未満のテキストはなし。 inside でルールを画面に限定します。ノードにサイズがなければ、テキストスタイルのサイズを使います。
{"rules": [
{
"id": "screen-min-text",
"severity": "warning",
"message": "{name} is {value}pt; text in screens is at least 12pt",
"match": {"type": "text", "inside": {"kind": "screen"}},
"expect": [{"check": "range", "property": "fontSize", "min": 12}],
"fix": {"set": {"fontSize": 12}}
}
]}
色は brand/* の変数から。 塗りと線。修正では、いちばん近い brand/ の変数をリンクします。
{"rules": [
{
"id": "brand-colors",
"severity": "warning",
"message": "{name}: {property} is {value}, use {expected}",
"expect": [
{"check": "colorVariable", "property": "fill", "prefix": "brand/"},
{"check": "colorVariable", "property": "stroke", "prefix": "brand/"}
],
"fix": {"link": "variable"}
}
]}
アイコン名はケバブケース。 名前に対する正規表現。
{"rules": [
{
"id": "icon-kebab-case",
"severity": "info",
"message": "icon \"{name}\" should be named in kebab-case, like arrow-left",
"match": {"type": "icon"},
"expect": [{"check": "name", "regex": "^[a-z0-9]+(-[a-z0-9]+)*$"}]
}
]}
スペーシングは 8 の倍数。 フレームの gap と padding。パディングは 4 辺すべてが通るときだけ通ります。
{"rules": [
{
"id": "spacing-8",
"severity": "info",
"message": "{name}: {property} {value} is not a multiple of {expected}",
"match": {"type": "frame"},
"expect": [{"check": "multipleOf", "property": ["gap", "padding"], "value": 8}]
}
]}
設定 ▸ スキル ▸ リントルール は、silverpoint lint-rules と同じように、最前面のドキュメントで有効なルールを一覧します。組み込みのルール、あなたのフォルダのルール、リンクしたライブラリのルール、ドキュメント自身のルールが、ID ごとに、重大度、出どころ(同梱、ユーザフォルダ、ライブラリとそのエイリアス、この書類)、上書きしているものとともに表示されます。検証に通らないファイルは独立した行になり、ファイル、ルールの ID、理由が表示されます。デザインを開いていないときは、組み込みのルールとあなたのフォルダのルールだけが一覧されます。
組み込みルールにはそれぞれスイッチがあります。オフにすると、その組み込みルールは最前面のドキュメントでだけオフになり(set_builtin_lint_rule と同じ変更です)、1 回の取り消しステップになり、ドキュメントがその選択を保ちます。新しい Silverpoint で作られたドキュメントは読み取り専用なので、スイッチは使えません。カスタムルールにはスイッチがないので、置き換えるか削除してください。
ルールを追加… は、あなたのフォルダに雛形のファイル(new-rule.json、次は new-rule-2.json…。既存のファイルを上書きすることはありません)を書き込みます。中身は上の icon-kebab-case のサンプルを重大度 info にしたもので、ID はファイル名です。編集できるよう Finder で表示します。フォルダを表示 はあなたのフォルダを Finder で表示し(なければ作ります)、再読み込み はルールを読み直します。
silverpoint score --expect の noLint の期待値は、まだ組み込みルールしか指定できません。カスタムの ID はまだ受け付けません。(カスタムの問題は lint.counts で数えられ、スコアから読み取れます。)