@alexkroman1/aai 0.8.8 → 0.9.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 (292) hide show
  1. package/dist/{sdk/_internal_types.d.ts → _internal-types.d.ts} +0 -3
  2. package/dist/_internal-types.js +19 -0
  3. package/dist/{sdk/_mock_ws.d.ts → _mock-ws.d.ts} +16 -5
  4. package/dist/_mock-ws.js +158 -0
  5. package/dist/{sdk/_utils.d.ts → _utils.d.ts} +1 -2
  6. package/dist/_utils.js +8 -0
  7. package/dist/{sdk/builtin_tools.d.ts → builtin-tools.d.ts} +5 -8
  8. package/dist/builtin-tools.js +270 -0
  9. package/dist/{sdk/direct_executor.d.ts → direct-executor.d.ts} +3 -7
  10. package/dist/direct-executor.js +125 -0
  11. package/dist/{sdk/mod.d.ts → index.d.ts} +0 -4
  12. package/dist/index.js +2 -0
  13. package/dist/{sdk/kv.d.ts → kv.d.ts} +23 -20
  14. package/dist/kv.js +99 -0
  15. package/dist/{sdk/protocol.d.ts → protocol.d.ts} +65 -29
  16. package/dist/protocol.js +142 -0
  17. package/dist/runtime.d.ts +18 -0
  18. package/dist/runtime.js +16 -0
  19. package/dist/s2s.d.ts +110 -0
  20. package/dist/s2s.js +242 -0
  21. package/dist/{sdk/server.d.ts → server.d.ts} +3 -23
  22. package/dist/server.js +105 -0
  23. package/dist/{sdk/session.d.ts → session.d.ts} +4 -11
  24. package/dist/session.js +312 -0
  25. package/dist/tsdown.config.d.ts +2 -0
  26. package/dist/{sdk/types.d.ts → types.d.ts} +41 -25
  27. package/dist/types.js +139 -0
  28. package/dist/{sdk/vector.d.ts → vector.d.ts} +14 -15
  29. package/dist/vector.js +56 -0
  30. package/dist/{sdk/worker_entry.d.ts → worker-entry.d.ts} +2 -5
  31. package/dist/worker-entry.js +59 -0
  32. package/dist/{sdk/ws_handler.d.ts → ws-handler.d.ts} +10 -8
  33. package/dist/ws-handler.js +155 -0
  34. package/package.json +66 -149
  35. package/README.md +0 -34
  36. package/dist/aai.js +0 -3
  37. package/dist/cli/tsconfig.tsbuildinfo +0 -1
  38. package/dist/cli.js +0 -2811
  39. package/dist/sdk/_internal_types.d.ts.map +0 -1
  40. package/dist/sdk/_internal_types.js +0 -25
  41. package/dist/sdk/_internal_types.js.map +0 -1
  42. package/dist/sdk/_mock_ws.d.ts.map +0 -1
  43. package/dist/sdk/_mock_ws.js +0 -154
  44. package/dist/sdk/_mock_ws.js.map +0 -1
  45. package/dist/sdk/_render_check.d.ts +0 -10
  46. package/dist/sdk/_render_check.d.ts.map +0 -1
  47. package/dist/sdk/_render_check.js +0 -72
  48. package/dist/sdk/_render_check.js.map +0 -1
  49. package/dist/sdk/_utils.d.ts.map +0 -1
  50. package/dist/sdk/_utils.js +0 -7
  51. package/dist/sdk/_utils.js.map +0 -1
  52. package/dist/sdk/builtin_tools.d.ts.map +0 -1
  53. package/dist/sdk/builtin_tools.js +0 -309
  54. package/dist/sdk/builtin_tools.js.map +0 -1
  55. package/dist/sdk/capnweb.d.ts +0 -102
  56. package/dist/sdk/capnweb.d.ts.map +0 -1
  57. package/dist/sdk/capnweb.js +0 -219
  58. package/dist/sdk/capnweb.js.map +0 -1
  59. package/dist/sdk/define_agent.d.ts +0 -36
  60. package/dist/sdk/define_agent.d.ts.map +0 -1
  61. package/dist/sdk/define_agent.js +0 -71
  62. package/dist/sdk/define_agent.js.map +0 -1
  63. package/dist/sdk/direct_executor.d.ts.map +0 -1
  64. package/dist/sdk/direct_executor.js +0 -145
  65. package/dist/sdk/direct_executor.js.map +0 -1
  66. package/dist/sdk/host.d.ts +0 -59
  67. package/dist/sdk/host.d.ts.map +0 -1
  68. package/dist/sdk/host.js +0 -131
  69. package/dist/sdk/host.js.map +0 -1
  70. package/dist/sdk/kv.d.ts.map +0 -1
  71. package/dist/sdk/kv.js +0 -94
  72. package/dist/sdk/kv.js.map +0 -1
  73. package/dist/sdk/memory_tools.d.ts +0 -38
  74. package/dist/sdk/memory_tools.d.ts.map +0 -1
  75. package/dist/sdk/memory_tools.js +0 -77
  76. package/dist/sdk/memory_tools.js.map +0 -1
  77. package/dist/sdk/mod.d.ts.map +0 -1
  78. package/dist/sdk/mod.js +0 -27
  79. package/dist/sdk/mod.js.map +0 -1
  80. package/dist/sdk/protocol.d.ts.map +0 -1
  81. package/dist/sdk/protocol.js +0 -133
  82. package/dist/sdk/protocol.js.map +0 -1
  83. package/dist/sdk/runtime.d.ts +0 -36
  84. package/dist/sdk/runtime.d.ts.map +0 -1
  85. package/dist/sdk/runtime.js +0 -27
  86. package/dist/sdk/runtime.js.map +0 -1
  87. package/dist/sdk/s2s.d.ts +0 -74
  88. package/dist/sdk/s2s.d.ts.map +0 -1
  89. package/dist/sdk/s2s.js +0 -218
  90. package/dist/sdk/s2s.js.map +0 -1
  91. package/dist/sdk/server.d.ts.map +0 -1
  92. package/dist/sdk/server.js +0 -144
  93. package/dist/sdk/server.js.map +0 -1
  94. package/dist/sdk/session.d.ts.map +0 -1
  95. package/dist/sdk/session.js +0 -303
  96. package/dist/sdk/session.js.map +0 -1
  97. package/dist/sdk/system_prompt.d.ts +0 -6
  98. package/dist/sdk/system_prompt.d.ts.map +0 -1
  99. package/dist/sdk/system_prompt.js +0 -35
  100. package/dist/sdk/system_prompt.js.map +0 -1
  101. package/dist/sdk/tsconfig.tsbuildinfo +0 -1
  102. package/dist/sdk/types.d.ts.map +0 -1
  103. package/dist/sdk/types.js +0 -96
  104. package/dist/sdk/types.js.map +0 -1
  105. package/dist/sdk/vector.d.ts.map +0 -1
  106. package/dist/sdk/vector.js +0 -63
  107. package/dist/sdk/vector.js.map +0 -1
  108. package/dist/sdk/winterc_server.d.ts +0 -56
  109. package/dist/sdk/winterc_server.d.ts.map +0 -1
  110. package/dist/sdk/winterc_server.js +0 -77
  111. package/dist/sdk/winterc_server.js.map +0 -1
  112. package/dist/sdk/worker_entry.d.ts.map +0 -1
  113. package/dist/sdk/worker_entry.js +0 -68
  114. package/dist/sdk/worker_entry.js.map +0 -1
  115. package/dist/sdk/worker_shim.d.ts +0 -19
  116. package/dist/sdk/worker_shim.d.ts.map +0 -1
  117. package/dist/sdk/worker_shim.js +0 -141
  118. package/dist/sdk/worker_shim.js.map +0 -1
  119. package/dist/sdk/ws_handler.d.ts.map +0 -1
  120. package/dist/sdk/ws_handler.js +0 -158
  121. package/dist/sdk/ws_handler.js.map +0 -1
  122. package/dist/ui/_cn.d.ts +0 -5
  123. package/dist/ui/_cn.d.ts.map +0 -1
  124. package/dist/ui/_cn.js +0 -22
  125. package/dist/ui/_cn.js.map +0 -1
  126. package/dist/ui/_components/app.d.ts +0 -5
  127. package/dist/ui/_components/app.d.ts.map +0 -1
  128. package/dist/ui/_components/app.js +0 -12
  129. package/dist/ui/_components/app.js.map +0 -1
  130. package/dist/ui/_components/button.d.ts +0 -11
  131. package/dist/ui/_components/button.d.ts.map +0 -1
  132. package/dist/ui/_components/button.js +0 -17
  133. package/dist/ui/_components/button.js.map +0 -1
  134. package/dist/ui/_components/chat_view.d.ts +0 -5
  135. package/dist/ui/_components/chat_view.d.ts.map +0 -1
  136. package/dist/ui/_components/chat_view.js +0 -15
  137. package/dist/ui/_components/chat_view.js.map +0 -1
  138. package/dist/ui/_components/controls.d.ts +0 -4
  139. package/dist/ui/_components/controls.d.ts.map +0 -1
  140. package/dist/ui/_components/controls.js +0 -10
  141. package/dist/ui/_components/controls.js.map +0 -1
  142. package/dist/ui/_components/error_banner.d.ts +0 -8
  143. package/dist/ui/_components/error_banner.d.ts.map +0 -1
  144. package/dist/ui/_components/error_banner.js +0 -8
  145. package/dist/ui/_components/error_banner.js.map +0 -1
  146. package/dist/ui/_components/message_bubble.d.ts +0 -7
  147. package/dist/ui/_components/message_bubble.d.ts.map +0 -1
  148. package/dist/ui/_components/message_bubble.js +0 -11
  149. package/dist/ui/_components/message_bubble.js.map +0 -1
  150. package/dist/ui/_components/message_list.d.ts +0 -4
  151. package/dist/ui/_components/message_list.d.ts.map +0 -1
  152. package/dist/ui/_components/message_list.js +0 -45
  153. package/dist/ui/_components/message_list.js.map +0 -1
  154. package/dist/ui/_components/sidebar_layout.d.ts +0 -20
  155. package/dist/ui/_components/sidebar_layout.d.ts.map +0 -1
  156. package/dist/ui/_components/sidebar_layout.js +0 -19
  157. package/dist/ui/_components/sidebar_layout.js.map +0 -1
  158. package/dist/ui/_components/start_screen.d.ts +0 -25
  159. package/dist/ui/_components/start_screen.d.ts.map +0 -1
  160. package/dist/ui/_components/start_screen.js +0 -28
  161. package/dist/ui/_components/start_screen.js.map +0 -1
  162. package/dist/ui/_components/state_indicator.d.ts +0 -8
  163. package/dist/ui/_components/state_indicator.d.ts.map +0 -1
  164. package/dist/ui/_components/state_indicator.js +0 -6
  165. package/dist/ui/_components/state_indicator.js.map +0 -1
  166. package/dist/ui/_components/thinking_indicator.d.ts +0 -5
  167. package/dist/ui/_components/thinking_indicator.d.ts.map +0 -1
  168. package/dist/ui/_components/thinking_indicator.js +0 -10
  169. package/dist/ui/_components/thinking_indicator.js.map +0 -1
  170. package/dist/ui/_components/tool_call_block.d.ts +0 -7
  171. package/dist/ui/_components/tool_call_block.d.ts.map +0 -1
  172. package/dist/ui/_components/tool_call_block.js +0 -46
  173. package/dist/ui/_components/tool_call_block.js.map +0 -1
  174. package/dist/ui/_components/tool_icons.d.ts +0 -18
  175. package/dist/ui/_components/tool_icons.d.ts.map +0 -1
  176. package/dist/ui/_components/tool_icons.js +0 -26
  177. package/dist/ui/_components/tool_icons.js.map +0 -1
  178. package/dist/ui/_components/transcript.d.ts +0 -7
  179. package/dist/ui/_components/transcript.d.ts.map +0 -1
  180. package/dist/ui/_components/transcript.js +0 -9
  181. package/dist/ui/_components/transcript.js.map +0 -1
  182. package/dist/ui/_dom_shim.d.ts +0 -7
  183. package/dist/ui/_dom_shim.d.ts.map +0 -1
  184. package/dist/ui/_dom_shim.js +0 -21
  185. package/dist/ui/_dom_shim.js.map +0 -1
  186. package/dist/ui/_hooks.d.ts +0 -21
  187. package/dist/ui/_hooks.d.ts.map +0 -1
  188. package/dist/ui/_hooks.js +0 -35
  189. package/dist/ui/_hooks.js.map +0 -1
  190. package/dist/ui/_jsdom_setup.d.ts +0 -1
  191. package/dist/ui/_jsdom_setup.d.ts.map +0 -1
  192. package/dist/ui/_jsdom_setup.js +0 -6
  193. package/dist/ui/_jsdom_setup.js.map +0 -1
  194. package/dist/ui/_render_check.d.ts +0 -10
  195. package/dist/ui/_render_check.d.ts.map +0 -1
  196. package/dist/ui/_render_check.js +0 -72
  197. package/dist/ui/_render_check.js.map +0 -1
  198. package/dist/ui/_test_utils.js +0 -272
  199. package/dist/ui/_test_utils.js.map +0 -1
  200. package/dist/ui/audio.d.ts +0 -46
  201. package/dist/ui/audio.d.ts.map +0 -1
  202. package/dist/ui/audio.js +0 -130
  203. package/dist/ui/audio.js.map +0 -1
  204. package/dist/ui/components.d.ts +0 -14
  205. package/dist/ui/components.d.ts.map +0 -1
  206. package/dist/ui/components.js +0 -15
  207. package/dist/ui/components.js.map +0 -1
  208. package/dist/ui/components_mod.d.ts +0 -34
  209. package/dist/ui/components_mod.d.ts.map +0 -1
  210. package/dist/ui/components_mod.js +0 -32
  211. package/dist/ui/components_mod.js.map +0 -1
  212. package/dist/ui/mod.d.ts +0 -23
  213. package/dist/ui/mod.d.ts.map +0 -1
  214. package/dist/ui/mod.js +0 -22
  215. package/dist/ui/mod.js.map +0 -1
  216. package/dist/ui/mount.d.ts +0 -44
  217. package/dist/ui/mount.d.ts.map +0 -1
  218. package/dist/ui/mount.js +0 -61
  219. package/dist/ui/mount.js.map +0 -1
  220. package/dist/ui/mount_context.d.ts +0 -22
  221. package/dist/ui/mount_context.d.ts.map +0 -1
  222. package/dist/ui/mount_context.js +0 -10
  223. package/dist/ui/mount_context.js.map +0 -1
  224. package/dist/ui/session.d.ts +0 -96
  225. package/dist/ui/session.d.ts.map +0 -1
  226. package/dist/ui/session.js +0 -379
  227. package/dist/ui/session.js.map +0 -1
  228. package/dist/ui/session_mod.d.ts +0 -19
  229. package/dist/ui/session_mod.d.ts.map +0 -1
  230. package/dist/ui/session_mod.js +0 -18
  231. package/dist/ui/session_mod.js.map +0 -1
  232. package/dist/ui/signals.d.ts +0 -80
  233. package/dist/ui/signals.d.ts.map +0 -1
  234. package/dist/ui/signals.js +0 -137
  235. package/dist/ui/signals.js.map +0 -1
  236. package/dist/ui/tsconfig.tsbuildinfo +0 -1
  237. package/dist/ui/types.d.ts +0 -36
  238. package/dist/ui/types.d.ts.map +0 -1
  239. package/dist/ui/types.js +0 -4
  240. package/dist/ui/types.js.map +0 -1
  241. package/dist/ui/worklets/capture-processor.d.ts +0 -3
  242. package/dist/ui/worklets/capture-processor.d.ts.map +0 -1
  243. package/dist/ui/worklets/capture-processor.js +0 -61
  244. package/dist/ui/worklets/capture-processor.js.map +0 -1
  245. package/dist/ui/worklets/playback-processor.d.ts +0 -3
  246. package/dist/ui/worklets/playback-processor.d.ts.map +0 -1
  247. package/dist/ui/worklets/playback-processor.js +0 -109
  248. package/dist/ui/worklets/playback-processor.js.map +0 -1
  249. package/templates/.env +0 -1
  250. package/templates/_shared/.env.example +0 -5
  251. package/templates/_shared/CLAUDE.md +0 -1073
  252. package/templates/_shared/biome.json +0 -32
  253. package/templates/_shared/global.d.ts +0 -1
  254. package/templates/_shared/index.html +0 -16
  255. package/templates/_shared/package.json +0 -22
  256. package/templates/_shared/tsconfig.json +0 -16
  257. package/templates/code-interpreter/agent.ts +0 -27
  258. package/templates/code-interpreter/client.tsx +0 -3
  259. package/templates/dispatch-center/agent.ts +0 -1223
  260. package/templates/dispatch-center/client.tsx +0 -505
  261. package/templates/embedded-assets/agent.ts +0 -48
  262. package/templates/embedded-assets/client.tsx +0 -3
  263. package/templates/embedded-assets/knowledge.json +0 -20
  264. package/templates/health-assistant/agent.ts +0 -160
  265. package/templates/health-assistant/client.tsx +0 -3
  266. package/templates/infocom-adventure/agent.ts +0 -164
  267. package/templates/infocom-adventure/client.tsx +0 -300
  268. package/templates/math-buddy/agent.ts +0 -21
  269. package/templates/math-buddy/client.tsx +0 -3
  270. package/templates/memory-agent/agent.ts +0 -20
  271. package/templates/memory-agent/client.tsx +0 -3
  272. package/templates/night-owl/agent.ts +0 -98
  273. package/templates/night-owl/client.tsx +0 -12
  274. package/templates/personal-finance/agent.ts +0 -26
  275. package/templates/personal-finance/client.tsx +0 -3
  276. package/templates/pizza-ordering/agent.ts +0 -214
  277. package/templates/pizza-ordering/client.tsx +0 -264
  278. package/templates/simple/agent.ts +0 -6
  279. package/templates/simple/client.tsx +0 -3
  280. package/templates/smart-research/agent.ts +0 -164
  281. package/templates/smart-research/client.tsx +0 -3
  282. package/templates/solo-rpg/agent.ts +0 -1240
  283. package/templates/solo-rpg/client.tsx +0 -698
  284. package/templates/support/README.md +0 -62
  285. package/templates/support/agent.ts +0 -19
  286. package/templates/support/client.tsx +0 -3
  287. package/templates/travel-concierge/agent.ts +0 -29
  288. package/templates/travel-concierge/client.tsx +0 -3
  289. package/templates/tsconfig.json +0 -1
  290. package/templates/web-researcher/agent.ts +0 -17
  291. package/templates/web-researcher/client.tsx +0 -3
  292. package/ui/styles.css +0 -74
