エージェントとテーマを作る
MarsDawn のプレビューテーマを作る AI エージェント向けの参考資料です。エージェントは theme.json を1つ書き、コマンドラインツール marsdawn で検証してレンダリングし、リンクを渡します。人は「テーマを作る」ページで見た目を整えて投稿します。下のフィールド表は kit のソースコードから直接読み取ったもので、チェックによって一致が保たれています。
theme.json を書き、終了コードが 0 になるまで marsdawn theme validate theme.json --require-complete --json を実行し、marsdawn theme preview でライトとダークをレンダリングしてから、人にリンクを渡します。テーマはパラメーターだけで、CSS は含みません。
テーマとは
- ライトとダークそれぞれの色:基本パレットと、任意の構文色・図の色。どれも
#RRGGBBです。 - フォントデザイン:
sans、serif、roundedのいずれか。 - 閉じたスタイルオプションの集合:決まった範囲の数値と、決まったリストから選ぶ値。スタイルオプションの色は常に
accentのようなパレットのロールで、色の値を直接書くことはありません。 - 表示用の文字列:名前と概要、任意で作者とライセンス。
下の表にないキーはエラーで、同じキーを2回書くこともエラーです。ファイルは最大 16,384 バイトです。
検証とレンダリング
theme.json のあるフォルダで実行します。marsdawn ツールが必要です。AI エージェント向け marsdawnを参照してください。
marsdawn theme validate theme.json --require-complete --json
marsdawn theme css theme.json --json
marsdawn theme preview theme.json --appearance light -o light.png
marsdawn theme preview theme.json --appearance dark -o dark.png
- 終了コード:0 は有効、1 は無効(ルール ID 付き)、2 はファイルが見つからない、64 は使い方の誤りです。
previewにはさらに、PNG がすでにある場合の 4(--forceを付けるか別の名前にします)と、レンダリング失敗の 5 があります。 --jsonを付けると、無効なテーマは問題をissuesの下に並べ、それぞれにruleID、path、messageが付きます。直して再実行してください。--require-completeは公開するテーマ向けのチェックで、両方のパレットにsyntaxとdiagramの色も求めます。cssはプレビューが使う CSS を出力し、previewはサンプル文書を PNG にレンダリングします。どちらも先に検証するので、無効なテーマはレンダリングされません。- テーマを渡す前に、ライトとダークの PNG を両方確認してください。
組み込みテーマから始める
4つの組み込みテーマのどれかをコピーして変更します。どれも完全で有効なファイルです。
/assets/theme-sim/kit/themes/dawn.json: 既定のテーマで、下の例/assets/theme-sim/kit/themes/classic.json: より落ち着いた、文書らしいパレット/assets/theme-sim/kit/themes/modern.json: より涼しげで現代的なパレット/assets/theme-sim/kit/themes/vivid.json: より明るくコントラストの強いパレット
例:Dawn
dawn.json を1バイトも変えずに載せています。スタイルオプションは hr の細いアクセントカラーの線だけです。
{
"schemaVersion": 1,
"id": "dawn",
"version": "1.0.0",
"name": { "en": "Dawn" },
"summary": { "en": "Warm Martian sunrise" },
"fontDesign": "sans",
"scenarios": ["agent-review"],
"light": {
"background": "#FFFDFB", "surface": "#F6F0EC", "text": "#26211F", "muted": "#6F6660",
"border": "#EADFD8", "heading": "#26211F", "accent": "#C8471B", "link": "#B03C0C", "quote": "#D97A4A",
"syntax": { "keyword": "#B03C0C", "string": "#2F6F5E", "comment": "#746B66", "number": "#9A5B00", "function": "#5B3E8C", "type": "#1F6FB2" },
"diagram": { "node": "#FBE9E0", "nodeBorder": "#CA6C3C", "text": "#26211F", "line": "#8A6A5C", "secondary": "#E6F1EE", "tertiary": "#FFF6F1", "note": "#FFF1D6" }
},
"dark": {
"background": "#1C1A1F", "surface": "#262229", "text": "#EBE4DF", "muted": "#A39992",
"border": "#3A343A", "heading": "#F4EEEA", "accent": "#FF8A50", "link": "#FF9E6B", "quote": "#E08A5C",
"syntax": { "keyword": "#FF9E6B", "string": "#7FD1B9", "comment": "#938A84", "number": "#F2C572", "function": "#C7A6F5", "type": "#6CB6FF" },
"diagram": { "node": "#3A2A26", "nodeBorder": "#E08A5C", "text": "#EBE4DF", "line": "#B8A69C", "secondary": "#23332F", "tertiary": "#2B2427", "note": "#3D3322" }
},
"style": {
"hr": { "style": { "type": "line", "color": "accent", "thickness": 1 } }
}
}
フィールド
下のオブジェクトはどれも同じように読まれます。required はキーが必須という意味で、載っていないキーはエラーです。
型:string、integer、number、boolean、map(言語タグからテキストへ)、enum(挙げた値のいずれか)、role(パレットのロール)、object(リンク先の表)。型の後ろの [] はリストを表します。
theme.json
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
schemaVersion | integer | required | 常に 1。 |
id | string | required | 1〜32文字:小文字と数字を、単独のハイフンでつないだ区切り。例:calm-green。 |
version | string | required | MAJOR.MINOR.PATCH。例:1.0.0。 |
name | map | required | 言語タグからテキストへ。en は必須で、ほかのキーは zh-Hant のような言語タグです。各テキストは最大48文字で、リンクや改行は使えません。 |
summary | map | required | name と同じ形式で、テキストごとに最大120文字。 |
fontDesign | enum | required | sans, serif, rounded |
scenarios | enum[] | required | agent-review, technical-docs, formal-output, notes-sharing — 1つまたは2つ、重複不可。テーマが満たすべきコントラストの水準を決めます。 |
author | object | optional | author |
license | string | optional | SPDX 識別子。例:Apache-2.0。投稿されたテーマは Apache-2.0 で公開されます。 |
light | object | required | light, dark |
dark | object | required | light, dark |
style | object | optional | style |
author
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
name | string | required | 最大64文字、リンク不可。 |
github | string | optional | GitHub のログイン名。投稿の場合は、投稿する人のものを入れます。 |
light, dark
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
background | string | required | # と16進数6桁。例:#1C1C1C。 |
surface | string | required | # と16進数6桁。例:#1C1C1C。 |
text | string | required | # と16進数6桁。例:#1C1C1C。 |
muted | string | required | # と16進数6桁。例:#1C1C1C。 |
border | string | required | # と16進数6桁。例:#1C1C1C。 |
heading | string | required | # と16進数6桁。例:#1C1C1C。 |
accent | string | required | # と16進数6桁。例:#1C1C1C。 |
link | string | required | # と16進数6桁。例:#1C1C1C。 |
quote | string | required | # と16進数6桁。例:#1C1C1C。 |
syntax | object | optional (公開には必須。--require-complete で検証) | syntax |
diagram | object | optional (公開には必須。--require-complete で検証) | diagram |
syntax
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
keyword | string | required | # と16進数6桁。例:#1C1C1C。 |
string | string | required | # と16進数6桁。例:#1C1C1C。 |
comment | string | required | # と16進数6桁。例:#1C1C1C。 |
number | string | required | # と16進数6桁。例:#1C1C1C。 |
function | string | required | # と16進数6桁。例:#1C1C1C。 |
type | string | required | # と16進数6桁。例:#1C1C1C。 |
diagram
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
node | string | required | # と16進数6桁。例:#1C1C1C。 |
nodeBorder | string | required | # と16進数6桁。例:#1C1C1C。 |
text | string | required | # と16進数6桁。例:#1C1C1C。 |
line | string | required | # と16進数6桁。例:#1C1C1C。 |
secondary | string | required | # と16進数6桁。例:#1C1C1C。 |
tertiary | string | required | # と16進数6桁。例:#1C1C1C。 |
note | string | required | # と16進数6桁。例:#1C1C1C。 |
style
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
bodySize | number | optional | 範囲 |
lineHeight | number | optional | 範囲 |
headingWeight | number | optional | 範囲 |
radius | number | optional | 範囲 |
maxWidth | number | optional | 範囲 |
h1 | object | optional | style.h1 |
h2 | object | optional | style.h2 |
blockquote | object | optional | style.blockquote |
hr | object | optional | style.hr |
table | object | optional | style.table |
listMarker | role | optional | パレットのロール |
inlineCode | role | optional | パレットのロール — text か構文ロールのみ:keyword、string、comment、number、function、type。 |
link | object | optional | style.link |
syntax | object | optional | style.syntax |
style.h1
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
size | number | optional | 範囲 |
letterSpacing | number | optional | 範囲 |
align | enum | optional | left, center |
decoration | object | optional | type |
style.h2
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
letterSpacing | number | optional | 範囲 |
decoration | object | optional | type |
italic | boolean | optional | true, false |
style.blockquote
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
style | object | optional | type |
italic | boolean | optional | true, false |
style.hr
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
style | object | optional | type |
style.table
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
header | object | optional | type |
verticalRules | boolean | optional | true, false |
rounded | boolean | optional | true, false |
style.link
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
underline | boolean | optional | true, false |
style.syntax
| フィールド | 型 | 必須か | 値と備考 |
|---|---|---|---|
boldKeywords | boolean | optional | true, false |
type を持つオプション
これらのスタイルオプションは type を持つオブジェクトです。それぞれの type は、そこに挙げたフィールドだけを受け付けます。
| オプション | type | フィールド | 必須か | 型 |
|---|---|---|---|---|
style.h1.decoration | rule | — | — | — |
style.h1.decoration | none | — | — | — |
style.h1.decoration | shortRule | color | required | role |
style.h1.decoration | gradientBar | from | required | role |
style.h1.decoration | gradientBar | to | required | role |
style.h2.decoration | rule | — | — | — |
style.h2.decoration | none | — | — | — |
style.h2.decoration | dot | color | required | role |
style.blockquote.style | bar | width | optional | number 範囲 |
style.blockquote.style | panel | — | — | — |
style.hr.style | line | color | optional | role |
style.hr.style | line | thickness | optional | number 範囲 |
style.hr.style | shortCentered | color | required | role |
style.hr.style | gradient | colors | required | role[] ロールを2つまたは3つ。 |
style.table.header | surface | — | — | — |
style.table.header | accentRule | color | required | role |
style.table.header | filled | background | required | role |
style.table.header | filled | text | required | role |
style.table.header | filled | border | optional | role |
パレットのロール
パレットのロールは次の名前のいずれかです。
background, surface, text, muted, border, heading, accent, link, quote, keyword, string, comment, number, function, type
数値
数値は最も近い刻みの倍数に丸められ、最小と最大の間に収まる必要があります。収まらない場合のルールは number.range です。
| フィールド | 最小 | 最大 | 刻み |
|---|---|---|---|
style.bodySize | 14 | 18 | 1 |
style.lineHeight | 1.4 | 1.9 | 0.05 |
style.headingWeight | 400 | 900 | 50 |
style.radius | 0 | 16 | 1 |
style.maxWidth | 600 | 1000 | 1 |
style.h1.size | 1.8 | 2.4 | 0.1 |
style.h1.letterSpacing | -0.03 | 0.03 | 0.005 |
style.h2.letterSpacing | -0.03 | 0.03 | 0.005 |
style.blockquote.style.width | 2 | 4 | 1 |
style.hr.style.thickness | 1 | 4 | 1 |
ほかに検証されること
- コントラスト。
background上のtextのように、プレビューが描く色の組はすべて、テキストは 4.5:1、線やそのほかの非テキストは 3:1 に達する必要があります。指定したシナリオによって、一部の色は 4.5:1 に引き上げられます。メッセージには、その組と比率、必要な比率が示されます。 - 文字列。名前、概要、作者名が空、長すぎる、またはリンク・制御文字・不可視文字・双方向書式文字を含む場合は拒否されます。
- ルール ID。すべての問題には
contrast.pair、color.hex、number.range、id.pattern、schema.unknownKey、palette.incompleteなどの ID が付きます。ID とpathが示すとおりにファイルを直してください。
リンクとして渡す
「テーマを作る」ページは、リンクからテーマを開けるので、人が見た目を整えられます。リンクは、そのページのアドレス、#theme=、パディングなしの base64url にしたファイルのバイト列でできています。ファイルは最大 16,384 バイトです。次の1行で、macOS と Linux の zsh と bash でリンクを作れます。
printf 'https://marsdawn.southern-light.dev/ja/themes/new/#theme=%s\n' "$(base64 < theme.json | tr -d '\n=' | tr '+/' '-_')"
テーマはブラウザがサイトに送らない # の後ろに入り、サイトもそれをどこにも送りません。ただしリンクはシェルとブラウザの履歴に残り、リンクを貼った相手はテーマを読めます。
投稿する
エージェントがファイルとリンクを用意し、投稿は人が行います。どちらの方法でも Developer Certificate of Origin と Apache-2.0 での公開への確認が必要で、この確認は人が自分で行います。エージェントがチェックボックスにチェックしたり、代わりに署名したりすることはありません。
- Issue。人がリンクを開いて「テーマを作る」ページの Submit を押すか、Issue フォームを開いて JSON を Theme に貼り付けます。ワークフローがテーマを検証して返信します。
- Pull request。
themes/<id>/theme.jsonだけを変更し、author.githubを pull request の作者のログイン名にして、すべてのコミットにgit commit -sで署名します。ルールは CONTRIBUTING.md にあります。
投稿されたテーマの作者名、名前、概要、GitHub のログイン名は永久に公開されます。author.name には、その人が公開してよいと考える名前を入れてください。
公開されているテーマ
公開されているテーマの見た目は、テーマギャラリーで確認できます。