feature image

2023年1月22日 | ブログ記事

VSCodeのカラーテーマを作り始めた話

はじめに

色々あってVSCodeのカラーテーマの自作を始めました。その記録をまとめます。

詳細な作成手順についてはより詳しい文献が多数存在するため、本ブログ記事では"お気持ち"の部分にフォーカスしてまとめています。

カラーテーマを自作したい人向けの資料

自己紹介

"それ"を作った人間がどんな人間かを知りたいタイプの人間なので、自己紹介をします。

こんにちは、@d_etteiu8383です。かわいくてかっこいいものがすきです。
普段はWebフロントエンドと3DCGを触っています。他にやっていることは過去のブログ記事を参照してください。

実際にできたカラーテーマ

Monoeye - Visual Studio Marketplace
Extension for Visual Studio Code - High contrast color scheme based on Monokai Pro

本カラーテーマは現在作成途中であり、将来的に配色やシンタックスハイライトの大幅な変更が行われる可能性があります。

制作記録

制作のきっかけ

  1. dotfilesを整備し始める
  2. Neovimを触り始める
  3. Neovimのカラースキームをデフォルトのものから変えたくなった
  4. 色々探したが"好きな"カラースキームが見つからなかった
  5. 「そういえばVSCodeではどんなテーマ使ってたっけ...」
  6. 「なんかVSCodeのテーマもよくよく見ると好きじゃないな...」
  7. 「作るか」

方向性の決定

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にあります。コードリーディングのお時間です。

カラーテーマ設定に関係しそうな部分をピックアップし、大まかに以下のような仕組みでカラーテーマが設定されることが分かりました。

  1. IColorRegistry.registerColor()(https://github.com/microsoft/vscode/blob/bcc823272187b5a723631fa64815c79b0299ee88/src/vs/platform/theme/common/colorRegistry.ts#L84-L90)を用いて、コード内で"色設定用のID(ColorIdentifier)"と"デフォルトの色"を登録する
  2. 登録された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": []
      }
    }
  },
  ...
}

長いので一部省略していますが、

といったデータをJSONにまとめてみました。

もともと欲しかったのはデフォルトの設定色でしたが、調査の中で設定箇所間の依存関係の情報を手に入れることができました。
依存関係とデフォルト色はgistの"デフォルト値"セクションにまとめています(人力で収集したデータのため誤りが含まれている可能性大)。

このデータは、カラーテーマ作成時の設定箇所を決定する指針に使えそうです。

デフォルト色の依存関係を元にした最小構成の構築

前節で説明したように、一部の設定箇所ではtransparent(activityBar.foreground, 0.4)のように他の箇所の色を参照してデフォルト色の決定が行われています。

これはつまり、例えば「activityBar.foregroundを決定するだけで、activityBar.inactiveForegroundもデフォルト設定の計算によってイイ感じに設定される」ことを意味しています。
依存関係の根をピックアップして色を設定すれば、その子に当たる設定箇所は自動的にイイ感じの色になるわけです。

ということで、次に依存関係を整理し、「依存関係の根」となっている設定箇所を抽出し、カラーテーマの最小構成を決定しました。この時点で、全約660箇所あった設定項目から、約280箇所にまで設定項目を削減することができました🎉

パレットの確定

設定箇所をリストアップすることができたので、これを参考に、使用する色数を決定しました。

作成したカラーパレット

なるべく管理する色数を減らしたかったため、背景色4色、前景色3色、有彩色7色を使用することにしました。透明度も100%, 30%, 50%, 10%から選んで使用するようにしました。これでも多いと感じたので今後もっと減らすことになるかも。

基本的には"すきな色か"を基準に選びましたが、最低限の視認性を確保するため、Figmaのプラグイン Contrast を使用して文字色/背景色のコントラスト比を確認しながら配色を決定しました。コメントアウトに用いる色は敢えて見づらくするなどしています。

Figma上で文字のコントラスト比の確認を行っている様子

パレットの割り当て

設定箇所と使用色が決定できたので、いよいよ割り当てです。

上記のようなメモを常に開き、配色の思考回路がブレないよう注意して割り当てました。この辺りの考え方などは自作Vimカラースキーム「Iceberg」の配色戦略に影響されています。ベースとしているMonokai自体はカラフルなカラーテーマですが、Monoeyeでは私の好きな色をメインに使用しています。

また、直接JSONファイルにカラーコードを記入していてはあまりにもメンテナンス性が悪いので、TypeScriptを用いて配色の定義ファイルとカラーパレットの定義ファイルから自動的にJSONを生成するようにしました。これで色の調整が簡単になりました。バリエーションも簡単に増やせそうです。
詳細な実装はeyemono-moe/monoeye-vscodeを参照してください。

完成・公開

ということでひとまず完成しました。

現在のMonoeyeテーマ

途中、このテーマに合うフォントを作るために脱線したり...

JetBrains MonoとNasuフォントを合成したフォントを作った
これで単一フォントしか指定できない環境でも好きな英語/日本語フォントの組み合わせが使えるようになった
ついでにNerd Fontsの記号もぶち込まれているのでターミナルもこれに統一した pic.twitter.com/ZqFOl2Dr2r

— でっていう (@d_etteiu8383) January 13, 2023

卒業研究も大詰めを迎えており研究が忙しかったりと、なかなか進捗が生めていませんでしたが、なんとか満足のいくカラーテーマを作ることができました。

今後もこのカラーテーマを育てていきたいですね。

終わりに

解説記事というわけでもない中途半端な記事でしたが、最後までお読みいただきありがとうございます。ぜひ皆さんもオリジナルのカラーテーマを作ってみてはいかがでしょうか?皆さんの"すき"が詰まったテーマを見てみたいです...

d_etteiu8383 icon
この記事を書いた人
d_etteiu8383

グラフィック班とゲーム班とSysAd班所属 いろいろ活動しています

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2023年4月17日
ポケモンを飼いたい夢を叶える
tqk icon tqk
2024年12月18日
ISUCON14にツールの力で勝ちたかった
mazrean icon mazrean
2024年9月14日
わたくしの開発環境を紹介させていただきます
mehm8128 icon mehm8128
2022年11月27日
Chromebook&VSCode Server(プレビューアクセスなし)で開発環境を作る
oribe icon oribe
2024年12月15日
おなかが空いたら golangci-lint の Module Plugin 使おう
ikura-hamu icon ikura-hamu
2023年12月8日
Emoji Prefix with your `core.editor` (2)
ikura-hamu icon ikura-hamu
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記