@@ -1,698 +0,0 @@
1
- import "@alexkroman1/aai/ui/styles.css";
2
- import { useState } from "preact/hooks";
3
- import {
4
- ChatView,
5
- SidebarLayout,
6
- StartScreen,
7
- mount,
8
- useToolResult,
9
- } from "@alexkroman1/aai/ui";
10
-
11
- // ── Types ────────────────────────────────────────────────────────────────────
12
-
13
- type Disposition = "hostile" | "distrustful" | "neutral" | "friendly" | "loyal";
14
-
15
- interface NPC {
16
- id: string;
17
- name: string;
18
- description: string;
19
- disposition: Disposition;
20
- bond: number;
21
- agenda: string;
22
- status: "active" | "background" | "deceased";
23
- }
24
-
25
- interface ClockData {
26
- id: string;
27
- name: string;
28
- clockType: "threat" | "progress" | "scheme";
29
- segments: number;
30
- filled: number;
31
- triggerDescription: string;
32
- }
33
-
34
- interface StoryInfo {
35
- structureType: string;
36
- currentAct: number;
37
- totalActs: number;
38
- centralConflict: string;
39
- thematicThread: string;
40
- storyComplete: boolean;
41
- currentPhase: string;
42
- }
43
-
44
- interface SessionLogEntry {
45
- scene: number;
46
- summary: string;
47
- location: string;
48
- }
49
-
50
- interface GameState {
51
- initialized: boolean;
52
- phase: string;
53
- settingGenre: string;
54
- settingTone: string;
55
- settingArchetype: string;
56
- settingDescription: string;
57
- playerName: string;
58
- characterConcept: string;
59
- edge: number; heart: number; iron: number; shadow: number; wits: number;
60
- health: number; spirit: number; supply: number;
61
- momentum: number; maxMomentum: number;
62
- currentLocation: string;
63
- currentSceneContext: string;
64
- timeOfDay: string;
65
- chaosFactor: number;
66
- crisisMode: boolean;
67
- gameOver: boolean;
68
- sceneCount: number;
69
- npcs: NPC[];
70
- clocks: ClockData[];
71
- storyBlueprint: StoryInfo | null;
72
- kidMode: boolean;
73
- sessionLog: SessionLogEntry[];
74
- }
75
-
76
- const INITIAL: GameState = {
77
- initialized: false,
78
- phase: "genre",
79
- settingGenre: "", settingTone: "", settingArchetype: "",
80
- settingDescription: "",
81
- playerName: "", characterConcept: "",
82
- edge: 1, heart: 1, iron: 1, shadow: 1, wits: 1,
83
- health: 5, spirit: 5, supply: 5,
84
- momentum: 2, maxMomentum: 10,
85
- currentLocation: "", currentSceneContext: "", timeOfDay: "",
86
- chaosFactor: 5, crisisMode: false, gameOver: false,
87
- sceneCount: 0,
88
- npcs: [], clocks: [],
89
- storyBlueprint: null,
90
- kidMode: false,
91
- sessionLog: [],
92
- };
93
-
94
- // ── Color Palette ────────────────────────────────────────────────────────────
95
- const C = {
96
- bg: "#0a0a0c",
97
- surface: "#0f0f12",
98
- surfaceLight: "#16161b",
99
- border: "#1e1e26",
100
- borderLight: "#2a2a36",
101
- accent: "#c9a84c", // gold
102
- accentDim: "#8a7232",
103
- accentGlow: "rgba(201,168,76,0.15)",
104
- text: "#e0dcd0",
105
- textMuted: "rgba(224,220,208,0.5)",
106
- textDim: "rgba(224,220,208,0.25)",
107
- health: "#8b3030",
108
- healthBright: "#c44040",
109
- spirit: "#3a5a8a",
110
- spiritBright: "#5a8acd",
111
- supply: "#4a6a3a",
112
- supplyBright: "#6a9a4a",
113
- chaos: {
114
- low: "#3a6a3a",
115
- mid: "#8a7a3a",
116
- high: "#8a4a2a",
117
- critical: "#8b2020",
118
- },
119
- disposition: {
120
- hostile: "#c44040",
121
- distrustful: "#c47a30",
122
- neutral: "#888888",
123
- friendly: "#4a9a4a",
124
- loyal: "#c9a84c",
125
- },
126
- threat: "#8b2020",
127
- progress: "#3a7a9a",
128
- scheme: "#7a4a8a",
129
- };
130
-
131
- // ── Disposition Icons ────────────────────────────────────────────────────────
132
- const DISP_ICON: Record<Disposition, string> = {
133
- hostile: "\u2620", distrustful: "\u26A0", neutral: "\u25CB",
134
- friendly: "\u2665", loyal: "\u2726",
135
- };
136
-
137
- // ── Time Labels ──────────────────────────────────────────────────────────────
138
- const TIME_LABELS: Record<string, string> = {
139
- early_morning: "Dawn", morning: "Morning", midday: "Midday",
140
- afternoon: "Afternoon", evening: "Dusk", late_evening: "Twilight",
141
- night: "Night", deep_night: "Witching Hour",
142
- };
143
-
144
- // ── Genre Labels ─────────────────────────────────────────────────────────────
145
- const GENRE_LABELS: Record<string, string> = {
146
- dark_fantasy: "Dark Fantasy", high_fantasy: "High Fantasy",
147
- science_fiction: "Sci-Fi", horror_mystery: "Horror / Mystery",
148
- steampunk: "Steampunk", cyberpunk: "Cyberpunk",
149
- urban_fantasy: "Urban Fantasy", victorian_crime: "Victorian Crime",
150
- historical_roman: "Historical", fairy_tale: "Fairy Tale",
151
- slice_of_life_90s: "Slice of Life", outdoor_survival: "Survival",
152
- };
153
-
154
- // ── Phase Labels ─────────────────────────────────────────────────────────────
155
- const PHASE_LABELS: Record<string, string> = {
156
- setup: "Act I", confrontation: "Act II", climax: "Act III",
157
- ki_introduction: "Ki", sho_development: "Sho",
158
- ten_twist: "Ten", ketsu_resolution: "Ketsu",
159
- };
160
-
161
- // ── Components ───────────────────────────────────────────────────────────────
162
-
163
- function ResourceBar({ label, current, max, color, colorBright, icon }: {
164
- label: string; current: number; max: number; color: string; colorBright: string; icon: string;
165
- }) {
166
- const pips = [];
167
- for (let i = 0; i < max; i++) {
168
- const filled = i < current;
169
- pips.push(
170
- <div
171
- key={i}
172
- style={{
173
- width: "18px", height: "10px", borderRadius: "2px",
174
- background: filled
175
- ? `linear-gradient(135deg, ${color}, ${colorBright})`
176
- : "rgba(255,255,255,0.03)",
177
- border: `1px solid ${filled ? colorBright : "rgba(255,255,255,0.06)"}`,
178
- boxShadow: filled ? `0 0 4px ${color}66` : "none",
179
- transition: "all 0.4s ease",
180
- }}
181
- />,
182
- );
183
- }
184
- return (
185
- <div style={{ marginBottom: "8px" }}>
186
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "3px" }}>
187
- <span style={{ fontSize: "10px", color: C.textDim, letterSpacing: "0.05em" }}>
188
- {icon} {label}
189
- </span>
190
- <span style={{ fontSize: "11px", fontWeight: 700, color: current > 0 ? colorBright : C.threat }}>
191
- {current}
192
- </span>
193
- </div>
194
- <div style={{ display: "flex", gap: "2px" }}>{pips}</div>
195
- </div>
196
- );
197
- }
198
-
199
- function MomentumTrack({ momentum, max }: { momentum: number; max: number }) {
200
- const range: number[] = [];
201
- for (let i = -6; i <= 10; i++) range.push(i);
202
- return (
203
- <div style={{ marginBottom: "8px" }}>
204
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "3px" }}>
205
- <span style={{ fontSize: "10px", color: C.textDim, letterSpacing: "0.05em" }}>Momentum</span>
206
- <span style={{
207
- fontSize: "11px", fontWeight: 700,
208
- color: momentum > 0 ? C.spiritBright : momentum < 0 ? C.healthBright : C.textMuted,
209
- }}>
210
- {momentum > 0 ? "+" : ""}{momentum}
211
- </span>
212
- </div>
213
- <div style={{ display: "flex", gap: "1px" }}>
214
- {range.map((v) => (
215
- <div
216
- key={v}
217
- style={{
218
- flex: 1, height: "6px", borderRadius: "1px",
219
- background:
220
- v > max ? "rgba(255,255,255,0.01)"
221
- : v <= momentum && v > 0 ? C.spiritBright
222
- : v >= momentum && v < 0 ? C.healthBright
223
- : v === 0 ? "rgba(255,255,255,0.12)"
224
- : "rgba(255,255,255,0.03)",
225
- boxShadow:
226
- (v <= momentum && v > 0) ? `0 0 3px ${C.spirit}` :
227
- (v >= momentum && v < 0) ? `0 0 3px ${C.health}` : "none",
228
- transition: "all 0.3s ease",
229
- }}
230
- />
231
- ))}
232
- </div>
233
- <div style={{ display: "flex", justifyContent: "space-between", marginTop: "1px" }}>
234
- <span style={{ fontSize: "7px", color: C.textDim }}>-6</span>
235
- <span style={{ fontSize: "7px", color: C.textDim }}>0</span>
236
- <span style={{ fontSize: "7px", color: C.textDim }}>+10</span>
237
- </div>
238
- </div>
239
- );
240
- }
241
-
242
- function ChaosGauge({ chaos }: { chaos: number }) {
243
- const pct = ((chaos - 3) / 6) * 100;
244
- const color = chaos <= 4 ? C.chaos.low : chaos <= 6 ? C.chaos.mid : chaos <= 8 ? C.chaos.high : C.chaos.critical;
245
- const label = chaos <= 4 ? "Calm" : chaos <= 6 ? "Tense" : chaos <= 8 ? "Volatile" : "Critical";
246
- return (
247
- <div style={{ marginBottom: "8px" }}>
248
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "3px" }}>
249
- <span style={{ fontSize: "10px", color: C.textDim, letterSpacing: "0.05em" }}>Chaos</span>
250
- <span style={{ fontSize: "9px", fontWeight: 600, color, textTransform: "uppercase", letterSpacing: "0.08em" }}>
251
- {label} ({chaos})
252
- </span>
253
- </div>
254
- <div style={{ height: "4px", borderRadius: "2px", background: "rgba(255,255,255,0.04)", overflow: "hidden" }}>
255
- <div style={{
256
- height: "100%", width: `${pct}%`, borderRadius: "2px",
257
- background: `linear-gradient(90deg, ${C.chaos.low}, ${color})`,
258
- boxShadow: `0 0 6px ${color}66`,
259
- transition: "width 0.5s ease, background 0.5s ease",
260
- }} />
261
- </div>
262
- </div>
263
- );
264
- }
265
-
266
- function StatPip({ label, value }: { label: string; value: number }) {
267
- return (
268
- <div style={{ textAlign: "center" }}>
269
- <div style={{ fontSize: "8px", color: C.textDim, textTransform: "uppercase", letterSpacing: "0.1em" }}>
270
- {label}
271
- </div>
272
- <div style={{
273
- fontSize: "18px", fontWeight: 700, color: C.accent, lineHeight: 1,
274
- textShadow: `0 0 8px ${C.accentGlow}`,
275
- }}>
276
- {value}
277
- </div>
278
- </div>
279
- );
280
- }
281
-
282
- function ClockDisplay({ clock }: { clock: ClockData }) {
283
- const typeColor = clock.clockType === "threat" ? C.threat :
284
- clock.clockType === "progress" ? C.progress : C.scheme;
285
- const segments = [];
286
- for (let i = 0; i < clock.segments; i++) {
287
- segments.push(
288
- <div
289
- key={i}
290
- style={{
291
- width: "10px", height: "10px", borderRadius: "50%",
292
- background: i < clock.filled
293
- ? typeColor
294
- : "rgba(255,255,255,0.04)",
295
- border: `1px solid ${i < clock.filled ? typeColor : "rgba(255,255,255,0.08)"}`,
296
- boxShadow: i < clock.filled ? `0 0 4px ${typeColor}66` : "none",
297
- transition: "all 0.3s ease",
298
- }}
299
- />,
300
- );
301
- }
302
- const isFull = clock.filled >= clock.segments;
303
- return (
304
- <div style={{
305
- marginBottom: "8px", padding: "6px 8px",
306
- borderRadius: "4px", background: "rgba(255,255,255,0.015)",
307
- border: `1px solid ${isFull ? typeColor : "rgba(255,255,255,0.04)"}`,
308
- opacity: isFull ? 0.5 : 1,
309
- }}>
310
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "4px" }}>
311
- <span style={{ fontSize: "10px", fontWeight: 600, color: C.text }}>{clock.name}</span>
312
- <span style={{
313
- fontSize: "8px", padding: "1px 4px", borderRadius: "2px",
314
- background: `${typeColor}22`, color: typeColor, textTransform: "uppercase",
315
- letterSpacing: "0.06em", border: `1px solid ${typeColor}44`,
316
- }}>
317
- {clock.clockType}
318
- </span>
319
- </div>
320
- <div style={{ display: "flex", gap: "3px", flexWrap: "wrap" }}>{segments}</div>
321
- </div>
322
- );
323
- }
324
-
325
- function NpcCard({ npc }: { npc: NPC }) {
326
- const dispColor = C.disposition[npc.disposition] || C.textMuted;
327
- const icon = DISP_ICON[npc.disposition] || "\u25CB";
328
- return (
329
- <div style={{
330
- marginBottom: "6px", padding: "6px 8px",
331
- borderRadius: "4px", background: "rgba(255,255,255,0.015)",
332
- borderLeft: `2px solid ${dispColor}`,
333
- }}>
334
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
335
- <span style={{ fontSize: "11px", fontWeight: 600, color: C.text }}>{npc.name}</span>
336
- <span style={{ fontSize: "10px", color: dispColor }}>{icon}</span>
337
- </div>
338
- {npc.agenda && (
339
- <div style={{ fontSize: "9px", color: C.textMuted, marginTop: "2px", fontStyle: "italic" }}>
340
- {npc.agenda}
341
- </div>
342
- )}
343
- <div style={{ display: "flex", gap: "8px", marginTop: "3px" }}>
344
- <span style={{ fontSize: "8px", color: C.textDim }}>
345
- {npc.disposition}
346
- </span>
347
- {npc.bond !== 0 && (
348
- <span style={{ fontSize: "8px", color: npc.bond > 0 ? C.supplyBright : C.healthBright }}>
349
- bond {npc.bond > 0 ? "+" : ""}{npc.bond}
350
- </span>
351
- )}
352
- </div>
353
- </div>
354
- );
355
- }
356
-
357
- function StoryArc({ story }: { story: StoryInfo }) {
358
- const pct = story.totalActs > 0 ? ((story.currentAct - 1) / story.totalActs) * 100 : 0;
359
- const phaseLabel = PHASE_LABELS[story.currentPhase] || story.currentPhase;
360
- return (
361
- <div style={{ marginBottom: "8px" }}>
362
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "3px" }}>
363
- <span style={{ fontSize: "10px", color: C.textDim, letterSpacing: "0.05em" }}>Story Arc</span>
364
- <span style={{ fontSize: "9px", color: C.accent }}>
365
- {phaseLabel} ({story.currentAct}/{story.totalActs})
366
- </span>
367
- </div>
368
- <div style={{ height: "3px", borderRadius: "2px", background: "rgba(255,255,255,0.04)", overflow: "hidden" }}>
369
- <div style={{
370
- height: "100%", width: `${pct}%`, borderRadius: "2px",
371
- background: `linear-gradient(90deg, ${C.accentDim}, ${C.accent})`,
372
- transition: "width 0.5s ease",
373
- }} />
374
- </div>
375
- {story.storyComplete && (
376
- <div style={{
377
- fontSize: "8px", color: C.accent, textTransform: "uppercase",
378
- letterSpacing: "0.1em", marginTop: "3px", textAlign: "center",
379
- }}>
380
- Story Complete
381
- </div>
382
- )}
383
- </div>
384
- );
385
- }
386
-
387
- // ── Sidebar ──────────────────────────────────────────────────────────────────
388
-
389
- function Sidebar({ game }: { game: GameState }) {
390
- return (
391
- <div style={{
392
- height: "100%", overflowY: "auto", background: C.bg,
393
- fontFamily: "'Crimson Text', 'Georgia', serif",
394
- }}>
395
- <style>
396
- {`
397
- @import url('https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400&display=swap');
398
- .et-section { border-bottom: 1px solid ${C.border}; padding: 10px 12px; }
399
- .et-section:last-child { border-bottom: none; }
400
- .et-label {
401
- font-size: 9px; text-transform: uppercase; letter-spacing: 0.14em;
402
- color: ${C.textDim}; margin-bottom: 6px; font-family: sans-serif;
403
- }
404
- .et-gold { color: ${C.accent}; text-shadow: 0 0 8px ${C.accentGlow}; }
405
- .et-crisis-pulse { animation: crisisPulse 2s ease-in-out infinite; }
406
- @keyframes crisisPulse {
407
- 0%,100% { opacity: 0.6; } 50% { opacity: 1; }
408
- }
409
- .et-scroll::-webkit-scrollbar { width: 3px; }
410
- .et-scroll::-webkit-scrollbar-thumb { background: ${C.borderLight}; border-radius: 3px; }
411
- .et-scroll::-webkit-scrollbar-track { background: transparent; }
412
- `}
413
- </style>
414
-
415
- {/* Header */}
416
- <div class="et-section" style={{ textAlign: "center", paddingTop: "16px", paddingBottom: "12px" }}>
417
- <div style={{
418
- fontSize: "8px", letterSpacing: "0.3em", color: C.textDim,
419
- textTransform: "uppercase", fontFamily: "sans-serif",
420
- }}>
421
- Solo RPG
422
- </div>
423
- {game.initialized ? (
424
- <>
425
- <div class="et-gold" style={{ fontSize: "16px", fontWeight: 700, marginTop: "4px" }}>
426
- {game.playerName}
427
- </div>
428
- {game.characterConcept && (
429
- <div style={{ fontSize: "11px", color: C.textMuted, fontStyle: "italic", marginTop: "2px" }}>
430
- {game.characterConcept}
431
- </div>
432
- )}
433
- {game.settingGenre && (
434
- <div style={{
435
- fontSize: "8px", color: C.accentDim, marginTop: "4px",
436
- textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "sans-serif",
437
- }}>
438
- {GENRE_LABELS[game.settingGenre] || game.settingGenre}
439
- </div>
440
- )}
441
- </>
442
- ) : (
443
- <div style={{ fontSize: "11px", color: C.textDim, marginTop: "8px", fontStyle: "italic" }}>
444
- Creating your story...
445
- </div>
446
- )}
447
- </div>
448
-
449
- {/* Pre-init placeholder */}
450
- {!game.initialized && (
451
- <div class="et-section" style={{ textAlign: "center", padding: "32px 12px" }}>
452
- <div style={{ fontSize: "36px", opacity: 0.08 }}>{"\u2726"}</div>
453
- <div style={{
454
- fontSize: "10px", color: C.textDim, marginTop: "10px",
455
- lineHeight: 1.7, fontStyle: "italic",
456
- }}>
457
- Choose your world.<br />Shape your character.<br />Begin your tale.
458
- </div>
459
- </div>
460
- )}
461
-
462
- {game.initialized && (
463
- <>
464
- {/* Crisis / Game Over Banner */}
465
- {(game.crisisMode || game.gameOver) && (
466
- <div class="et-section et-crisis-pulse" style={{
467
- textAlign: "center", padding: "8px 12px",
468
- background: `${C.threat}15`, borderBottom: `1px solid ${C.threat}33`,
469
- }}>
470
- <div style={{
471
- fontSize: "10px", fontWeight: 700, color: C.healthBright,
472
- textTransform: "uppercase", letterSpacing: "0.15em", fontFamily: "sans-serif",
473
- }}>
474
- {game.gameOver ? (game.kidMode ? "In Trouble" : "Finale") :
475
- (game.kidMode ? "In Trouble" : "Crisis")}
476
- </div>
477
- </div>
478
- )}
479
-
480
- {/* Stats */}
481
- <div class="et-section">
482
- <div class="et-label">Attributes</div>
483
- <div style={{ display: "flex", justifyContent: "space-between", padding: "0 4px" }}>
484
- <StatPip label="Edge" value={game.edge} />
485
- <StatPip label="Heart" value={game.heart} />
486
- <StatPip label="Iron" value={game.iron} />
487
- <StatPip label="Shadow" value={game.shadow} />
488
- <StatPip label="Wits" value={game.wits} />
489
- </div>
490
- </div>
491
-
492
- {/* Resources */}
493
- <div class="et-section">
494
- <ResourceBar label="Health" current={game.health} max={5} color={C.health} colorBright={C.healthBright} icon={"\u2665"} />
495
- <ResourceBar label="Spirit" current={game.spirit} max={5} color={C.spirit} colorBright={C.spiritBright} icon={"\u25C6"} />
496
- <ResourceBar label="Supply" current={game.supply} max={5} color={C.supply} colorBright={C.supplyBright} icon={"\u25A0"} />
497
- <MomentumTrack momentum={game.momentum} max={game.maxMomentum} />
498
- <ChaosGauge chaos={game.chaosFactor} />
499
- </div>
500
-
501
- {/* Location & Time */}
502
- <div class="et-section">
503
- <div class="et-label">Location</div>
504
- <div class="et-gold" style={{ fontSize: "13px", fontWeight: 600 }}>
505
- {game.currentLocation || "Unknown"}
506
- </div>
507
- {game.currentSceneContext && (
508
- <div style={{ fontSize: "10px", color: C.textMuted, marginTop: "3px", fontStyle: "italic", lineHeight: 1.4 }}>
509
- {game.currentSceneContext}
510
- </div>
511
- )}
512
- {game.timeOfDay && (
513
- <div style={{
514
- fontSize: "9px", color: C.accentDim, marginTop: "4px",
515
- textTransform: "uppercase", letterSpacing: "0.08em", fontFamily: "sans-serif",
516
- }}>
517
- {TIME_LABELS[game.timeOfDay] || game.timeOfDay}
518
- </div>
519
- )}
520
- </div>
521
-
522
- {/* Story Arc */}
523
- {game.storyBlueprint && (
524
- <div class="et-section">
525
- <StoryArc story={game.storyBlueprint} />
526
- </div>
527
- )}
528
-
529
- {/* Clocks */}
530
- {game.clocks.length > 0 && (
531
- <div class="et-section">
532
- <div class="et-label">Clocks</div>
533
- {game.clocks.map((clock) => (
534
- <ClockDisplay key={clock.id || clock.name} clock={clock} />
535
- ))}
536
- </div>
537
- )}
538
-
539
- {/* NPCs */}
540
- {game.npcs.filter(n => n.status !== "deceased").length > 0 && (
541
- <div class="et-section">
542
- <div class="et-label">Characters</div>
543
- {game.npcs.filter(n => n.status === "active").map((npc) => (
544
- <NpcCard key={npc.id} npc={npc} />
545
- ))}
546
- {game.npcs.filter(n => n.status === "background").length > 0 && (
547
- <>
548
- <div style={{
549
- fontSize: "8px", color: C.textDim, textTransform: "uppercase",
550
- letterSpacing: "0.1em", margin: "6px 0 4px", fontFamily: "sans-serif",
551
- }}>
552
- Known
553
- </div>
554
- {game.npcs.filter(n => n.status === "background").map((npc) => (
555
- <div key={npc.id} style={{
556
- fontSize: "10px", color: C.textMuted, marginBottom: "2px",
557
- paddingLeft: "8px", borderLeft: `1px solid ${C.border}`,
558
- }}>
559
- {npc.name}
560
- <span style={{ fontSize: "8px", color: C.textDim, marginLeft: "4px" }}>
561
- {npc.disposition}
562
- </span>
563
- </div>
564
- ))}
565
- </>
566
- )}
567
- </div>
568
- )}
569
-
570
- {/* Session Log */}
571
- {game.sessionLog.length > 0 && (
572
- <div class="et-section">
573
- <div class="et-label">Chronicle</div>
574
- {game.sessionLog.slice(-5).map((entry, i) => (
575
- <div
576
- key={i}
577
- style={{
578
- fontSize: "10px", color: C.textDim,
579
- fontStyle: "italic", lineHeight: 1.5, marginBottom: "4px",
580
- paddingLeft: "8px", borderLeft: `1px solid ${C.border}`,
581
- }}
582
- >
583
- <span style={{ color: C.textMuted, fontStyle: "normal", fontSize: "8px" }}>
584
- {entry.scene}.{" "}
585
- </span>
586
- {entry.summary}
587
- </div>
588
- ))}
589
- </div>
590
- )}
591
-
592
- {/* Scene Counter */}
593
- <div class="et-section" style={{ textAlign: "center", padding: "8px 12px" }}>
594
- <span style={{ fontSize: "8px", color: C.textDim, letterSpacing: "0.15em", fontFamily: "sans-serif" }}>
595
- {game.kidMode ? "\u2726 " : ""}SCENE {game.sceneCount}{game.kidMode ? " \u2726" : ""}
596
- </span>
597
- </div>
598
- </>
599
- )}
600
- </div>
601
- );
602
- }
603
-
604
- // ── App ──────────────────────────────────────────────────────────────────────
605
-
606
- function SoloRPGApp() {
607
- const [game, setGame] = useState<GameState>(structuredClone(INITIAL));
608
-
609
- // Merge a full-state result into the game
610
- const mergeState = (result: any, prev: GameState): GameState => ({
611
- initialized: result.initialized ?? prev.initialized,
612
- phase: result.phase ?? prev.phase,
613
- settingGenre: result.settingGenre ?? prev.settingGenre,
614
- settingTone: result.settingTone ?? prev.settingTone,
615
- settingArchetype: result.settingArchetype ?? prev.settingArchetype,
616
- settingDescription: result.settingDescription ?? prev.settingDescription,
617
- playerName: result.playerName ?? prev.playerName,
618
- characterConcept: result.characterConcept ?? prev.characterConcept,
619
- edge: result.edge ?? result.stats?.edge ?? prev.edge,
620
- heart: result.heart ?? result.stats?.heart ?? prev.heart,
621
- iron: result.iron ?? result.stats?.iron ?? prev.iron,
622
- shadow: result.shadow ?? result.stats?.shadow ?? prev.shadow,
623
- wits: result.wits ?? result.stats?.wits ?? prev.wits,
624
- health: result.health ?? prev.health,
625
- spirit: result.spirit ?? prev.spirit,
626
- supply: result.supply ?? prev.supply,
627
- momentum: result.momentum ?? prev.momentum,
628
- maxMomentum: result.maxMomentum ?? prev.maxMomentum,
629
- currentLocation: result.currentLocation ?? prev.currentLocation,
630
- currentSceneContext: result.currentSceneContext ?? prev.currentSceneContext,
631
- timeOfDay: result.timeOfDay ?? prev.timeOfDay,
632
- chaosFactor: result.chaosFactor ?? prev.chaosFactor,
633
- crisisMode: result.crisisMode ?? prev.crisisMode,
634
- gameOver: result.gameOver ?? prev.gameOver,
635
- sceneCount: result.sceneCount ?? prev.sceneCount,
636
- npcs: result.npcs ?? prev.npcs,
637
- clocks: result.clocks ?? prev.clocks,
638
- storyBlueprint: result.storyBlueprint ?? prev.storyBlueprint,
639
- kidMode: result.kidMode ?? prev.kidMode,
640
- sessionLog: result.sessionLog ?? prev.sessionLog,
641
- });
642
-
643
- useToolResult((toolName, result: any) => {
644
- // setup_character and update_state both return full state
645
- if ((toolName === "setup_character" || toolName === "update_state") && result.success) {
646
- setGame((prev) => mergeState(result, prev));
647
- }
648
-
649
- // action_roll auto-applies consequences — sync sidebar
650
- if (toolName === "action_roll" && result.currentHealth !== undefined) {
651
- setGame((prev) => ({
652
- ...prev,
653
- health: result.currentHealth,
654
- spirit: result.currentSpirit ?? prev.spirit,
655
- supply: result.currentSupply ?? prev.supply,
656
- momentum: result.currentMomentum ?? prev.momentum,
657
- chaosFactor: result.chaosFactor ?? prev.chaosFactor,
658
- crisisMode: result.crisisMode ?? prev.crisisMode,
659
- gameOver: result.gameOver ?? prev.gameOver,
660
- sceneCount: result.sceneCount ?? prev.sceneCount,
661
- }));
662
- }
663
-
664
- // burn_momentum resets momentum
665
- if (toolName === "burn_momentum" && result.burned) {
666
- setGame((prev) => ({ ...prev, momentum: result.newMomentum }));
667
- }
668
-
669
- // load_game restores full state
670
- if (toolName === "load_game" && result.loaded) {
671
- setGame((prev) => mergeState(result, prev));
672
- }
673
- });
674
-
675
- return (
676
- <StartScreen
677
- icon={<span style={{ fontSize: "28px", color: C.accent }}>{"\u2726"}</span>}
678
- title="Solo RPG"
679
- subtitle="A Narrative Solo-RPG Engine"
680
- buttonText="Begin Your Story"
681
- >
682
- <SidebarLayout sidebar={<Sidebar game={game} />} width="260px" side="right">
683
- <ChatView />
684
- </SidebarLayout>
685
- </StartScreen>
686
- );
687
- }
688
-
689
- mount(SoloRPGApp, {
690
- title: "Solo RPG",
691
- theme: {
692
- bg: C.bg,
693
- primary: C.accent,
694
- text: C.text,
695
- surface: C.surface,
696
- border: C.border,
697
- },
698
- });