# dsh-theme-palette

[English](README.md) · [中文](README-zh.md) · [日本語](README-ja.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)

DeepSeek Harness（Web / デスクトップ）向けの配色プラグイン：**4 つのプリセット + カスタム配色 × ライト/ダーク**、2 つの軸は互いに独立しています。

![設定ページ：5 つの配色、強さ、パネル面](assets/screenshot-settings-light.png)

*上の画像は実機のパネル幅（内容領域 564 px）で静的に描画したものです。*

| ダーク | カスタムパネル | ハイコントラスト |
|---|---|---|
| ![ダーク](assets/screenshot-settings-dark.png) | ![カスタムパネル](assets/screenshot-settings-custom.png) | ![ハイコントラスト](assets/screenshot-settings-hc.png) |

## Compatibility

| 項目 | 状態 |
|---|---|
| DSH デスクトップ / Web クライアント | 0.2.x |
| Node.js | 22.19.0+（22.x 系）または 24.0.0+ |
| ホストのソースへの変更 | なし |

package.json の `engines` は `^22.19.0 || >=24.0.0` —— 上の表と同じ要件です。

プラグインは `ctx.theme.overrideTokens` で色トークンの層を重ねるだけで、テーマの登録もホストの改変も「外観」設定の変更もしません。

## What it does

- **4 プリセット + カスタム** —— モノクロ / ウォームサンド / インディゴ / モスグリーンがライトとダークをそれぞれ独立に適応し、さらに 3 色から派生するカスタム配色；
- 色階は置き換えではなく**全体を再計算**：OKLCH 再構築 → 役割ごとの彩度 → **sRGB ガマット・クランプ** → 実際の面でコントラストを解く；
- ホストの色トークン：着色パレットで 179（+ プラグイン自前 13）、モノクロで 19（1080 通りの設定を全走査）。**ビルド済み CSS が実際に消費する色トークン 66 個はすべてプラグインに解決されます**：本文、二次、三次、注記、リンク、サイドバー、カード、ユーザー吹き出し、プライマリボタン、スクロールバー、スイッチ、Markdown 見出し/太字、コードブロック、そして**エラー/成功/警告の状態色とファイル diff の +/− 行**（赤/緑/アンバーの三色階が初めて再構築に参加。色相の回転は 8° まで、温度だけを合わせるので意味は変わりません）；
- 調整可：テキストの着色 3 段、サイドバー 3 段、Markdown 強調、スクロールバー、スイッチの配色；
- **カスタム配色**（背景 / テキスト / アクセントの 3 色。テキストの色相も派生に参加し、背景が明確に暗い／明るい場合はそのモードのキャンバス明度になります。極端なアクセントは正規化されます）、**設定のエクスポート/インポート**（`dshs1.` ショートコードに 3 色を含む）、**ハイコントラスト**、UI 4 言語；
- **自己修復**：ホストがオーバーライド層を破棄すると自動で再適用。連続失敗すると自動再適用を停止し、設定ページに「再有効化」の入口を出します；
- **コントラストの約束**：本文はライト 12:1 / ダーク 10:1（ハイコントラスト 15:1）、二次 ≥ 6.2（ライト）/ 8.0（ダーク）、三次 ≥ 4.85（ライト）/ 6.4（ダーク）（HC 7 / 7.6）、リンク ≥ 4.95（ライト）/ 4.62（ダーク）（HC 7。ライト側は色覚特性の余裕を含む）。ダークのリンクはさらに APCA Lc ≥ 60（HC 75）—— いずれもテキストが実際に載る面で実測（ダーク側の要求が厳しいのは、暗い背景では WCAG の比が読みやすさを過大評価するため）；
- 約束する面はライト 00/60 とダーク 950/875。ダークの 800（モジュール面）と 850（サブ面）は**本文を保証しません** —— レポートでは「ポリシー外」として別枠（達成にも未達にも数えない）；
- UI は 简体中文 / 繁體中文 / English / 日本語（ホストに追随、手動固定も可）。

## Install

