ui-chan-mcp 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/.claude-plugin/marketplace.json +13 -0
  2. package/.claude-plugin/plugin.json +6 -0
  3. package/.env.example +13 -0
  4. package/LICENSE +36 -0
  5. package/README.md +214 -0
  6. package/agents/mode.md +47 -0
  7. package/agents/talk.md +23 -0
  8. package/bin/ui-chan-mcp.mjs +11 -0
  9. package/bin/ui-chan-node +35 -0
  10. package/bin/ui-chan.mjs +350 -0
  11. package/context/AFFINITY.md +94 -0
  12. package/context/SOUL.md +79 -0
  13. package/context/VOCABULARY.md +108 -0
  14. package/cue.schema.json +109 -0
  15. package/cues/default.json +21 -0
  16. package/cues/emo_anger.json +14 -0
  17. package/cues/emo_anger_hi.json +19 -0
  18. package/cues/emo_anger_lo.json +16 -0
  19. package/cues/emo_antic.json +18 -0
  20. package/cues/emo_antic_hi.json +16 -0
  21. package/cues/emo_antic_lo.json +6 -0
  22. package/cues/emo_disgust.json +19 -0
  23. package/cues/emo_disgust_hi.json +20 -0
  24. package/cues/emo_disgust_lo.json +6 -0
  25. package/cues/emo_fear.json +19 -0
  26. package/cues/emo_fear_hi.json +19 -0
  27. package/cues/emo_fear_lo.json +19 -0
  28. package/cues/emo_joy.json +17 -0
  29. package/cues/emo_joy_hi.json +15 -0
  30. package/cues/emo_joy_lo.json +13 -0
  31. package/cues/emo_sad.json +15 -0
  32. package/cues/emo_sad_hi.json +18 -0
  33. package/cues/emo_sad_lo.json +14 -0
  34. package/cues/emo_surprise.json +15 -0
  35. package/cues/emo_surprise_hi.json +14 -0
  36. package/cues/emo_surprise_lo.json +11 -0
  37. package/cues/emo_trust.json +16 -0
  38. package/cues/emo_trust_hi.json +20 -0
  39. package/cues/emo_trust_lo.json +6 -0
  40. package/cues/idling_doze_1.json +9 -0
  41. package/cues/idling_doze_2.json +9 -0
  42. package/cues/idling_doze_3.json +9 -0
  43. package/cues/idling_giggle_1.json +9 -0
  44. package/cues/idling_giggle_2.json +9 -0
  45. package/cues/idling_lookaround_1.json +10 -0
  46. package/cues/idling_lookaround_2.json +10 -0
  47. package/cues/idling_lookaround_3.json +10 -0
  48. package/cues/idling_ponder.json +9 -0
  49. package/cues/idling_sigh_1.json +11 -0
  50. package/cues/idling_sigh_2.json +11 -0
  51. package/cues/idling_yawn_1.json +9 -0
  52. package/cues/idling_yawn_2.json +12 -0
  53. package/cues/idling_yawn_3.json +12 -0
  54. package/cues/mix_anger_antic.json +16 -0
  55. package/cues/mix_antic_joy.json +16 -0
  56. package/cues/mix_disgust_anger.json +17 -0
  57. package/cues/mix_fear_surprise.json +18 -0
  58. package/cues/mix_joy_trust.json +19 -0
  59. package/cues/mix_joy_trust_hi.json +18 -0
  60. package/cues/mix_sad_disgust.json +12 -0
  61. package/cues/mix_surprise_sad.json +21 -0
  62. package/cues/mix_surprise_sad_hi.json +14 -0
  63. package/cues/mix_trust_fear.json +18 -0
  64. package/cues/pose_arms_crossed.json +9 -0
  65. package/cues/pose_banzai.json +17 -0
  66. package/cues/pose_smug_arms.json +11 -0
  67. package/cues/pose_smug_hips.json +11 -0
  68. package/cues/pose_think.json +8 -0
  69. package/cues/pose_umbrella.json +9 -0
  70. package/cues/self_guilt.json +20 -0
  71. package/cues/self_pride.json +10 -0
  72. package/cues/self_shame.json +19 -0
  73. package/cues/self_shy.json +16 -0
  74. package/cues/self_shy_hi.json +17 -0
  75. package/cues/sys_address.json +9 -0
  76. package/cues/sys_awkward.json +18 -0
  77. package/cues/sys_beam.json +18 -0
  78. package/cues/sys_blank.json +11 -0
  79. package/cues/sys_care.json +18 -0
  80. package/cues/sys_confused.json +12 -0
  81. package/cues/sys_dazed.json +10 -0
  82. package/cues/sys_dread.json +21 -0
  83. package/cues/sys_fluster.json +20 -0
  84. package/cues/sys_intro.json +15 -0
  85. package/cues/sys_laugh.json +20 -0
  86. package/cues/sys_neutral.json +5 -0
  87. package/cues/sys_present.json +9 -0
  88. package/cues/sys_rain.json +15 -0
  89. package/cues/sys_refuse.json +18 -0
  90. package/cues/sys_relief.json +15 -0
  91. package/cues/sys_sleepy.json +8 -0
  92. package/cues/sys_smirk.json +10 -0
  93. package/cues/sys_stream.json +15 -0
  94. package/cues/sys_success.json +15 -0
  95. package/cues/sys_think.json +9 -0
  96. package/dist/app/assets.js +54 -0
  97. package/dist/app/cues.js +130 -0
  98. package/dist/app/editor-main.js +199 -0
  99. package/dist/app/editor-preload.js +17 -0
  100. package/dist/app/main.js +527 -0
  101. package/dist/app/persona.js +136 -0
  102. package/dist/app/preload.js +14 -0
  103. package/dist/app/state.js +850 -0
  104. package/dist/app/tts.js +257 -0
  105. package/dist/mcp-server.js +408 -0
  106. package/dist/renderer/bundle.js +17983 -0
  107. package/dist/renderer/editor.html +150 -0
  108. package/dist/renderer/editor.js +17917 -0
  109. package/dist/renderer/index.html +425 -0
  110. package/dist/shared/paths.js +169 -0
  111. package/dist/shared/set-cue-schema.js +66 -0
  112. package/dist/shared/types.js +14 -0
  113. package/docs/CLIENTS.md +110 -0
  114. package/docs/CUE_AUTHORING.md +76 -0
  115. package/docs/DEVELOPMENT.md +129 -0
  116. package/docs/PERSONA.md +61 -0
  117. package/docs/PSD_LAYERS.md +123 -0
  118. package/docs/README.md +43 -0
  119. package/docs/SETUP.html +684 -0
  120. package/docs/STYLE.md +107 -0
  121. package/docs/TOOLS.md +33 -0
  122. package/docs/TROUBLESHOOTING.md +122 -0
  123. package/docs/TTS.md +61 -0
  124. package/docs/design/CUE_CATALOG.md +259 -0
  125. package/docs/images/faces.png +0 -0
  126. package/docs/images/panel.png +0 -0
  127. package/hooks/fire-event.js +14 -0
  128. package/hooks/hooks.json +77 -0
  129. package/hooks/lib/mascot.js +76 -0
  130. package/hooks/notify.js +15 -0
  131. package/hooks/reaction.js +46 -0
  132. package/hooks/session-start.js +80 -0
  133. package/package.json +96 -0
  134. package/persona/ui-chan.md +111 -0
  135. package/plugins/hermes/ui-chan/__init__.py +98 -0
  136. package/plugins/hermes/ui-chan/plugin.yaml +7 -0
  137. package/plugins/opencode/ui-chan.mjs +105 -0
  138. package/skills/beam/SKILL.md +37 -0
  139. package/skills/eli14/SKILL.md +139 -0
  140. package/skills/eli14/references/base.html +495 -0
  141. package/skills/mode/SKILL.md +67 -0
  142. package/skills/talk/SKILL.md +27 -0
  143. package/tools/setup/check-package.mjs +47 -0
  144. package/tools/setup/clients.mjs +399 -0
  145. package/tools/setup/doctor.mjs +105 -0
  146. package/tools/setup/home.mjs +126 -0
  147. package/tools/setup/prompt.mjs +134 -0
  148. package/tools/setup/update-check.mjs +8 -0
  149. package/tools/setup/update.mjs +350 -0
  150. package/tools/stop-app.mjs +22 -0
  151. package/ui-chan.config.json +973 -0
