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,684 @@
1
+ <title>ういを動かすまで</title>
2
+ <link rel="preconnect" href="https://fonts.googleapis.com">
3
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
4
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Zen+Maru+Gothic:wght@500;700&family=Zen+Kaku+Gothic+New:wght@400;500&family=Roboto+Mono:wght@400;500&display=swap">
5
+
6
+ <style>
7
+ :root {
8
+ --ground: #eaeef5;
9
+ --card: #f7f9fc;
10
+ --ink: #1b2230;
11
+ --ink-soft: #55607a;
12
+ --ink-faint: #8b94a8;
13
+ --rule: #ccd4e4;
14
+ --accent: #4f5fc9;
15
+ --accent-soft: #dfe3fa;
16
+ --warm: #d1804f;
17
+ --warm-soft: #f6e4d8;
18
+ --drop: #a8b6dd;
19
+ }
20
+
21
+ @media (prefers-color-scheme: dark) {
22
+ :root:not([data-theme="light"]) {
23
+ --ground: #12151d;
24
+ --card: #1a1f2b;
25
+ --ink: #e6eaf3;
26
+ --ink-soft: #a3adc2;
27
+ --ink-faint: #6d7791;
28
+ --rule: #2c3444;
29
+ --accent: #97a4f2;
30
+ --accent-soft: #262e4d;
31
+ --warm: #e4a071;
32
+ --warm-soft: #3a2a1e;
33
+ --drop: #3d4966;
34
+ }
35
+ }
36
+
37
+ :root[data-theme="dark"] {
38
+ --ground: #12151d;
39
+ --card: #1a1f2b;
40
+ --ink: #e6eaf3;
41
+ --ink-soft: #a3adc2;
42
+ --ink-faint: #6d7791;
43
+ --rule: #2c3444;
44
+ --accent: #97a4f2;
45
+ --accent-soft: #262e4d;
46
+ --warm: #e4a071;
47
+ --warm-soft: #3a2a1e;
48
+ --drop: #3d4966;
49
+ }
50
+
51
+ * { box-sizing: border-box; }
52
+
53
+ body {
54
+ margin: 0;
55
+ background: var(--ground);
56
+ color: var(--ink);
57
+ font-family: "Zen Kaku Gothic New", system-ui, sans-serif;
58
+ font-size: 16px;
59
+ line-height: 1.85;
60
+ -webkit-font-smoothing: antialiased;
61
+ }
62
+
63
+ .wrap {
64
+ max-width: 720px;
65
+ margin: 0 auto;
66
+ padding: 0 24px 96px;
67
+ display: flex;
68
+ flex-direction: column;
69
+ gap: 72px;
70
+ }
71
+
72
+ h1, h2, .display {
73
+ font-family: "Zen Maru Gothic", "Zen Kaku Gothic New", system-ui, sans-serif;
74
+ font-weight: 700;
75
+ text-wrap: balance;
76
+ line-height: 1.4;
77
+ margin: 0;
78
+ }
79
+
80
+ .label {
81
+ font-family: "Roboto Mono", ui-monospace, monospace;
82
+ font-size: 12px;
83
+ letter-spacing: 0.14em;
84
+ text-transform: uppercase;
85
+ color: var(--ink-faint);
86
+ margin: 0;
87
+ }
88
+
89
+ p { margin: 0; }
90
+ .lede { color: var(--ink-soft); }
91
+
92
+ /* ---- hero ---- */
93
+ header {
94
+ position: relative;
95
+ padding: 88px 0 8px;
96
+ display: flex;
97
+ flex-direction: column;
98
+ gap: 20px;
99
+ }
100
+
101
+ h1 { font-size: clamp(34px, 7vw, 52px); }
102
+ h1 .ruby { display: block; font-size: 14px; letter-spacing: 0.3em; color: var(--accent); font-weight: 500; }
103
+
104
+ .hero-note {
105
+ color: var(--ink-soft);
106
+ max-width: 34em;
107
+ }
108
+
109
+ /* ---- sections ---- */
110
+ section { display: flex; flex-direction: column; gap: 18px; }
111
+ h2 { font-size: clamp(21px, 3.4vw, 26px); }
112
+ h2 .n { color: var(--accent); font-family: "Roboto Mono", monospace; font-size: 0.62em; margin-right: 0.6em; }
113
+
114
+ .fig {
115
+ background: var(--card);
116
+ border: 1px solid var(--rule);
117
+ border-radius: 14px;
118
+ padding: 22px;
119
+ overflow-x: auto;
120
+ }
121
+ .fig svg { display: block; width: 100%; height: auto; min-width: 380px; }
122
+
123
+ .cap { color: var(--ink-faint); font-size: 14px; }
124
+
125
+ /* ---- profile ---- */
126
+ .profile {
127
+ display: grid;
128
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
129
+ gap: 1px;
130
+ background: var(--rule);
131
+ border: 1px solid var(--rule);
132
+ border-radius: 14px;
133
+ overflow: hidden;
134
+ }
135
+ .profile div {
136
+ background: var(--card);
137
+ padding: 14px 16px;
138
+ display: flex;
139
+ flex-direction: column;
140
+ gap: 2px;
141
+ }
142
+ .profile dt {
143
+ font-family: "Roboto Mono", monospace;
144
+ font-size: 11px;
145
+ letter-spacing: 0.12em;
146
+ color: var(--ink-faint);
147
+ margin: 0;
148
+ }
149
+ .profile dd {
150
+ margin: 0;
151
+ font-family: "Zen Maru Gothic", sans-serif;
152
+ font-size: 19px;
153
+ font-variant-numeric: tabular-nums;
154
+ }
155
+
156
+ /* ---- band strip ---- */
157
+ .bands { display: flex; flex-direction: column; gap: 10px; }
158
+ .band {
159
+ display: grid;
160
+ grid-template-columns: 88px 1fr;
161
+ gap: 14px;
162
+ align-items: baseline;
163
+ padding: 12px 16px;
164
+ border-radius: 12px;
165
+ background: var(--card);
166
+ border: 1px solid var(--rule);
167
+ }
168
+ .band b {
169
+ font-family: "Zen Maru Gothic", sans-serif;
170
+ color: var(--accent);
171
+ font-size: 15px;
172
+ }
173
+ .band.warm b { color: var(--warm); }
174
+ .band span { color: var(--ink-soft); font-size: 15px; }
175
+
176
+ .callout {
177
+ border-left: 3px solid var(--warm);
178
+ background: var(--warm-soft);
179
+ padding: 14px 18px;
180
+ border-radius: 0 12px 12px 0;
181
+ color: var(--ink);
182
+ }
183
+
184
+ code {
185
+ font-family: "Roboto Mono", ui-monospace, monospace;
186
+ font-size: 0.88em;
187
+ background: var(--accent-soft);
188
+ color: var(--ink);
189
+ padding: 1px 6px;
190
+ border-radius: 5px;
191
+ }
192
+
193
+ .steps { display: flex; flex-direction: column; gap: 12px; }
194
+ .step {
195
+ display: grid;
196
+ grid-template-columns: 34px 1fr;
197
+ gap: 14px;
198
+ background: var(--card);
199
+ border: 1px solid var(--rule);
200
+ border-radius: 12px;
201
+ padding: 14px 16px;
202
+ }
203
+ .step .no {
204
+ font-family: "Roboto Mono", monospace;
205
+ font-size: 13px;
206
+ color: var(--accent);
207
+ padding-top: 3px;
208
+ }
209
+ .step h3 {
210
+ margin: 0;
211
+ font-family: "Zen Maru Gothic", sans-serif;
212
+ font-size: 16px;
213
+ font-weight: 700;
214
+ }
215
+ .step p { color: var(--ink-soft); font-size: 14.5px; }
216
+ .step pre,
217
+ .fig > pre {
218
+ margin: 8px 0 0;
219
+ background: var(--ground);
220
+ border: 1px solid var(--rule);
221
+ border-radius: 8px;
222
+ padding: 10px 12px;
223
+ overflow-x: auto;
224
+ font-family: "Roboto Mono", monospace;
225
+ font-size: 13px;
226
+ line-height: 1.7;
227
+ color: var(--ink);
228
+ }
229
+ .step .body { display: flex; flex-direction: column; gap: 4px; }
230
+ .fig > pre { margin: 0; min-width: 380px; }
231
+
232
+ /* 雨:スクロールしても付いてくる全面レイヤー。常にコンテンツの後ろ */
233
+ .rain {
234
+ position: fixed;
235
+ inset: 0;
236
+ z-index: 0;
237
+ pointer-events: none;
238
+ overflow: hidden;
239
+ }
240
+ .rain i {
241
+ position: absolute;
242
+ top: -12vh;
243
+ width: 2px;
244
+ height: 16px;
245
+ border-radius: 1px;
246
+ background: var(--drop);
247
+ opacity: 0.5;
248
+ }
249
+ .wrap { position: relative; z-index: 1; }
250
+
251
+ @media (prefers-reduced-motion: no-preference) {
252
+ .rain i { animation: fall linear infinite; }
253
+ @keyframes fall {
254
+ from { transform: translateY(0); opacity: 0; }
255
+ 8% { opacity: 0.5; }
256
+ 92% { opacity: 0.5; }
257
+ to { transform: translateY(118vh); opacity: 0; }
258
+ }
259
+ }
260
+ @media (prefers-reduced-motion: reduce) {
261
+ .rain { display: none; }
262
+ }
263
+
264
+ /* ---- テーマ切り替え ---- */
265
+ .theme-toggle {
266
+ position: fixed;
267
+ top: 16px;
268
+ right: 16px;
269
+ z-index: 2;
270
+ display: inline-flex;
271
+ align-items: center;
272
+ gap: 7px;
273
+ padding: 7px 13px 7px 11px;
274
+ border: 1px solid var(--rule);
275
+ border-radius: 999px;
276
+ background: var(--card);
277
+ color: var(--ink-soft);
278
+ font-family: "Roboto Mono", ui-monospace, monospace;
279
+ font-size: 11px;
280
+ letter-spacing: 0.1em;
281
+ cursor: pointer;
282
+ transition: color 120ms ease, border-color 120ms ease;
283
+ }
284
+ .theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
285
+ .theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
286
+ .theme-toggle svg { display: block; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
287
+ .theme-toggle .sun { display: none; }
288
+ .theme-toggle[data-mode="dark"] .sun { display: block; }
289
+ .theme-toggle[data-mode="dark"] .moon { display: none; }
290
+ .theme-toggle .now::after { content: "DARK"; }
291
+ .theme-toggle[data-mode="dark"] .now::after { content: "LIGHT"; }
292
+
293
+ @media (max-width: 600px) {
294
+ .theme-toggle .now { display: none; }
295
+ .theme-toggle { padding: 8px; }
296
+ }
297
+
298
+ footer {
299
+ border-top: 1px solid var(--rule);
300
+ padding-top: 22px;
301
+ color: var(--ink-faint);
302
+ font-size: 14px;
303
+ display: flex;
304
+ flex-direction: column;
305
+ gap: 6px;
306
+ }
307
+ footer a { color: var(--accent); }
308
+
309
+ </style>
310
+
311
+ <button class="theme-toggle" type="button" aria-live="polite">
312
+ <svg class="moon" viewBox="0 0 20 20" aria-hidden="true"><path d="M16 12.2A6.6 6.6 0 0 1 7.8 4a6.6 6.6 0 1 0 8.2 8.2z"></path></svg>
313
+ <svg class="sun" viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="3.6"></circle><path d="M10 2.2v1.6M10 16.2v1.6M2.2 10h1.6M16.2 10h1.6M4.5 4.5l1.1 1.1M14.4 14.4l1.1 1.1M15.5 4.5l-1.1 1.1M5.6 14.4l-1.1 1.1"></path></svg>
314
+ <span class="now"></span>
315
+ </button>
316
+
317
+ <div class="rain" aria-hidden="true">
318
+ <i style="left: 4%; height: 14px; animation-duration: 5.2s; animation-delay: -0.4s;"></i>
319
+ <i style="left: 11%; height: 18px; animation-duration: 6.6s; animation-delay: -2.9s;"></i>
320
+ <i style="left: 19%; height: 12px; animation-duration: 4.6s; animation-delay: -1.7s;"></i>
321
+ <i style="left: 27%; height: 16px; animation-duration: 7.2s; animation-delay: -4.1s;"></i>
322
+ <i style="left: 34%; height: 20px; animation-duration: 5.8s; animation-delay: -0.9s;"></i>
323
+ <i style="left: 42%; height: 13px; animation-duration: 6.1s; animation-delay: -3.3s;"></i>
324
+ <i style="left: 49%; height: 17px; animation-duration: 4.9s; animation-delay: -2.2s;"></i>
325
+ <i style="left: 57%; height: 15px; animation-duration: 7.6s; animation-delay: -5.0s;"></i>
326
+ <i style="left: 64%; height: 19px; animation-duration: 5.5s; animation-delay: -1.1s;"></i>
327
+ <i style="left: 71%; height: 12px; animation-duration: 6.9s; animation-delay: -3.8s;"></i>
328
+ <i style="left: 79%; height: 16px; animation-duration: 5.0s; animation-delay: -2.6s;"></i>
329
+ <i style="left: 86%; height: 18px; animation-duration: 7.0s; animation-delay: -0.2s;"></i>
330
+ <i style="left: 93%; height: 14px; animation-duration: 6.3s; animation-delay: -4.4s;"></i>
331
+ <i style="left: 97%; height: 17px; animation-duration: 5.4s; animation-delay: -1.9s;"></i>
332
+ </div>
333
+
334
+ <div class="wrap">
335
+
336
+ <header>
337
+ <p class="label">ELI14 — セットアップ</p>
338
+ <h1><span class="ruby">S E T U P</span>ういを動かすまで</h1>
339
+ <p class="hero-note">
340
+ クローンしてきてから、画面のすみっこにういが出てくるまで。
341
+ Claude Code と Claude Desktop、どっちでも動く。ただし入れるものが少し違う。
342
+ </p>
343
+ </header>
344
+
345
+ <section>
346
+ <h2><span class="n">01</span>まず、3つ用意する</h2>
347
+ <p class="lede">
348
+ ここが一番つまづくとこ。<b>ういの絵はリポジトリに入ってない。</b>
349
+ 権利のある素材だから、別で持ってくる必要がある。
350
+ </p>
351
+ <div class="fig">
352
+ <svg viewBox="0 0 620 200" role="img" aria-label="必要な3つのもの:Node、立ち絵PSD、音声合成アプリ">
353
+ <g fill="var(--card)" stroke="var(--rule)" stroke-width="1.5">
354
+ <rect x="14" y="30" width="186" height="140" rx="12"></rect>
355
+ <rect x="420" y="30" width="186" height="140" rx="12"></rect>
356
+ </g>
357
+ <rect x="217" y="30" width="186" height="140" rx="12" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="2"></rect>
358
+ <g font-family="Zen Maru Gothic, sans-serif" font-size="16" fill="var(--ink)" text-anchor="middle">
359
+ <text x="107" y="72">Node.js</text>
360
+ <text x="310" y="72">立ち絵の PSD</text>
361
+ <text x="513" y="72">VoiSona Talk</text>
362
+ </g>
363
+ <g font-family="Zen Kaku Gothic New, sans-serif" font-size="13" fill="var(--ink-soft)" text-anchor="middle">
364
+ <text x="107" y="100">これが土台</text>
365
+ <text x="310" y="100">ういの体</text>
366
+ <text x="513" y="100">ういの声</text>
367
+ </g>
368
+ <g font-family="Roboto Mono, monospace" font-size="11" fill="var(--ink-faint)" text-anchor="middle">
369
+ <text x="107" y="132">npm が使えれば OK</text>
370
+ <text x="310" y="132">BOOTH で入手 → ういが取り込む</text>
371
+ <text x="513" y="132">voisona.com で入手(任意)</text>
372
+ </g>
373
+ <text x="310" y="156" text-anchor="middle" font-family="Zen Kaku Gothic New, sans-serif" font-size="12" fill="var(--accent)">ここだけ自分で用意</text>
374
+ </svg>
375
+ </div>
376
+ <p class="cap">
377
+ PSD は <a href="https://ui-roid.booth.pm/items/8593427" target="_blank" rel="noopener">BOOTH の配布ページ</a>
378
+ から入手する(<a href="https://www.ui-roid.com/guidelines" target="_blank" rel="noopener">キャラクターガイドライン</a>の範囲で利用)。
379
+ 声を出すなら <a href="https://voisona.com/talk/download/" target="_blank" rel="noopener">VoiSona Talk</a>
380
+ (テクノスピーチ・無料)を入れて、ボイスライブラリを1つ以上ダウンロードしておく。
381
+ Electron(ういの窓)は <code>npm install</code> で一緒に入る。VoiSona Talk が無くても
382
+ 吹き出しは出るし口もパクパクする。声が出ないだけ。
383
+ </p>
384
+ </section>
385
+
386
+ <section>
387
+ <h2><span class="n">02</span>コマンドは4つ</h2>
388
+ <div class="steps">
389
+ <div class="step">
390
+ <div class="no">01</div>
391
+ <div class="body">
392
+ <h3>持ってくる</h3>
393
+ <p>リポジトリを好きな場所に置く。パスは後で使うから覚えとく。</p>
394
+ <pre>git clone https://github.com/Uncle-Peke/ui-chan-mcp.git
395
+ cd ui-chan-mcp</pre>
396
+ </div>
397
+ </div>
398
+ <div class="step">
399
+ <div class="no">02</div>
400
+ <div class="body">
401
+ <h3>材料をそろえる</h3>
402
+ <p>これ1回でビルドまで終わる。<code>npm run build</code> は打たなくていい。</p>
403
+ <pre>npm install</pre>
404
+ </div>
405
+ </div>
406
+ <div class="step">
407
+ <div class="no">03</div>
408
+ <div class="body">
409
+ <h3>セットアップに答える</h3>
410
+ <p>
411
+ 対話形式。<b>PSD のパスと、声のカギを聞かれるだけ</b>。どっちも Enter で飛ばせる
412
+ (あとから <code>npx ui-chan</code> をもう一度打てばいい)。PSD は
413
+ <a href="https://ui-roid.booth.pm/items/8593427" target="_blank" rel="noopener">ui-roid.booth.pm</a>
414
+ から。声を使うなら
415
+ <a href="https://voisona.com/talk/download/" target="_blank" rel="noopener">VoiSona Talk</a>
416
+ の「編集 &gt; 環境設定 &gt; API」で REST API を有効にして、そこで決めたパスワードを答える。
417
+ 最後に、どのアプリに入れるかを ↑↓ と Space で選ぶ。
418
+ </p>
419
+ <pre>npx ui-chan</pre>
420
+ </div>
421
+ </div>
422
+ <div class="step">
423
+ <div class="no">04</div>
424
+ <div class="body">
425
+ <h3>足りてるか見る</h3>
426
+ <p>まとめて確認してくれる。⚠️ は「無くても動く」って意味。</p>
427
+ <pre>npx ui-chan doctor</pre>
428
+ </div>
429
+ </div>
430
+ </div>
431
+ <p class="cap">
432
+ 答えた内容は<b>クローンの外</b>、<code>~/.ui-chan/</code> に入る(PSD・声のカギ・自分で足した表情)。
433
+ だから<b>アップデートしても消えない</b>し、クローンごと捨ててもここは残る。
434
+ シェルに <code>export</code> してもよくて、その場合は<b>環境変数のほうが勝つ</b>。
435
+ </p>
436
+ </section>
437
+
438
+ <section>
439
+ <h2><span class="n">03</span>入れ方は2つ。Desktop は両方いる</h2>
440
+ <p class="lede">
441
+ 入れ方は「プラグイン」と「コネクタ」の2つ。<b>プラグインは道具箱、コネクタは電源コード</b>って
442
+ 思っとくといい。<b>電源コードはどのアプリでもいる。</b>道具箱(<code>/talk</code> などのコマンド)は
443
+ Claude Code 専用。上の <code>npx ui-chan</code> は、選んだぶんを両方やってくれる。
444
+ </p>
445
+ <div class="fig">
446
+ <svg viewBox="0 0 620 240" role="img" aria-label="Claude Code と Claude Desktop で、プラグインとコネクタのどちらが必要かの表">
447
+ <g font-family="Zen Maru Gothic, sans-serif" font-size="15" fill="var(--ink)" text-anchor="middle">
448
+ <text x="330" y="34">Claude Code</text>
449
+ <text x="500" y="34">Claude Desktop</text>
450
+ </g>
451
+
452
+ <rect x="14" y="48" width="592" height="84" rx="12" fill="var(--card)" stroke="var(--rule)" stroke-width="1.5"></rect>
453
+ <rect x="14" y="142" width="592" height="84" rx="12" fill="var(--card)" stroke="var(--rule)" stroke-width="1.5"></rect>
454
+
455
+ <rect x="256" y="56" width="148" height="68" rx="9" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="2"></rect>
456
+ <rect x="426" y="56" width="148" height="68" rx="9" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="2"></rect>
457
+ <rect x="426" y="150" width="148" height="68" rx="9" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="2"></rect>
458
+
459
+ <g font-family="Zen Maru Gothic, sans-serif" font-size="15" fill="var(--ink)">
460
+ <text x="34" y="82">プラグイン</text>
461
+ <text x="34" y="176">コネクタ</text>
462
+ </g>
463
+ <g font-family="Zen Kaku Gothic New, sans-serif" font-size="12" fill="var(--ink-faint)">
464
+ <text x="34" y="102">/talk などのコマンド</text>
465
+ <text x="34" y="118">失敗への自動リアクション</text>
466
+ <text x="34" y="196">画面に出る・喋る</text>
467
+ <text x="34" y="212">ういの性格</text>
468
+ </g>
469
+
470
+ <g font-family="Zen Maru Gothic, sans-serif" font-size="15" fill="var(--accent)" text-anchor="middle">
471
+ <text x="330" y="86">いる</text>
472
+ <text x="500" y="86">いる</text>
473
+ <text x="500" y="180">いる</text>
474
+ </g>
475
+ <g font-family="Zen Kaku Gothic New, sans-serif" font-size="11" fill="var(--ink-faint)" text-anchor="middle">
476
+ <text x="330" y="106">これ1つでぜんぶ</text>
477
+ <text x="500" y="106">コマンドは使える</text>
478
+ <text x="500" y="200">これが無いと喋らない</text>
479
+ </g>
480
+ <text x="330" y="180" text-anchor="middle" font-family="Zen Maru Gothic, sans-serif" font-size="15" fill="var(--accent)">いる</text>
481
+ <text x="330" y="200" text-anchor="middle" font-family="Zen Kaku Gothic New, sans-serif" font-size="11" fill="var(--ink-faint)">これが無いと喋らない</text>
482
+ </svg>
483
+ </div>
484
+ <div class="callout">
485
+ <b>プラグインは MCP サーバを持っていない。</b>昔は持たせていたけど、プラグインの外
486
+ (Claude Desktop、OpenCode、ほかのエージェント)では設定の中の
487
+ <code>${CLAUDE_PLUGIN_ROOT}</code> が展開されず<b>必ず起動に失敗する</b>ので、役割を分けた。
488
+ コネクタの登録は全部 <code>ui-chan install</code> がやる。
489
+ </div>
490
+ </section>
491
+
492
+ <section>
493
+ <h2><span class="n">04</span>プラグインを入れる(Code / Desktop 共通)</h2>
494
+ <p class="lede">
495
+ <code>npx ui-chan</code> で <b>claude-code-plugin</b> を選んでいれば、もう終わってる。
496
+ あとから足すならこの1行。<b>入れた内容は Claude Desktop にも共有される。</b>
497
+ </p>
498
+ <div class="steps">
499
+ <div class="step">
500
+ <div class="no">01</div>
501
+ <div class="body">
502
+ <h3>入れる</h3>
503
+ <p>
504
+ 置き場所の登録・インストール・クローンとの紐づけまで、これ1行。
505
+ <b>紐づけまでやるから、あとでリポジトリを直しても Claude Code が古いままにならない。</b>
506
+ </p>
507
+ <pre>npx ui-chan install claude-code-plugin</pre>
508
+ </div>
509
+ </div>
510
+ <div class="step">
511
+ <div class="no">02</div>
512
+ <div class="body">
513
+ <h3>開き直す</h3>
514
+ <p>
515
+ Claude Code は一度終了してもう一度開く。Claude Desktop も使うなら、そっちは
516
+ <b>完全に終了</b>してから起動(Mac は ⌘ + Q。ウィンドウを閉じるだけだと終わってない)。
517
+ 設定 → プラグイン に「ういちゃんデスクトップマスコット」が出ていればOK。
518
+ </p>
519
+ </div>
520
+ </div>
521
+ </div>
522
+ <p class="cap">
523
+ Claude Code のプラグイン機能は、リポジトリを <code>~/.claude/plugins/cache/</code> に
524
+ <b>コピー</b>して使う。つまりコピーが増えて、直す場所が2つになる。
525
+ <code>ui-chan install claude-code-plugin</code> はそのコピーを消して、クローンへの
526
+ ショートカット(symlink)に置き換える。これで<b>本物はクローンだけ</b>になる。
527
+ Desktop 側の追加ボタンは GitHub からの追加しかできないので、登録は Claude Code 側からやる。
528
+ </p>
529
+ </section>
530
+
531
+ <section>
532
+ <h2><span class="n">05</span>コネクタを入れる(どのアプリでも必要)</h2>
533
+ <p class="lede">
534
+ 喋らせるにはこれが必要。<b>アプリの名前を書くだけ。</b>設定ファイルの場所も書式も、
535
+ ういが知ってる。対応してるのは <code>claude-code</code> / <code>claude-desktop</code> /
536
+ <code>opencode</code> / <code>cursor</code> / <code>vscode</code> / <code>hermes</code>。
537
+ </p>
538
+ <div class="steps">
539
+ <div class="step">
540
+ <div class="no">01</div>
541
+ <div class="body">
542
+ <h3>登録する</h3>
543
+ <p>元の設定は <code>.bak</code> に残る。いくつでも並べて書ける。</p>
544
+ <pre>npx ui-chan install claude-desktop opencode</pre>
545
+ </div>
546
+ </div>
547
+ <div class="step">
548
+ <div class="no">02</div>
549
+ <div class="body">
550
+ <h3>アプリを開き直す</h3>
551
+ <p>
552
+ ⌘ + Q で<b>完全に終了</b>してから起動。<code>+</code> メニューの <b>コネクタ</b> に
553
+ ui-chan が出ていれば繋がってる(プラグインの棚とは別のところ)。
554
+ </p>
555
+ </div>
556
+ </div>
557
+ </div>
558
+ <p class="cap">
559
+ 手で書きたいなら、<b>設定</b>(⌘ + カンマ)→ <b>開発者</b> → <b>設定を編集</b> で
560
+ <code>claude_desktop_config.json</code> を開いて、<code>"mcpServers"</code> の中にこれを足す。
561
+ 外すのは <code>npx ui-chan uninstall claude-desktop</code>(<code>--all</code> で全部、
562
+ <code>--purge</code> を足すと <code>~/.ui-chan</code> ごと消える)。一覧にないアプリには
563
+ <code>npx ui-chan print</code> が貼り付け用の設定を出す。
564
+ </p>
565
+ <div class="fig">
566
+ <pre>{
567
+ "mcpServers": {
568
+ "ui-chan": {
569
+ "command": "&lt;ui-chan-mcp を置いた場所&gt;/bin/ui-chan-node",
570
+ "args": ["&lt;ui-chan-mcp を置いた場所&gt;/dist/mcp-server.js"]
571
+ }
572
+ }
573
+ }</pre>
574
+ </div>
575
+ <div class="callout">
576
+ ここで <code>"command": "node"</code> と書くと動かない。アプリから起動された Claude Desktop は
577
+ ターミナルとは別の環境で動いていて、<b>そこからは node が見えない</b>から。
578
+ <code>bin/ui-chan-node</code> は node を自分で探してくれる係。
579
+ </div>
580
+ </section>
581
+
582
+ <section>
583
+ <h2><span class="n">06</span>動いたかどうか</h2>
584
+ <p class="lede">
585
+ 新しいセッションを開けば、勝手にういの窓が出てくる。出てこないなら、
586
+ 先に単体で起動してみると原因が切り分けられる。
587
+ </p>
588
+ <div class="fig">
589
+ <svg viewBox="0 0 620 150" role="img" aria-label="セッション開始で自動起動、または手動起動">
590
+ <defs>
591
+ <marker id="s1" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="7" markerHeight="7" orient="auto">
592
+ <path d="M0 0 L8 4 L0 8 z" fill="var(--accent)"></path>
593
+ </marker>
594
+ </defs>
595
+ <rect x="14" y="24" width="220" height="46" rx="10" fill="var(--card)" stroke="var(--rule)" stroke-width="1.5"></rect>
596
+ <rect x="14" y="90" width="220" height="46" rx="10" fill="var(--card)" stroke="var(--rule)" stroke-width="1.5"></rect>
597
+ <rect x="386" y="57" width="220" height="46" rx="10" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="2"></rect>
598
+ <g stroke="var(--accent)" stroke-width="2" fill="none" marker-end="url(#s1)">
599
+ <path d="M238 47 C 320 47, 320 74, 382 78"></path>
600
+ <path d="M238 113 C 320 113, 320 86, 382 82"></path>
601
+ </g>
602
+ <g font-family="Zen Kaku Gothic New, sans-serif" font-size="14" fill="var(--ink)" text-anchor="middle">
603
+ <text x="124" y="52">セッションを開く</text>
604
+ <text x="124" y="118">単体で起動</text>
605
+ <text x="496" y="85">画面のすみに出る</text>
606
+ </g>
607
+ <g font-family="Roboto Mono, monospace" font-size="11" fill="var(--ink-faint)" text-anchor="middle">
608
+ <text x="124" y="68">自動</text>
609
+ <text x="124" y="134">npx ui-chan start</text>
610
+ </g>
611
+ </svg>
612
+ </div>
613
+ <div class="callout">
614
+ うんともすんとも言わないときは <code>npx ui-chan doctor</code> に戻る。
615
+ ❌ が出るのは「ビルドされてない」ときだけで、それ以外は動くはず。
616
+ </div>
617
+ </section>
618
+
619
+ <section>
620
+ <h2><span class="n">07</span>あとで直したとき</h2>
621
+ <p class="lede">
622
+ コードや台詞をいじったら、これだけ。<b>プラグインもコネクタも同じクローンを見てる</b>から、
623
+ 片方だけ古い、みたいなことは起きない。
624
+ </p>
625
+ <div class="steps">
626
+ <div class="step">
627
+ <div class="no">01</div>
628
+ <div class="body">
629
+ <h3>作り直す</h3>
630
+ <p>次のセッションから反映される。Cue(表情)の <code>.json</code> だけなら保存した瞬間に反映されるので、これも要らない。</p>
631
+ <pre>npm run build</pre>
632
+ </div>
633
+ </div>
634
+ <div class="step">
635
+ <div class="no">02</div>
636
+ <div class="body">
637
+ <h3>もし <code>/plugin install</code> を手で打ち直したら</h3>
638
+ <p>コピーが復活してつながりが切れるので、もう一度これを打つ。</p>
639
+ <pre>npx ui-chan install claude-code-plugin</pre>
640
+ </div>
641
+ </div>
642
+ </div>
643
+ </section>
644
+
645
+ <footer>
646
+ <p>立ち絵素材:雨衣(うい)/坂本アヒル様</p>
647
+ <p>利用は<a href="https://www.ui-roid.com/guidelines" target="_blank" rel="noopener">雨衣キャラクターガイドライン</a>の範囲で。</p>
648
+ </footer>
649
+
650
+ <script>
651
+ (function () {
652
+ var root = document.documentElement;
653
+ var btn = document.querySelector('.theme-toggle');
654
+ var KEY = 'ui-chan-setup-theme';
655
+ var dark = window.matchMedia('(prefers-color-scheme: dark)');
656
+
657
+ var saved = null;
658
+ try { saved = localStorage.getItem(KEY); } catch (e) { /* プライベートウィンドウなど */ }
659
+ if (saved === 'light' || saved === 'dark') root.dataset.theme = saved;
660
+
661
+ function current() {
662
+ return root.dataset.theme || (dark.matches ? 'dark' : 'light');
663
+ }
664
+ function sync() {
665
+ var now = current();
666
+ btn.dataset.mode = now;
667
+ btn.setAttribute(
668
+ 'aria-label',
669
+ now === 'dark' ? 'ライトテーマに切り替える' : 'ダークテーマに切り替える'
670
+ );
671
+ }
672
+
673
+ btn.addEventListener('click', function () {
674
+ var next = current() === 'dark' ? 'light' : 'dark';
675
+ root.dataset.theme = next;
676
+ root.style.colorScheme = next;
677
+ try { localStorage.setItem(KEY, next); } catch (e) { /* 保存できなくても切り替えは効く */ }
678
+ sync();
679
+ });
680
+ dark.addEventListener('change', sync);
681
+ sync();
682
+ })();
683
+ </script>
684
+ </div>