```bash
# npm から
cd ~/.dsh/profiles/desktop
pnpm add dsh-theme-palette
```

バージョンを固定するには `pnpm add dsh-theme-palette@<version>` —— [CHANGELOG.md](CHANGELOG.md) で「未发布」と付いた節は npm に一度も公開されていないので、それらを固定しないでください。
GitHub Release の tarball から入れる場合：[Releases ページ](https://github.com/zuoyunlai/dsh-theme-palette/releases) で資産を選び `pnpm add <tgz のパス>`。

インストール後は**必ず GUI を再起動**してください（実行中のプロセスは古いモジュールを保持します）。入口は左下のアバター → **設定** → 「**テーマ配色**」。

## Configuration

| 項目 | 選択肢 |
|---|---|
| 配色 | モノクロ · ウォームサンド · インディゴ · モスグリーン（サムネイルはライト/ダークに追随） |
| 強さ | 弱 / 標準 / 強 —— 本文と強調の着色量 |
| パネル面 | 左サイドバー（より明るく / 同色 / より暗く）。右パネルは一切着色しません：ホストのそのパネルは全高の透明オーバーレイで、着色するとメイン列を覆うためです（1.9.10 で経路ごと撤去） |
| その他のオプション | 言語、Markdown 強調、スクロールバー、スイッチ / チェック |

変更は即座に反映され `localStorage` に保存されます。ライト/ダークはホストの「外観」が持ちます。

## Palette engine

```
OKLCH(L, C, hue) ──► ガマット・クランプ（C を二分探索） ──► sRGB hex
        ▲
        └── 役割ごとの彩度 × 強さ、続いて {キャンバス, カード, サイドバー, オーバーレイ} でコントラストを解く
```

- セマンティックな別名は `var(--dsw-static-neutral-bluish-NN)` の参照連鎖を保つので、トークンに追随する要素は配色に追随します；
- ライト面は 00–300、ダーク面は 800–950 を使用；
- テキストの下限はビルド時に強制：本文 ≥ 12:1（ライト）/ 10:1（ダーク）（HC 15:1）、二次 ≥ 6.2 / 8.0（HC 9 / 9.6）、三次 ≥ 4.85 / 6.4（HC 7 / 7.6）、リンク ≥ 4.95 / 4.62（HC 7）、ダークのリンクは APCA Lc ≥ 60（HC 75）。サイドバーと吹き出しの文字は色階から派生し、実測はすべて ≥ 7（独立したコントラスト門は設けない）；
- 約束する面はライト 00/60 とダーク 950/875。ダーク 800（モジュール面）と 850（サブ面）は**本文を保証せず**、レポートで「ポリシー外」として別枠（達成にも未達にも数えない）。ただしどの面も AA の下限 4.5 は満たす必要があります；
- レポートは 3 つを分けて示します：宣言した目標、物理的上限（その面で黒または白の前景が到達できる比）、ポリシー免除。0.93 は求解の余白で、目標が上限を超えているかの判定にだけ使います；
- `node palette-dev.mjs` が 1080 通りの設定（5 配色 × 216 設定、標準/ハイコントラスト両方を含む）を走査して面レポートを表示します。`--hc` でハイコントラスト側に切り替え、ハード失敗時は終了コード 1。

コンポーネントごとの設計判断とコントラスト表は [docs/DESIGN.md](docs/DESIGN.md)、変更履歴は [CHANGELOG.md](CHANGELOG.md)。

## Development

```bash
npm run report                        # 全配色のトークンレポート（-- --hc でハイコントラスト）
npm run sheet                         # 配色ボード → tools/sheet.html
npm run shot-sheet                    # ボードを撮影（ヘッドレス Chrome/Edge）
npm run compare -- --dir tools/out/<run>   # ローカルのベースラインと比較
npm run preview -- --lang en          # 設定ページを描画
npm run contract                      # ホストのトークン / DOM コントラクト（strict：SKIP は失敗）
npm run release -- --dry              # リリースの事前チェック
npm run release -- --tag              # npm へ公開 + タグ
npm run release -- --ci               # CI リリース：タグのみ。公開は Actions の Trusted Publishing
npm run clean                         # ローカルの tarball / tools/out / dist を削除
```

スクリーンショット回帰は 2 層：配色ボード（ログイン不要）と、CDP 経由の実機デスクトップウィンドウ（`tools/shoot-desktop.mjs`、`--remote-debugging-port` が必要）。詳しくは [tools/README.md](tools/README.md)。


## Pitfalls we hit

1.7.0 の監査で最も直感に反した 5 件 —— いずれもスクリーンショットではなくテストが見つけました。

- **純白のアクセントが純白のリンクを生んでいた**（1.13:1）。コントラスト求解器は「背景から遠ざかる」一方向にしか動かず、背景より明るいアクセントは白へ向かう一方でした。
- **色を選ぶとページは変わったがパネルは変わらなかった。** コンポーネントは配色 id を購読しており、色を変えてもそれは変わりません。React はスナップショットを比較して差分なしと判断し、再描画を飛ばしました。
- **設定は共有されたが色は共有されなかった。** ショートコードは各モードを含むがカスタム 3 色を含まず、別のマシンでインポートすると成功と表示しつつローカルの値を残していました。
- **「約束しない」は「できない」ではない。** 旧レポートはダークのモジュール面を「面の上限」と表示していました（本文目標を最も暗い 800 と比較していたため）。しかし 800 でも白前景で約 10.22:1、850 で約 15.27:1 に達し、10:1 の目標を上回ります。物理的に不可能な面はなく、単に約束の範囲外だっただけです。現在は宣言目標・物理的上限・ポリシー免除を分けて示し、800/850 は「ポリシー外」として別枠にしています。
- **死んでいると思っていたセレクタは生きていた。** 監査は当初 `_markdown_` 関連を壊れていると判定しましたが、実際にビルドされた CSS に対するコントラクトテストがそれが残っていることを示しました。誤っていたのは結論で、コードではありません。

## Sharing

すべての設定 —— カスタム 3 色も含めて —— が 1 本のショートコードに入ります。インポート欄に貼り付けて「プレビュー」を押すと、適用前に何が変わるかを確認できます：

```text
dshs1.eyJ2IjoxLCJwIjoiY3VzdG9tIiwicyI6ImRlZXAiLCJ0IjoidGludGVkIiwiYyI6InRpbnRlZCIsImsiOiJhY2NlbnQiLCJtIjoib24iLCJoIjoib2ZmIiwibCI6InpoLUNOIiwieCI6eyJiZyI6IiNmNWVmZTYiLCJ0ZXh0IjoiIzFkMWExNyIsImFjY2VudCI6IiMzZjY2YTMifX0
```

この実例をデコードすると：

- 配色：カスタム · サイドバー：より暗く · テキスト：標準
- スクロールバー：追随 · コントロール：アクセント · Markdown 強調：オン · ハイコントラスト：オフ · 言語：zh-CN
- 3 色：`#f5efe6`（背景）· `#1d1a17`（テキスト）· `#3f66a3`（アクセント）

ショートコードは本番のエンコーダが生成し、デコードの往復で自己検査してからこの文書に入ります —— 手書きはしません。

## Trade-offs

この界隈の他のテーマプラグインはガラス、壁紙、アニメーションを提供します。私たちは意図的にやりません：

- **ガラスも壁紙もやらない。** その競争はスクリーンショットで決まりますが、私たちは証拠で競いたい。
- **テーマ市場も AI 生成色もやらない。** どちらも保証できない色を持ち込みます。コントラスト求解器が資産であり、予測不能な入力を流し込むのは自滅です。
- **配色をこれ以上増やさない。** 4 プリセット + 3 色生成は手選びの 10 セットより強い。数は堀ではありません。
- **目の保護を謳わない。** テキストが実際に載る面での実測比だけを報告し、約束の範囲外の面は「ポリシー外」と書く —— これは説明であって言い訳ではありません。


## License

MIT © 2026 Zuoyunlai
