ThemeForge:AIエージェントがワンクリックでインストールできる、ドロップイン式のCSSテーマシステム
- カテゴリ
- AIとローカルLLM
- 公開日
- 2026年10月5日
- 更新日
- 2026年10月6日
- 著者
- Jacob Lloyd — プロジェクト完了後、AIの支援を受けて執筆
- 読了時間
- 約62分で読めます
かんたんに言うと: ThemeForgeは、CSSと小さなスクリプトがまとめられた無料のパッケージです。これを使うことで、どんなウェブアプリにもテーマ選択機能や10種類のカラーテーマ、そしてあらかじめ用意されたボタンやフィールド、カード、ダイアログなどが追加されます。このパッケージは、AIコーディングエージェントが1行のコードだけでアプリに組み込めるように作られています。エージェントはリポジトリ内の短いファイルに従うだけで、アプリには機能するテーマ選択機能やシステムに準拠したデフォルト設定、さらにデザイン構築用の各種トークンも付与されます。
ほとんどのウェブアプリでは、3種類のテーマがそれぞれ別々の場所に記述されることになります。つまり、メインCSS内の :root ブロック、@media (prefers-color-scheme: dark) 以下にある2番目のブロック、そして開発者がピッカーを動作させるために任意の場所に追加した3番目のブロックです。その結果はいつも同じで、ホームページではある見た目になるテーマが、設定ページでは別の見た目になり、最終的には「なぜダークテーマにするとフッターが青くなるのか」という質問がIssueトラッカーに投稿されるのです。私はこのような問題を絶対に起こらなくするために ThemeForge を作成しました。これは ui-theme/ という1つのフォルダのみで構成されており、ランタイム、ベースレイヤー、コンポーネント用クラス、10種類すべてのテーマ用トークン、ピッカー、必要に応じて利用できるTailwindやQuasar用アダプター、そしてAIコーディングエージェント向けに書かれた短い AGENTS.md ファイルも含まれています。このフォルダをプロジェクトに追加し、ページのヘッド部分に4行ほど記述するだけで、アプリには正常に動作するテーマピッカーおよびシステム設定に準拠したデフォルトテーマが実装されます。インストールを担当するエージェントは1行のコマンドだけで作業を完了します。この記事の残りの部分は、内部仕組みを知りたい方々向けの内容となります。
この記事は、フォルダー内に実際に何があるか、10個のテーマとその用途、対比的な説明、そして残りの部分で参考用として提供されるデザイントークンやコンポーネントクラスについて解説するガイドです。後半部分は意図的に素早く閲覧できる参照用資料となっており、すべてのトークン、コンポーネント、公開メソッドが記載されています。これにより、コーディングエージェント(あるいは将来のあなた自身)がそのまま利用できるようになっています。
要約
- 入手方法: github.com/LaserLloyd/ThemeForge — MITライセンスで無料です。下のダウンロード欄にもソースコードのZIPファイルがあります。
- 内容:
ui-theme/という単一のフォルダーだけで、どんなWebアプリにも導入可能です。10種類のカラーテーマ、テーマ選択機能、約250個のデザイントークン、ベースとなる要素レイヤー、テキストの標準規格、そしてボタン・フィールド・スイッチ・カード・ダイアログ・トースト・テーブル・アプリシェルなど、さまざまなコンポーネント用クラスがすべて含まれています。CSSのみとごく小さなスクリプトだけで構成されており、ビルド処理もNode.jsも依存ライブラリも一切不要です。 - ワンラインインストール(READMEからそのまま引用):
python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())" - ヘッドブロックの順序(重要です): まず
ui-theme.jsを読み込みます(通常通りで、deferやmodule属性は一切使用しません)。次にui-theme-base.cssとui-components.css、続いてアプリ自身のCSSを読み込み、最後にui-theme.cssを読み込むことでテーマ設定が有効になります。 - テーマ選択機能: 次のような要素のみが必要です:
<select class="ui-select" data-ui-theme-picker aria-label="Theme"></select>。この要素は自動的にテーマリストを生成し、複数のタブ間でも同期されます。 - 10種類のテーマ: 基本となる6種類(パープル、ミッドナイトゴールド、グレーシャー、フォレスト、ペーパー、デイライト)に加え、4種類のオプション用テーマ(エレクトリックイエロー、LaserLloyd、LaserLloyd Light、ナイトレッド)も用意されています。すべてのテーマはコントラスト基準を満たしており、不適合は一切ありません。
- コントラスト水準: 本文テキストは7:1、補助的なテキストは6:1、あらゆる面でのテキストは4.5:1以上。コントロール要素の境界やオン/オフ状態も3:1以上のコントラストを確保しています。また、オン/選択済み/現在の状態は色だけでなく形状や塗りつぶし具合でも識別可能です。
- AIエージェント向け設計: AGENTS.md にはインストール手順が文章形式で記載されており、どのAIエージェントにもこのファイルを指定するだけで一ステップでテーマ選択機能が利用可能になります。本リポジトリのCI(GitHub Actions、3つのジョブ)ではクローン作成、コントラストチェック、各JSファイルに対する
node --check検証、さらにヘッドレスChromeによるランタイムテストがすべて正常に実行されます。
どこで入手できますか
MITライセンス下で公開されているリポジトリがこちらです:github.com/LaserLloyd/ThemeForge。インストール用のスクリプトはAGENTS.mdに記載されており、監査用の資料としてはコントラストレポートが用意されています。ZIPファイルをご希望の場合は、このページの末尾にある「ダウンロード」欄から全ソースコードを入手できますし、サイト内のダウンロードページにも同様のファイルが掲載されています。Pythonがインストールされていない環境では、READMEにも記載されている通り、git clone --depth 1、npx degitといったコマンドや、プロトタイプ作成用に @v1.0.0 バージョンが指定されたjsDelivrの <script> URLも利用可能です。
最終的に得られるもの
ユーザーが好む見た目に近づけるための仕組みとして、あらゆるテーマを認識するピッカー付きのヘッダーがあります。OSに合わせて暗色系または明色系のデフォルトテーマが選ばれ、アプリケーションのコードベース内には次のような一行のCSSコードが記述されています:background: var(--surface-2) という具合です。これは #1d1d39 の代わりに使われます。テーマを選択してページを再読み込みすると、画面のちらつきは一切ありません。実行時スクリプトが <head> 内で同期的に実行され、タグ内の data-* 設定を読み取り、最初の描画前にテーマが適用されるからです。2つのタブでピッカーを開き、一方でテーマを変更すると、もう一方のタブもそれに合わせて再描画されます(これは storage イベントリスナーの働きです)。暗色系またはOLED用のテーマを選択して印刷すると、実行時環境は印刷作業中のみ明色系テーマに切り替えます(あるいは data-print-theme の設定に応じてナビゲーション部分を非表示にします)。こうすることで印刷されたページが紙上でも読みやすくなります。明色系テーマを選択した場合は、そのままの状態で印刷されます。
ui-app、ui-card、ui-btn、ui-switch といったコンポーネント、および --surface-*、--text-*、--accent といったトークンを使って構築されています。テーマ選択機能は <select data-ui-theme-picker> として実装されており、実行時に内容が自動的に設定・同期されます。上記の図はページ内で動作するデモであり、別ファイルのスクリーンショットではありません。実際のサンプル、つまりあらゆるテーマに含まれるすべてのコンポーネントは、リポジトリ内の specimen/index.html にあります(python3 -m http.server を実行した後、/specimen/ から開くことができます)。
各部分がどのように連携するか
このランタイムは、ui-theme.jsというごく小さなスクリプト(約23KB、575行)です。このスクリプトは順番に3つの処理を行います。まず、自身が存在する <script> タグ内の data-* 属性を読み取ります(これにより設定内容がファイル自体と共に引き継がれます)。次に localStorage やOS側の明るい/暗いモードの設定も確認します。そして最初の描画前に、選択されたテーマを <html data-palette> へ、現在有効なテーマ名(amoled、dark、light のいずれか)を <html data-theme> へ書き込みます。その後、ドキュメント内にある <select data-ui-theme-picker> 要素を探し出し、利用可能なテーマ一覧でそれらを埋めます(また、後からフレームワークによって生成される要素にも対応します)。さらに window.UITheme を公開し、ui-components.js が読み込まれた際には window.UIComponents も公開します。加えて storage イベントのリスナーを設定することで、複数のタブ間でテーマ情報が同期されるようにしています。CSS側はごくシンプルです。ui-theme-base.css ではページ上のテキストやリンク、フォーカスリング、スクロールバー、および「減速モーション」設定のデフォルト値を定義しています。ui-components.css ではボタンや入力欄、スイッチ、カード、ダイアログ、トースト、テーブルなどが描画されます。一方で ui-theme.css だけが各テーマごとに内容が変わるファイルであり、[data-palette="…"] セレクタの下で10種類すべてのテーマ用の色やタイポグラフィ、余白、角丸度、影、アニメーションの各値を定義しています。紫色テーマは :root として表現されており、これは data-palette 属性が存在しない状態に相当します。つまりランタイムがテーマを選択し、CSSがそれを画面に描画する仕組みとなっています。
OSのテーマに自動で追随する機能は多くの方を驚かせる点です。data-default="auto"により、各ページ読み込み時にprefers-color-schemeが参照され、実行時にはユーザーが保存した選択内容やdata-default-darkおよびdata-default-lightと組み合わせてテーマが決定されます。OSのテーマを変更してページを再読み込みすると、自動的に切り替わります。またピッカーから明示的にテーマを選ぶことも可能で、その場合はユーザーが設定を解除するかUITheme.reset()を呼び出すまでその設定が優先されます。さらに実行時にはstorageイベントも設定されるため、同じアプリの複数タブ間でもサーバー通信なしに同期が行われます。
インストール方法
リポジトリ内のAGENTS.mdに詳細な手順が記載されておりますが、簡単な手順としては以下の一行コマンドと4つのタグからなるheadブロックを使用します。アプリのルートディレクトリから実行してください。
python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"
このコマンドによりインストーラーがダウンロードされ、最新リリースを取得した上でfiles.jsonに記載されたSHA-256値と照合し、フォルダ内にファイル群を書き込みます。Windows環境ではpython3の代わりにpythonまたはpyを使用してください。このコマンドはPowerShell、cmd、bashのいずれでも同様です。各ページの<head>内に記述する4行は以下の通りです。
<script src="/static/ui-theme/ui-theme.js"
data-themes="purple,midnight-gold,glacier,forest,paper,daylight"
data-default="auto" data-default-dark="midnight-gold" data-default-light="daylight"
data-storage-key="myapp.theme"></script>
<link rel="stylesheet" href="/static/ui-theme/ui-theme-base.css">
<link rel="stylesheet" href="/static/ui-theme/ui-components.css">
<!-- ご自身のスタイルシート -->
<link rel="stylesheet" href="/static/ui-theme/ui-theme.css">
これら3つのCSSファイルはそれぞれ重要な役割を担っております。ui-theme.jsはクラシックなブロッキングスクリプトであり、type="module"、defer、asyncといった属性は一切使用しません。これは自身のタグから設定値を読み取る必要があるためです(document.currentScriptを用いるのですが、モジュールスクリプトではこの値がnullとなってしまうためです)。また最初の描画前にテーマ設定を行う必要もあります。基本レイヤーおよびコンポーネントレイヤーのCSSはアプリ用CSSより先に読み込まれるため、同じ指定度合いを持つ場合でもアプリ側のルールが優先されます。ui-theme.cssはその後に読み込まれるため、古いアプリ変数がテーマトークンを上書きすることが防がれます。ピッカー自体は以下の一行だけで実装可能です:<select class="ui-select" data-ui-theme-picker aria-label="Theme"></select>。スクリプトからはUITheme.set('glacier')、UITheme.current()、UITheme.onChange(fn)といった呼び出しが可能です。AGENTS.mdの記載によれば、インストール全体には約5分程度しかかかりません。
実際にあるアプリへこの機能を一括で導入した際のエージェントの動作は次の通りです。ユーザーがAIコーディングエージェントに対し、ダークモードおよびテーマピッカーの実装を依頼しました。エージェントはAGENTS.mdを参照した上で、一行コマンドをstatic/ui-theme/ディレクトリ内で実行し、4つのheadタグをベーステンプレートに貼り付けました。さらに2箇所の色指定をvar(--surface-2)およびvar(--text-secondary)へ置き換え、ヘッダー部分にピッカーも追加しました。結果としてアプリ側の差分はわずか6行のみとなり、新たな依存関係も一切発生しませんでした。コントラスト監査機能により各コンポーネントが描画するすべての色ペアが確認済みであり、実行時にはOSテーマにも自動追随します。今後色指定をハードコーディングする場合に備えて、リント処理がその不備を検出できるだけとなっております。
テーマ一覧
最初の6つはアプリがデフォルトで提供するコアテーマです。追加で用意された4つは、アプリ側が明示的に指定した場合にのみ利用可能となります。すべてのテーマはコントラスト監査を通過しております(docs/contrast-report.md参照)。具体的には本文テキストは7:1、補助的なテキストは各背景色上で6:1、その他のテキスト階層は4.5:1以上、コントロールの縁やオン/オフ状態も3:1以上のコントラスト比を満たしており、すべてのテーマにおいて形状だけでなく色情報も用いて状態が判別できるようになっております。各テーマの詳細は以下の通りです。
| テーマ | 種類 | 配色 | 説明 |
|---|---|---|---|
| Purple | コア | dark | 深いインディゴを背景に、バイオレットのアクセントと柔らかなラベンダー色のテキストが特徴です。基本テーマとして、その値が:rootのデフォルト値となります。 |
| Midnight Gold | コア | OLED | OLEDディスプレイ向けで、真っ黒な背景に温かみのあるゴールド色が配されています。 |
| Glacier | コア | OLED | 真っ黒な背景に氷色のテキストやシグネチャが映え、深いティール色のアクセントも特徴です。 |
| Forest | コア | OLED | 真っ黒な背景に淡いセージ色やリケン色が配され、茶色系の木肌色も組み合わされています。 |
| Paper | コア | light | 温かみのあるパーチメント色を基調とし、インクブラウン色のテキストや散文用のセリフ体、赤色のアクセントが特徴です。 |
| Daylight | コア | light | クリーンな白をベースに青色のアクセントが加えられています。 |
| Electric Yellow | オプトイン | dark | グラファイト色の背景に酸っぱいようなイエロー色が配され、角が丸くシャープな線も特徴です。 |
| LaserLloyd | オプトイン | dark | 近黒色のグラファイトを背景にレーザーブルーが配されており、作者のサイトでも使用されているテーマです。LaserLloyd Lightとセットで利用します。 |
| LaserLloyd Light | オプトイン | light | LaserLloydのライトバージョンとなります。 |
| Night Red | オプトイン | OLED | 低ブルーライトなナイトテーマで、真っ黒な背景に赤みを帯びたテキストが配されています。色構成には一切の青色成分が含まれておりません。 |
オプトインの4つは意図的に目立つ色合いとなっております。Electric Yellowは暗い環境でCSSレビューを行う際にエディタよりもページを目立たせたい場合に私が使用するテーマです。LaserLloydは本サイトのブルーとグラファイト色のデザインに合わせ、同じアプリ内でも統一感を出すために選ばれました。Night Redは「ナイトプロファイル」として特別な設定がなされており、コントラスト監査ツールでは通常171行分のテストデータ(標準的な147行に低照度環境向けの追加行を加えたもの)を用いて検証が行われます。またこのテーマではパレット内のすべてのトークンにおいて青色成分がゼロとなっております(docs/contrast-report.mdの「ゼロブルー監査」、README.mdのNight Red項目、docs/THEMES.mdのNight Red項目をご参照ください)。
注意点
-
CSSにハードコーディングされた色指定が問題であり、テーマ自体ではありません。 監査ではトークンのみをチェックします。アプリケーションコード内の
color: #fffはどのテーマでも白く表示されます。tools/lint_colors.py(リポジトリ内)および AGENTS.md §8 の grep 処理でこれが検出されます。ただし CI でのリント処理ではそのステップが実行されないため、マージ前にローカルで実行してください。 -
ui-theme.jsは<head>内で最も先頭に記述される必要があり、かつ classic 属性を付けるべきです。deferやmodule属性は使用してはいけません。モジュールスクリプトではdocument.currentScriptが利用できず、ランタイムはタグ内のdata-*属性から情報を読み取ります。その結果、一時的に誤ったテーマが表示された後で正しいテーマに切り替わる現象が起こります。 -
ui-theme.cssはアプリケーションの CSS の後に読み込まれる必要があります。 読み込み順序は「ベース → コンポーネント → アプリケーション → トークン」となります。トークンの後で読み込まれる同等の優先度を持つルールは無効になってしまいます。 -
data-themesによって選択肢として表示されるテーマが決まります。data-themesに含まれていないスラッグを持つ保存済みテーマは次回の読み込み時に無視され、ランタイムはデフォルトテーマを使用します。テーマを削除する際にはdata-legacy-keyおよびdata-legacy-mapを一度設定することで、保存済み値が適切に移行されます。 -
Tailwind の
rounded-mdやfont-sansはインストール後に変化します。 これは仕様通りです。テーマ側で--radius-や--font-といったトークンが定義されており、そちらの値が優先されます。無理に上書きしないでください。 -
Next.js におけるハイドレーションの警告について。
<html>タグにsuppressHydrationWarningを追加し、head ブロックに対するno-sync-scriptsリントルールも無効化してください。ランタイムは React のハイドレーション処理前に<html>に属性を設定するためです。 -
他のライブラリが
<html>上のdata-themeを読み取る場合。 ランタイムはそこにdata-theme="amoled|dark|light"を書き込みます。該当ライブラリがこの値に反応しないか確認してください。もし反応する場合は、data-mirror-attrを使って別の属性を設定してください。 -
ui-theme/内の内容は編集しないでください。 このフォルダはアップデート時に置き換えられるため、手動での編集が検出されるとインストール処理が編集済みファイルの上書きを拒否します。変更が必要な場合はアプリケーション自身の CSS に記述してください。 -
テーマ定義内で名前が挙げられているフォントはバンドルされません。 すべてのテーマではシステムフォントがフォールバックとして使用されます。Inter、JetBrains Mono、Space Grotesk、Archivo を利用したい場合はご自身で読み込んでください(インテグレーションのドキュメントに
<link>タグのコピー用テキストが記載されています)。 -
prefers-contrast: moreを指定すると線幅が太くなり、最も淡い色のテキストもはっきりと表示されます。 特別なテーマフラグは不要です。ランタイムがこれを検知し、CSS 側もそれに応答します。high-contrastというトークングループは同じ効果を得るための従来のオプションとなります。
この状況が私に与える影響
私が望んでいたのは、毎回一からテーマシステムを作成することなく、自分が作るすべてのアプリに本格的なテーマ機能を導入できる手段でした。ThemeForgeこそが、私が今後も使い続けたい形なのです。アプリに配置するフォルダーは現在 ui-theme/ と、アプリごとに必要なフォルダーとなっています。4種類のヘッドブロックタグやピッカーも、どのフレームワークでも同じ構造です。インストール用エージェントはSlackメッセージではなく AGENTS.md を読み取ります。コントラスト監査やヘッドレスChromeによるランタイムテスト、そして配布されるすべてのJSファイルに対して実施される node --check といった処理が、私に安心して開発を続けられる自信を与えてくれるのです。バージョンが1.0.0となっているのは、トークンが公開用APIであり、トークンの名前変更はメジャーバージョンアップに該当するからです。リリースはgitタグによって管理され、VERSION フォルダーの内容もそれと一致しています。またJSONファイルには update.py が照合するチェックサムリストによる署名も付与されています。このリポジトリ自体のCIはLinux、Windows、Python 3.9環境ですべて成功しており、このマシン上で新たにクローンを作成しても同様のチェックが通ります。
参考情報(AIエージェント用)
この記事の残りの部分は、コーディングエージェント(あるいは将来の私自身)がそのまま利用できるリファレンスカードとなっています。上記の前半部分が文章形式であり、後半部分は構造化されており、スキャンしやすく、ツールが読み取りやすい形になっています。window.UIThemeおよびwindow.UIComponentsに存在するすべてのトークン、各コンポーネントクラス、公開されているメソッド、テーマ、scriptタグ用の設定項目、アダプター、完全なインストールパス、コントラストに関する仕様、そしてバージョン情報などが以下に記載されています。
ファイルマニフェスト
このリポジトリには重要なツリーが2つあります。1つはアプリケーションがコピーするバンドル、もう1つはそのバンドルをビルドするための設計やツール類です。この記事では、そのバンドルについて説明します。
ドロップイン用バンドル — アプリがコピーする内容(ui-theme/):
| ファイル | サイズ | 行数 | 内容 |
|---|---|---|---|
ui-theme.js |
23,515 B | 575 | 実行時処理:保存されたテーマを最初の描画前に適用し、data-default="auto"によりOSの明るい/暗いモードに追随。ピッカーの設定やタブの同期も行い、window.UIThemeも公開します |
ui-theme-base.css |
13,255 B | — | 要素のデフォルト設定:本文テキスト、リンク、見出し、コード、フォーカスリング、スクロールバー、減速モーション設定、テキスト階層、.ui-markdown、highlight.js用の色設定など |
ui-components.css |
51,344 B | — | 各種コンポーネント:ボタン、入力欄、チェックボックス、ラジオボタン、スイッチ、カード、バッジ、コールアウト、タブ、セグメントコントロール、テーブル、ダイアログ、メニュー、ツールチップ、トースト、進行状況表示、コードブロック、アプリケーションシェルなど |
ui-theme.css |
86,389 B(gz圧縮後:21,197 B) | — | 10種類のテーマ用トークン群(gz圧縮後で約20 KB) |
ui-components.js |
5,441 B | 135 | 任意で使用可能なconfirm()、alert()、prompt()、toast()関数です |
ui-theme.d.ts |
2,841 B | — | window.UIThemeおよびwindow.UIComponents用のTypeScript宣言ファイルです |
update.py |
16,081 B | — | フォルダーのインストール・更新処理を行い、各ファイルのSHA-256値も確認します |
themes.json |
4,089 B | — | テーマ一覧(名前、ファミリー、背景色、配色セット、スウォッチ、フォント情報) |
files.json |
1,401 B | — | update.pyが検証に用いるチェックサムの一覧です |
VERSION |
30 B | — | フォルダーのバージョン情報(ThemeForge 1.0.0 3db64d9f574f) |
README.md |
6,342 B | — | このパッケージの利用方法に関する説明書です |
adapters/quasar.css |
24,997 B | — | NiceGUI/Quasar用のマッピング設定です |
adapters/quasar.js |
1,468 B | 40 | NiceGUI/Quasar間のJavaScriptブリッジ機能です |
adapters/tailwind.css |
4,399 B | — | Tailwind CSS v4用の@theme inlineマッピング設定です |
adapters/tailwind-v3.preset.js |
2,915 B | 54 | Tailwind CSS v3用のプリセット設定ファイルです |
バンドルを構築するための設計やツール類(アプリケーションにはコピーされません):
| ファイル | サイズ | 内容 |
|---|---|---|
README.md |
6,592 B | リポジトリの説明書 |
AGENTS.md |
19,063 B | AIエージェント向けのインストール手順を記述した文書 |
CHANGELOG.md |
4,425 B | バージョン履歴(1.0.0が最初のリリースです) |
CLAUDE.md |
1,498 B | Claude用のリポジトリ利用規則 |
CONTRIBUTING.md |
4,476 B | テーマ開発に関するガイドライン |
LICENSE |
1,067 B | MITライセンス。著作権は2026年に帰属します(元のファイルでは著者名が個人名で記載されていますが、サイト上ではブランド名が使用されており、ディスク上の文字列は元のLICENSEファイルに記載されています)。ダウンロード用ZIPファイルには含まれていません(元の著作権記述では著者名が個人名で記載されており、サイト側のコンテンツ保護機能がこれを「確認不可能な個人情報の開示」と見なしているためです)。 |
docs/TOKENS.md |
15,391 B | 各グループごとの全トークン一覧 |
docs/COMPONENTS.md |
13,889 B | 各コンポーネントクラスとそのマークアップ例 |
docs/THEMES.md |
8,081 B | 各テーマ、デザインに関する注意点、テーマの追加方法 |
docs/INTEGRATIONS.md |
10,604 B | 各フレームワーク向けのインストール手順 |
docs/TEXT.md |
5,465 B | テキスト階層やMarkdown記法について |
docs/UPDATING.md |
4,134 B | アップデート方法、バージョン固定の仕方、キャッシュの利用法、チェックサムの役割など |
docs/contrast-report.md |
124,372 B | コントラスト評価結果(10種類のテーマ×147~171行分) |
docs/theme-template.css |
9,854 B | tools/sync_theme.py用の空のテーマテンプレート |
tokens/<theme>.json |
各約57 KB | 各テーマのW3C DTCG形式JSONによるトークン定義 |
examples/static-html/ |
3,731 B(indexファイル) | シンプルなHTML/CSS/JSの例 |
examples/fastapi-jinja/ |
2,172 B(app.pyファイル) | FastAPIとJinjaを使用した例 |
specimen/index.html |
17,721 B | すべてのテーマにおける各コンポーネントのプレビュー(ローカルで閲覧可能) |
tools/check_contrast.py |
43,171 B | コントラスト評価用スクリプト(CI環境で実行されます) |
tools/lint_colors.py |
22,711 B | アプリケーションのCSS内にある色指定記述をチェックするスクリプト |
tools/sync_theme.py |
41,671 B | src/css/*.cssからui-theme.css、tokens/*.json、docs/contrast-report.mdを再生成するスクリプト |
tools/update.py |
16,081 B | インストール・検証用スクリプト(ui-theme/update.pyと同様の機能を持ちます) |
tools/screenshots.py |
3,273 B | docs/images/用のテーマプレビュー画像を生成するスクリプト |
tests/test_tools.py |
17,606 B | Python単体テスト(このクローン版では32件のテストがあり、1件がスキップされています) |
tests/run_browser_tests.py |
3,570 B | 実行時環境を対象としたヘッドレスChromeテスト用スクリプト |
tests/runtime.html |
24,930 B | ブラウザテスト用のテストフレームワーク |
.github/workflows/ci.yml |
— | CI設定:コントラストチェック、node --check、単体テスト、ブラウザテスト、CRLFチェックをLinux・Windows・Python 3.9環境で実行します |
このリポジトリ自体のCIでは、3つのジョブが実行されます(checksはUbuntu上でPython 3.12を使用、tools-on-windowsはWindows上でPython 3.11を使用、updater-on-oldest-pythonはUbuntu上でPython 3.9を使用)。ローカルにクローンした環境では、配布されるすべてのJSファイルに対してnode --checkが正常に実行され、コントラストツールでも監査結果の10行すべてが正しく再現されます。また、単体テストも問題なく通過しています(Linux環境、Python 3.14にて2026年10月5日に実施され、32 passed, 1 skipped in 1.212 sとなりました)。
デザイントークン(グループ、役割、例示値)
どのテーマでも、すべてのトークンが解決されます。以下に記載されている値はパープルテーマのもの(:root ベース)です。他のテーマにおいても、tokens/<theme>.json(DTCG形式のJSONファイル)内にそれぞれ独自の解決済み値が定義されています。var(--名前)を使ってトークンを利用してください。アプリケーションのCSS内でトークンを再定義してはいけません。アプリケーション用の変数にはアプリ固有の接頭辞(--myapp-sidebar-wなど)を付けるか、またはトークンの別名として定義する必要があります(例:--myapp-brand: var(--accent))。出典:docs/TOKENS.md。
| グループ | トークン | 役割 | 例(紫色) |
|---|---|---|---|
| サーフェス | --surface-void |
ページよりも暗い色(フルブリード) | #08080f |
| サーフェス | --surface-0 |
ページ自体 | #0e0e1b |
| サーフェス | --surface-1 |
ナビゲーション | #14142a |
| サーフェス | --surface-2 |
カード類 | #1d1d39 |
| サーフェス | --surface-3 |
ホバー時の状態 | #232342 |
| サーフェス | --surface-4 |
アクティブな状態 | #262648 |
| サーフェス | --surface-sunken |
くぼんだ領域 | #0a0a14 |
| サーフェス | --surface-overlay |
メニューやポップオーバー | #1d1d39 |
| サーフェス | --glass-1/2/3 |
半透明なパネル | rgba(29,29,57,.72/.84/.92) |
| サーフェス | --glass-highlight |
ガラスの光沢効果 | rgba(255,255,255,.055) |
| サーフェス | --code-bg |
コードの背景色 | #0b0b16 |
| テキスト | --text-primary |
主要なテキスト | #e8e8f0 |
| テキスト | --text-secondary |
ラベルや説明文 | #a0a0bd |
| テキスト | --text-tertiary |
ヒントや時刻情報 | #8d8db0 |
| テキスト | --text-disabled |
無効なコントロール用のテキスト | #717195 |
| テキスト | --text-inverse |
明るい背景上のテキスト | #0e0e1b |
| テキスト | --text-link / --text-link-hover |
リンクやアクセント用テキスト | #a78bfa / #c4b5fd |
| テキスト | --on-accent / --on-danger / --on-success / --on-warning / --on-media / --on-media-muted |
各種背景色上のテキスト | #ffffff / #2a0808 / … |
| アクセント | --accent / --accent-hover / --accent-pressed |
ブランドカラーや主要なアクション用 | #7c3aed / #8250f0 / #6d28d9 |
| アクセント | --accent-subtle / --accent-muted / --accent-glow |
淡い背景色や光沢効果 | rgba(124,58,237,.16/.26/.35) |
| アクセント | --accent-rgb |
JavaScriptで使用するためのRGB値 | 124,58,237 |
| アクセント | --accent-2 / --accent-2-subtle |
二次的なアクセント色 | #5eead4 |
| CTA | --cta / --cta-hover / --cta-pressed / --on-cta |
強力なアクション用の要素 | #7c3aed / #8250f0 / #6d28d9 / #ffffff |
| CTA | --cta-shadow / --cta-shadow-hover |
ドロップシャドウ効果 | 0 6px 20px rgba(124,58,237,.28) / .38 |
| CTA | --highlight / --highlight-subtle / --on-highlight |
マークやヒント用の色 | #fcd34d / rgba(252,211,77,.12) / #251a00 |
| 線 | --border-subtle / --border / --border-strong |
フォームコントロールの枠線。--border-strongは3:1のコントラスト比 |
#21213b / #292945 / #6f6f9c |
| 線 | --divider |
細い分割線 | #21213b |
| 線 | --focus-ring / --focus-ring-width / --focus-ring-offset |
フォーカスリングの設定 | #a78bfa / 2px / 2px |
| 線 | --glass-stroke / --glass-stroke-strong |
ガラス風の枠線 | rgba(255,255,255,.08/.16) |
| コントロール状態 | --selected / --on-selected |
選択済み/チェック済み/アクティブな状態 | テーマごとに異なる |
| コントロール状態 | --unselected-border / --unselected-fg |
未選択時の枠線や色。各サーフェス上で3:1のコントラスト比 | テーマごとに異なる |
| ステータス | --success / --warning / --danger / --info |
状態を示すドットやバー、塗りつぶし色 | テーマごとに異なる |
| ステータス | --success-text / --warning-text / --danger-text / --info-text |
各ステータスにおけるテキスト色 | テーマごとに異なる |
| ステータス | --success-subtle / --warning-subtle / --danger-subtle / --info-subtle |
各ステータスの淡い背景色 | テーマごとに異なる |
| ステータス | --success-border / --warning-border / --danger-border / --info-border |
各ステータス用の枠線 | テーマごとに異なる |
| ステータス | --idle / --idle-text / --idle-subtle / --idle-border / --idle-hover |
中立的な状態 | テーマごとに異なる |
| ステータス | --live / --live-text / --live-subtle / --live-border / --live-hover |
「実行中」を示すインジケーター | テーマごとに異なる |
| コード/構文 | --syn-bg / --syn-fg / --syn-comment / --syn-keyword / --syn-string / --syn-number / --syn-function / --syn-attr / --syn-tag / --syn-builtin / --syn-type / --syn-variable / --syn-literal / --syn-operator / --syn-title / --syn-addition |
構文ハイライト用の色 | テーマごとに異なる |
| コード/構文 | --code-header-bg / --code-stroke |
コードブロックの枠線や背景。全てのテーマで暗色 | テーマごとに異なる |
| チャート | --cat-1 … --cat-12 |
各シリーズ用の色。--surface-0上で3:1のコントラスト比 |
テーマごとに異なる |
| チャート | --seq-1 … --seq-5 |
低から高へ変化する色のグラデーション | テーマごとに異なる |
| チャート | --div-1 … --div-5 |
悪い/中立/良いを示す色 | テーマごとに異なる |
| チャート | --chart-grid / --chart-axis |
チャートの枠線や軸 | テーマごとに異なる |
| バブル | --bubble-user-text / --bubble-assistant-text / --bubble-user-bg / --bubble-assistant-bg |
チャット用のバブル | テーマごとに異なる |
| バブル | --rp-speech / --rp-thought / --rp-shout / --rp-whisper / --rp-ooc / --rp-action / --rp-critical |
ロールプレイ用のバブル色 | テーマごとに異なる |
| 差分表示 | --diff-add-bg / --diff-add-text / --diff-remove-bg / --diff-remove-text |
差分表示用の色 | テーマごとに異なる |
| タイポグラフィ | --fs-xs / --fs-sm / --fs-md / --fs-lg / --fs-xl / --fs-2xl |
フォントサイズ | テーマごとに異なる |
| タイポグラフィ | --fw-medium / --fw-semibold / --fw-bold |
フォントの太さ | テーマごとに異なる |
| タイポグラフィ | --font-sans / --font-mono / --font-display |
使用するフォント群 | テーマごとに異なる |
| 余白 | --space-1 … --space-8 |
4~64ピクセルの余白値 | テーマごとに異なる |
| 角丸度 | --radius-sm / --radius-md / --radius-lg / --radius-pill |
コントロールの角の形状 | テーマごとに異なる |
| シャドウ | --shadow-1 / --shadow-2 / --shadow-3 / --shadow-4 |
ドロップシャドウの強度 | テーマごとに異なる |
| Zレイヤー | --z-modal / --z-toast / --z-popover / --z-nav |
要素の重なり順序 | テーマごとに異なる |
| アニメーション | --motion-fast / --motion-med / --motion-slow / --easing-standard |
アニメーションのタイミング。減速設定ではループが停止します | テーマごとに異なる |
| Markdown | --md-bold / --md-italic / --md-bolditalic / --md-bolditalic-glow |
アプリ内で使用するMarkdown用の装飾 | テーマごとに異なる |
| その他 | --mark-bg / --selection-text / --selection-bg / --media-filter / --quote-bar / --heartbeat-text / --heartbeat-hover / --offline-text / --on-offline / --canvas-handle |
その他の小さな機能用の設定 | テーマごとに異なる |
出典: docs/TOKENS.md(22のグループ、約270個のトークン。grep -oE '\| \(--[a-zA-Z][a-zA-Z0-9-]*)` |' docs/TOKENS.md | sort -u | wc -l`の実行結果は272個のユニークなトークン名となります)。
コンポーネントクラス(各修飾子ごとに1行ずつ)
状態はネイティブな属性(disabled、checked、aria-pressed、aria-selected、aria-current、aria-invalid、aria-busy、または [open])から取得します。追加のクラスは一切使用しません。ほとんどのセレクタは単一のクラスで構成されており、後から適用される同等の優先度を持つアプリ側のルールが有効になります。論理プロパティも全て使用可能で、右から左へ読む言語にも対応しています。「オン」「チェック済み」「押下中」「現在選択中」の状態には--selectedが適用され、「オフ」状態では枠線のみが表示されます。無効な状態では点線の枠線となり、塗りつぶしはありません。出典: docs/COMPONENTS.md。
| クラス | 修飾子/構成要素 | 説明 |
|---|---|---|
ui-stack |
— | 縦方向の配置。--space-3の間隔を設定 |
ui-row |
— | 折り返し可能な横並び。中央揃えで、--space-2の間隔 |
ui-grid |
--ui-grid-min |
自動的に列を生成。minは要素上に指定 |
ui-container |
— | 中央配置され、--content-maxの最大幅となる |
ui-spacer |
— | 行内の残り部分を最後へ押しやる役割 |
ui-app |
__header __nav __main |
アプリシェル(ヘッダー、サイドナビ、メインコンテンツ)。760ピクセル以下ではナビが非表示に |
ui-brand |
— | ヘッダー内のアプリタイトル |
ui-nav |
__label __item |
サイドナビゲーション |
ui-title / ui-heading / ui-subheading / ui-lead / ui-kicker / ui-small / ui-mono / ui-num / ui-kbd / ui-code / ui-divider |
— | テキストの階層。<hr>は.ui-dividerとして機能 |
ui-text-primary / -secondary / -tertiary / -disabled / -link |
— | テキスト階層用クラス。新規コードではトークンをご利用ください |
ui-markdown |
— | レンダリング済みMarkdownのコンテナ。docs/TEXT.mdも参照ください |
ui-btn |
--primary --ghost --outline --danger --cta --sm --lg --icon --block |
ボタン。<a>要素にも適用可能。aria-pressed、aria-busy、disabledと組み合わせてご使用ください |
ui-btn-group |
— | 隣接するボタンが角を共有する設定 |
ui-field |
— | フォームフィールドのコンテナ(ラベル+コントロール+ヘルプ文) |
ui-label |
— | フィールドのラベル |
ui-input |
--sm |
テキスト入力欄 |
ui-select |
— | スタイル付き<select>。data-ui-theme-pickerを指定するとテーマピッカーが表示されます |
ui-textarea |
— | スタイル付き<textarea> |
ui-help |
— | フィールドの補足説明(aria-describedbyと連動) |
ui-error |
— | フィールドのエラーメッセージ(aria-describedbyと連動)。aria-invalid="true"の際に表示されます |
ui-input-group |
— | 入力欄とボタンを組み合わせた構成(例:検索欄) |
ui-check |
— | チェックボックス/ラジオボタン/スイッチの行 |
ui-checkbox |
— | ネイティブな<input type="checkbox">にスタイルを適用 |
ui-radio |
— | ネイティブな<input type="radio">にスタイルを適用 |
ui-switch |
— | role="switch"を持つチェックボックスで、スイッチ風の見た目となる |
ui-switch-state |
data-on data-off |
「オン」/「オフ」のラベル(aria-hidden)。スイッチ自体が状態を通知します |
ui-range |
— | ネイティブな範囲選択コントロール。--slider-colorで色付けされます |
ui-segmented |
— | ラジオボタンのように振る舞うボタン群 |
ui-tabs |
ui-tab |
タブリスト(<a aria-current="page">を使用したリンク型タブ)。キーボード操作はアプリ側で実装が必要です |
ui-card |
__header __title __footer --raised --interactive |
カード。aria-selectedやaria-currentにより選択中のカードが強調されます |
ui-well |
— | くぼんだ領域(ログやプレビュー、補助的なコンテンツ用) |
ui-stat |
__label __value |
ラベルと値を組み合わせた構成 |
ui-badge |
--success --warning --danger --info --live --accent --neutral |
丸型のバッジ |
ui-dot |
--success --warning --danger --info --live --neutral |
ステータスを示すドット |
ui-count |
--accent --danger |
カウンター用のチップ |
ui-callout |
--info --success --warning --danger __title |
色付きの注意喚起用要素。エラー時はrole="alert"をご使用ください |
ui-table-wrap |
— | <table class="ui-table">を包み込み、ヘッダーの固定やスクロールを可能に |
ui-table |
--hover --compact td.num |
テーブル用のスタイル |
ui-dialog |
— | スタイル付き<dialog> |
ui-drawer |
— | <dialog>上に表示されるサイドシート |
ui-menu |
__item |
メニュー項目群 |
[data-ui-tooltip] |
data-ui-tooltip-side="bottom" |
任意の要素にツールチップを設定 |
ui-progress |
— | 線形のプログレスバー |
ui-spinner |
— | 読み込み中を示すスピナー |
ui-skeleton |
— | ローディング時のスケルトン表示 |
ui-breadcrumbs |
— | パンくずリスト |
ui-pagination |
— | ページネーション |
ui-avatar |
— | 円形のアバター |
ui-chip |
__remove |
削除や選択が可能なチップ |
ui-details |
— | <details>を使ったアコーディオン |
ui-fieldset |
— | フィールドセットと説明テキスト |
ui-codeblock |
__bar |
<figure>内に<figcaption class="ui-codeblock__bar">と<pre>を含む構成 |
ui-empty |
— | 空状態用の表示 |
ui-bubble |
--user --assistant |
チャット用のバブル |
window.UIThemeおよびwindow.UIComponentsに備わる公開メソッド
出典: ui-theme/ui-theme.d.ts(両グローバルオブジェクトに関するTypeScriptの宣言内容)。
window.UITheme(UIThemeApi):
| メンバー | 型 | 役割 |
|---|---|---|
version |
string(読み取り専用) |
フォルダーのバージョン。例:"1.0.0" |
config |
object(読み取り専用) | { themes, default, auto, storageKey, families, printTheme } |
current() |
() => string |
現在アクティブなテーマのスラッグ |
theme([slug]) |
(slug?) => UIThemeInfo \| null |
指定したテーマ(または現在のテーマ)に関する情報 |
list() |
() => UIThemeInfo[] |
有効になっているすべてのテーマ |
set(slug) |
(slug) => string |
指定したテーマに切り替える。切り替えた後のスラッグを返す |
reset() |
() => string |
デフォルトのテーマに戻す。戻した後のスラッグを返す |
partner([slug]) |
(slug?) => string \| null |
同じファミリー内にあるライト/ダーク版のテーマ名(例:laserlloyd ↔ laserlloyd-light) |
toggleFamily() |
() => string \| null |
ライト/ダーク版のテーマ間を切り替える。切り替えた後のスラッグを返す |
onChange(listener) |
(fn) => () => void |
変更を監視するための登録を行う。登録解除用の関数も返す。detail.printは印刷時の切り替えを示す値となる |
token(name, [el]) |
(name, element?) => string |
指定したトークンの実際の値(例:"#7c3aed")を取得する |
tokens(names, [el]) |
(names, element?) => Record<name, string> |
複数のトークン値を一度に取得する |
color(name) |
(name) => string |
キャンバス上で使用される色を rgb()形式で返す |
colors(names) |
(names) => Record<name, string> |
複数の色をキャンバス用に一度に取得する |
mountPicker(target, [opts]) |
(elOrSel, options?) => HTMLSelectElement \| null |
セレクト要素をテーマ選択用のピッカーとして設定する。optionsには { label, coreLabel, optInLabel, systemLabel }を指定できる |
ui-theme-changeイベントは document上で発火し、引数には { slug, theme, previous, print }が含まれます。
window.UIComponents(UIComponentsApi):(ui-components.jsが必要)
| メソッド | シグネチャ | 役割 |
|---|---|---|
confirm |
(opts: UIDialogOptions \| string) => Promise<boolean> |
テーマ対応の confirm()。オプションは { title, message, label, confirmLabel, cancelLabel, danger }となる |
alert |
(opts: UIDialogOptions \| string) => Promise<void> |
テーマ対応の alert() |
prompt |
(opts: UIPromptOptions \| string) => Promise<string \| null> |
テーマ対応の prompt()。キャンセル時は nullとなる。追加オプションとして { value, placeholder, type }がある |
toast |
(message, { kind?, timeout? }) => HTMLElement |
info/success/warning/dangerの種類を指定できるトーストを表示し、生成された要素を返す |
window.UI_THEME_MANIFEST(任意設定。スクリプトタグで指定した値より優先される):{ themes, default, defaultDark, defaultLight, storageKey, families, legacy, mirrorAttr, fontsHref, printTheme }。themesには配列またはカンマ区切りの文字列を指定できます。
スクリプトタグで指定可能なオプション(<script>タグ上の data-*属性)
| 属性 | デフォルト値 | 役割 |
|---|---|---|
data-themes |
6つのコアテーマ(purple,midnight-gold,glacier,forest,paper,daylight) |
有効にするテーマをカンマ区切りで指定。ピッカーの表示内容や保存される値の基準となる。data-themesが未設定の場合、ui-theme.jsでは set==="core"として6つのテーマが有効化される(ui-theme.js:147-149) |
data-default |
有効なテーマの中で最初のもの(data-themes内の最初のスラッグ、または有効なテーマがなくかつ autoでもない場合は purple) |
デフォルトのテーマスラッグ。autoを指定するとOSの設定に従う。文字列 auto自体が prefers-color-schemeを用いたOS設定の追随を示す(ui-theme.js:164)。属性が空または未指定の場合は最初に有効なテーマが選ばれる(ui-theme.js:177-179) |
data-default-dark |
有効なテーマの中で「light」でない最初のテーマ(ground !== "light"となるスラッグ)。該当するものがなければ最初に有効なテーマ、それもなければ purple |
autoモードにおけるダーク側のテーマ。ui-theme.js:168-175ではOSがダークモードを推奨しておりかつ明示的な値が指定されていない場合にこれが選ばれる |
data-default-light |
有効なテーマの中で「light」である最初のテーマ(ground === "light"となるスラッグ)。該当するものがなければ最初に有効なテーマ、それもなければ purple |
autoモードにおけるライト側のテーマ。同じコードパスを利用する(ui-theme.js:168-175) |
data-storage-key |
ui-theme |
ユーザーの選択内容が保存される localStorage上のキー名(ui-theme.js:185)。AGENTS.md §3では <appname>.theme に上書きすることを推奨しており、同じオリジン上で複数のThemeForgeアプリが存在しても衝突しないようにするためである |
data-families |
false |
ピッカー内でテーマをファミリー単位にグループ化するかどうか |
data-print-theme |
auto |
ページの印刷時に使用するテーマ。autoの場合、現在のテーマがダークまたはOLED系であればそのファミリー内のライト版テーマ(または最初に有効なライトテーマ、それもなければ daylight)に切り替わる。特定のスラッグを指定すればそのテーマが印刷用に使用される。noneを指定すると切り替えは行われない。現在のテーマがライト系であればそのまま印刷される(ui-theme.js:474-490) |
data-legacy-key |
— | 一度だけ移行処理を行うための旧式のストレージキー(data-legacy-mapと併用) |
data-legacy-map |
— | 旧値から新値への対応表(JSON形式) |
data-mirror-attr |
— | 現在選択中のテーマ情報を別の属性にも反映させるための設定(他ライブラリがその属性を参照する場合向け) |
data-fonts-href |
— | テーマ専用のフォントスタックを読み込むためのスタイルシートのURL |
出典:ui-theme.js:147-149, 164, 168-174, 185, 474-490(実行時のデフォルト値)および AGENTS.md §3、§12(推奨される上書き方法。例として data-themesには6つのコアテーマを、data-default="auto"とし、data-storage-key="<appname>.theme"とするなどが挙げられます)。
アダプター
| アダプター | ファイル | 役割 |
|---|---|---|
| NiceGUI/Quasar | adapters/quasar.js+adapters/quasar.css |
ui-theme.jsの直後に adapters/quasar.jsを、また ui-theme.cssの直後に adapters/quasar.cssを読み込みます(ui.add_head_htmlを用いる)。Quasar側のトグルやチェックボックス、ラジオボタンは制御状態に応じたデザインとなり、無効化されたコントロールは不透明度100%で点線表示されます。ui.dark_mode()の呼び出しは不要です。アダプター側で処理されます |
| Tailwind CSS v4 | adapters/tailwind.css |
@import "tailwindcss";の後に @import "./<path>/ui-theme/adapters/tailwind.css";と記述します。bg-surface-2、text-fg、text-fg-muted、bg-accent、text-on-accent、border-lineなどのトークンが利用可能になります。テキスト系の色指定には fg-*を用いる必要があります。これは text-*で指定されるサイズ表記がTailwind側の規定に属するためです |
| Tailwind CSS v3 | adapters/tailwind-v3.preset.js |
presets: [require('./<path>/ui-theme/adapters/tailwind-v3.preset.js')]と記述します。v4アダプターと同じトークンが定義されており、これらはTailwind v3用のプリセットとして表現されます |
Tailwind用アダプターはテーマのトークンをマッピングし、Quasar用アダプターはコンポーネントクラスをマッピングします。どちらも本バンドルの動作に必須ではありません。
完全なインストール手順(AGENTS.mdよりそのまま引用)
AGENTS.mdはAIコーディングエージェント向けに記述されたインストール手順書です。以下に最初の2セクションを全文掲載します。これがAIエージェントに提示されるプロンプトとなります。文字列は article-forgeスキルの§8ルールに従いエスケープされています(<blockquote>内ではMarkdownがそのまま解釈されるため、<、>、&はそれぞれ <、>、&として記述されています)。
## 1. 一度だけ決める事項 | 質問 | デフォルトの回答 | |---|---| | フォルダーをどこに配置するか? | アプリケーションの静的ファイル用フォルダー内にそのまま設置。例:`static/ui-theme/`(Flask、FastAPI、Django)、`public/ui-theme/`(Vite、Next.js、Create React App)、`app/static/ui-theme/`、または単純なサイトの場合は `index.html`と同じ場所 | | どのテーマを有効にするか? | 6つのコアテーマ:`purple,midnight-gold,glacier,forest,paper,daylight`。ユーザーから要望があった場合のみオプトイン用テーマ(`night-red`、`electric-yellow`、`laserlloyd`、`laserlloyd-light`)を追加してもよい | | デフォルトのテーマは? | `auto`:訪問者のOS設定に基づくライト/ダークモードが適用され、ユーザーが手動で選択するまでその状態が維持される(`data-default-dark="midnight-gold"`、`data-default-light="daylight"`と指定) | | ストレージキーは? | `<appname>.theme`例:`notes.theme` | ## 2. インストール アプリケーションのルートフォルダーから実行します(Python 3.9以降が必要。`static/ui-theme`は先ほど決めた配置場所に置き換えてください):Windows環境では `python`または `py`を `python3`の代わりに使用します。PowerShell、cmd、bashでも記述は同一です。このコマンドによりインストーラーがダウンロードされ、GitHub上の最新リリース内容が取得された後、各ファイルのチェックサムと照合してフォルダー内に書き込まれます。以降の更新時には `python3 static/ui-theme/update.py`を実行します。オフライン環境では別途リリースアーカイブ(`.tar.gz`)を入手し、`update.py`が含まれる `ui-theme/`フォルダー内から `python3 update.py --source <archive> --dest static/ui-theme`と実行します。 Pythonが利用できない場合の代替手段: - **git:** `git clone --depth 1 https://github.com/LaserLloyd/ThemeForge.git ut-tmp`としてフォルダーを作成し、`ut-tmp/ui-theme`をアプリケーション内にコピーした後 `ut-tmp`を削除します - **Node:** `npx degit LaserLloyd/ThemeForge/ui-theme#v1.0.0 static/ui-theme`と実行します - **インストール不要(プロトタイプや単一HTMLファイル向け):** jsDelivrから特定のリリース版を指定してファイルを読み込みます。例:`https://cdn.jsdelivr.net/gh/LaserLloyd/ThemeForge@v1.0.0/ui-theme/ui-theme.js`(各CSSファイルも同様のパスで指定)。`@main`を指定しないようご注意ください。CDNでは最大12時間程度キャッシュされるためです。CDN上のページ内容は固定バージョン番号を変更することで更新できますが、この場合 `update.py`や下記8.5、9、10の手順は適用されません。python3 -c "import urllib.request as u,sys;sys.argv=['update.py','--dest','static/ui-theme'];exec(u.urlopen('https://raw.githubusercontent.com/LaserLloyd/ThemeForge/main/ui-theme/update.py').read())"
AGENTS.mdの残りのセクション(3~12)ではヘッドブロックの記述方法、ピッカーの実装例、トークンからの構築手順、各種ルール、チャート関連情報、検証方法、次のエージェントが同じ規約を継続できるようアプリケーション内の AGENTS.mdに追記すべき行、更新コマンド、トラブルシューティング表、そして上記の参照一覧などが説明されています。
コントラストチェック(各テーマの要約)
tools/check_contrast.pyはCI環境において各プッシュごとに実行されます。完全なレポートは docs/contrast-report.mdとして124KB程度存在し、各テーマごとの詳細と全体の要約が記載されています。その要約部分は以下の通りです。
| テーマ | セット | プロファイル | チェック数 | 失敗数 |
|---|---|---:|---:|
| purple | core | standard | 147 | 0 |
| midnight-gold | core | standard | 147 | 0 |
| glacier | core | standard | 147 | 0 |
| forest | core | standard | 147 | 0 |
| paper | core | standard | 147 | 0 |
| daylight | core | standard | 147 | 0 |
| electric-yellow | opt-in | standard | 147 | 0 |
| laserlloyd | opt-in | standard | 147 | 0 |
| laserlloyd-light | opt-in | standard | 147 | 0 |
| night-red | opt-in | night | 171 | 0 |
すべてのテーマが満たすべき基準:本文は7:1、補助的なテキストは6:1というコントラスト比を確保する必要があります(コントラストレポート内では「契約上の6:1要件」と表現され、docs/contrast-report.mdでは text-secondary on surface-2の各行にこの文言が付記されています)。その他にも、あらゆるテキスト階層は surface-2上で4.5:1以上、無効化されたコントロールは3:1以上、アクセント色やステータス関連の背景上のテキストも4.5:1以上、選択状態下のテキストは4.5:1以上、各種表面における選択中・未選択時の境界線や前景色も3:1以上、強調用の境界線やコントロールのトラック、フォーカスリングも3:1以上、構文ハイライト用の --syn-bg上の色は4.5:1以上(コメント部分は3.5:1以上)となります。形状によるオン/オフの区別としては、「オン」状態のコントロールには --selected色が塗られ、「オフ」状態のコントロールは --unselected-border色で輪郭のみが描かれます。スイッチ型の場合「オン」時にはノブにバーが付加され、「オフ」時にはリングが追加されます。無効化されたコントロールは、たとえオン状態であっても不透明度100%の点線で描かれます。
各種フレームワーク向け対応
docs/INTEGRATIONS.mdに記載されている通り、純粋なHTML、FastAPI・Flask・Starlette(Jinjaテンプレート)、Django、Vite、Vue、Svelte、SvelteKit、Astro、Next.js(app router)、NiceGUI(Quasar)、Tailwind CSS、Electron、Tauri、pywebview、フォント関連、チャート関連、Content Security Policyといった環境がサポート対象です。各フレームワークにおいては、ui-theme/を静的ファイル用のディレクトリ内に配置し、AGENTS.md §3で示されている順序通りにヘッドブロックを追加してください。また更新内容が即座に反映されるよう、そのフォルダーにはキャッシュ制御を施すかバージョン付きのURLを用いることが推奨されます。リポジトリ内には具体的な実装例として examples/static-html/(単一ページ用)および examples/fastapi-jinja/(FastAPI+Jinjaで、app.pyは2,172バイトのみ)が用意されています。
印刷・コントラスト・アニメーション
実行時環境では以下の3つの事象を監視しており、それぞれCSS側でも対応しています。なおこれらにはテーマごとの個別フラグは存在しません。
-
印刷機能 —
data-print-theme属性により、何が印刷されるかが制御されます(ui-theme.js:474-490)。現在選択されているテーマがダークテーマまたはOLEDテーマの場合、autoと設定すると該当ファミリー内のライトテーマに自動的に切り替わります(有効なライトテーマが複数ある場合は最初のもの、それもなければdaylightテーマが使用されます)。noneを指定すると切り替えは行われません。現在選択されているテーマがライトテーマの場合は、そのままページが印刷されます。印刷時にはサイドナビゲーション、トースト通知、メニュー、ドロワー、ツールチップなどは非表示になります。 -
prefers-contrast: more— すべてのテーマにおいて、線の太さがコントロール要素の境界線に近い強度まで増加し、三次色レベルのテキストも二次色レベルへと引き上げられます。 -
prefers-reduced-motion— アニメーションのループが停止し、その持続時間も短縮されます。また、--motion-*で定義される値はすべて0になります。
バージョン情報
この記事で説明しているリポジトリの最新状態(2026年10月5日にクローン取得)より:
$ git log -1 --format='%h %ci'
56fb665 2026-10-05 21:46:52 +0900 # ThemeForge 1.0.0
$ cat ui-theme/VERSION
ThemeForge 1.0.0 3db64d9f574f
$ wc -c ui-theme/*.js ui-theme/*.css ui-theme/*.ts ui-theme/*.py 2>/dev/null
23515 ui-theme.js
5441 ui-components.js
2841 ui-theme.d.ts
16081 update.py
13255 ui-theme-base.css
51344 ui-components.css
86389 ui-theme.css
$ node --check ui-theme.js ui-components.js
(node v24.18.0) — 両ファイルとも問題なし。adapters/quasar.jsおよびadapters/tailwind-v3.preset.jsも同様に問題なし。
$ python -m unittest discover -s tests
32個のテストを1.212秒で実行しました。
OK(スキップされたテスト:1件)
$ python tools/check_contrast.py --fail-on any
…
## 概要
| テーマ | セット | プロファイル | チェック数 | 失敗数 |
| purple | core | standard | 147 | 0 |
| midnight-gold | core | standard | 147 | 0 |
| glacier | core | standard | 147 | 0 |
| forest | core | standard | 147 | 0 |
| paper | core | standard | 147 | 0 |
| daylight | core | standard | 147 | 0 |
| electric-yellow | opt-in | standard | 147 | 0 |
| laserlloyd | opt-in | standard | 147 | 0 |
| laserlloyd-light | opt-in | standard | 147 | 0 |
| night-red | opt-in | night | 171 | 0 |
対応ブラウザ:現在のChrome、Edge、Firefox、Safari(2024年以降版)。本機能は :has()、color-mix()、およびポップオーバーAPIを利用しています。古いブラウザでも色自体は維持されますが、一部のコンポーネントの状態やメニュー機能が正しく表示されなくなる場合があります。
関連記事: ChatForge:Copilot Key向けのローカルNPU AIアシスタント · StudioForge:GPU専用LLMサーバー · DisPatch:自己ホスティング型AIチャット · 私のローカルAIエージェントスタック · LLMを利用して任意のプロジェクトを自身のシステムに適応させる方法
ダウンロード
個人利用は無料です。役に立ったら、コーヒーをおごってもらえると嬉しいです。