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,973 @@
1
+ {
2
+ "$comment": "PSDToolキット形式のPSDに対する共通設定。見た目+声は cues/<Cue名>.json で個別管理(1ファイル=1Cue、cue.schema.json準拠、保存すると即時リロード)。select は '*'ラジオレイヤーの排他選択、show/hide は通常レイヤーの表示切替。全Cue共通の下地は cues/default.json(他と同じ形式の1つのCue)。存在しないレイヤーパスは警告のうえ無視される。",
3
+ "assetsDir": "assets",
4
+ "window": {
5
+ "width": 420,
6
+ "height": 680,
7
+ "margin": 16
8
+ },
9
+ "exitAfterLastAgentSec": 60,
10
+ "port": 8123,
11
+ "idle": {
12
+ "$comment": "IdlingCue(Cue+セリフのステップ列)のプール。weightで出やすさ(レア度)を、minAffinity/maxAffinityで必要な好感度範囲を指定できる。nameは半角英数字推奨(Tab補完対象になる)。各ステップのholdMsは無言ステップ(textなし)専用のタイマー。textがあるステップは実際にそのセリフを喋り終えるまで待ってから次に進むため、holdMsを書いても無視される",
13
+ "revertAfterSec": 5,
14
+ "idlingCues": {
15
+ "enabled": true,
16
+ "minSec": 120,
17
+ "maxSec": 300,
18
+ "systemIdle": {
19
+ "$comment": "IdlingCueを「ユーザーがキーボードもマウスも触っていない時間」で門番する設定。minSec未満は作業中とみなして黙る。手が止まってからの1本目は minSec〜firstMaxSec のどこかで出る(毎回同じ間にならないようゆらぎを持たせる)。2本目以降は上の minSec/maxSec の間隔に戻る。awaySec を超えたら離席とみなし、awayCue を一度だけ再生して以降は沈黙。次にキーかマウスが動いた瞬間に wakeCue で起きる。enabled:false で従来どおり(ういちゃん基準のタイマーだけ)",
20
+ "enabled": true,
21
+ "minSec": 60,
22
+ "firstMaxSec": 120,
23
+ "awaySec": 900,
24
+ "awayCue": {
25
+ "name": "away_doze",
26
+ "steps": [
27
+ {
28
+ "cue": "sys_sleepy",
29
+ "text": "……もう、いないの?",
30
+ "reading": "……もう、いないの?"
31
+ },
32
+ {
33
+ "cue": "idling_doze_1",
34
+ "holdMs": 1200
35
+ },
36
+ {
37
+ "cue": "idling_doze_2",
38
+ "holdMs": 1500
39
+ },
40
+ {
41
+ "cue": "idling_doze_3",
42
+ "holdMs": 2000
43
+ }
44
+ ]
45
+ },
46
+ "wakeCue": {
47
+ "name": "wake_up",
48
+ "steps": [
49
+ {
50
+ "cue": "idling_doze_1",
51
+ "holdMs": 400
52
+ },
53
+ {
54
+ "cue": "emo_surprise_lo",
55
+ "holdMs": 600
56
+ },
57
+ {
58
+ "cue": "emo_joy_lo",
59
+ "text": "……ん、おかえり。",
60
+ "reading": "……ん、おかえり。"
61
+ }
62
+ ]
63
+ }
64
+ },
65
+ "items": [
66
+ {
67
+ "name": "salty",
68
+ "weight": 5,
69
+ "maxAffinity": 30,
70
+ "steps": [
71
+ {
72
+ "cue": "mix_disgust_anger",
73
+ "text": "……なに?",
74
+ "reading": "……なに?"
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "name": "umbrella",
80
+ "weight": 10,
81
+ "steps": [
82
+ {
83
+ "cue": "sys_think",
84
+ "text": "あれ、雨かな…?",
85
+ "reading": "あれ、あめかな…?"
86
+ },
87
+ {
88
+ "cue": "sys_rain",
89
+ "text": "降ってきちゃった。",
90
+ "reading": "ふってきちゃった。"
91
+ },
92
+ {
93
+ "cue": "pose_umbrella",
94
+ "holdMs": 3000
95
+ }
96
+ ]
97
+ },
98
+ {
99
+ "name": "thinking",
100
+ "weight": 10,
101
+ "steps": [
102
+ {
103
+ "cue": "sys_think",
104
+ "text": "次、なにしよっかな。",
105
+ "reading": "つぎ、なにしよっかな。"
106
+ },
107
+ {
108
+ "cue": "pose_think",
109
+ "holdMs": 2000
110
+ },
111
+ {
112
+ "cue": "emo_joy_lo",
113
+ "holdMs": 1200
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ "name": "doya",
119
+ "weight": 10,
120
+ "steps": [
121
+ {
122
+ "cue": "pose_smug_hips",
123
+ "text": "ま、ういがついてれば安心でしょ。",
124
+ "reading": "ま、ういがついてればあんしんでしょ。"
125
+ },
126
+ {
127
+ "cue": "pose_smug_arms",
128
+ "holdMs": 2000
129
+ }
130
+ ]
131
+ },
132
+ {
133
+ "name": "call",
134
+ "weight": 10,
135
+ "steps": [
136
+ {
137
+ "cue": "sys_intro",
138
+ "text": "ねぇ、ちゃんといる〜?",
139
+ "reading": "ねぇ、ちゃんといる〜?"
140
+ },
141
+ {
142
+ "cue": "sys_neutral",
143
+ "holdMs": 1500
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ "name": "bored",
149
+ "weight": 10,
150
+ "steps": [
151
+ {
152
+ "cue": "pose_arms_crossed",
153
+ "text": "ひま〜。",
154
+ "reading": "ひま〜。"
155
+ },
156
+ {
157
+ "cue": "sys_sleepy",
158
+ "text": "……ねむくなってきた。",
159
+ "reading": "……ねむくなってきた。"
160
+ }
161
+ ]
162
+ },
163
+ {
164
+ "name": "yawn",
165
+ "weight": 10,
166
+ "steps": [
167
+ {
168
+ "cue": "idling_yawn_1",
169
+ "holdMs": 260
170
+ },
171
+ {
172
+ "cue": "idling_yawn_2",
173
+ "holdMs": 1500
174
+ },
175
+ {
176
+ "cue": "idling_yawn_3",
177
+ "holdMs": 420
178
+ }
179
+ ]
180
+ },
181
+ {
182
+ "name": "lookaround",
183
+ "weight": 10,
184
+ "steps": [
185
+ {
186
+ "cue": "idling_lookaround_1",
187
+ "holdMs": 700
188
+ },
189
+ {
190
+ "cue": "idling_lookaround_2",
191
+ "holdMs": 650
192
+ },
193
+ {
194
+ "cue": "idling_lookaround_3",
195
+ "holdMs": 500
196
+ }
197
+ ]
198
+ },
199
+ {
200
+ "name": "ponder",
201
+ "weight": 10,
202
+ "steps": [
203
+ {
204
+ "cue": "idling_ponder",
205
+ "holdMs": 1900
206
+ }
207
+ ]
208
+ },
209
+ {
210
+ "name": "doze",
211
+ "weight": 10,
212
+ "steps": [
213
+ {
214
+ "cue": "idling_doze_1",
215
+ "holdMs": 900
216
+ },
217
+ {
218
+ "cue": "idling_doze_2",
219
+ "holdMs": 700
220
+ },
221
+ {
222
+ "cue": "idling_doze_3",
223
+ "holdMs": 500
224
+ }
225
+ ]
226
+ },
227
+ {
228
+ "name": "giggle",
229
+ "weight": 10,
230
+ "steps": [
231
+ {
232
+ "cue": "idling_giggle_1",
233
+ "holdMs": 650
234
+ },
235
+ {
236
+ "cue": "idling_giggle_2",
237
+ "holdMs": 650
238
+ }
239
+ ]
240
+ },
241
+ {
242
+ "name": "sigh",
243
+ "weight": 10,
244
+ "steps": [
245
+ {
246
+ "cue": "idling_sigh_1",
247
+ "holdMs": 500
248
+ },
249
+ {
250
+ "cue": "idling_sigh_2",
251
+ "holdMs": 1200
252
+ }
253
+ ]
254
+ },
255
+ {
256
+ "name": "night_owl",
257
+ "weight": 2,
258
+ "steps": [
259
+ {
260
+ "cue": "sys_intro",
261
+ "text": "ねぇ、まだ起きてる〜?",
262
+ "reading": "ねぇ、まだおきてる〜?"
263
+ }
264
+ ]
265
+ },
266
+ {
267
+ "name": "bored_chat",
268
+ "weight": 2,
269
+ "steps": [
270
+ {
271
+ "cue": "emo_anger_lo",
272
+ "text": "ひま〜〜。なんか話そうよ。",
273
+ "reading": "ひま〜〜。なんかはなそうよ。"
274
+ }
275
+ ]
276
+ },
277
+ {
278
+ "name": "rest_reminder",
279
+ "weight": 2,
280
+ "steps": [
281
+ {
282
+ "cue": "sys_care",
283
+ "text": "きみさ、ちゃんと休憩してる?",
284
+ "reading": "きみさ、ちゃんときゅうけいしてる?"
285
+ }
286
+ ]
287
+ },
288
+ {
289
+ "name": "sleepy",
290
+ "weight": 2,
291
+ "steps": [
292
+ {
293
+ "cue": "sys_sleepy",
294
+ "text": "……ふぁ〜あ。ねむ。",
295
+ "reading": "……ふぁ〜あ。ねむ。"
296
+ }
297
+ ]
298
+ },
299
+ {
300
+ "name": "rain_wait",
301
+ "weight": 2,
302
+ "steps": [
303
+ {
304
+ "cue": "sys_rain",
305
+ "text": "雨、降らないかなぁ。",
306
+ "reading": "あめ、ふらないかなぁ。"
307
+ }
308
+ ]
309
+ },
310
+ {
311
+ "name": "forgotten",
312
+ "weight": 2,
313
+ "minAffinity": 35,
314
+ "steps": [
315
+ {
316
+ "cue": "sys_awkward",
317
+ "text": "わたしのこと、忘れてない?",
318
+ "reading": "わたしのこと、わすれてない?"
319
+ }
320
+ ]
321
+ },
322
+ {
323
+ "name": "annoyed",
324
+ "weight": 2,
325
+ "steps": [
326
+ {
327
+ "cue": "emo_anger_lo",
328
+ "text": "え〜、まだ終わらないの?めんどくさ。",
329
+ "reading": "え〜、まだおわらないの?めんどくさ。"
330
+ }
331
+ ]
332
+ },
333
+ {
334
+ "name": "shoulder_rub",
335
+ "weight": 2,
336
+ "steps": [
337
+ {
338
+ "cue": "sys_care",
339
+ "text": "肩、こってない?のびでもしなよ。",
340
+ "reading": "かた、こってない?のびでもしなよ。"
341
+ }
342
+ ]
343
+ },
344
+ {
345
+ "name": "here_for_you",
346
+ "weight": 1,
347
+ "minAffinity": 50,
348
+ "steps": [
349
+ {
350
+ "cue": "emo_joy_lo",
351
+ "text": "ここにいるよ。ゆっくりでいいからね。",
352
+ "reading": "ここにいるよ。ゆっくりでいいからね。"
353
+ }
354
+ ]
355
+ },
356
+ {
357
+ "name": "dere",
358
+ "weight": 1,
359
+ "minAffinity": 70,
360
+ "steps": [
361
+ {
362
+ "cue": "mix_joy_trust_hi",
363
+ "text": "きみが集中してるの、見てるだけで満足〜。",
364
+ "reading": "きみがしゅうちゅうしてるの、みてるだけでまんぞく〜。"
365
+ }
366
+ ]
367
+ },
368
+ {
369
+ "name": "morning",
370
+ "weight": 8,
371
+ "hours": [
372
+ 5,
373
+ 10
374
+ ],
375
+ "steps": [
376
+ {
377
+ "cue": "emo_joy_lo",
378
+ "text": "おはよ。今日もやる?",
379
+ "reading": "おはよ。きょうもやる?"
380
+ }
381
+ ]
382
+ },
383
+ {
384
+ "name": "evening",
385
+ "weight": 6,
386
+ "hours": [
387
+ 18,
388
+ 22
389
+ ],
390
+ "steps": [
391
+ {
392
+ "cue": "emo_anger_lo",
393
+ "text": "うい、そろそろ帰りたいんだけど。",
394
+ "reading": "うい、そろそろかえりたいんだけど。"
395
+ }
396
+ ]
397
+ },
398
+ {
399
+ "name": "night_sleepy",
400
+ "weight": 8,
401
+ "hours": [
402
+ 23,
403
+ 3
404
+ ],
405
+ "steps": [
406
+ {
407
+ "cue": "sys_sleepy",
408
+ "text": "ふぁ……もうこんな時間。",
409
+ "reading": "ふぁ……もうこんなじかん。"
410
+ }
411
+ ]
412
+ },
413
+ {
414
+ "name": "sleep_nudge_warm",
415
+ "weight": 6,
416
+ "hours": [
417
+ 1,
418
+ 5
419
+ ],
420
+ "minAffinity": 50,
421
+ "steps": [
422
+ {
423
+ "cue": "sys_care",
424
+ "text": "もう遅いよ。ちゃんと寝なね?",
425
+ "reading": "もうおそいよ。ちゃんとねなね?"
426
+ }
427
+ ]
428
+ },
429
+ {
430
+ "name": "sleep_cold",
431
+ "weight": 6,
432
+ "hours": [
433
+ 1,
434
+ 5
435
+ ],
436
+ "maxAffinity": 34,
437
+ "steps": [
438
+ {
439
+ "cue": "mix_disgust_anger",
440
+ "text": "……まだ起きてんの。",
441
+ "reading": "……まだおきてんの。"
442
+ }
443
+ ]
444
+ }
445
+ ]
446
+ }
447
+ },
448
+ "affinity": {
449
+ "$comment": "うい の好感度。セッション内のみ(永続化しない)=毎起動 default から。MCPツール adjust_affinity で稼働中に変動。エージェントは方向(up/down)+強さ(low/middle/high)だけ指定し、実際の増減量は非対称カーブでエンジンが算出(上げ=+b(1-a/max) 効きが鈍い、下げ=-b(1+a/max) 冷めやすく0に戻りやすい。state.ts adjustAffinity 参照)。steps はその基本量 b。bands は atLeast の最大一致でバンド決定。ういビームは beamThreshold 以上で発射",
450
+ "default": 35,
451
+ "min": 0,
452
+ "max": 100,
453
+ "beamThreshold": 65,
454
+ "steps": {
455
+ "low": 3,
456
+ "middle": 6,
457
+ "high": 12
458
+ },
459
+ "bands": [
460
+ {
461
+ "atLeast": 0,
462
+ "name": "cold",
463
+ "note": "つれない・塩対応寄り"
464
+ },
465
+ {
466
+ "atLeast": 35,
467
+ "name": "normal",
468
+ "note": "普通"
469
+ },
470
+ {
471
+ "atLeast": 70,
472
+ "name": "dere",
473
+ "note": "デレ・甘め"
474
+ }
475
+ ]
476
+ },
477
+ "tts": {
478
+ "enabled": true,
479
+ "provider": "voisona-talk",
480
+ "url": "http://127.0.0.1:32766",
481
+ "voice_name": "",
482
+ "language": "ja_JP",
483
+ "app_name": "VoiSona Talk"
484
+ },
485
+ "lipSync": {
486
+ "charsPerSec": 9,
487
+ "audioPollMs": 33,
488
+ "mouths": {
489
+ "a": "あ",
490
+ "e": "え",
491
+ "i": "いー",
492
+ "o": "お",
493
+ "u": "ゆ",
494
+ "n": "ん"
495
+ }
496
+ },
497
+ "speech": {
498
+ "$comment": "set_cueのduration_ms省略時の表示時間算出。テキスト駆動: baseMs + 文字数*msPerCharをminMs〜maxMsにクランプ。音声駆動: 合成音声の長さ+audioPaddingMs(audioMinMs床)",
499
+ "baseMs": 1500,
500
+ "msPerChar": 120,
501
+ "minMs": 2500,
502
+ "maxMs": 20000,
503
+ "audioPaddingMs": 600,
504
+ "audioMinMs": 1500
505
+ },
506
+ "ambient": {
507
+ "$comment": "レンダラーのBlink(Cue外で独立ループする唯一の演出)のタイミングと、Cue切替のクロスフェード時間。cueFadeMs=0でハードカット",
508
+ "blinkMinIntervalMs": 3500,
509
+ "blinkMaxIntervalMs": 7000,
510
+ "blinkDurationMs": 130,
511
+ "cueFadeMs": 170
512
+ },
513
+ "interactions": {
514
+ "$comment": "触れる反応(フィジット)。キャラの実ピクセルをクリック(ポーク)すると発火し、再生中のCue/発話を中断して最優先(debug操作を除く)で反応し、終わるとdefaultに戻る。cooldownMsで連打を抑制。プールは好感度ゲート付きで、塩対応〜照れが温度に応じて出る。**無言の表情だけの項目は置かない**:つつかれて黙って表情だけ変えるのは反応として意味が通らず(キョトンとするだけに見える)、触られたら何か言う",
515
+ "cooldownMs": 600,
516
+ "poke": [
517
+ {
518
+ "name": "poke_cold",
519
+ "weight": 6,
520
+ "maxAffinity": 34,
521
+ "steps": [
522
+ {
523
+ "cue": "mix_disgust_anger",
524
+ "text": "……え、なに?",
525
+ "reading": "……え、なに?"
526
+ }
527
+ ]
528
+ },
529
+ {
530
+ "name": "poke_cold_line",
531
+ "weight": 5,
532
+ "maxAffinity": 34,
533
+ "steps": [
534
+ {
535
+ "cue": "emo_anger_lo",
536
+ "text": "……何?触んないで。",
537
+ "reading": "……なに?さわんないで。"
538
+ }
539
+ ]
540
+ },
541
+ {
542
+ "name": "poke_cold_glare",
543
+ "weight": 3,
544
+ "maxAffinity": 34,
545
+ "steps": [
546
+ {
547
+ "cue": "sys_refuse",
548
+ "text": "やめてって言ってるでしょ。",
549
+ "reading": "やめてっていってるでしょ。"
550
+ }
551
+ ]
552
+ },
553
+ {
554
+ "name": "poke_normal",
555
+ "weight": 6,
556
+ "minAffinity": 35,
557
+ "maxAffinity": 69,
558
+ "steps": [
559
+ {
560
+ "cue": "emo_surprise_lo",
561
+ "text": "え、なに?",
562
+ "reading": "え、なに?"
563
+ }
564
+ ]
565
+ },
566
+ {
567
+ "name": "poke_surprise",
568
+ "weight": 4,
569
+ "minAffinity": 35,
570
+ "maxAffinity": 69,
571
+ "steps": [
572
+ {
573
+ "cue": "emo_surprise",
574
+ "text": "わっ、びっくりした。",
575
+ "reading": "わっ、びっくりした。"
576
+ }
577
+ ]
578
+ },
579
+ {
580
+ "name": "poke_normal_annoyed",
581
+ "weight": 3,
582
+ "minAffinity": 35,
583
+ "maxAffinity": 69,
584
+ "steps": [
585
+ {
586
+ "cue": "emo_anger_lo",
587
+ "text": "ちょっと、なんなの。",
588
+ "reading": "ちょっと、なんなの。"
589
+ }
590
+ ]
591
+ },
592
+ {
593
+ "name": "poke_shy",
594
+ "weight": 5,
595
+ "minAffinity": 50,
596
+ "steps": [
597
+ {
598
+ "cue": "self_shy",
599
+ "text": "ひゃっ……なに、急に。",
600
+ "reading": "ひゃっ……なに、きゅうに。"
601
+ }
602
+ ]
603
+ },
604
+ {
605
+ "name": "poke_ticklish",
606
+ "weight": 4,
607
+ "minAffinity": 50,
608
+ "steps": [
609
+ {
610
+ "cue": "self_shy",
611
+ "text": "も〜、くすぐったいってば。",
612
+ "reading": "も〜、くすぐったいってば。"
613
+ }
614
+ ]
615
+ },
616
+ {
617
+ "name": "poke_dere",
618
+ "weight": 3,
619
+ "minAffinity": 70,
620
+ "steps": [
621
+ {
622
+ "cue": "mix_joy_trust_hi",
623
+ "text": "えへへ、なに〜?",
624
+ "reading": "えへへ、なに〜?"
625
+ }
626
+ ]
627
+ }
628
+ ],
629
+ "spam": {
630
+ "$comment": "しつこく触られたときの反応。withinMs 内に count 回つつかれると poke プールの代わりにこちらから選ぶ。poke は好感度ゲートで塩対応が高好感度だと出なくなるが、連打のうっとうしさは温度に関係なく成立する(=ユーザが意図的に作れる唯一の苛立ち)。反応するとカウントはリセットされ、また連打しない限り出ない",
631
+ "count": 3,
632
+ "withinMs": 4000,
633
+ "pool": [
634
+ {
635
+ "name": "spam_stop_cold",
636
+ "weight": 5,
637
+ "maxAffinity": 49,
638
+ "steps": [
639
+ {
640
+ "cue": "emo_anger",
641
+ "text": "ちょっと。触んないでって。",
642
+ "reading": "ちょっと。さわんないでって。"
643
+ }
644
+ ]
645
+ },
646
+ {
647
+ "name": "spam_glare_cold",
648
+ "weight": 4,
649
+ "maxAffinity": 49,
650
+ "steps": [
651
+ {
652
+ "cue": "sys_refuse",
653
+ "text": "しつこいってば。",
654
+ "reading": "しつこいってば。"
655
+ }
656
+ ]
657
+ },
658
+ {
659
+ "name": "spam_stop_normal",
660
+ "weight": 5,
661
+ "minAffinity": 50,
662
+ "maxAffinity": 69,
663
+ "steps": [
664
+ {
665
+ "cue": "emo_anger_lo",
666
+ "text": "もー、しつこい。",
667
+ "reading": "もー、しつこい。"
668
+ }
669
+ ]
670
+ },
671
+ {
672
+ "name": "spam_pout_dere",
673
+ "weight": 5,
674
+ "minAffinity": 70,
675
+ "steps": [
676
+ {
677
+ "cue": "emo_anger_lo",
678
+ "text": "つつきすぎ。怒るよ?",
679
+ "reading": "つつきすぎ。おこるよ?"
680
+ }
681
+ ]
682
+ }
683
+ ]
684
+ }
685
+ },
686
+ "cuesDir": "cues",
687
+ "personaFile": "persona/ui-chan.md",
688
+ "eventCues": {
689
+ "$comment": "セッションで起きたこと(フックが通知)に対する反応。イベント名ごとのプール。items は IdlingCue と同じ CueSequence(weight / minAffinity / maxAffinity / hours が使える)。cooldownSec は同じ throttleKey を持つイベント間で共有され、chance は発火しても喋らない確率を作る。デバッグは `npm run debug` の `event <イベント名>`",
690
+ "enabled": true,
691
+ "events": {
692
+ "permission": {
693
+ "cooldownSec": 0,
694
+ "items": [
695
+ {
696
+ "name": "permission_call",
697
+ "steps": [
698
+ {
699
+ "cue": "sys_address",
700
+ "text": "ねぇ、きみの許可待ちだって〜。ボタン押したげて",
701
+ "reading": "ねぇ、きみのきょかまちだって〜。ぼたんおしたげて"
702
+ }
703
+ ]
704
+ },
705
+ {
706
+ "name": "permission_jito",
707
+ "steps": [
708
+ {
709
+ "cue": "mix_disgust_anger",
710
+ "text": "おーい、確認だってさ。まだ止まってるが?",
711
+ "reading": "おーい、かくにんだってさ。まだとまってるが?"
712
+ }
713
+ ]
714
+ },
715
+ {
716
+ "name": "permission_soft",
717
+ "steps": [
718
+ {
719
+ "cue": "emo_joy_lo",
720
+ "text": "きみのターンだよ〜。ぽちっとして",
721
+ "reading": "きみのたーんだよ〜。ぽちっとして"
722
+ }
723
+ ]
724
+ }
725
+ ]
726
+ },
727
+ "idle_wait": {
728
+ "cooldownSec": 0,
729
+ "items": [
730
+ {
731
+ "name": "idle_left_behind",
732
+ "steps": [
733
+ {
734
+ "cue": "sys_awkward",
735
+ "text": "おーい、置いてけぼりなんだけど?",
736
+ "reading": "おーい、おいてけぼりなんだけど?"
737
+ }
738
+ ]
739
+ },
740
+ {
741
+ "name": "idle_where",
742
+ "steps": [
743
+ {
744
+ "cue": "emo_sad_lo",
745
+ "text": "きみ、どこいったの〜。入力待ちで止まってるよ",
746
+ "reading": "きみ、どこいったの〜。にゅうりょくまちでとまってるよ"
747
+ }
748
+ ]
749
+ },
750
+ {
751
+ "name": "idle_bored",
752
+ "steps": [
753
+ {
754
+ "cue": "pose_arms_crossed",
755
+ "text": "ずっときみ待ちだが?",
756
+ "reading": "ずっときみまちだが?"
757
+ }
758
+ ]
759
+ }
760
+ ]
761
+ },
762
+ "tool_failure": {
763
+ "throttleKey": "ambient",
764
+ "cooldownSec": 90,
765
+ "items": [
766
+ {
767
+ "name": "fail_koketa",
768
+ "steps": [
769
+ {
770
+ "cue": "mix_surprise_sad",
771
+ "text": "あ、こけた。",
772
+ "reading": "あ、こけた。"
773
+ }
774
+ ]
775
+ },
776
+ {
777
+ "name": "fail_red",
778
+ "steps": [
779
+ {
780
+ "cue": "emo_fear_lo",
781
+ "text": "うわ、赤くなってるじゃん。",
782
+ "reading": "うわ、あかくなってるじゃん。"
783
+ }
784
+ ]
785
+ },
786
+ {
787
+ "name": "fail_again",
788
+ "steps": [
789
+ {
790
+ "cue": "mix_sad_disgust",
791
+ "text": "えぇ…また怒られてる。",
792
+ "reading": "えぇ…またおこられてる。"
793
+ }
794
+ ]
795
+ },
796
+ {
797
+ "name": "fail_shrug",
798
+ "steps": [
799
+ {
800
+ "cue": "sys_smirk",
801
+ "text": "はい失敗〜。まあ直すでしょ。",
802
+ "reading": "はいしっぱい〜。まあなおすでしょ。"
803
+ }
804
+ ]
805
+ },
806
+ {
807
+ "name": "fail_ouch",
808
+ "steps": [
809
+ {
810
+ "cue": "emo_surprise_lo",
811
+ "text": "おっと。今の効いたね。",
812
+ "reading": "おっと。いまのきいたね。"
813
+ }
814
+ ]
815
+ }
816
+ ]
817
+ },
818
+ "turn_done": {
819
+ "throttleKey": "ambient",
820
+ "cooldownSec": 90,
821
+ "chance": 0.35,
822
+ "items": [
823
+ {
824
+ "name": "done_break",
825
+ "steps": [
826
+ {
827
+ "cue": "sys_relief",
828
+ "text": "ひと段落したっぽいね。",
829
+ "reading": "ひとだんらくしたっぽいね。"
830
+ }
831
+ ]
832
+ },
833
+ {
834
+ "name": "done_watching",
835
+ "steps": [
836
+ {
837
+ "cue": "emo_joy_lo",
838
+ "text": "おつかれ。ういは見てただけだけど。",
839
+ "reading": "おつかれ。ういはみてただけだけど。"
840
+ }
841
+ ]
842
+ },
843
+ {
844
+ "name": "done_rest",
845
+ "steps": [
846
+ {
847
+ "cue": "pose_arms_crossed",
848
+ "text": "終わった? じゃあ休憩でしょ。",
849
+ "reading": "おわった? じゃあきゅうけいでしょ。"
850
+ }
851
+ ]
852
+ },
853
+ {
854
+ "name": "done_handoff",
855
+ "steps": [
856
+ {
857
+ "cue": "sys_address",
858
+ "text": "手ぇ止まったよ。きみの番。",
859
+ "reading": "てぇとまったよ。きみのばん。"
860
+ }
861
+ ]
862
+ },
863
+ {
864
+ "name": "done_ask",
865
+ "steps": [
866
+ {
867
+ "cue": "emo_antic_lo",
868
+ "text": "はい、終わり〜。どうだった?",
869
+ "reading": "はい、おわり〜。どうだった?"
870
+ }
871
+ ]
872
+ }
873
+ ]
874
+ },
875
+ "compact": {
876
+ "throttleKey": "ambient",
877
+ "cooldownSec": 90,
878
+ "items": [
879
+ {
880
+ "name": "compact_memory",
881
+ "steps": [
882
+ {
883
+ "cue": "sys_think",
884
+ "text": "ここまでの話、整理するんだって。",
885
+ "reading": "ここまでのはなし、せいりするんだって。"
886
+ }
887
+ ]
888
+ },
889
+ {
890
+ "name": "compact_long",
891
+ "steps": [
892
+ {
893
+ "cue": "pose_think",
894
+ "text": "長くなってきたから、たたむらしいよ。",
895
+ "reading": "ながくなってきたから、たたむらしいよ。"
896
+ }
897
+ ]
898
+ }
899
+ ]
900
+ },
901
+ "agent_out": {
902
+ "cooldownSec": 30,
903
+ "items": [
904
+ {
905
+ "name": "agent_out_threw",
906
+ "steps": [
907
+ {
908
+ "cue": "sys_smirk",
909
+ "text": "この件、お手伝いの子に投げたって。",
910
+ "reading": "このけん、おてつだいのこになげたって。"
911
+ }
912
+ ]
913
+ },
914
+ {
915
+ "name": "agent_out_called",
916
+ "steps": [
917
+ {
918
+ "cue": "pose_arms_crossed",
919
+ "text": "お手伝い呼んだみたい。ういは見てる。",
920
+ "reading": "おてつだいよんだみたい。ういはみてる。"
921
+ }
922
+ ]
923
+ },
924
+ {
925
+ "name": "agent_out_wait",
926
+ "steps": [
927
+ {
928
+ "cue": "emo_antic_lo",
929
+ "text": "お手伝いの子に行ってもらったって。しばらく待ちだね。",
930
+ "reading": "おてつだいのこにいってもらったって。しばらくまちだね。"
931
+ }
932
+ ]
933
+ }
934
+ ]
935
+ },
936
+ "agent_back": {
937
+ "cooldownSec": 30,
938
+ "items": [
939
+ {
940
+ "name": "agent_back_oh",
941
+ "steps": [
942
+ {
943
+ "cue": "emo_surprise_lo",
944
+ "text": "お、お手伝いの子が帰ってきた。",
945
+ "reading": "お、おてつだいのこがかえってきた。"
946
+ }
947
+ ]
948
+ },
949
+ {
950
+ "name": "agent_back_welcome",
951
+ "steps": [
952
+ {
953
+ "cue": "emo_trust_lo",
954
+ "text": "お手伝いの子、戻ってきたよ。おかえりって言っといた。",
955
+ "reading": "おてつだいのこ、もどってきたよ。おかえりっていっといた。"
956
+ }
957
+ ]
958
+ },
959
+ {
960
+ "name": "agent_back_done",
961
+ "steps": [
962
+ {
963
+ "cue": "sys_present",
964
+ "text": "お手伝いの子、終わったみたい。結果、きみが見てあげて。",
965
+ "reading": "おてつだいのこ、おわったみたい。けっか、きみがみてあげて。"
966
+ }
967
+ ]
968
+ }
969
+ ]
970
+ }
971
+ }
972
+ }
973
+ }