@@ -0,0 +1,110 @@
1
+ # クライアントへの入れかた
2
+
3
+ > **どのアプリに、何が書き込まれるのかを知りたいとき**に読みます。
4
+ > 入れるだけなら [../README.md](../README.md) で足ります。
5
+
6
+ ---
7
+
8
+ ## `01` 対応クライアント
9
+
10
+ | id | クライアント | 書き込み先 |
11
+ |---|---|---|
12
+ | `claude-code` | Claude Code(MCPサーバ) | `claude mcp add -s user` |
13
+ | `claude-code-plugin` | Claude Code プラグイン(`/talk` `/mode` 等のスキル・サブエージェント・EventCueフック) | `~/.claude/plugins`(インストール後にクローンへ symlink 化) |
14
+ | `claude-desktop` | Claude Desktop | `claude_desktop_config.json` |
15
+ | `opencode` | OpenCode | `~/.config/opencode/opencode.json`(MCP+EventCueプラグイン) |
16
+ | `cursor` | Cursor | `~/.cursor/mcp.json` |
17
+ | `vscode` | VS Code (Copilot Chat) | `User/mcp.json` |
18
+ | `hermes` | Hermes Agent | `~/.hermes/config.yaml` の `mcp_servers:`+`~/.hermes/plugins/ui-chan/`(EventCue。`HERMES_HOME` / `UI_CHAN_HERMES_CONFIG` で変更可) |
19
+
20
+ 一覧に無いクライアントには `ui-chan print <id>`(引数なしなら汎用の stdio 設定)が
21
+ 貼り付け用のスニペットを出します。新しいホストへの対応は `tools/setup/clients.mjs` に
22
+ 1エントリ追加するだけで、インストーラを書き足す必要はありません。
23
+
24
+ 登録される起動コマンドは、どのクライアントでも同じです。
25
+
26
+ ```
27
+ <パッケージ>/bin/ui-chan-node <パッケージ>/dist/mcp-server.js
28
+ ```
29
+
30
+ `bin/ui-chan-node` は node を自力で探して exec するランチャです。GUI から起動される
31
+ クライアント(Claude Desktop など)は launchd の最小 PATH しか持たず、Homebrew や nvm の
32
+ `node` が見えないため、`"command": "node"` と書くと**何も出さずに起動失敗**します。
33
+
34
+
35
+ ---
36
+
37
+ ## `02` ui-chan コマンド
38
+
39
+ ```bash
40
+ ui-chan # 対話セットアップ
41
+ ui-chan install claude-desktop opencode # 指定クライアントへ登録(--all で全部)
42
+ ui-chan uninstall --all # 全クライアントから解除(ユーザーデータは残る)
43
+ ui-chan uninstall --all --purge # ~/.ui-chan ごと消す
44
+ ui-chan doctor # 状態チェック
45
+ ui-chan print opencode # 設定スニペットだけ表示
46
+ ui-chan home # ユーザーデータの場所
47
+ ui-chan start / stop # マスコットの起動・停止
48
+ ui-chan update # 最新版にする(--check で確認だけ)
49
+ ```
50
+
51
+ **登録した時点で完了です。** アプリと VoiSona Talk はセッション開始時に自動起動し、人格は
52
+ MCP のハンドシェイク(`instructions`)に乗って渡ります。人格ファイルを貼り付ける作業はありません。
53
+
54
+ マスコット右上のつまみを開くと、接続中のセッション(クライアント名とプロジェクト名)と操作が出ます。
55
+
56
+ ---
57
+
58
+ ## `03` 複数のコピーが入っている場合
59
+
60
+ npm 版を入れたあとに開発用のクローンを作る、という流れはよくあります。**両方あっても構いません。**
61
+ どちらが動くかはクライアントの設定に書かれたパスだけが決めるので、
62
+
63
+ - `ui-chan use` … 登録済みのクライアントを、**そのコマンドを打ったコピー**へ向け直す
64
+ - `ui-chan doctor` … いま動いているコピーと、各クライアントがどこを指しているかを表示。
65
+ ズレていれば警告する
66
+
67
+ なお、アプリ本体は同時に1つしか起動できません(ポートの取り合いになるため)。
68
+ 切り替えたら `ui-chan stop` してから起こし直してください。
69
+
70
+ ---
71
+
72
+ ## `04` プラグインとコネクタの違い
73
+
74
+ | | MCPサーバ(コネクタ) | プラグイン |
75
+ |---|---|---|
76
+ | ツール(`set_cue` ほか) | ○ | ✕ |
77
+ | 人格(ハンドシェイクで注入) | ○ | ○(SessionStart フック) |
78
+ | アプリ・音声エンジンの自動起動 | ○ | ○ |
79
+ | `/talk` `/mode` `/beam` `/eli14` | ✕ | ○ |
80
+ | サブエージェント(talk / mode) | ✕ | ○ |
81
+ | 作業への自動リアクション(EventCue) | ✕ | ○ |
82
+
83
+ **EventCue** は、セッション中に起きたこと(コマンドの失敗、ターンの終了、サブエージェントの
84
+ 往復など)に反応して自動で再生される演目です。`ui-chan install <id>` が MCP 登録と同時に配置します。
85
+
86
+ | ホスト | 状態 |
87
+ |---|---|
88
+ | Claude Code | ✅ 実機で確認済み |
89
+ | OpenCode | 実装済み・**未検証**(`event` / `tool.execute.*` フック) |
90
+ | Hermes Agent | 実装済み・**未検証**(Python プラグイン) |
91
+
92
+ 未検証のものは、設定への書き込みと構文までは確認済みですが、実際に発火するところまでは
93
+ 確認できていません。試して問題があれば [Issue](https://github.com/Uncle-Peke/ui-chan-mcp/issues) へ。
94
+
95
+ フック側が決めるのは「**何が起きたか**」だけです。セリフ・重み・クールダウン・好感度ゲートは
96
+ `ui-chan.config.json` の `eventCues` にあるので、ホストが違っても反応は同じですし、
97
+ セリフを直すのに JavaScript を触る必要はありません。
98
+
99
+ 以前はプラグインが MCP サーバも兼ねていましたが、プラグイン文脈の外では設定中の
100
+ `${CLAUDE_PLUGIN_ROOT}` が展開されず**必ず起動に失敗する**ため、役割を分けました。
101
+ MCP の登録はどのクライアントでも `ui-chan install <id>` に統一されています。
102
+ Claude Code で全部入りにするなら `ui-chan install claude-code claude-code-plugin`。
103
+
104
+ Claude Desktop はプラグインの台帳を Claude Code と共有しますが、**プラグイン同梱の MCP サーバは
105
+ 起動しません**(実測)。Desktop では「スキルはプラグインから、ツールと人格はコネクタから」という
106
+ 組み合わせになります。
107
+
108
+ ---
109
+
110
+ <sub>次に読むなら [TROUBLESHOOTING.md](TROUBLESHOOTING.md)(繋いだのに動かないとき) / [TOOLS.md](TOOLS.md)(エージェントから何ができるか)</sub>
@@ -0,0 +1,76 @@
1
+ # Cue を書く / 設定を変える
2
+
3
+ > **新しい表情(Cue)を足すとき**と、**設定を調整するとき**に読みます。
4
+ > 使えるレイヤー名の早見表は [PSD_LAYERS.md](PSD_LAYERS.md)、カタログ全体の方針は [design/CUE_CATALOG.md](design/CUE_CATALOG.md)。
5
+
6
+ ---
7
+
8
+ ## `01` Cue(cues/)
9
+
10
+ 見た目+声のセットは **`cues/<Cue名>.json` に 1 Cue = 1 ファイル**で管理します
11
+ (`cue.schema.json` 準拠)。ファイル名がそのまま `set_cue` の `cue` 名になり、ファイルを追加すれば
12
+ 新しいCueが増えます。継承なし・完全に自己完結(同じレイヤー指定が複数ファイルに重複してもよい)。
13
+ **保存すると即時リロード**され、表示中のCueにもすぐ反映されるので、アプリを再起動せずに調整できます。
14
+
15
+ ```json
16
+ {
17
+ "select": ["!眉/*上がり", "!目/*にっこり2", "!口/*あは", "!頬・顔色/*頬2"],
18
+ "blink": false,
19
+ "voice": {
20
+ "style_weights": { "Happy": 0.7, "Bashful": 0.3 }
21
+ }
22
+ }
23
+ ```
24
+
25
+ - `select / show / hide` — 生の PSD レイヤーパス指定(全Cue共通の `cues/default.json` に上書きされる
26
+ 差分だけ書けばよい)。顔・腕・エフェクトを区別せず、そのCueに必要なレイヤーパスを並べるだけでよい
27
+ - `blink` — まばたきの有効化(目が開いているCueのみ true 推奨)
28
+ - `voice.style_weights` — スタイル名 → 重みのオブジェクト。省略すればデフォルトの声
29
+ - `voice.alp` / `voice.huskiness` — このCue固有の声色パラメータ(VoiSona の `global_parameters` にそのまま渡る)
30
+ - 強さ違い(例: 「激おこ」)は intensity ではなく別ファイル(例 `gekioko.json`)として作る
31
+ - JSON が壊れている、または `cue.schema.json` に適合しないファイルはスキップされ、`get_state` の
32
+ `warnings` に出ます
33
+ - `cues/default.json` は全Cue共通の下地(旧`config.base`+腕の基本ポーズに相当)で、他のCueと
34
+ 同じ形式の1ファイル。`set_cue`はこの`default`のdirectivesの上に指定されたCueのdirectivesを重ねて合成する
35
+ - `description`(任意) — このCueがどんな場面・気持ちを表すかの短い説明。`set_cue`の実行には一切
36
+ 使われず、`persona` MCPプロンプトが起動のたびに`cues/`の中身から動的にAI向けカタログを生成する
37
+ ためだけに読まれる(手書きの早見表を持たないので、Cue追加時にドキュメント更新を忘れてズレる、
38
+ ということが起きない)
39
+ - `internal`(任意・真偽値) — `true`にすると、そのCueはAI向けカタログから除外される(`set_cue`で
40
+ 直接呼べば動作はする)。IdlingCueが内部的に組み立てるための部品Cue(`cues/idling_*.json`)に付与
41
+
42
+ Cue選定・PSDレイヤー名カタログなど、**新規Cue制作のための人間向け参照ドキュメント**は
43
+ `docs/PSD_LAYERS.md` を参照。実行時にもAIのコンテキストにもロードされない(`context/`ではなく
44
+ あえて`docs/`に置いている)。
45
+
46
+ ---
47
+
48
+ ## `02` 設定(ui-chan.config.json)
49
+
50
+ - `assetsDir` — PSD を探すディレクトリ(最初に見つかった `.psd` を使用)
51
+ - `window` — ウィンドウサイズ・画面端からのマージン
52
+ - `exitAfterLastAgentSec` — 最後のエージェントが切断してから終了するまでの秒数(既定 60、`0` で無効)。
53
+ アプリは detached で起動するため、これが無いとクライアントを閉じても残り続ける。
54
+ 猶予を置くのは、Claude Code の再起動による一時的な切断で消えないようにするため
55
+ - `cuesDir` — Cueのディレクトリ(デフォルト `cues`)
56
+ - `idle.idlingCues` — アイドル中に自発的に再生される**IdlingCue**(Cue+任意のセリフのステップ列)のプール。
57
+ `items[].steps[]`は`{ cue?, text?, reading?, holdMs? }`で、`cue`を省略すると直前のCueを維持する。
58
+ 各 IdlingCue は `weight`(出やすさ、デフォルト 1)、`minAffinity`(必要な好感度)、`maxAffinity`(上限好感度)を持てる。
59
+ 無言の仕草(あくび、きょろきょろなど)は `weight` を高く、レアな独り言や高好感度専用セリフは `weight` を低く/`minAffinity` を高く、低好感度専用の冷たい反応は `maxAffinity` を低く設定する。
60
+ - `lipSync` — リップシンク設定。`mouths` は母音(a/e/i/o/u/n)→ 口レイヤー名、`charsPerSec` は口を
61
+ 動かす速度、`audioPollMs`(デフォルト33)は音声駆動リップシンクが再生位置をチェックする間隔。
62
+ 読みのかなを母音に変換して口形を切り替える。漢字など読めない文字はパクパク
63
+ (開閉交互)にフォールバック。発話終了時・無音区間は `n`(閉じ口)に自動復帰
64
+ - `speech` — `set_cue`の`duration_ms`省略時の表示時間算出パラメータ。テキスト駆動は
65
+ `baseMs + 文字数*msPerChar` を `minMs`〜`maxMs` にクランプ、音声駆動は合成音声の長さ +
66
+ `audioPaddingMs`(`audioMinMs`床)
67
+ - `ambient` — レンダラーのBlink(`blinkMinIntervalMs`/`blinkMaxIntervalMs`/`blinkDurationMs`)の
68
+ タイミング。VISION.mdの語彙でBlinkはCue/Idling外で唯一独立ループする演出なので、IdlingCueとは
69
+ 別枠でレンダラー側に残る
70
+
71
+ レイヤーパスは `/` 区切りで PSD のレイヤー名と完全一致。存在しないパスは無視され、
72
+ `get_state` の `warnings` に報告されます(別 PSD への差し替えを安全にするため)。
73
+
74
+ ---
75
+
76
+ <sub>次に読むなら [PSD_LAYERS.md](PSD_LAYERS.md)(レイヤー名を引く) / [TTS.md](TTS.md)(声色の指定)</sub>
@@ -0,0 +1,129 @@
1
+ # 開発ガイド
2
+
3
+ > **ういちゃんMCP そのものを直すとき**に読みます。設計判断とその理由は [../CLAUDE.md](../CLAUDE.md)、用語は [../VISION.md](../VISION.md) に。
4
+
5
+ ---
6
+
7
+ ## `01` 開発の準備
8
+
9
+ ```bash
10
+ git clone https://github.com/Uncle-Peke/ui-chan-mcp.git && cd ui-chan-mcp
11
+ npm install # 依存の取得 + ビルド(prepare で dist/ まで)
12
+ npx ui-chan # 対話セットアップ
13
+ npx ui-chan use # クライアントの参照先をこのクローンに向ける(npm 版も入れている場合)
14
+ ```
15
+
16
+ `npx ui-chan doctor` が「このコピー」と、各クライアントがどのコピーを指しているかを表示します。
17
+ **npm 版とクローンを同時に入れても構いません** — どちらが動くかはクライアントの設定に
18
+ 書かれたパスで決まり、`ui-chan use` を打ったコピーが担当になります。
19
+
20
+ ---
21
+
22
+ ## `02` コマンド
23
+
24
+ | コマンド | 説明 |
25
+ |---|---|
26
+ | `npx ui-chan` | 対話セットアップ(TUI) |
27
+ | `npx ui-chan update` | 本体を最新にして再ビルド(`--check` で確認のみ、`--branch <名前>` で追従先指定) |
28
+ | `npx ui-chan use` | 登録済みクライアントの参照先を「このコピー」に切り替える |
29
+ | `npm run doctor` | セットアップの事前チェック(=`ui-chan doctor`) |
30
+ | `npm run app` / `stop` / `restart` | Electron アプリの起動/終了/再起動 |
31
+ | `npm run build` | `src/` を `dist/` にビルド(`npm install` 時に自動実行) |
32
+ | `npm run editor` | Cue エディタ「雨衣ちゃんのデバッグルーム」 |
33
+ | `npm run dump-psd -- assets/foo.psd` | PSD レイヤー構造のダンプ |
34
+ | `npm run validate-cues` | `cues/*.json` のスキーマ検証 |
35
+ | `npm run lint` / `lint:fix` / `format` | Biome |
36
+ | `node tools/mcp-test.mjs` | MCP stdio 経由の E2E テスト |
37
+
38
+ ---
39
+
40
+ ## `03` パッケージとユーザーデータ
41
+
42
+ **アップデートしても壊れない**のはこれのおかげ。
43
+
44
+ | | 場所 | 中身 | 更新時 |
45
+ |---|---|---|---|
46
+ | パッケージ | クローン/`node_modules` | コード・同梱Cue・人格・設定の既定値 | **まるごと入れ替わる** |
47
+ | ユーザーデータ | `~/.ui-chan/`(`UI_CHAN_HOME` で変更可) | PSD・`.env`・`config.json`・自作Cue・人格の上書き | **触られない** |
48
+
49
+ 上書きしたいものだけ置けば済みます。全部を複製する必要はありません。
50
+
51
+ | 対象 | 解決のしかた |
52
+ |---|---|
53
+ | `config.json` | 同梱の設定に**深いマージで上書き**。3行だけ書いても、後から増えた項目は継承される |
54
+ | `cues/` | 同梱と**両方読み込み**、同名はユーザー側が勝つ |
55
+ | `context/` | 同じくファイル名単位。`persona/ui-chan.md` も置けばそちらが使われる |
56
+ | `assets/` | 立ち絵。同梱できないため実質ここだけ |
57
+ | `.env` | 環境変数があればそちらが優先 |
58
+
59
+ ---
60
+
61
+ ## `04` スクリーンショットを撮る
62
+
63
+ マスコットのウィンドウは透過なので、そのまま撮ると白以外の場所に置けない画像になります。
64
+ `ui-chan shot` は**撮る瞬間だけ背景を敷いて**から撮ります。
65
+
66
+ ```bash
67
+ ui-chan shot # ~/.ui-chan/ui-chan-shot.png(背景 light)
68
+ ui-chan shot hero.png dark # ファイル名と背景を指定
69
+ ui-chan shot x.png "#1a1926" # CSS の値をそのまま渡してもいい
70
+ ```
71
+
72
+ 背景のプリセットは `light` / `dark` / `desk` / `white`。それ以外の文字列は CSS の
73
+ `background` にそのまま渡されるので、グラデーションでも画像でも指定できます。
74
+ README に載せている画像もこれで撮っています。
75
+
76
+ ---
77
+
78
+ ## `05` 変更が反映されるタイミング
79
+
80
+ | 直したもの | 反映 |
81
+ |---|---|
82
+ | `cues/*.json` | **保存した瞬間**(ホットリロード) |
83
+ | `ui-chan.config.json` | アプリの再起動 |
84
+ | `persona/*.md`・`context/*.md` | 次のセッション(またはプロンプト `persona` の再実行) |
85
+ | `src/**` | `npm run build` → アプリ再起動。**MCP サーバはセッション開始時のコードを抱えたまま動く**ので、繋ぎ直すかセッションを開き直す |
86
+
87
+ レンダラ(`src/renderer/`)は tsc だけでは反映されません。esbuild が要るので `npm run build` を使ってください。
88
+
89
+ ---
90
+
91
+ ## `06` アーキテクチャ
92
+
93
+ MCP サーバは薄いブリッジで、**状態はすべて Electron アプリ側に一元化**されています。
94
+ 複数のエージェントが同時に繋いでも状態が食い違いません。
95
+
96
+ ```mermaid
97
+ flowchart LR
98
+ agent["エージェント<br/>(Claude Code 等)"]
99
+ mcp["dist/mcp-server.js<br/>ステートレスなブリッジ"]
100
+
101
+ subgraph app["Electron アプリ (dist/app/main.js)"]
102
+ direction TB
103
+ state["UiChanState<br/>発話キュー・好感度・アイドル"]
104
+ tts["VoiSonaTalkClient<br/>音声合成"]
105
+ renderer["レンダラ<br/>PSD合成・吹き出し・口パク"]
106
+ end
107
+
108
+ voisona["VoiSona Talk<br/>REST API :32766"]
109
+
110
+ agent -- "stdio (MCP)" --> mcp
111
+ mcp -- "WebSocket :8123" --> state
112
+ mcp -. "未起動なら自動起動" .-> app
113
+ mcp -. "未起動なら自動起動" .-> voisona
114
+ state --> tts
115
+ tts -- "WAV + 音素タイミング" --> renderer
116
+ tts <--> voisona
117
+ state -- "IPC (RenderCommand)" --> renderer
118
+ ```
119
+
120
+ - **ポート** — `ui-chan.config.json` の `port`、または環境変数 `UI_CHAN_PORT`
121
+ - **自動起動** — アプリはセッション開始時(SessionStart フック)と各ツール呼び出し時に、
122
+ VoiSona Talk は MCP 起動時と `set_cue` のたびに、落ちていれば起こし直されます
123
+ - **エージェント名** — MCP クライアント情報から自動取得(`UI_CHAN_AGENT_NAME` で上書き可)
124
+
125
+ より詳しい実装のガイドは [CLAUDE.md](../CLAUDE.md) を参照。
126
+
127
+ ---
128
+
129
+ <sub>次に読むなら [../CLAUDE.md](../CLAUDE.md)(実装ガイド) / [STYLE.md](STYLE.md)(ドキュメントを書くとき)</sub>
@@ -0,0 +1,61 @@
1
+ # 人格の注入
2
+
3
+ > **性格や口調を変えたいとき**、および「なぜ繋いだだけでキャラクターが乗るのか」を
4
+ > 知りたいときに読みます。
5
+
6
+ ---
7
+
8
+ ## `01` 人格はどこにあるか
9
+
10
+ MCP が渡せるのはツール(=身体)だけです。**キャラクターの人格は、エージェント側の
11
+ コンテキストに文章として入れる**必要があります。置き場所は2つ。
12
+
13
+ | 場所 | 中身 |
14
+ |---|---|
15
+ | `persona/ui-chan.md` | 基本人格とツール使用方針(`reading` を必ず付ける、セリフは1〜2文で区切る、など)。`personaFile` で変更可 |
16
+ | `context/*.md` | 追加コンテキスト。`SOUL.md`(価値観・内面)、`VOCABULARY.md`(語彙・口癖・NGワード)、`AFFINITY.md`(好感度の機微)。**ファイル名順に全部**読み込まれます |
17
+
18
+ `~/.ui-chan/` 側に同じ名前で置けば、同梱のものを上書きできます。パッケージを更新しても
19
+ 消えません。
20
+
21
+ > [!IMPORTANT]
22
+ > **`context/` に人間向けの資料を置かないでください。** ここは中身を問わず丸ごと AI に
23
+ > 注入される場所です。PSD レイヤーパスの一覧のような、AI が読んでも意味のないものを置くと、
24
+ > 毎セッション無駄なトークンを食います。制作用の資料は `docs/` へ
25
+ > ([PSD_LAYERS.md](PSD_LAYERS.md) がその例)。
26
+
27
+ 利用できる Cue の一覧は `context/` には**書きません**。`cues/*.json` の `description` から
28
+ 起動のたびに生成して渡すので、手で書いた一覧が古くなることがありません。
29
+
30
+ ---
31
+
32
+ ## `02` どうやって届くか
33
+
34
+ 3つの経路があり、上ほど手間がかかりません。**どれも同じ本文**(`buildPersonaText()`)を配ります。
35
+
36
+ | | 経路 | 対象 | いつ |
37
+ |:---:|---|---|---|
38
+ | 1 | MCP ハンドシェイクの `instructions` | **すべての MCP クライアント** | 接続時に自動。何もしなくてよい |
39
+ | 2 | SessionStart フック | Claude Code(プラグイン導入時) | セッション開始時に自動 |
40
+ | 3 | MCP プロンプト `persona` | すべての MCP クライアント | 手動。Claude Code なら `/mcp__ui-chan__persona` |
41
+
42
+ 3 はファイルを編集したあとの読み込み直しに使います。呼ぶたびにファイルを読むので、
43
+ 編集が即座に反映されます。
44
+
45
+ > [!TIP]
46
+ > 1 と 2 の両方が効いていると、同じ人格が二重に入ります。無駄だと感じたら
47
+ > `UI_CHAN_NO_PERSONA_INSTRUCTIONS=1`(サーバ側)か `UI_CHAN_NO_PERSONA_HOOK=1`(フック側)で
48
+ > 片方を止められます。
49
+
50
+ ---
51
+
52
+ ## `03` 別のキャラクターにする
53
+
54
+ `persona/` と `context/` を書き換え、PSD に合わせて `cues/` とレイヤー設定を作り直します。
55
+ どれも `~/.ui-chan/` 側に置けば上書きになるので、同梱物を削る必要はありません。
56
+
57
+ 手順は [CUE_AUTHORING.md](CUE_AUTHORING.md) を参照してください。
58
+
59
+ ---
60
+
61
+ <sub>次に読むなら [TOOLS.md](TOOLS.md)(人格が使うツール) / [../CLAUDE.md](../CLAUDE.md)(実装の詳細)</sub>
@@ -0,0 +1,123 @@
1
+ # PSD レイヤー早見表
2
+
3
+ > **Cue を書くときに「どのレイヤー名を指定すればいいか」を引く表**です。書式は [CUE_AUTHORING.md](CUE_AUTHORING.md)。
4
+
5
+ ---
6
+
7
+ ## `01` 使い方の基本(Cue制作者向け)
8
+
9
+ - 場面に合う Cue 名を選んで `set_cue({ cue: "emo_joy", text: "やったー!", reading: "やったー!" })`
10
+ - 無言で見た目だけ変えたいときは `text` を省略できる
11
+ - 声の抑揚を1行だけ変えたいときは `pitch`/`speed`/`volume`/`intonation` を渡す(Cueに焼き込まれた
12
+ `voice.style_weights`/`alp`/`huskiness` の上にアドリブとして重なる)
13
+ - 存在しない Cue 名を指定すると `default` にフォールバックし、結果に `note` が付く
14
+ - 強さ違いは別の Cue 名(`emo_anger`→`emo_anger_hi`、`emo_joy`→`emo_joy_hi` のように)。intensityパラメータは無い
15
+ - 新しいCueを作ったら、必ず`description`フィールドに「どんな場面・気持ちのCueか」を短く書く
16
+ (これが唯一、AIに伝わる経路)
17
+ - AIに直接選ばせたくない、IdlingCue専用の内部部品Cueには`"internal": true`を付ける(後述)。
18
+ ファイル名のprefix等の暗黙の命名規則には頼らない — 明示的なフラグでのみ判定する
19
+
20
+ ---
21
+
22
+ ---
23
+
24
+ ## `02` 新規Cue制作のためのパーツ・カタログ
25
+
26
+ `cues/*.json` の `select`/`show`/`hide` には生のPSDレイヤーパスをそのまま書く。以下は
27
+ そのパスを組み立てるための参照表(旧 `set_face`/`set_pose` が使っていたスロット分類を、
28
+ 制作用メモとして残したもの。実行時のツールやconfigとしては存在しない)。
29
+
30
+ ### 目は3階層になっている
31
+ - `!目/*<形>` … 目まるごとの形(ジト目・閉じ・上向き…)。`基本目セット` を選ぶと下2つで詰められる
32
+ - `!目/*基本目セット/!白目/*<白目>` … 白目のかたち(`基本目セット` のときだけ効く)
33
+ - `!目/*基本目セット/*<視線>` … 黒目の向き・種類(`基本目セット` のときだけ効く)
34
+
35
+ **注意**: `!目/*基本目セット/*<視線>`(ネストした選択)と `!目/*<形>`(`!目`直下の兄弟)は、
36
+ どちらも最終的に同じ `!目` レベルのラジオ排他に巻き込まれる。同じCueのselect配列内で両方を
37
+ 指定すると、後に書いた方が親ごと勝ち、先に書いた方(とその配下)は丸ごと非表示になり無意味に
38
+ なる(`emo_anger_hi.json`等で実際に起きていた事故。同じ軸を2回指定しないこと)。
39
+
40
+ ### `eyes` — 目まるごと(`!目/*...`、13)
41
+ | 名前 | どんな目 |
42
+ |---|---|
43
+ | `基本目セット` | 標準の目。これを選ぶと白目/視線で詰められる |
44
+ | `ジト目` | 半目のジト目。塩鮭・呆れ・「ふ〜ん」 |
45
+ | `○○` | まん丸見開き。びっくり |
46
+ | `ぐるぐる` | ぐるぐる目。混乱・目が回る |
47
+ | `><` | ぎゅっと閉じた `><`。爆笑・痛い・きゃっきゃ |
48
+ | `ーー` | 一本線の閉じ目。眠い・真顔・悟り |
49
+ | `閉じ` | 穏やかに閉じた目。安らぎ・まばたき |
50
+ | `にっこり1` | 笑い目(控えめ) |
51
+ | `にっこり2` | 笑い目(大きめ・満面) |
52
+ | `細目` | 細めたドヤ目。にやり・自信家 |
53
+ | `細目ハート` | 細めた目+ハート。ういおじ・でれ |
54
+ | `コンセント` | 光の消えた目(コンセント顔)。無・虚無・真顔ネタ |
55
+ | `上向き1` | 上目遣い(考え中) |
56
+ | `上向き2` | 上目遣い(強め・遠い目) |
57
+
58
+ ### 白目(`!目/*基本目セット/!白目/*...`、3)
59
+ `白目基本` / `白目ジト`(半目・呆れの詰め) / `白目見開き`(かっと見開いた白目、衝撃)
60
+
61
+ ### 視線(`!目/*基本目セット/*...`、10)
62
+ `正面1`(デフォルト) / `正面2` / `カメラ目線1` / `カメラ目線2` / `目そらし1` / `目そらし2`(強め、照れ・
63
+ 気まずい) / `きらきら目`(ワクワク・尊い) / `ハート目`(mix_joy_trust) / `ぐるぐる目` / `縮小`(恐怖・戦慄)
64
+
65
+ ### 口(`!口/*...`、22)
66
+ `ん`=閉じ(標準) / `あ``え``お`=小さく開く / `お`=すぼめ丸口 / `あは`=笑い / `あはー`=大笑い /
67
+ `えへ`=てへ照れ笑い / `ほほえみ`=にっこり閉じ / `にし`=にやり(ドヤ) / `むふ`=含み笑い / `ほわ`=とろけ /
68
+ `ほあー`=ほへ〜(脱力) / `ゆ`=きゅっ(照れ) / `んー`=思案のハミング / `む`=むっ(ふくれ) / `え`(えー)=不満の口 /
69
+ `えあー`=あわあわ(困り) / `いー`=歯を食いしばる(力み・怒り) / `おおー`=感嘆の大口 / `おー`=おお /
70
+ `△`=三角口(緊張) / `うわー`=大口(絶叫・泣き) / `お`(小)=ぽかん
71
+
72
+ ### 眉(`!眉/*...`、5)
73
+ `普通`(標準) / `上がり`=上げ眉(驚き・喜び) / `困り`=困り眉(下がり) / `怒り1`=怒り / `怒り2`=激おこ
74
+
75
+ ### 頬・顔色(`!頬・顔色/*...`、7)
76
+ `頬1`(標準) / `頬2`(血色よい) / `頬赤め1`=照れ赤 / `頬赤め2`=真っ赤 / `青ざめ1`=青ざめ /
77
+ `青ざめ2`=真っ青 / `(非表示)`=頬色なし
78
+
79
+ ### 重ねエフェクト(`show`/`hide` で指定)
80
+ `!汗・涙/汗1`=汗1滴(焦り) / `!汗・涙/汗2`=汗だく(パニック) / `!汗・涙/涙`=涙 / `!頬・顔色/かげり`=顔の影(暗い・絶望・げんなり)
81
+
82
+ ### 腕(`!奥の腕/*...` / `!手前の腕/*...`)— 現在使用中のCueが焼き込んでいる組み合わせ
83
+ | 腕の見た目 | 使っているCue |
84
+ |---|---|
85
+ | 通常(`default`に焼き込み) | 全Cue共通の下地 |
86
+ | 傘さし | `pose_umbrella` |
87
+ | 両手ばんざい | `pose_banzai` |
88
+ | あご手(考え中) | `pose_think` |
89
+ | 腕組み | `pose_smug_arms`, `pose_arms_crossed` |
90
+ | 腰に手 | `pose_smug_hips` |
91
+
92
+ 以下は旧 `set_pose` カタログに存在したが、現在どのCueにも焼き込まれていない腕の組み合わせ。
93
+ 新しいCueが必要になったときの生レイヤーパスの参照用(実在確認はPSD側で行うこと):
94
+
95
+ | 名前(旧pose名) | 生レイヤーパス | 使いどころの目安 |
96
+ |---|---|---|
97
+ | `call` | `!奥の腕/*呼びかけ` + `!手前の腕/*呼びかけ` | 登場・「はいどうも〜」・挨拶 |
98
+ | `fist` | `!奥の腕/*基本` + `!手前の腕/*ぐっ` | やる気・気合い |
99
+ | `point` | `!奥の腕/*基本` + `!手前の腕/*指さし手前` | 強調・ういビーム代用 |
100
+ | `point_side` | `!奥の腕/*指さし横` + `!手前の腕/*基本` | 説明・案内・「あれ見て」 |
101
+ | `mic` | `!奥の腕/*マイク` + `!手前の腕/*基本` | 配信・実況・発表 |
102
+ | `palm_up` | `!奥の腕/*手のひら上` + `!手前の腕/*手のひら上` | どうぞ・提示・愛でる |
103
+ | `mouth_cover` | `!奥の腕/*口元` + `!手前の腕/*基本` | くすっ・「すいませんねぇ」・しまった |
104
+
105
+ > 注意: 傘(`pose_umbrella`)は吹き出しと干渉することがある。傘のときは長ゼリフを避けるか位置に注意。
106
+
107
+ ---
108
+
109
+ ---
110
+
111
+ ## `03` IdlingCue専用Cue(`idling_*`)
112
+
113
+ `cues/idling_yawn_1〜3` / `idling_lookaround_1〜3` / `idling_ponder` / `idling_doze_1〜3` /
114
+ `idling_giggle_1〜2` / `idling_sigh_1〜2` は、`ui-chan.config.json` の `idle.idlingCues`
115
+ (あくび・きょろきょろ・ぼんやり・うたた寝・くすくす・ため息)が内部的に参照する、無言の一瞬の
116
+ 表情変化用Cue。他のCueと形式は同じだが、単体で場面に当てる想定ではなく複数ステップの一部として
117
+ 使うために作られている。全ファイルに`"internal": true`を明示しており、`buildCueCatalog()`が
118
+ AI向けの一覧生成時にこのフラグを見て除外している(ファイル名が`idling_`で始まることは判定条件では
119
+ ない。たまたま命名が揃っているだけ)。`set_cue`から直接呼んでも動作はするが、通常は呼ばない。
120
+
121
+ ---
122
+
123
+ <sub>次に読むなら [CUE_AUTHORING.md](CUE_AUTHORING.md)(書式と保存先) / [design/CUE_CATALOG.md](design/CUE_CATALOG.md)(何を作るべきか)</sub>
package/docs/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # ドキュメント索引
2
+
3
+ > **どのページを読めばいいか分からないとき**に見ます。
4
+ > 入れて使うだけなら [../README.md](../README.md) で足ります。
5
+
6
+ ---
7
+
8
+ ## `01` 使う人向け
9
+
10
+ | やりたいこと | 読むもの |
11
+ |---|---|
12
+ | 図解でセットアップを見る | [SETUP.html](SETUP.html) |
13
+ | どのアプリに何が書き込まれるか知る | [CLIENTS.md](CLIENTS.md) |
14
+ | 動かないので調べる | [TROUBLESHOOTING.md](TROUBLESHOOTING.md) |
15
+ | 声を出す・調整する | [TTS.md](TTS.md) |
16
+ | エージェントから何ができるか知る | [TOOLS.md](TOOLS.md) |
17
+
18
+ ---
19
+
20
+ ## `02` 作る人向け
21
+
22
+ | やりたいこと | 読むもの |
23
+ |---|---|
24
+ | 開発を始める(準備・コマンド・全体像) | [DEVELOPMENT.md](DEVELOPMENT.md) |
25
+ | コードを直す(設計判断と、その理由) | [../CLAUDE.md](../CLAUDE.md) |
26
+ | 用語を確認する(Idling / Cue / EventCue …) | [../VISION.md](../VISION.md) |
27
+ | 新しい表情(Cue)を足す | [CUE_AUTHORING.md](CUE_AUTHORING.md) → レイヤー名は [PSD_LAYERS.md](PSD_LAYERS.md) |
28
+ | 性格・口調を変える | [PERSONA.md](PERSONA.md) |
29
+ | Cueカタログの設計方針を知る | [design/CUE_CATALOG.md](design/CUE_CATALOG.md) |
30
+ | **ドキュメントを書く・直す** | [STYLE.md](STYLE.md) |
31
+
32
+ ---
33
+
34
+ ## `03` ドキュメントではないもの
35
+
36
+ > [!IMPORTANT]
37
+ > `persona/` と `context/` の Markdown は**資料ではなく、AI に注入される設定**です。
38
+ > 編集するとういちゃんの振る舞いが変わります。人間向けの制作資料をそこに置かないでください
39
+ > (理由は [PERSONA.md](PERSONA.md))。
40
+
41
+ ---
42
+
43
+ <sub>ページの型・色の使い分け・口調のルールは [STYLE.md](STYLE.md) にあります。</sub>