agmon 0.2.0 → 0.2.1

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 (278) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/fallback-build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +8 -8
  5. package/.next/server/app/_global-error.html +1 -1
  6. package/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  11. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/.next/server/app/_not-found.html +1 -1
  13. package/.next/server/app/_not-found.rsc +15 -14
  14. package/.next/server/app/_not-found.segments/_full.segment.rsc +15 -14
  15. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +4 -3
  16. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  17. package/.next/server/app/api/media/route.js.nft.json +1 -1
  18. package/.next/server/app/api/reports/tokens/route.js.nft.json +1 -1
  19. package/.next/server/app/api/sessions/[id]/transcript/route.js.nft.json +1 -1
  20. package/.next/server/app/api/traces/stream/route.js.nft.json +1 -1
  21. package/.next/server/app/api/version/route.js.nft.json +1 -1
  22. package/.next/server/app/api/workspace/file-content/route.js.nft.json +1 -1
  23. package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
  24. package/.next/server/app/chat/page.js.nft.json +1 -1
  25. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  26. package/.next/server/app/chat.html +1 -1
  27. package/.next/server/app/chat.rsc +20 -19
  28. package/.next/server/app/chat.segments/_full.segment.rsc +20 -19
  29. package/.next/server/app/chat.segments/_tree.segment.rsc +2 -2
  30. package/.next/server/app/chat.segments/chat/__PAGE__.segment.rsc +21 -20
  31. package/.next/server/app/index.html +1 -1
  32. package/.next/server/app/index.rsc +20 -18
  33. package/.next/server/app/index.segments/__PAGE__.segment.rsc +8 -8
  34. package/.next/server/app/index.segments/_full.segment.rsc +20 -18
  35. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  36. package/.next/server/app/page.js.nft.json +1 -1
  37. package/.next/server/app/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/reports/page.js.nft.json +1 -1
  39. package/.next/server/app/reports/page_client-reference-manifest.js +1 -1
  40. package/.next/server/app/reports.html +1 -1
  41. package/.next/server/app/reports.rsc +4 -4
  42. package/.next/server/app/reports.segments/_full.segment.rsc +4 -4
  43. package/.next/server/app/reports.segments/_tree.segment.rsc +2 -2
  44. package/.next/server/app/reports.segments/reports/__PAGE__.segment.rsc +4 -4
  45. package/.next/server/app/store/page.js.nft.json +1 -1
  46. package/.next/server/app/store/page_client-reference-manifest.js +1 -1
  47. package/.next/server/app/store.html +1 -1
  48. package/.next/server/app/store.rsc +5 -5
  49. package/.next/server/app/store.segments/_full.segment.rsc +5 -5
  50. package/.next/server/app/store.segments/_tree.segment.rsc +2 -2
  51. package/.next/server/app/store.segments/store/__PAGE__.segment.rsc +5 -5
  52. package/.next/server/chunks/_0ao-_t4jkb46h._.js +2 -2
  53. package/.next/server/chunks/_0ao-_t4jkb46h._.js.map +1 -1
  54. package/.next/server/chunks/src_lib_watchers_antigravityWatcher_0w1-atg39y__p.js.map +1 -1
  55. package/.next/server/chunks/ssr/[root-of-the-server]__0i2rbwbkxbdog._.js +3 -0
  56. package/.next/server/chunks/ssr/[root-of-the-server]__0i2rbwbkxbdog._.js.map +1 -0
  57. package/.next/server/chunks/ssr/[root-of-the-server]__0qzscpxebh28_._.js +3 -0
  58. package/.next/server/chunks/ssr/[root-of-the-server]__0qzscpxebh28_._.js.map +1 -0
  59. package/.next/server/chunks/ssr/[root-of-the-server]__1jwplflwix8wi._.js +427 -0
  60. package/.next/server/chunks/ssr/[root-of-the-server]__1jwplflwix8wi._.js.map +1 -0
  61. package/.next/server/chunks/ssr/[root-of-the-server]__1kt7h7bz59mdn._.js +1 -1
  62. package/.next/server/chunks/ssr/[root-of-the-server]__1kt7h7bz59mdn._.js.map +1 -1
  63. package/.next/server/chunks/ssr/[root-of-the-server]__1otsvjy81s8my._.js +427 -0
  64. package/.next/server/chunks/ssr/[root-of-the-server]__1otsvjy81s8my._.js.map +1 -0
  65. package/.next/server/chunks/ssr/_0--937zhi743v._.js +3 -0
  66. package/.next/server/chunks/ssr/_0--937zhi743v._.js.map +1 -0
  67. package/.next/server/chunks/ssr/_0e3frtjrk-wi9._.js +3 -0
  68. package/.next/server/chunks/ssr/_0e3frtjrk-wi9._.js.map +1 -0
  69. package/.next/server/chunks/ssr/_0h29jdf4relbq._.js +3 -0
  70. package/.next/server/chunks/ssr/_0h29jdf4relbq._.js.map +1 -0
  71. package/.next/server/chunks/ssr/_1487-zi23c5eb._.js +1 -1
  72. package/.next/server/chunks/ssr/_1487-zi23c5eb._.js.map +1 -1
  73. package/.next/server/chunks/ssr/_1vgwoe-shb9z7._.js +3 -0
  74. package/.next/server/chunks/ssr/_1vgwoe-shb9z7._.js.map +1 -0
  75. package/.next/server/chunks/ssr/_1zm4m-s8k7oe3._.js +3 -0
  76. package/.next/server/chunks/ssr/_1zm4m-s8k7oe3._.js.map +1 -0
  77. package/.next/server/chunks/ssr/_202tntue-jj6s._.js +3 -0
  78. package/.next/server/chunks/ssr/_202tntue-jj6s._.js.map +1 -0
  79. package/.next/server/chunks/ssr/{node_modules_1wlwrgnt65zus._.js → node_modules_00ebs67b4u61w._.js} +1 -1
  80. package/.next/server/chunks/ssr/{node_modules_0m3ihe65818y_._.js → node_modules_01p9ctt-n2dxp._.js} +1 -1
  81. package/.next/server/chunks/ssr/{node_modules_1kr1c-ncf8q9t._.js → node_modules_05i69rc9pwcdx._.js} +1 -1
  82. package/.next/server/chunks/ssr/{node_modules_02jwra-d9iqim._.js → node_modules_06mgkab1v5iox._.js} +2 -2
  83. package/.next/server/chunks/ssr/{node_modules_1dff7b_kvngr-._.js → node_modules_07bjxeq9dfgn1._.js} +2 -2
  84. package/.next/server/chunks/ssr/{node_modules_02vtgweceovke._.js → node_modules_08q6a-f2itxyo._.js} +1 -1
  85. package/.next/server/chunks/ssr/{node_modules_13nsmuhey_ti_._.js → node_modules_09v49jhajmvl4._.js} +2 -2
  86. package/.next/server/chunks/ssr/{node_modules_0oukyh0iq21ow._.js → node_modules_0b8zi3pbl-y9n._.js} +2 -2
  87. package/.next/server/chunks/ssr/{node_modules_061uaylfjwqk7._.js → node_modules_0d2ios01ot1in._.js} +1 -1
  88. package/.next/server/chunks/ssr/{node_modules_0b8ndnuql44z1._.js → node_modules_0dw0vozejrnml._.js} +2 -2
  89. package/.next/server/chunks/ssr/{node_modules_05w7qhtrzvnk6._.js → node_modules_0e3njj436xau-._.js} +1 -1
  90. package/.next/server/chunks/ssr/{node_modules_0z7rdbaf13024._.js → node_modules_0e6qoh__e4a69._.js} +1 -1
  91. package/.next/server/chunks/ssr/{node_modules_1ll-58c1c-qab._.js → node_modules_0hb0q0epwvp--._.js} +1 -1
  92. package/.next/server/chunks/ssr/{node_modules_0f773uqgzj7y7._.js → node_modules_0jla9ugf1y6rb._.js} +1 -1
  93. package/.next/server/chunks/ssr/{node_modules_0fd1swhk15cx3._.js → node_modules_0l-y0kqtu_r3o._.js} +1 -1
  94. package/.next/server/chunks/ssr/{node_modules_1zs2nou5uogby._.js → node_modules_0l814qpw677vm._.js} +1 -1
  95. package/.next/server/chunks/ssr/{node_modules_1c8i3jrmo4393._.js → node_modules_0lqovp8j8ld76._.js} +1 -1
  96. package/.next/server/chunks/ssr/{node_modules_0z3elum1675ve._.js → node_modules_0o63z1gd17rhb._.js} +1 -1
  97. package/.next/server/chunks/ssr/{node_modules_1xyxigbqzb8vs._.js → node_modules_0sjdrli5douui._.js} +1 -1
  98. package/.next/server/chunks/ssr/{node_modules_1iovyom0-y7o_._.js → node_modules_0xh8tnq1niblb._.js} +1 -1
  99. package/.next/server/chunks/ssr/{node_modules_0nde84kzuwv2n._.js → node_modules_0yayrqhzfk8wy._.js} +1 -1
  100. package/.next/server/chunks/ssr/{node_modules_0__m9_odts7_e._.js → node_modules_0z1e37smavebg._.js} +2 -2
  101. package/.next/server/chunks/ssr/{node_modules_0f4xh33v3iltc._.js → node_modules_0zb0i39mnjdf3._.js} +1 -1
  102. package/.next/server/chunks/ssr/{node_modules_02nv3yff2pqh8._.js → node_modules_10g1mmrf63d8a._.js} +2 -2
  103. package/.next/server/chunks/ssr/{node_modules_0-6sb1gkbjo93._.js → node_modules_152txg4c7ose3._.js} +2 -2
  104. package/.next/server/chunks/ssr/{node_modules_12qn4bepdou5v._.js → node_modules_185fuy4cv7loa._.js} +2 -2
  105. package/.next/server/chunks/ssr/{node_modules_0dq0dsblt-q0g._.js → node_modules_1aqaelh-8fme6._.js} +1 -1
  106. package/.next/server/chunks/ssr/{node_modules_1-iyhsn_1p9nx._.js → node_modules_1d4sreyq0ubqg._.js} +2 -2
  107. package/.next/server/chunks/ssr/{node_modules_0hqa9oxz17hip._.js → node_modules_1e_nc2eyg4djz._.js} +1 -1
  108. package/.next/server/chunks/ssr/{node_modules_1rlnehdn16ay-._.js → node_modules_1hd7j-tdb8drq._.js} +1 -1
  109. package/.next/server/chunks/ssr/{node_modules_12qw2ucebdvol._.js → node_modules_1i3x2csuq_-jt._.js} +1 -1
  110. package/.next/server/chunks/ssr/{node_modules_0zc49fdcopqu9._.js → node_modules_1l2g7btuh3e4s._.js} +2 -2
  111. package/.next/server/chunks/ssr/{node_modules_1-sz_-qddwilq._.js → node_modules_1l46or7mgko0z._.js} +1 -1
  112. package/.next/server/chunks/ssr/{node_modules_0fs8mckuwk2tj._.js → node_modules_1ltys5mwtcv-n._.js} +1 -1
  113. package/.next/server/chunks/ssr/{node_modules_0vn0kjn_84lmn._.js → node_modules_1nz3ckv6tu_66._.js} +1 -1
  114. package/.next/server/chunks/ssr/{node_modules_0t4h1rucl35hl._.js → node_modules_1pquu5wprusnc._.js} +2 -2
  115. package/.next/server/chunks/ssr/{node_modules_0-nvg0c4pgfb8._.js → node_modules_1qnypguag6s_l._.js} +1 -1
  116. package/.next/server/chunks/ssr/{node_modules_1v4lexrfhnlhs._.js → node_modules_1r6w-jlme6d10._.js} +1 -1
  117. package/.next/server/chunks/ssr/{node_modules_1f4geuvkvlxj1._.js → node_modules_1st9dwe66yx93._.js} +1 -1
  118. package/.next/server/chunks/ssr/{node_modules_0kovk4b6czb22._.js → node_modules_1tskcaktx6ods._.js} +1 -1
  119. package/.next/server/chunks/ssr/{node_modules_07maxxr-t28ql._.js → node_modules_1wew4nn7i1uup._.js} +1 -1
  120. package/.next/server/chunks/ssr/{node_modules_1216007ogd5om._.js → node_modules_1zbmc81s-4zsm._.js} +1 -1
  121. package/.next/server/chunks/ssr/{node_modules_1kv6lsckqs-m0._.js → node_modules_1zii7uk468cay._.js} +2 -2
  122. package/.next/server/chunks/ssr/{node_modules_katex_dist_katex_mjs_0bmuudv_6eypr._.js → node_modules_katex_dist_katex_mjs_0kqo9zl9cgwbo._.js} +1 -1
  123. package/.next/server/chunks/ssr/{node_modules_katex_dist_katex_mjs_0qyy6pq9uzpk0._.js → node_modules_katex_dist_katex_mjs_1604s1ky8db8u._.js} +1 -1
  124. package/.next/server/chunks/ssr/{node_modules_lucide-react_dist_esm_1d8fezw1qsiob._.js → node_modules_lucide-react_dist_esm_0-5bcc79665lq._.js} +2 -2
  125. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_0-5bcc79665lq._.js.map +1 -0
  126. package/.next/server/chunks/ssr/{node_modules_lucide-react_dist_esm_0pezg1352q13j._.js → node_modules_lucide-react_dist_esm_0axoa1eg51x1-._.js} +2 -2
  127. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_0axoa1eg51x1-._.js.map +1 -0
  128. package/.next/server/chunks/ssr/{node_modules_lucide-react_dist_esm_131i-tjzse3ye._.js → node_modules_lucide-react_dist_esm_18ei1-na3kusb._.js} +2 -2
  129. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_18ei1-na3kusb._.js.map +1 -0
  130. package/.next/server/chunks/ssr/{node_modules_lucide-react_dist_esm_1to-9cv1ysvs6._.js → node_modules_lucide-react_dist_esm_1tx493x2_auzs._.js} +2 -2
  131. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_1tx493x2_auzs._.js.map +1 -0
  132. package/.next/server/chunks/ssr/node_modules_mermaid_dist_mermaid_core_mjs_06it7ktosm1dr._.js +3 -0
  133. package/.next/server/chunks/ssr/node_modules_mermaid_dist_mermaid_core_mjs_06it7ktosm1dr._.js.map +1 -0
  134. package/.next/server/chunks/ssr/src_app_page_1vqfk0-j72fp6.js +1 -1
  135. package/.next/server/chunks/ssr/src_app_page_1vqfk0-j72fp6.js.map +1 -1
  136. package/.next/server/chunks/ssr/src_components_reports_TokenReportView_jsx_1g3p_enbbsadt._.js +1 -1
  137. package/.next/server/chunks/ssr/src_components_reports_TokenReportView_jsx_1g3p_enbbsadt._.js.map +1 -1
  138. package/.next/server/middleware-build-manifest.js +3 -3
  139. package/.next/server/pages/404.html +1 -1
  140. package/.next/server/pages/500.html +1 -1
  141. package/.next/server/preview-props.json +3 -3
  142. package/.next/server/server-reference-manifest.js +1 -1
  143. package/.next/server/server-reference-manifest.json +1 -1
  144. package/.next/static/chunks/0r9apkv3exqv-.js +1 -0
  145. package/.next/static/chunks/17jorrh_pfel_.js +1 -0
  146. package/.next/static/chunks/1n_lb7wmn81jj.js +1 -0
  147. package/.next/static/chunks/2-w116ewoshm1.js +1 -0
  148. package/.next/static/chunks/23uup1e8841av.js +1 -0
  149. package/.next/static/chunks/25l0z48vlvdu4.css +1 -0
  150. package/.next/static/chunks/2rx7xvi55ohln.js +1 -0
  151. package/.next/static/chunks/3og0e9qcff393.js +425 -0
  152. package/.next/static/chunks/3rtpnpqd981z9.js +1 -0
  153. package/.next/trace +1 -1
  154. package/.next/trace-build +1 -1
  155. package/bin/cli.js +12 -0
  156. package/package.json +1 -1
  157. package/src/app/chat/page.js +14 -14
  158. package/src/app/globals.css +128 -0
  159. package/src/app/layout.js +6 -1
  160. package/src/app/page.js +1 -1
  161. package/src/components/chat/ChatMessageItem.js +12 -12
  162. package/src/components/chat/CodeBlock.js +5 -5
  163. package/src/components/chat/DiffViewer.js +27 -27
  164. package/src/components/chat/MarkdownRenderer.js +19 -19
  165. package/src/components/chat/SessionChatView.js +41 -41
  166. package/src/components/chat/SessionSearch.js +8 -8
  167. package/src/components/chat/ThinkingAccordion.js +3 -3
  168. package/src/components/chat/ToolCallCard.js +6 -6
  169. package/src/components/chat/ToolOutputView.js +19 -19
  170. package/src/components/factory/office-canvas.js +134 -3
  171. package/src/components/factory/scene/characters.js +267 -32
  172. package/src/components/layout/CommandPalette.jsx +12 -0
  173. package/src/components/layout/EditorTabs.jsx +17 -0
  174. package/src/components/layout/LayoutToggles.jsx +31 -2
  175. package/src/components/layout/LeftSidebar.jsx +27 -3
  176. package/src/components/layout/RightSidebar.jsx +8 -8
  177. package/src/components/layout/TitleBar.jsx +5 -1
  178. package/src/components/layout/VSCodeWorkbench.jsx +78 -14
  179. package/src/components/store/Item3DRenderer.jsx +602 -48
  180. package/src/components/store/LiveFittingRoom.jsx +55 -791
  181. package/src/components/store/LiveReactAgent.jsx +1637 -0
  182. package/src/components/store/SupporterStoreModal.jsx +3 -2
  183. package/src/components/store/SupporterStoreView.jsx +94 -34
  184. package/src/components/theme/ThemeSettingsModal.jsx +40 -40
  185. package/src/components/ui/Button.jsx +4 -4
  186. package/src/components/ui/Input.jsx +1 -1
  187. package/src/components/ui/Modal.jsx +6 -6
  188. package/src/components/ui/Select.jsx +3 -3
  189. package/src/lib/catalog/auras.js +226 -1199
  190. package/src/lib/catalog/index.js +60 -1
  191. package/src/lib/catalog/pets.js +291 -2398
  192. package/src/lib/catalog/props.js +488 -4199
  193. package/src/lib/catalog/skins.js +773 -3249
  194. package/src/lib/catalog/trophies.js +226 -1199
  195. package/src/lib/mockTraces.js +15 -15
  196. package/src/lib/supporterStore.js +1 -1
  197. package/src/lib/traceContract.js +1 -1
  198. package/src/lib/watchers/claudeWatcher.js +24 -19
  199. package/.next/server/chunks/ssr/[root-of-the-server]__19s2v5rryc14o._.js +0 -3
  200. package/.next/server/chunks/ssr/[root-of-the-server]__19s2v5rryc14o._.js.map +0 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__1_jerxrctq6ev._.js +0 -427
  202. package/.next/server/chunks/ssr/[root-of-the-server]__1_jerxrctq6ev._.js.map +0 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__1pvso-uyf--97._.js +0 -427
  204. package/.next/server/chunks/ssr/[root-of-the-server]__1pvso-uyf--97._.js.map +0 -1
  205. package/.next/server/chunks/ssr/[root-of-the-server]__1y78dc7oiz7ks._.js +0 -3
  206. package/.next/server/chunks/ssr/[root-of-the-server]__1y78dc7oiz7ks._.js.map +0 -1
  207. package/.next/server/chunks/ssr/_0ozao7omdwbvd._.js +0 -3
  208. package/.next/server/chunks/ssr/_0ozao7omdwbvd._.js.map +0 -1
  209. package/.next/server/chunks/ssr/_0rcmpdyxc1qwj._.js +0 -3
  210. package/.next/server/chunks/ssr/_0rcmpdyxc1qwj._.js.map +0 -1
  211. package/.next/server/chunks/ssr/_0wv0xnhun3mk7._.js +0 -3
  212. package/.next/server/chunks/ssr/_0wv0xnhun3mk7._.js.map +0 -1
  213. package/.next/server/chunks/ssr/_17rmaft1zusua._.js +0 -3
  214. package/.next/server/chunks/ssr/_17rmaft1zusua._.js.map +0 -1
  215. package/.next/server/chunks/ssr/_1e-d4pcj59a7a._.js +0 -3
  216. package/.next/server/chunks/ssr/_1e-d4pcj59a7a._.js.map +0 -1
  217. package/.next/server/chunks/ssr/_1qr5gnh64z8pg._.js +0 -3
  218. package/.next/server/chunks/ssr/_1qr5gnh64z8pg._.js.map +0 -1
  219. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_0pezg1352q13j._.js.map +0 -1
  220. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_131i-tjzse3ye._.js.map +0 -1
  221. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_1d8fezw1qsiob._.js.map +0 -1
  222. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_1to-9cv1ysvs6._.js.map +0 -1
  223. package/.next/static/chunks/0_3s_e4gd9xl0.js +0 -1
  224. package/.next/static/chunks/0i4kx4yl-dwfg.js +0 -425
  225. package/.next/static/chunks/0z0jbobmmvqoc.js +0 -1
  226. package/.next/static/chunks/1_a_gmob5qzho.js +0 -1
  227. package/.next/static/chunks/1ifqr4qo4697b.js +0 -1
  228. package/.next/static/chunks/2ccq9i8ev4dsx.js +0 -1
  229. package/.next/static/chunks/2mif7onk_9jy-.css +0 -1
  230. package/.next/static/chunks/40wyf-mv0tiu3.js +0 -1
  231. /package/.next/server/chunks/ssr/{node_modules_1c8i3jrmo4393._.js.map → node_modules_00ebs67b4u61w._.js.map} +0 -0
  232. /package/.next/server/chunks/ssr/{node_modules_02vtgweceovke._.js.map → node_modules_01p9ctt-n2dxp._.js.map} +0 -0
  233. /package/.next/server/chunks/ssr/{node_modules_1kr1c-ncf8q9t._.js.map → node_modules_05i69rc9pwcdx._.js.map} +0 -0
  234. /package/.next/server/chunks/ssr/{node_modules_02jwra-d9iqim._.js.map → node_modules_06mgkab1v5iox._.js.map} +0 -0
  235. /package/.next/server/chunks/ssr/{node_modules_1dff7b_kvngr-._.js.map → node_modules_07bjxeq9dfgn1._.js.map} +0 -0
  236. /package/.next/server/chunks/ssr/{node_modules_0m3ihe65818y_._.js.map → node_modules_08q6a-f2itxyo._.js.map} +0 -0
  237. /package/.next/server/chunks/ssr/{node_modules_0-6sb1gkbjo93._.js.map → node_modules_09v49jhajmvl4._.js.map} +0 -0
  238. /package/.next/server/chunks/ssr/{node_modules_0oukyh0iq21ow._.js.map → node_modules_0b8zi3pbl-y9n._.js.map} +0 -0
  239. /package/.next/server/chunks/ssr/{node_modules_061uaylfjwqk7._.js.map → node_modules_0d2ios01ot1in._.js.map} +0 -0
  240. /package/.next/server/chunks/ssr/{node_modules_02nv3yff2pqh8._.js.map → node_modules_0dw0vozejrnml._.js.map} +0 -0
  241. /package/.next/server/chunks/ssr/{node_modules_0-nvg0c4pgfb8._.js.map → node_modules_0e3njj436xau-._.js.map} +0 -0
  242. /package/.next/server/chunks/ssr/{node_modules_0fs8mckuwk2tj._.js.map → node_modules_0e6qoh__e4a69._.js.map} +0 -0
  243. /package/.next/server/chunks/ssr/{node_modules_0t4h1rucl35hl._.js.map → node_modules_0hb0q0epwvp--._.js.map} +0 -0
  244. /package/.next/server/chunks/ssr/{node_modules_0f773uqgzj7y7._.js.map → node_modules_0jla9ugf1y6rb._.js.map} +0 -0
  245. /package/.next/server/chunks/ssr/{node_modules_0dq0dsblt-q0g._.js.map → node_modules_0l-y0kqtu_r3o._.js.map} +0 -0
  246. /package/.next/server/chunks/ssr/{node_modules_0zc49fdcopqu9._.js.map → node_modules_0l814qpw677vm._.js.map} +0 -0
  247. /package/.next/server/chunks/ssr/{node_modules_1wlwrgnt65zus._.js.map → node_modules_0lqovp8j8ld76._.js.map} +0 -0
  248. /package/.next/server/chunks/ssr/{node_modules_0z3elum1675ve._.js.map → node_modules_0o63z1gd17rhb._.js.map} +0 -0
  249. /package/.next/server/chunks/ssr/{node_modules_1xyxigbqzb8vs._.js.map → node_modules_0sjdrli5douui._.js.map} +0 -0
  250. /package/.next/server/chunks/ssr/{node_modules_1-iyhsn_1p9nx._.js.map → node_modules_0xh8tnq1niblb._.js.map} +0 -0
  251. /package/.next/server/chunks/ssr/{node_modules_0nde84kzuwv2n._.js.map → node_modules_0yayrqhzfk8wy._.js.map} +0 -0
  252. /package/.next/server/chunks/ssr/{node_modules_0__m9_odts7_e._.js.map → node_modules_0z1e37smavebg._.js.map} +0 -0
  253. /package/.next/server/chunks/ssr/{node_modules_0f4xh33v3iltc._.js.map → node_modules_0zb0i39mnjdf3._.js.map} +0 -0
  254. /package/.next/server/chunks/ssr/{node_modules_0b8ndnuql44z1._.js.map → node_modules_10g1mmrf63d8a._.js.map} +0 -0
  255. /package/.next/server/chunks/ssr/{node_modules_1-sz_-qddwilq._.js.map → node_modules_152txg4c7ose3._.js.map} +0 -0
  256. /package/.next/server/chunks/ssr/{node_modules_12qn4bepdou5v._.js.map → node_modules_185fuy4cv7loa._.js.map} +0 -0
  257. /package/.next/server/chunks/ssr/{node_modules_0fd1swhk15cx3._.js.map → node_modules_1aqaelh-8fme6._.js.map} +0 -0
  258. /package/.next/server/chunks/ssr/{node_modules_13nsmuhey_ti_._.js.map → node_modules_1d4sreyq0ubqg._.js.map} +0 -0
  259. /package/.next/server/chunks/ssr/{node_modules_0hqa9oxz17hip._.js.map → node_modules_1e_nc2eyg4djz._.js.map} +0 -0
  260. /package/.next/server/chunks/ssr/{node_modules_1rlnehdn16ay-._.js.map → node_modules_1hd7j-tdb8drq._.js.map} +0 -0
  261. /package/.next/server/chunks/ssr/{node_modules_07maxxr-t28ql._.js.map → node_modules_1i3x2csuq_-jt._.js.map} +0 -0
  262. /package/.next/server/chunks/ssr/{node_modules_1iovyom0-y7o_._.js.map → node_modules_1l2g7btuh3e4s._.js.map} +0 -0
  263. /package/.next/server/chunks/ssr/{node_modules_1ll-58c1c-qab._.js.map → node_modules_1l46or7mgko0z._.js.map} +0 -0
  264. /package/.next/server/chunks/ssr/{node_modules_0z7rdbaf13024._.js.map → node_modules_1ltys5mwtcv-n._.js.map} +0 -0
  265. /package/.next/server/chunks/ssr/{node_modules_0vn0kjn_84lmn._.js.map → node_modules_1nz3ckv6tu_66._.js.map} +0 -0
  266. /package/.next/server/chunks/ssr/{node_modules_1zs2nou5uogby._.js.map → node_modules_1pquu5wprusnc._.js.map} +0 -0
  267. /package/.next/server/chunks/ssr/{node_modules_05w7qhtrzvnk6._.js.map → node_modules_1qnypguag6s_l._.js.map} +0 -0
  268. /package/.next/server/chunks/ssr/{node_modules_1v4lexrfhnlhs._.js.map → node_modules_1r6w-jlme6d10._.js.map} +0 -0
  269. /package/.next/server/chunks/ssr/{node_modules_1f4geuvkvlxj1._.js.map → node_modules_1st9dwe66yx93._.js.map} +0 -0
  270. /package/.next/server/chunks/ssr/{node_modules_0kovk4b6czb22._.js.map → node_modules_1tskcaktx6ods._.js.map} +0 -0
  271. /package/.next/server/chunks/ssr/{node_modules_12qw2ucebdvol._.js.map → node_modules_1wew4nn7i1uup._.js.map} +0 -0
  272. /package/.next/server/chunks/ssr/{node_modules_1216007ogd5om._.js.map → node_modules_1zbmc81s-4zsm._.js.map} +0 -0
  273. /package/.next/server/chunks/ssr/{node_modules_1kv6lsckqs-m0._.js.map → node_modules_1zii7uk468cay._.js.map} +0 -0
  274. /package/.next/server/chunks/ssr/{node_modules_katex_dist_katex_mjs_0bmuudv_6eypr._.js.map → node_modules_katex_dist_katex_mjs_0kqo9zl9cgwbo._.js.map} +0 -0
  275. /package/.next/server/chunks/ssr/{node_modules_katex_dist_katex_mjs_0qyy6pq9uzpk0._.js.map → node_modules_katex_dist_katex_mjs_1604s1ky8db8u._.js.map} +0 -0
  276. /package/.next/static/{sQnXeiP8rV6y2v0az_xw3 → 1y6Da0YgnPr2_6ncpWrbV}/_buildManifest.js +0 -0
  277. /package/.next/static/{sQnXeiP8rV6y2v0az_xw3 → 1y6Da0YgnPr2_6ncpWrbV}/_clientMiddlewareManifest.js +0 -0
  278. /package/.next/static/{sQnXeiP8rV6y2v0az_xw3 → 1y6Da0YgnPr2_6ncpWrbV}/_ssgManifest.js +0 -0
