はじめに
色々あってVSCodeのカラーテーマの自作を始めました。その記録をまとめます。
詳細な作成手順についてはより詳しい文献が多数存在するため、本ブログ記事では"お気持ち"の部分にフォーカスしてまとめています。
カラーテーマを自作したい人向けの資料
- https://code.visualstudio.com/api/extension-guides/color-theme#create-a-new-color-theme
- VSCode公式によるカラーテーマ作成手順のガイド。これに従えばとりあえず完成する。
- https://css-tricks.com/creating-a-vs-code-theme/
- 利用者の多いNight Owlというテーマの作成者によるガイド記事。作成開始から公開までの流れを、その時々での思考回路と共に紹介しています。私が本ブログを執筆するきっかけにもなった記事です。
- https://github.com/MatiasOlivera/universe-theme
- テーマの自動生成をするにあたって参考にさせていただいたリポジトリ。
自己紹介
"それ"を作った人間がどんな人間かを知りたいタイプの人間なので、自己紹介をします。
こんにちは、@d_etteiu8383です。かわいくてかっこいいものがすきです。
普段はWebフロントエンドと3DCGを触っています。他にやっていることは過去のブログ記事を参照してください。
実際にできたカラーテーマ
本カラーテーマは現在作成途中であり、将来的に配色やシンタックスハイライトの大幅な変更が行われる可能性があります。
制作記録
制作のきっかけ
- dotfilesを整備し始める
- Neovimを触り始める
- Neovimのカラースキームをデフォルトのものから変えたくなった
- 色々探したが"好きな"カラースキームが見つからなかった
- 「そういえばVSCodeではどんなテーマ使ってたっけ...」
- 「なんかVSCodeのテーマもよくよく見ると好きじゃないな...」
- 「作るか」
方向性の決定
Marketplaceで検索すれば、"良い"カラーテーマはたくさん見つかります。かわいいテーマ、かっこいいテーマ、見やすいテーマ...しかし、私が欲しかったのは"好き"なテーマでした。俺の、俺による、俺のためのオレオレテーマが欲しいのです。ならば作るしかありません。俺が。
ということで"好き"なテーマを作ることを第一目標としました。
ベースとなるテーマのピックアップ
テーマ制作にあたり、初動の時点で0から10まで自作するのは無謀であると考え、まずはベースとするカラーテーマを選ぶところから始めました。
"そこそこ好き"なテーマであることを条件としていくつかピックアップし、最終的にMonokaiをベースとすることにしました。"配色がカラフルでかわいい"ことも選考理由の一つですが、最大の理由はその名前です。
話は少しそれますが、私は単眼のお方がすきです。そういう趣味です。許してください。
単眼...モノアイ......Mono eye...Monokai......?
「Monokaiをベースとした"Monoeye"という名前のテーマを作ったらとても好きになれそうじゃん!」
ということで選ばれたのはMonokaiでした。また、このような理由から、「カラーテーマの世界観」を"単眼", "モノアイ"を中心に構成することにしました。
好きな色のピックアップ
好きなカラーテーマは好きな色で構成されるはずです。というわけで次に好きな色のピックアップをしました。好きなもの、好きなキャラクター、好きなデザインで使われている色をピックアップしました。
私が普段SNSなどで使用しているアイコンもそうなのですが、「メインカラー紫 サブカラー黄緑」の組み合わせが大好きです。これをカラーテーマに取り込まない理由がありません。
とにかくこの時点では視認性などは一切考えず、好きかどうかで色を選びました。俺のパレットの完成です。
ベーステーマの色を置き換える
次にベースのテーマで使用されている色を、機械的に"好きな色"と置き換えました。
Monokaiはソースコードが公開されていないため、ローカルにダウンロードされたカラーテーマデータをコピーして置換テーマを作成しました。
Windowsでは%HOMEPATH%\.vscode\extensions
にVSCodeの拡張機能データが保存され、カラーテーマのデータファイルもここにダウンロードされます。
VSCodeのカラーテーマの実体は、以下のような形式のJSONファイルです。
{
"name": "hoge",
"type": "dark",
"colors": {
"editor.background": "#1e1e1e",
"editor.foreground": "#d4d4d4",
"editorIndentGuide.background": "#404040",
"editorRuler.foreground": "#333333",
"activityBarBadge.background": "#007acc",
"sideBarTitle.foreground": "#bbbbbb",
...
}
}
設定箇所を表すIDがkey、色がvalueとなったオブジェクトでテーマを決定します。このファイルに記載していない設定箇所にはデフォルト色(伏線)が使用されます。
このファイルの色情報部分を単純に置換したり、一部調整して最初の自作テーマが完成しました。
しかし、ただ置換しただけでは「"その色"を"そこに"設定した意図がわからない」テーマとなっていました。私が作ったわけではないですからね。
後の調査でわかるのですが、エディターの色設定箇所(editor.background
など)は約660箇所あります。「色の設定意図」を踏まえた設定ができるように、まずは"どのような仕組みで色が設定されるのか"、"どこに色を設定できるのか"、そして"各設定箇所のデフォルト色"を調査することにしました。
実装の確認
どうやって調査するのか?
...VSCodeのすべてはhttps://github.com/microsoft/vscodeにあります。コードリーディングのお時間です。
カラーテーマ設定に関係しそうな部分をピックアップし、大まかに以下のような仕組みでカラーテーマが設定されることが分かりました。
IColorRegistry.registerColor()
(https://github.com/microsoft/vscode/blob/bcc823272187b5a723631fa64815c79b0299ee88/src/vs/platform/theme/common/colorRegistry.ts#L84-L90)を用いて、コード内で"色設定用のID(ColorIdentifier
)"と"デフォルトの色"を登録する- 登録された
ColorIdentifier
をkeyとしてカラーテーマファイルから設定色取得する。
つまり、VSCodeのソースコード中でIColorRegistry.registerColor()
が使用されている箇所をピックアップすることで、おそらくすべての設定可能箇所とデフォルト色を抽出できるわけです。
なお、その他の有用そうな知見はgistにまとめています。
ということでIColorRegistry.registerColor()
が使用されている箇所をピックアップ(人力)しました。手元にcloneしても良かったのですが、ファイル数がめちゃくちゃ多そうだったのでひたすらGitHub上で検索して抽出しました。
そんなこんなで抽出したデータを以下のような形式に整形しました。この作業が一番大変でした。
{
"activityBar.activeBackground": {
"id": "activityBar.activeBackground",
"description": "Activity bar background color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.",
"uses": {
"dark": [],
"light": []
},
"needsTransparency": false,
"defaults": {
"dark": {
"value": null,
"dependence": []
},
"light": {
"value": null,
"dependence": []
}
}
},
"activityBar.activeBorder": {
"id": "activityBar.activeBorder",
"description": "Activity bar border color for the active item. The activity bar is showing on the far left or right and allows to switch between views of the side bar.",
"uses": {
"dark": [],
"light": []
},
"needsTransparency": false,
"defaults": {
"dark": {
"value": "activityBar.foreground",
"dependence": ["activityBar.foreground"]
},
"light": {
"value": "activityBar.foreground",
"dependence": ["activityBar.foreground"]
}
}
},
"activityBar.background": {
"id": "activityBar.background",
"description": "Activity bar background color. The activity bar is showing on the far left or right and allows to switch between views of the side bar.",
"uses": {
"dark": ["activityBarItem.profilesBackground"],
"light": ["activityBarItem.profilesBackground"]
},
"needsTransparency": false,
"defaults": {
"dark": {
"value": "#333333",
"dependence": []
},
"light": {
"value": "#2C2C2C",
"dependence": []
}
}
},
...
}
長いので一部省略していますが、
- テーマ設定時に使用するid
- 配色使用箇所の説明
- デフォルトで設定される色
- 他の設定箇所の色を元にデフォルト色が決定される場合、その依存関係
- 例えば
activityBar.inactiveForeground
はtransparent(activityBar.foreground, 0.4)
のように他の箇所の色を参照して色の決定が行われる
- 例えば
といったデータをJSONにまとめてみました。
もともと欲しかったのはデフォルトの設定色でしたが、調査の中で設定箇所間の依存関係の情報を手に入れることができました。
依存関係とデフォルト色はgistの"デフォルト値"セクションにまとめています(人力で収集したデータのため誤りが含まれている可能性大)。
このデータは、カラーテーマ作成時の設定箇所を決定する指針に使えそうです。
デフォルト色の依存関係を元にした最小構成の構築
前節で説明したように、一部の設定箇所ではtransparent(activityBar.foreground, 0.4)
のように他の箇所の色を参照してデフォルト色の決定が行われています。
これはつまり、例えば「activityBar.foreground
を決定するだけで、activityBar.inactiveForeground
もデフォルト設定の計算によってイイ感じに設定される」ことを意味しています。
依存関係の根をピックアップして色を設定すれば、その子に当たる設定箇所は自動的にイイ感じの色になるわけです。
ということで、次に依存関係を整理し、「依存関係の根」となっている設定箇所を抽出し、カラーテーマの最小構成を決定しました。この時点で、全約660箇所あった設定項目から、約280箇所にまで設定項目を削減することができました🎉
パレットの確定
設定箇所をリストアップすることができたので、これを参考に、使用する色数を決定しました。
なるべく管理する色数を減らしたかったため、背景色4色、前景色3色、有彩色7色を使用することにしました。透明度も100%, 30%, 50%, 10%から選んで使用するようにしました。これでも多いと感じたので今後もっと減らすことになるかも。
基本的には"すきな色か"を基準に選びましたが、最低限の視認性を確保するため、Figmaのプラグイン Contrast を使用して文字色/背景色のコントラスト比を確認しながら配色を決定しました。コメントアウトに用いる色は敢えて見づらくするなどしています。
パレットの割り当て
設定箇所と使用色が決定できたので、いよいよ割り当てです。
- fg/main: 基本前景色, アクティブな要素に用いる
- fg/sub: インアクティブな要素に用いる
- fg/shadow: 選択不可能な要素, コメントに用いる
- red: (only) error
- orange: 検索結果
- yellow: warning
- green: git added, success
- cyan: function name
- blue: type, class, interface name
- purple: メインアクセントカラー, keyword
上記のようなメモを常に開き、配色の思考回路がブレないよう注意して割り当てました。この辺りの考え方などは自作Vimカラースキーム「Iceberg」の配色戦略に影響されています。ベースとしているMonokai自体はカラフルなカラーテーマですが、Monoeyeでは私の好きな色をメインに使用しています。
また、直接JSONファイルにカラーコードを記入していてはあまりにもメンテナンス性が悪いので、TypeScriptを用いて配色の定義ファイルとカラーパレットの定義ファイルから自動的にJSONを生成するようにしました。これで色の調整が簡単になりました。バリエーションも簡単に増やせそうです。
詳細な実装はeyemono-moe/monoeye-vscodeを参照してください。
完成・公開
ということでひとまず完成しました。
途中、このテーマに合うフォントを作るために脱線したり...
JetBrains MonoとNasuフォントを合成したフォントを作った
— でっていう (@d_etteiu8383) January 13, 2023
これで単一フォントしか指定できない環境でも好きな英語/日本語フォントの組み合わせが使えるようになった
ついでにNerd Fontsの記号もぶち込まれているのでターミナルもこれに統一した pic.twitter.com/ZqFOl2Dr2r
卒業研究も大詰めを迎えており研究が忙しかったりと、なかなか進捗が生めていませんでしたが、なんとか満足のいくカラーテーマを作ることができました。
今後もこのカラーテーマを育てていきたいですね。
終わりに
解説記事というわけでもない中途半端な記事でしたが、最後までお読みいただきありがとうございます。ぜひ皆さんもオリジナルのカラーテーマを作ってみてはいかがでしょうか?皆さんの"すき"が詰まったテーマを見てみたいです...