@@ -64,25 +64,25 @@ export default function ToolOutputView({ output = "", onImageClick }) {
64
64
  };
65
65
 
66
66
  return (
67
- <div className="mt-2 rounded-xl border border-slate-800 bg-slate-950/80 overflow-hidden text-xs font-mono">
67
+ <div className="mt-2 rounded-xl border border-[var(--border-card)] bg-[var(--bg-chat-code)] overflow-hidden text-xs font-mono">
68
68
  {/* Header bar */}
69
- <div className="flex items-center justify-between px-3 py-1.5 bg-slate-900/80 border-b border-slate-800 text-[11px] text-slate-400">
69
+ <div className="flex items-center justify-between px-3 py-1.5 bg-[var(--bg-card-inner)] border-b border-[var(--border-subtle)] text-[11px] text-[var(--text-muted)]">
70
70
  <div className="flex items-center gap-2">
71
71
  <Terminal className="w-3.5 h-3.5 text-cyan-400" />
72
- <span className="font-medium text-slate-300">Tool Output</span>
73
- <span className="text-[10px] text-slate-500 font-mono">({totalLines} lines)</span>
72
+ <span className="font-medium text-[var(--text-bright)]">Tool Output</span>
73
+ <span className="text-[10px] text-[var(--text-muted)] font-mono">({totalLines} lines)</span>
74
74
  </div>
75
75
 
76
76
  <div className="flex items-center gap-1.5 font-sans">
77
77
  {/* JSON Tree vs Raw Text Switcher */}
78
78
  {parsedJson && (
79
- <div className="flex items-center bg-slate-950 rounded-lg p-0.5 border border-slate-800 mr-1">
79
+ <div className="flex items-center bg-[var(--bg-card)] rounded-lg p-0.5 border border-[var(--border-card)] mr-1">
80
80
  <button
81
81
  onClick={() => setViewMode("raw")}
82
- className={`flex items-center gap-1 px-2 py-0.5 rounded text-[10px] transition-colors ${
82
+ className={`flex items-center gap-1 px-2 py-0.5 rounded text-[10px] transition-colors cursor-pointer ${
83
83
  viewMode === "raw"
84
- ? "bg-slate-800 text-slate-200"
85
- : "text-slate-400 hover:text-slate-300"
84
+ ? "bg-[var(--bg-selection)] text-[var(--text-bright)] font-semibold"
85
+ : "text-[var(--text-muted)] hover:text-[var(--text-bright)]"
86
86
  }`}
87
87
  >
88
88
  <AlignLeft className="w-3 h-3" />
@@ -90,10 +90,10 @@ export default function ToolOutputView({ output = "", onImageClick }) {
90
90
  </button>
91
91
  <button
92
92
  onClick={() => setViewMode("json")}
93
- className={`flex items-center gap-1 px-2 py-0.5 rounded text-[10px] transition-colors ${
93
+ className={`flex items-center gap-1 px-2 py-0.5 rounded text-[10px] transition-colors cursor-pointer ${
94
94
  viewMode === "json"
95
95
  ? "bg-indigo-600/30 text-indigo-300 border border-indigo-500/40"
96
- : "text-slate-400 hover:text-slate-300"
96
+ : "text-[var(--text-muted)] hover:text-[var(--text-bright)]"
97
97
  }`}
98
98
  >
99
99
  <Braces className="w-3 h-3 text-indigo-400" />
@@ -105,7 +105,7 @@ export default function ToolOutputView({ output = "", onImageClick }) {
105
105
  {/* Copy Button */}
106
106
  <button
107
107
  onClick={handleCopy}
108
- className="flex items-center gap-1 px-2 py-0.5 rounded hover:bg-slate-800 text-slate-400 hover:text-slate-200 transition-colors border border-slate-800/80"
108
+ className="flex items-center gap-1 px-2 py-0.5 rounded hover:bg-[var(--bg-hover)] text-[var(--text-muted)] hover:text-[var(--text-bright)] transition-colors border border-[var(--border-subtle)] cursor-pointer"
109
109
  title="Copy output"
110
110
  >
111
111
  {copied ? (
@@ -115,7 +115,7 @@ export default function ToolOutputView({ output = "", onImageClick }) {
115
115
  </>
116
116
  ) : (
117
117
  <>
118
- <Copy className="w-3 h-3" />
118
+ <Copy className="w-3.5 h-3.5" />
119
119
  <span className="text-[10px]">Copy</span>
120
120
  </>
121
121
  )}
@@ -125,8 +125,8 @@ export default function ToolOutputView({ output = "", onImageClick }) {
125
125
 
126
126
  {/* Detected Image Thumbnails / Chips */}
127
127
  {imageMatches.length > 0 && (
128
- <div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 bg-slate-900/40 border-b border-slate-800/80 text-[11px]">
129
- <span className="text-slate-400 flex items-center gap-1">
128
+ <div className="flex flex-wrap items-center gap-1.5 px-3 py-1.5 bg-[var(--bg-card-inner)] border-b border-[var(--border-subtle)] text-[11px]">
129
+ <span className="text-[var(--text-muted)] flex items-center gap-1">
130
130
  <ImageIcon className="w-3.5 h-3.5 text-cyan-400" />
131
131
  <span>Image output:</span>
132
132
  </span>
@@ -137,7 +137,7 @@ export default function ToolOutputView({ output = "", onImageClick }) {
137
137
  src: `/api/media?path=${encodeURIComponent(imgP)}`,
138
138
  alt: imgP.split("/").pop()
139
139
  })}
140
- className="flex items-center gap-1 px-2 py-0.5 rounded bg-cyan-950/60 hover:bg-cyan-900/80 border border-cyan-500/40 text-cyan-300 font-mono transition-colors text-[10px]"
140
+ className="flex items-center gap-1 px-2 py-0.5 rounded bg-[var(--bg-chat-user)] hover:brightness-110 border border-[var(--border-chat-user)] text-[var(--accent-secondary)] font-mono transition-colors text-[10px] cursor-pointer"
141
141
  title="Click to view full image popup"
142
142
  >
143
143
  <span>{imgP.split("/").pop()}</span>
@@ -148,22 +148,22 @@ export default function ToolOutputView({ output = "", onImageClick }) {
148
148
 
149
149
  {/* JSON Inspector View */}
150
150
  {parsedJson && viewMode === "json" ? (
151
- <div className="p-2 bg-black/60">
151
+ <div className="p-2 bg-[var(--bg-chat-tool)]">
152
152
  <JsonInspector data={parsedJson} title="JSON Output View" />
153
153
  </div>
154
154
  ) : (
155
155
  /* Raw Output text */
156
- <pre className="p-3 text-[11px] text-slate-300 leading-relaxed overflow-x-auto max-h-80 overflow-y-auto whitespace-pre font-mono">
156
+ <pre className="p-3 text-[11px] text-[var(--text-chat-code)] leading-relaxed overflow-x-auto max-h-80 overflow-y-auto whitespace-pre font-mono">
157
157
  {displayedText}
158
158
  </pre>
159
159
  )}
160
160
 
161
161
  {/* Expand/Collapse Footer for Raw View */}
162
162
  {viewMode === "raw" && hasManyLines && (
163
- <div className="px-3 py-1.5 bg-slate-900/60 border-t border-slate-800 text-center">
163
+ <div className="px-3 py-1.5 bg-[var(--bg-card-inner)] border-t border-[var(--border-subtle)] text-center">
164
164
  <button
165
165
  onClick={() => setExpanded(!expanded)}
166
- className="text-[11px] text-cyan-400 hover:text-cyan-300 underline transition-colors"
166
+ className="text-[11px] text-[var(--accent-secondary)] hover:underline transition-colors cursor-pointer"
167
167
  >
168
168
  {expanded ? "Show less (first 50 lines)" : `Show all ${totalLines} lines`}
169
169
  </button>
@@ -1,14 +1,24 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect, useRef, useState } from "react";
4
- import { ZoomIn, ZoomOut, Maximize2 } from "lucide-react";
4
+ import { ZoomIn, ZoomOut, Maximize2, Minimize2, Sparkles, Volume2, VolumeX, Maximize } from "lucide-react";
5
5
  import { mountOfficeScene } from "./office-scene";
6
6
  import { SUPPORTER_CHANGE_EVENT } from "@/lib/supporterStore";
7
7
 
8
- export default function OfficeCanvas({ traces = [], onStats, onSelect, selectedId = null }) {
8
+ export default function OfficeCanvas({
9
+ traces = [],
10
+ onStats,
11
+ onSelect,
12
+ selectedId = null,
13
+ isZenFullscreen = false,
14
+ onToggleZenFullscreen = null,
15
+ soundEnabled = false,
16
+ onToggleSound = null,
17
+ }) {
9
18
  const hostRef = useRef(null);
10
19
  const sceneRef = useRef(null);
11
20
  const [zoomPct, setZoomPct] = useState(100);
21
+ const [showToast, setShowToast] = useState(false);
12
22
  const latest = useRef({ onSelect, selectedId, traces });
13
23
 
14
24
  useEffect(() => {
@@ -111,8 +121,49 @@ export default function OfficeCanvas({ traces = [], onStats, onSelect, selectedI
111
121
  return () => clearInterval(id);
112
122
  }, [onStats]);
113
123
 
124
+ // Re-fit canvas layout whenever fullscreen mode changes
125
+ useEffect(() => {
126
+ const timer = setTimeout(() => {
127
+ if (typeof window !== "undefined") {
128
+ window.dispatchEvent(new Event("resize"));
129
+ }
130
+ sceneRef.current?.fit?.();
131
+ }, 60);
132
+ return () => clearTimeout(timer);
133
+ }, [isZenFullscreen]);
134
+
135
+ // Toast notification when entering Chill Mode
136
+ useEffect(() => {
137
+ if (isZenFullscreen) {
138
+ setShowToast(true);
139
+ const timer = setTimeout(() => setShowToast(false), 3500);
140
+ return () => clearTimeout(timer);
141
+ } else {
142
+ setShowToast(false);
143
+ }
144
+ }, [isZenFullscreen]);
145
+
146
+ // Global ESC key listener to exit Chill Mode
147
+ useEffect(() => {
148
+ if (!isZenFullscreen) return;
149
+ const handleKeyDown = (e) => {
150
+ if (e.key === "Escape") {
151
+ e.preventDefault();
152
+ onToggleZenFullscreen?.(false);
153
+ }
154
+ };
155
+ window.addEventListener("keydown", handleKeyDown);
156
+ return () => window.removeEventListener("keydown", handleKeyDown);
157
+ }, [isZenFullscreen, onToggleZenFullscreen]);
158
+
114
159
  return (
115
- <div className="relative h-full w-full overflow-hidden rounded-xl border border-slate-800 bg-[#080d14] shadow-2xl">
160
+ <div
161
+ className={`relative h-full w-full overflow-hidden bg-[#080d14] ${
162
+ isZenFullscreen
163
+ ? "!fixed !inset-0 !z-[99] !w-screen !h-screen !rounded-none !border-none"
164
+ : "rounded-xl border border-slate-800 shadow-2xl"
165
+ }`}
166
+ >
116
167
  <div ref={hostRef} className="absolute inset-0" />
117
168
  {error && (
118
169
  <div className="absolute inset-0 flex items-center justify-center p-6 text-center text-sm text-rose-400">
@@ -120,6 +171,41 @@ export default function OfficeCanvas({ traces = [], onStats, onSelect, selectedI
120
171
  </div>
121
172
  )}
122
173
 
174
+ {/* Chill Mode Entry Toast Banner */}
175
+ {showToast && (
176
+ <div className="absolute top-5 left-1/2 -translate-x-1/2 z-30 pointer-events-none transition-all duration-300 animate-in fade-in slide-in-from-top-2">
177
+ <div className="flex items-center gap-2 px-4 py-2 rounded-xl bg-slate-950/90 border border-cyan-500/40 text-cyan-200 text-xs shadow-2xl backdrop-blur-md">
178
+ <Sparkles className="w-4 h-4 text-cyan-400 shrink-0" />
179
+ <span>Chế độ Chill toàn màn hình · Nhấn <kbd className="px-1.5 py-0.5 rounded bg-slate-800 text-amber-300 font-mono text-[10px]">ESC</kbd> hoặc click nút góc trên để thoát</span>
180
+ </div>
181
+ </div>
182
+ )}
183
+
184
+ {/* Chill Mode Floating Top Control Bar */}
185
+ {isZenFullscreen && (
186
+ <div className="absolute top-4 right-4 z-30 flex items-center gap-2 animate-in fade-in duration-200">
187
+ <div className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-slate-950/70 border border-slate-800/80 backdrop-blur-md shadow-xl text-xs text-slate-300 select-none">
188
+ <span className="relative flex h-2 w-2">
189
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75" />
190
+ <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-500" />
191
+ </span>
192
+ <span className="font-medium text-[11px]">Virtual Office · Chill Mode</span>
193
+ <span className="text-[10px] text-slate-400 font-mono">({traces.length} Bots)</span>
194
+ </div>
195
+
196
+ <button
197
+ type="button"
198
+ data-testid="exit-zen-fullscreen-btn"
199
+ onClick={() => onToggleZenFullscreen?.(false)}
200
+ title="Thoát chế độ toàn màn hình Chill Mode (ESC)"
201
+ className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-slate-900/80 hover:bg-slate-800 border border-slate-700/60 hover:border-amber-500/50 text-slate-300 hover:text-white backdrop-blur-md shadow-xl transition-all cursor-pointer text-xs font-medium group"
202
+ >
203
+ <Minimize2 className="w-3.5 h-3.5 text-amber-400 group-hover:scale-110 transition-transform" />
204
+ <span className="text-[11px]">Thoát ESC</span>
205
+ </button>
206
+ </div>
207
+ )}
208
+
123
209
  {/* Floating Canvas Camera Controls */}
124
210
  <div className="absolute bottom-3 left-3 z-10 flex items-center gap-1 rounded-lg border border-slate-800/80 bg-slate-950/80 p-1 backdrop-blur-md shadow-xl text-slate-400">
125
211
  <button
@@ -151,6 +237,51 @@ export default function OfficeCanvas({ traces = [], onStats, onSelect, selectedI
151
237
  >
152
238
  <Maximize2 className="w-3.5 h-3.5" />
153
239
  </button>
240
+
241
+ {onToggleZenFullscreen && (
242
+ <>
243
+ <div className="w-[1px] h-3.5 bg-slate-800 my-auto" />
244
+ <button
245
+ type="button"
246
+ data-testid="canvas-camera-zen-fullscreen-btn"
247
+ onClick={() => onToggleZenFullscreen(!isZenFullscreen)}
248
+ title={
249
+ isZenFullscreen
250
+ ? "Thoát toàn màn hình (ESC)"
251
+ : "Chế độ Chill toàn màn hình Virtual Office (ESC để thoát)"
252
+ }
253
+ className={`p-1.5 rounded-md transition-colors cursor-pointer ${
254
+ isZenFullscreen
255
+ ? "bg-amber-500/20 text-amber-300 hover:bg-amber-500/30"
256
+ : "hover:bg-slate-800 hover:text-cyan-300 text-slate-400"
257
+ }`}
258
+ >
259
+ {isZenFullscreen ? (
260
+ <Minimize2 className="w-3.5 h-3.5 text-amber-400" />
261
+ ) : (
262
+ <Maximize className="w-3.5 h-3.5" />
263
+ )}
264
+ </button>
265
+ </>
266
+ )}
267
+
268
+ {onToggleSound && (
269
+ <>
270
+ <div className="w-[1px] h-3.5 bg-slate-800 my-auto" />
271
+ <button
272
+ type="button"
273
+ onClick={onToggleSound}
274
+ title={soundEnabled ? "Âm thanh: BẬT" : "Âm thanh: TẮT"}
275
+ className={`p-1.5 rounded-md transition-colors cursor-pointer ${
276
+ soundEnabled
277
+ ? "text-emerald-400 hover:bg-slate-800"
278
+ : "text-slate-500 hover:text-slate-300 hover:bg-slate-800"
279
+ }`}
280
+ >
281
+ {soundEnabled ? <Volume2 className="w-3.5 h-3.5" /> : <VolumeX className="w-3.5 h-3.5" />}
282
+ </button>
283
+ </>
284
+ )}
154
285
  </div>
155
286
  </div>
156
287
  );
@@ -51,24 +51,81 @@ export function createCharacter({ color, depth = 1, scale = 1, seed = 0, trimCol
51
51
  const skinItem = typeof skin === "string" ? getItemById(skin) : null;
52
52
  const hasCustomSkin = Boolean(skinItem || (skin && skin !== "classic" && skin !== "none"));
53
53
  const skinArchetype = skinItem?.archetype || (skin === "cat" ? "cyber_cat" : skin === "ninja" ? "stealth_ninja" : skin === "hacker" ? "matrix_hacker" : skin || "cyber_classic");
54
+ const skinVariant = skinItem?.variant || "tactical_visor";
54
55
  const skinColor = skinItem?.color ? parseHexColor(skinItem.color, trimColor ?? defaultTrim) : (trimColor ?? defaultTrim);
56
+ const skinSecondaryColor = skinItem?.secondaryColor ? parseHexColor(skinItem.secondaryColor, 0x111827) : 0x111827;
57
+ const skinAccentColor = skinItem?.accentColor ? parseHexColor(skinItem.accentColor, 0xffffff) : 0xffffff;
55
58
  const trim = skinColor;
56
59
  const SHELL = hasCustomSkin ? 0x1e2430 : 0xf3f5f9;
57
60
  const SHADE = hasCustomSkin ? 0x111622 : 0xc9d0dc;
58
61
 
59
- // Torso: two stacked shells with a coloured band between them.
62
+ // Torso: 5 Distinct Staff Uniforms & Silhouettes
60
63
  const body = new Graphics();
61
- body.roundRect(-17, -30, 34, 22, 11).fill(vgrad(0xffffff, SHELL, SHADE));
62
- body.roundRect(-17, -30, 34, 8, 8).fill({ color: 0xffffff, alpha: 0.6 });
63
- body.roundRect(-14, -12, 28, 8, 4).fill({ color: trim });
64
- body.roundRect(-16, -8, 32, 16, 8).fill(vgrad(SHELL, SHADE, 0x8c97a9));
65
- body.roundRect(-16, 2, 32, 6, 4).fill({ color: SHADE, alpha: 0.6 });
66
-
67
- // Chest arc reactor for equipped custom skins
68
- if (hasCustomSkin) {
69
- body.circle(0, -18, 4).fill({ color: 0x0f172a });
70
- body.circle(0, -18, 4).stroke({ width: 1.2, color: skinColor });
71
- body.circle(0, -18, 2).fill({ color: skinColor });
64
+ if (skinArchetype === "mecha_pilot") {
65
+ // Heavy Industrial Exoskeleton Vest
66
+ body.poly([-22, -30, 22, -30, 18, -6, -18, -6]).fill({ color: 0x18181b }).stroke({ width: 1.5, color: skinColor });
67
+ // Pauldrons
68
+ body.poly([-27, -29, -20, -33, -17, -25, -25, -20]).fill({ color: 0x27272a }).stroke({ width: 1, color: skinColor });
69
+ body.poly([27, -29, 20, -33, 17, -25, 25, -20]).fill({ color: 0x27272a }).stroke({ width: 1, color: skinColor });
70
+ // Hazard Chevrons
71
+ body.poly([-12, -26, -7, -26, -3, -20, -8, -20]).fill({ color: 0xeab308 });
72
+ body.poly([2, -26, 7, -26, 11, -20, 6, -20]).fill({ color: 0xeab308 });
73
+ // Heavy Tactical Harness Straps
74
+ body.rect(-13, -30, 2, 24).fill({ color: skinColor });
75
+ body.rect(11, -30, 2, 24).fill({ color: skinColor });
76
+ // Central Fusion Core with Cage Grille
77
+ body.circle(0, -14, 5.5).fill({ color: 0x09090b }).stroke({ width: 1.4, color: skinColor });
78
+ body.circle(0, -14, 3).fill({ color: skinColor });
79
+ body.rect(-4, -15, 8, 2).fill({ color: 0xffffff });
80
+ } else if (skinArchetype === "stealth_ninja") {
81
+ // Sleek Form-Fitting Shinobi Gi
82
+ body.poly([-16, -30, 16, -30, 13, -6, -13, -6]).fill({ color: 0x090d16 }).stroke({ width: 1.4, color: skinColor });
83
+ // Crossed Kimono Lapels
84
+ body.poly([-16, -30, 5, -14, 2, -14, -16, -28]).fill({ color: skinColor });
85
+ // Diagonal Tactical Sash
86
+ body.poly([-16, -28, -11, -30, 14, -9, 9, -7]).fill({ color: skinColor, alpha: 0.9 });
87
+ // Obi Waist Sash & Knot
88
+ body.roundRect(-14, -12, 28, 6, 2).fill({ color: 0x1e1b4b }).stroke({ width: 1.2, color: skinColor });
89
+ body.poly([3, -7, 6, 1, 4, 6, 1, 1, 3, -7]).fill({ color: skinColor });
90
+ } else if (skinArchetype === "matrix_hacker") {
91
+ // Loose Oversized Slouchy Techwear Hoodie Body
92
+ body.roundRect(-21, -30, 42, 25, 7).fill({ color: 0x121217 }).stroke({ width: 1.5, color: skinColor });
93
+ // Cowl Neck Collar
94
+ body.roundRect(-18, -32, 36, 10, 4).fill({ color: 0x1f1f28 }).stroke({ width: 1.2, color: skinColor });
95
+ // Hanging Drawstrings with Metal Aglets
96
+ body.rect(-7, -23, 2, 16).fill({ color: 0xffffff });
97
+ body.rect(-7.5, -7, 3, 4).fill({ color: skinColor });
98
+ body.rect(5, -23, 2, 16).fill({ color: 0xffffff });
99
+ body.rect(4.5, -7, 3, 4).fill({ color: skinColor });
100
+ // Kangaroo Pouch Pocket
101
+ body.poly([-15, -14, 15, -14, 13, -6, -13, -6]).fill({ color: 0x09090d }).stroke({ width: 1, color: 0x27272a });
102
+ } else if (skinArchetype === "celestial_astro") {
103
+ // Pressurized Flight Suit Body
104
+ body.poly([-18, -30, 18, -30, 16, -6, -16, -6]).fill({ color: 0xf1f5f9 }).stroke({ width: 1.4, color: skinColor });
105
+ // Hermetic Helmet Seal Ring
106
+ body.roundRect(-14, -33, 28, 5, 2).fill({ color: 0x334155 }).stroke({ width: 1.2, color: skinColor });
107
+ // Gold Command Epaulets on Shoulders
108
+ body.roundRect(-24, -31, 8, 4.5, 1).fill({ color: 0xf59e0b }).stroke({ width: 0.8, color: 0x78350f });
109
+ body.roundRect(16, -31, 8, 4.5, 1).fill({ color: 0xf59e0b }).stroke({ width: 0.8, color: 0x78350f });
110
+ // Dual Atmospheric Pressure Regulator Dials
111
+ body.circle(-7, -17, 3.5).fill({ color: 0x0f172a }).stroke({ width: 1.2, color: skinColor });
112
+ body.circle(-7, -17, 1.5).fill({ color: 0x22c55e });
113
+ body.circle(7, -17, 3.5).fill({ color: 0x0f172a }).stroke({ width: 1.2, color: skinColor });
114
+ body.circle(7, -17, 1.5).fill({ color: 0x38bdf8 });
115
+ } else {
116
+ // Default Cyber Suit (Corporate Tech Field Ops / Executive Security)
117
+ body.poly([-18, -30, 18, -30, 15, -6, -15, -6]).fill(vgrad(0xffffff, SHELL, SHADE)).stroke({ width: 1.2, color: skinColor });
118
+ // Sharp Lapels
119
+ body.poly([-17, -30, -7, -14, -13, -14]).fill({ color: 0x0d1117 });
120
+ body.poly([17, -30, 7, -14, 13, -14]).fill({ color: 0x0d1117 });
121
+ // Security ID Badge Lanyard
122
+ body.poly([-5, -30, 0, -18, 5, -30]).stroke({ width: 1.2, color: skinAccentColor, alpha: 0.85 });
123
+ body.roundRect(-4.5, -19, 9, 12, 1.5).fill({ color: 0x090d16 }).stroke({ width: 1, color: skinColor });
124
+ body.rect(-3, -17.5, 6, 4.5).fill({ color: skinColor });
125
+ body.rect(-3, -11, 6, 1.5).fill({ color: 0xffffff });
126
+ // Corporate Belt & Buckle
127
+ body.rect(-15, -10, 30, 4).fill({ color: 0x020617 });
128
+ body.roundRect(-3.5, -11, 7, 6, 1).fill({ color: 0x1e293b }).stroke({ width: 1, color: skinColor });
72
129
  }
73
130
 
74
131
  const neck = new Graphics();
@@ -108,42 +165,220 @@ export function createCharacter({ color, depth = 1, scale = 1, seed = 0, trimCol
108
165
  head.ellipse(0, -53, 20, 15.5).fill({ color: 0x0f141c });
109
166
  head.ellipse(-5, -58, 11, 5).fill({ color: 0xffffff, alpha: 0.06 });
110
167
 
111
- // Custom Skin Accessories on Head according to 5 Archetypes
112
- if (skinArchetype === "cyber_suit") {
113
- // Cyber Suit: Angular Tactical Brow Visor & Wing Antennas
168
+ // Custom Skin Accessories on Head matching 50 Curated Variants
169
+ // 1. CYBER SUIT VARIANTS
170
+ if (skinVariant === "tactical_visor") {
114
171
  head.roundRect(-24, -66, 48, 7, 2.5).fill({ color: 0x0f172a });
115
172
  head.roundRect(-24, -66, 48, 7, 2.5).stroke({ width: 1.6, color: skinColor });
116
173
  head.poly([-26, -66, -34, -76, -26, -72]).fill({ color: skinColor });
117
174
  head.poly([26, -66, 34, -76, 26, -72]).fill({ color: skinColor });
118
- head.circle(0, -62.5, 2.5).fill({ color: skinColor });
119
- } else if (skinArchetype === "stealth_ninja" || skinArchetype === "ninja") {
120
- // Ninja Headband & Laser Visor
121
- head.roundRect(-24, -66, 48, 8, 3).fill({ color: 0x1e1b4b });
122
- head.roundRect(-24, -66, 48, 8, 3).stroke({ width: 1.5, color: skinColor });
175
+ head.circle(0, -62.5, 2.5).fill({ color: skinAccentColor });
176
+ } else if (skinVariant === "laser_scout") {
177
+ head.circle(8, -57, 7).stroke({ width: 1.6, color: skinColor });
178
+ head.circle(8, -57, 2.5).fill({ color: 0xff0000 });
179
+ } else if (skinVariant === "riot_shield") {
180
+ head.roundRect(-25, -68, 50, 9, 3).fill({ color: 0x1e2430 });
181
+ head.roundRect(-25, -68, 50, 9, 3).stroke({ width: 1.8, color: skinColor });
182
+ head.circle(-16, -64, 2.5).fill({ color: skinAccentColor });
183
+ head.circle(16, -64, 2.5).fill({ color: skinAccentColor });
184
+ } else if (skinVariant === "cyber_horns") {
185
+ head.poly([-20, -70, -30, -88, -14, -76]).fill({ color: skinColor });
186
+ head.poly([20, -70, 30, -88, 14, -76]).fill({ color: skinColor });
187
+ } else if (skinVariant === "crown_radiator") {
188
+ head.poly([-16, -72, -14, -86, -8, -74]).fill({ color: skinColor });
189
+ head.poly([-4, -74, 0, -92, 4, -74]).fill({ color: skinColor });
190
+ head.poly([8, -74, 14, -86, 16, -72]).fill({ color: skinColor });
191
+ head.circle(0, -70, 3).fill({ color: skinAccentColor });
192
+ } else if (skinVariant === "gas_respirator") {
193
+ head.circle(-14, -44, 6).fill({ color: 0x1e2430 }).stroke({ width: 1.5, color: skinColor });
194
+ head.circle(14, -44, 6).fill({ color: 0x1e2430 }).stroke({ width: 1.5, color: skinColor });
195
+ head.circle(-14, -44, 3).fill({ color: skinColor });
196
+ head.circle(14, -44, 3).fill({ color: skinColor });
197
+ } else if (skinVariant === "prism_goggles") {
198
+ head.poly([-16, -62, -8, -66, -2, -62, -2, -52, -8, -48, -16, -52]).fill({ color: 0x0c4a6e }).stroke({ width: 1.6, color: skinColor });
199
+ head.poly([2, -62, 8, -66, 16, -62, 16, -52, 8, -48, 2, -52]).fill({ color: 0x0c4a6e }).stroke({ width: 1.6, color: skinColor });
200
+ head.circle(-9, -57, 2.5).fill({ color: skinAccentColor });
201
+ head.circle(9, -57, 2.5).fill({ color: skinAccentColor });
202
+ } else if (skinVariant === "samurai_crest") {
203
+ head.poly([-22, -72, 0, -88, 22, -72, 0, -80]).fill({ color: skinColor });
204
+ head.circle(0, -78, 3).fill({ color: skinAccentColor });
205
+ } else if (skinVariant === "overdrive_vents") {
206
+ head.poly([-18, -72, -28, -90, -14, -76]).fill({ color: skinColor });
207
+ head.poly([18, -72, 28, -90, 14, -76]).fill({ color: skinColor });
208
+ } else if (skinVariant === "holo_shroud") {
209
+ head.ellipse(0, -66, 28, 12).stroke({ width: 1.8, color: skinColor, alpha: 0.8 });
210
+ head.circle(0, -78, 4).fill({ color: skinAccentColor });
211
+ }
212
+ // 2. MECHA PILOT VARIANTS
213
+ else if (skinVariant === "v_fin") {
214
+ head.poly([-24, -88, -18, -92, 0, -76, 18, -92, 24, -88, 0, -72]).fill({ color: skinColor });
215
+ head.poly([-4, -72, 0, -78, 4, -72, 0, -68]).fill({ color: 0xef4444 });
216
+ } else if (skinVariant === "blast_shield") {
217
+ head.roundRect(-24, -68, 48, 14, 3).fill({ color: 0x0f172a }).stroke({ width: 2, color: skinColor });
218
+ head.circle(-18, -80, 3.5).fill({ color: 0xfde047 });
219
+ head.circle(18, -80, 3.5).fill({ color: 0xfde047 });
220
+ } else if (skinVariant === "eva_horn") {
221
+ head.poly([-3, -74, 0, -98, 3, -74]).fill({ color: skinColor });
222
+ head.roundRect(-28, -48, 5, 18, 2).fill({ color: skinColor });
223
+ head.roundRect(23, -48, 5, 18, 2).fill({ color: skinColor });
224
+ } else if (skinVariant === "cage_grille") {
225
+ head.roundRect(-16, -52, 32, 14, 2).fill({ color: 0x18181b }).stroke({ width: 1.6, color: skinColor });
226
+ head.roundRect(-22, -86, 4, 16, 1).fill({ color: 0x27272a }).stroke({ width: 1, color: skinColor });
227
+ head.roundRect(18, -86, 4, 16, 1).fill({ color: 0x27272a }).stroke({ width: 1, color: skinColor });
228
+ } else if (skinVariant === "missile_pod") {
229
+ head.roundRect(-30, -42, 8, 12, 2).fill({ color: 0x1c1917 }).stroke({ width: 1.5, color: skinColor });
230
+ head.roundRect(22, -42, 8, 12, 2).fill({ color: 0x1c1917 }).stroke({ width: 1.5, color: skinColor });
231
+ head.circle(-26, -38, 1.5).fill({ color: 0xef4444 });
232
+ head.circle(26, -38, 1.5).fill({ color: 0xef4444 });
233
+ } else if (skinVariant === "quad_array") {
234
+ head.poly([-22, -72, -26, -90, -20, -72]).fill({ color: skinColor });
235
+ head.poly([-12, -76, -14, -94, -10, -76]).fill({ color: skinColor });
236
+ head.poly([10, -76, 14, -94, 12, -76]).fill({ color: skinColor });
237
+ head.poly([20, -72, 26, -90, 22, -72]).fill({ color: skinColor });
238
+ head.circle(-26, -90, 2).fill({ color: skinAccentColor });
239
+ head.circle(26, -90, 2).fill({ color: skinAccentColor });
240
+ } else if (skinVariant === "halo_shield") {
241
+ head.poly([-32, -42, -26, -46, -20, -42, -20, -34, -26, -30, -32, -34]).fill({ color: 0x064e3b }).stroke({ width: 1.5, color: skinColor });
242
+ head.poly([20, -42, 26, -46, 32, -42, 32, -34, 26, -30, 20, -34]).fill({ color: 0x064e3b }).stroke({ width: 1.5, color: skinColor });
243
+ } else if (skinVariant === "ram_horns") {
244
+ head.poly([-18, -72, -34, -86, -18, -92, -14, -72]).fill({ color: skinColor });
245
+ head.poly([18, -72, 34, -86, 18, -92, 14, -72]).fill({ color: skinColor });
246
+ } else if (skinVariant === "radar_dish") {
247
+ head.ellipse(-24, -84, 7, 12).fill({ color: 0x18181b }).stroke({ width: 1.5, color: skinColor });
248
+ head.circle(-24, -84, 2).fill({ color: skinAccentColor });
249
+ } else if (skinVariant === "hyper_wings") {
250
+ head.poly([-26, -46, -44, -64, -34, -40]).fill({ color: skinColor });
251
+ head.poly([26, -46, 44, -64, 34, -40]).fill({ color: skinColor });
252
+ }
253
+ // 3. STEALTH NINJA VARIANTS
254
+ else if (skinVariant === "flowing_headband") {
255
+ head.roundRect(-24, -66, 48, 8, 2).fill({ color: 0x1e1b4b }).stroke({ width: 1.5, color: skinColor });
256
+ head.circle(0, -62, 3).fill({ color: 0x38bdf8 });
257
+ head.poly([24, -62, 38, -56, 46, -46, 36, -48, 24, -56]).fill({ color: skinColor });
258
+ } else if (skinVariant === "tactical_cowl") {
259
+ head.roundRect(-24, -68, 48, 24, 6).fill({ color: 0x0f172a, alpha: 0.8 }).stroke({ width: 1.4, color: skinColor });
260
+ head.circle(6, -57, 4.5).stroke({ width: 1.8, color: 0x22c55e });
261
+ head.circle(6, -57, 1.5).fill({ color: 0x22c55e });
262
+ } else if (skinVariant === "oni_mask") {
263
+ head.poly([-16, -72, -24, -88, -12, -76]).fill({ color: 0xef4444 });
264
+ head.poly([16, -72, 24, -88, 12, -76]).fill({ color: 0xef4444 });
265
+ head.poly([-16, -46, -10, -40, 0, -42, 10, -40, 16, -46, 12, -36, -12, -36]).fill({ color: 0xffffff });
266
+ } else if (skinVariant === "kitsune_ears") {
267
+ head.poly([-22, -72, -14, -88, -6, -76]).fill({ color: 0x1e2430 });
268
+ head.poly([-20, -73, -14, -85, -8, -76]).fill({ color: skinColor });
269
+ head.poly([6, -76, 14, -88, 22, -72]).fill({ color: 0x1e2430 });
270
+ head.poly([8, -76, 14, -85, 20, -73]).fill({ color: skinColor });
271
+ } else if (skinVariant === "conical_kasa") {
272
+ head.poly([-36, -72, 0, -92, 36, -72]).fill({ color: 0x18181b }).stroke({ width: 1.6, color: skinColor });
273
+ head.roundRect(-36, -72, 72, 2.5, 1).fill({ color: skinAccentColor });
274
+ } else if (skinVariant === "twin_katanas") {
275
+ head.poly([-24, -32, 28, -88, 25, -88, -27, -32]).fill({ color: skinColor });
276
+ head.poly([24, -32, -28, -88, -25, -88, 27, -32]).fill({ color: skinColor });
277
+ } else if (skinVariant === "tengu_beak") {
278
+ head.poly([-12, -48, 0, -34, 12, -48, 0, -44]).fill({ color: 0x0f172a }).stroke({ width: 1.5, color: skinColor });
279
+ } else if (skinVariant === "veil_shroud") {
280
+ head.roundRect(-22, -62, 44, 26, 6).fill({ color: 0x0f172a, alpha: 0.85 }).stroke({ width: 1.2, color: skinColor });
281
+ } else if (skinVariant === "scythe_crest") {
282
+ head.poly([-14, -66, 0, -88, 14, -66, 0, -82]).fill({ color: skinColor });
283
+ } else if (skinVariant === "void_mask") {
284
+ head.roundRect(-18, -62, 36, 20, 4).fill({ color: 0x000000 }).stroke({ width: 1.8, color: skinColor });
285
+ head.circle(0, -52, 3).fill({ color: skinColor });
286
+ }
287
+ // 4. MATRIX HACKER VARIANTS
288
+ else if (skinVariant === "hoodie_cowl") {
289
+ head.roundRect(-28, -74, 56, 46, 14).fill({ color: 0x051f0b, alpha: 0.9 }).stroke({ width: 1.8, color: skinColor });
290
+ } else if (skinVariant === "vr_goggles") {
291
+ head.roundRect(-22, -64, 44, 15, 3).fill({ color: 0x083344 }).stroke({ width: 1.8, color: skinColor });
292
+ head.circle(-16, -78, 2.5).fill({ color: skinAccentColor });
293
+ head.poly([-16, -64, -16, -78, -14, -78, -14, -64]).fill({ color: skinColor });
294
+ } else if (skinVariant === "daemon_horns") {
295
+ head.poly([-16, -70, -22, -86, -10, -74]).fill({ color: skinColor });
296
+ head.poly([16, -70, 22, -86, 10, -74]).fill({ color: skinColor });
297
+ } else if (skinVariant === "glitch_halo") {
298
+ head.rect(-28, -76, 56, 42).stroke({ width: 1.5, color: skinColor, alpha: 0.8 });
299
+ head.rect(-18, -82, 12, 6).fill({ color: skinColor, alpha: 0.7 });
300
+ } else if (skinVariant === "floating_hud") {
301
+ head.roundRect(24, -78, 30, 16, 2).fill({ color: 0x09090b }).stroke({ width: 1, color: skinColor });
302
+ } else if (skinVariant === "respirator_eq") {
303
+ head.roundRect(-18, -46, 36, 10, 3).fill({ color: 0x0f172a }).stroke({ width: 1.2, color: skinColor });
304
+ head.rect(-12, -43, 4, 5).fill({ color: 0x22c55e });
305
+ head.rect(-4, -45, 4, 7).fill({ color: 0xeab308 });
306
+ head.rect(4, -45, 4, 7).fill({ color: 0xef4444 });
307
+ head.rect(12, -43, 4, 5).fill({ color: 0x22c55e });
308
+ } else if (skinVariant === "heatsink_fins") {
309
+ head.rect(-18, -84, 4, 14).fill({ color: 0xea580c });
310
+ head.rect(-10, -88, 4, 18).fill({ color: 0xea580c });
311
+ head.rect(-2, -90, 4, 20).fill({ color: 0xea580c });
312
+ head.rect(6, -88, 4, 18).fill({ color: 0xea580c });
313
+ head.rect(14, -84, 4, 14).fill({ color: 0xea580c });
314
+ } else if (skinVariant === "cable_dreads") {
315
+ head.poly([-22, -62, -32, -48, -28, -12, -26, -12, -30, -48, -20, -62]).fill({ color: skinColor });
316
+ head.poly([22, -62, 32, -48, 28, -12, 26, -12, 30, -48, 20, -62]).fill({ color: skinColor });
317
+ } else if (skinVariant === "cyber_skull") {
318
+ head.circle(-7, -55, 4).fill({ color: 0x000000 }).stroke({ width: 1.5, color: skinColor });
319
+ head.circle(7, -55, 4).fill({ color: 0x000000 }).stroke({ width: 1.5, color: skinColor });
320
+ head.poly([-8, -40, 8, -40, 8, -38, -8, -38]).fill({ color: skinColor });
321
+ } else if (skinVariant === "wireframe_cube") {
322
+ head.rect(-24, -76, 48, 42).stroke({ width: 1.6, color: skinColor });
323
+ head.rect(-16, -68, 32, 26).stroke({ width: 1.2, color: skinAccentColor, alpha: 0.8 });
324
+ }
325
+ // 5. CELESTIAL ASTRO VARIANTS
326
+ else if (skinVariant === "bubble_dome") {
327
+ head.circle(0, -56, 28).stroke({ width: 2.5, color: skinColor, alpha: 0.9 });
328
+ head.circle(0, -84, 3.5).fill({ color: 0xfef08a });
329
+ } else if (skinVariant === "lunar_pack") {
330
+ head.rect(-20, -86, 2, 18).fill({ color: skinColor });
331
+ head.circle(-19, -86, 2).fill({ color: 0xffffff });
332
+ head.ellipse(0, -54, 24, 18).stroke({ width: 2, color: 0xe2e8f0 });
333
+ } else if (skinVariant === "sunburst_halo") {
334
+ head.ellipse(0, -64, 30, 8).stroke({ width: 2, color: skinColor, alpha: 0.85 });
335
+ head.circle(0, -76, 3).fill({ color: 0xfef08a });
336
+ head.circle(-22, -70, 2).fill({ color: 0xfef08a });
337
+ head.circle(22, -70, 2).fill({ color: 0xfef08a });
338
+ } else if (skinVariant === "saturn_ring") {
339
+ head.ellipse(0, -56, 36, 10).stroke({ width: 2.2, color: skinColor });
340
+ head.circle(28, -62, 3).fill({ color: skinAccentColor });
341
+ } else if (skinVariant === "star_crown") {
342
+ head.poly([-16, -74, -12, -86, -8, -76]).fill({ color: skinColor });
343
+ head.poly([-6, -76, 0, -92, 6, -76]).fill({ color: skinColor });
344
+ head.poly([8, -76, 12, -86, 16, -74]).fill({ color: skinColor });
345
+ head.circle(0, -74, 2.5).fill({ color: 0xffffff });
346
+ } else if (skinVariant === "eclipse_corona") {
347
+ head.ellipse(0, -56, 32, 18).stroke({ width: 3, color: skinColor, alpha: 0.6 });
348
+ head.circle(0, -56, 22).fill({ color: 0x000000 }).stroke({ width: 1.5, color: skinColor });
349
+ } else if (skinVariant === "pulsar_spires") {
350
+ head.poly([-1.5, -78, 1.5, -78, 1.5, -98, -1.5, -98]).fill({ color: skinColor });
351
+ head.circle(0, -98, 3).fill({ color: 0xffffff });
352
+ head.poly([-1.5, -34, 1.5, -34, 1.5, -18, -1.5, -18]).fill({ color: skinColor });
353
+ head.circle(0, -18, 3).fill({ color: 0xffffff });
354
+ } else if (skinVariant === "aurora_ribbons") {
355
+ head.ellipse(0, -78, 24, 6).stroke({ width: 2.5, color: skinColor, alpha: 0.75 });
356
+ } else if (skinVariant === "angel_wings") {
357
+ head.poly([-26, -46, -48, -78, -32, -38]).fill({ color: skinColor, alpha: 0.85 });
358
+ head.poly([26, -46, 48, -78, 32, -38]).fill({ color: skinColor, alpha: 0.85 });
359
+ head.ellipse(0, -80, 16, 5).stroke({ width: 1.6, color: skinAccentColor });
360
+ } else if (skinVariant === "singularity_core") {
361
+ head.ellipse(0, -56, 30, 26).stroke({ width: 2, color: 0xffffff, alpha: 0.9 });
362
+ head.circle(-22, -70, 2.5).fill({ color: skinAccentColor });
363
+ head.circle(22, -42, 2.5).fill({ color: skinAccentColor });
364
+ }
365
+ // Archetype fallbacks
366
+ else if (skinArchetype === "stealth_ninja" || skinArchetype === "ninja") {
367
+ head.roundRect(-24, -66, 48, 8, 3).fill({ color: 0x1e1b4b }).stroke({ width: 1.5, color: skinColor });
123
368
  head.circle(0, -62, 3).fill({ color: 0x38bdf8 });
124
- head.poly([24, -62, 38, -56, 32, -50, 22, -56]).fill({ color: skinColor, alpha: 0.9 });
125
369
  } else if (skinArchetype === "mecha_pilot") {
126
- // Dual Heavy Antennas
127
370
  head.poly([-22, -72, -18, -90, -12, -70]).fill({ color: skinColor });
128
371
  head.poly([12, -70, 18, -90, 22, -72]).fill({ color: skinColor });
129
- head.circle(-18, -90, 2.5).fill({ color: 0xffffff });
130
- head.circle(18, -90, 2.5).fill({ color: 0xffffff });
131
372
  } else if (skinArchetype === "celestial_astro") {
132
- // Golden Solar Halo
133
373
  head.ellipse(0, -64, 30, 8).stroke({ width: 2, color: skinColor, alpha: 0.85 });
134
- head.circle(0, -72, 3).fill({ color: 0xfef08a });
135
374
  } else if (skinArchetype === "matrix_hacker" || skinArchetype === "hacker") {
136
- // Hacker Matrix Hoodie Cowl
137
- head.roundRect(-27, -78, 54, 48, 16).fill({ color: 0x111827 });
138
- head.roundRect(-27, -78, 54, 48, 16).stroke({ width: 1.6, color: skinColor });
375
+ head.roundRect(-27, -78, 54, 48, 16).fill({ color: 0x111827 }).stroke({ width: 1.6, color: skinColor });
139
376
  } else if (skinArchetype === "cyber_cat" || skin === "cat") {
140
- // Cute Cat Ears
141
377
  head.poly([-22, -72, -14, -86, -6, -76]).fill({ color: SHELL });
142
- head.poly([-20, -73, -14, -83, -8, -76]).fill({ color: 0xf472b6, alpha: 0.8 }); // pink inner ear
378
+ head.poly([-20, -73, -14, -83, -8, -76]).fill({ color: 0xf472b6, alpha: 0.8 });
143
379
  head.poly([6, -76, 14, -86, 22, -72]).fill({ color: SHELL });
144
380
  head.poly([8, -76, 14, -83, 20, -73]).fill({ color: 0xf472b6, alpha: 0.8 });
145
381
  } else {
146
- // High-Tech Crest
147
382
  head.poly([-8, -68, 0, -78, 8, -68]).fill({ color: skinColor });
148
383
  }
149
384
 
@@ -22,6 +22,7 @@ import {
22
22
  Type,
23
23
  Files,
24
24
  FolderTree,
25
+ Maximize2,
25
26
  } from "lucide-react";
26
27
  import { openChatInNewWindow } from "../../lib/windowManager.js";
27
28
 
@@ -34,6 +35,7 @@ export default function CommandPalette({
34
35
  onToggleLeftSidebar,
35
36
  onToggleBottomPanel,
36
37
  onToggleRightSidebar,
38
+ onToggleZenFullscreen,
37
39
  onOpenChatSidebar,
38
40
  onOpenFilesExplorer,
39
41
  onToggleSound,
@@ -96,6 +98,16 @@ export default function CommandPalette({
96
98
  onClose();
97
99
  },
98
100
  },
101
+ {
102
+ id: "toggle-zen-fullscreen",
103
+ title: "View: Toggle Virtual Office Chill Mode (Full Screen)",
104
+ shortcut: "Shift+F",
105
+ icon: Maximize2,
106
+ action: () => {
107
+ onToggleZenFullscreen?.();
108
+ onClose();
109
+ },
110
+ },
99
111
  {
100
112
  id: "toggle-right",
101
113
  title: "View: Toggle Secondary Side Bar (Live Chat & Inspector)",