@oxy.so/bloom 7.1.4 → 7.2.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 (442) hide show
  1. package/assets/character-runtime/README.md +19 -114
  2. package/assets/character-runtime/legacy-engine.mjs +54 -406
  3. package/assets/character-runtime/legacy-geometry.mjs +85 -242
  4. package/assets/character-runtime/legacy-worker.mjs +23 -82
  5. package/assets/character-runtime/managed-avatar.mjs +18 -12
  6. package/assets/character-runtime/render-budget.mjs +11 -6
  7. package/assets/character-runtime/runtime.mjs +295 -744
  8. package/docs/adoption-matrix.mdx +12 -11
  9. package/docs/agent-avatar.mdx +8 -45
  10. package/docs/agent-creator.mdx +3 -13
  11. package/docs/app-shell.mdx +26 -2
  12. package/docs/appearance.mdx +16 -1
  13. package/docs/content-panel.mdx +4 -0
  14. package/docs/mail-thread.mdx +8 -0
  15. package/docs/page-footer.mdx +60 -0
  16. package/docs/sidebar.mdx +1 -1
  17. package/lib/commonjs/agent-avatar/AgentAvatar.js +1 -1
  18. package/lib/commonjs/agent-avatar/AgentAvatar.js.map +1 -1
  19. package/lib/commonjs/agent-avatar/CharacterAvatar.js +1 -2
  20. package/lib/commonjs/agent-avatar/CharacterAvatar.js.map +1 -1
  21. package/lib/commonjs/agent-avatar/config-character.js +0 -4
  22. package/lib/commonjs/agent-avatar/config-character.js.map +1 -1
  23. package/lib/commonjs/agent-avatar/legacy-recipe.js +6 -19
  24. package/lib/commonjs/agent-avatar/legacy-recipe.js.map +1 -1
  25. package/lib/commonjs/agent-creator/AgentCreatorBase.js +107 -67
  26. package/lib/commonjs/agent-creator/AgentCreatorBase.js.map +1 -1
  27. package/lib/commonjs/agent-creator/CharacterControls.js +5 -23
  28. package/lib/commonjs/agent-creator/CharacterControls.js.map +1 -1
  29. package/lib/commonjs/agent-creator/EmotionPicker.js +1 -8
  30. package/lib/commonjs/agent-creator/EmotionPicker.js.map +1 -1
  31. package/lib/commonjs/agent-creator/ShapeSilhouette.js +1 -8
  32. package/lib/commonjs/agent-creator/ShapeSilhouette.js.map +1 -1
  33. package/lib/commonjs/agent-creator/constants.js +17 -16
  34. package/lib/commonjs/agent-creator/constants.js.map +1 -1
  35. package/lib/commonjs/agent-creator/messages.js +1 -1
  36. package/lib/commonjs/agent-creator/messages.js.map +1 -1
  37. package/lib/commonjs/app-shell/AppShell.js +3 -2
  38. package/lib/commonjs/app-shell/AppShell.js.map +1 -1
  39. package/lib/commonjs/app-shell/AppShellBars.js +8 -5
  40. package/lib/commonjs/app-shell/AppShellBars.js.map +1 -1
  41. package/lib/commonjs/app-shell/AppShellEngine.js +81 -36
  42. package/lib/commonjs/app-shell/AppShellEngine.js.map +1 -1
  43. package/lib/commonjs/appearance/BloomScope.js +8 -3
  44. package/lib/commonjs/appearance/BloomScope.js.map +1 -1
  45. package/lib/commonjs/appearance/context.js.map +1 -1
  46. package/lib/commonjs/content-panel/ContentPanel.js +34 -23
  47. package/lib/commonjs/content-panel/ContentPanel.js.map +1 -1
  48. package/lib/commonjs/content-panel/ContentPanel.web.js +39 -17
  49. package/lib/commonjs/content-panel/ContentPanel.web.js.map +1 -1
  50. package/lib/commonjs/design-tokens/shapes.js +2 -2
  51. package/lib/commonjs/design-tokens/shapes.js.map +1 -1
  52. package/lib/commonjs/design-tokens/tokens.json +2 -2
  53. package/lib/commonjs/index.js +939 -927
  54. package/lib/commonjs/index.js.map +1 -1
  55. package/lib/commonjs/index.web.js +939 -927
  56. package/lib/commonjs/index.web.js.map +1 -1
  57. package/lib/commonjs/locale/translations/ar.js +1 -1
  58. package/lib/commonjs/locale/translations/ar.js.map +1 -1
  59. package/lib/commonjs/locale/translations/bn.js +1 -1
  60. package/lib/commonjs/locale/translations/bn.js.map +1 -1
  61. package/lib/commonjs/locale/translations/ca.js +1 -1
  62. package/lib/commonjs/locale/translations/ca.js.map +1 -1
  63. package/lib/commonjs/locale/translations/de.js +1 -1
  64. package/lib/commonjs/locale/translations/de.js.map +1 -1
  65. package/lib/commonjs/locale/translations/es.js +1 -1
  66. package/lib/commonjs/locale/translations/es.js.map +1 -1
  67. package/lib/commonjs/locale/translations/fr.js +1 -1
  68. package/lib/commonjs/locale/translations/fr.js.map +1 -1
  69. package/lib/commonjs/locale/translations/hi.js +1 -1
  70. package/lib/commonjs/locale/translations/hi.js.map +1 -1
  71. package/lib/commonjs/locale/translations/id.js +1 -1
  72. package/lib/commonjs/locale/translations/id.js.map +1 -1
  73. package/lib/commonjs/locale/translations/it.js +1 -1
  74. package/lib/commonjs/locale/translations/it.js.map +1 -1
  75. package/lib/commonjs/locale/translations/ja.js +1 -1
  76. package/lib/commonjs/locale/translations/ja.js.map +1 -1
  77. package/lib/commonjs/locale/translations/pt.js +1 -1
  78. package/lib/commonjs/locale/translations/pt.js.map +1 -1
  79. package/lib/commonjs/locale/translations/ru.js +1 -1
  80. package/lib/commonjs/locale/translations/ru.js.map +1 -1
  81. package/lib/commonjs/locale/translations/tr.js +1 -1
  82. package/lib/commonjs/locale/translations/tr.js.map +1 -1
  83. package/lib/commonjs/locale/translations/zh.js +1 -1
  84. package/lib/commonjs/locale/translations/zh.js.map +1 -1
  85. package/lib/commonjs/mail-thread/MailMessage.js +8 -14
  86. package/lib/commonjs/mail-thread/MailMessage.js.map +1 -1
  87. package/lib/commonjs/mail-thread/MailThread.js +6 -2
  88. package/lib/commonjs/mail-thread/MailThread.js.map +1 -1
  89. package/lib/commonjs/mail-thread/shared.js +2 -1
  90. package/lib/commonjs/mail-thread/shared.js.map +1 -1
  91. package/lib/commonjs/page-footer/PageFooter.js +137 -0
  92. package/lib/commonjs/page-footer/PageFooter.js.map +1 -0
  93. package/lib/commonjs/page-footer/PageFooterProvider.js +22 -0
  94. package/lib/commonjs/page-footer/PageFooterProvider.js.map +1 -0
  95. package/lib/commonjs/page-footer/context.js +11 -0
  96. package/lib/commonjs/page-footer/context.js.map +1 -0
  97. package/lib/commonjs/page-footer/index.js +27 -0
  98. package/lib/commonjs/page-footer/index.js.map +1 -0
  99. package/lib/commonjs/page-footer/types.js +6 -0
  100. package/lib/commonjs/page-footer/types.js.map +1 -0
  101. package/lib/commonjs/page-footer/use-page-footer-inset.js +19 -0
  102. package/lib/commonjs/page-footer/use-page-footer-inset.js.map +1 -0
  103. package/lib/commonjs/sidebar/Sidebar.js +6 -5
  104. package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
  105. package/lib/commonjs/styles/panel-chrome.js +15 -1
  106. package/lib/commonjs/styles/panel-chrome.js.map +1 -1
  107. package/lib/module/agent-avatar/AgentAvatar.js +1 -1
  108. package/lib/module/agent-avatar/AgentAvatar.js.map +1 -1
  109. package/lib/module/agent-avatar/CharacterAvatar.js +1 -2
  110. package/lib/module/agent-avatar/CharacterAvatar.js.map +1 -1
  111. package/lib/module/agent-avatar/config-character.js +0 -4
  112. package/lib/module/agent-avatar/config-character.js.map +1 -1
  113. package/lib/module/agent-avatar/legacy-recipe.js +6 -19
  114. package/lib/module/agent-avatar/legacy-recipe.js.map +1 -1
  115. package/lib/module/agent-creator/AgentCreatorBase.js +109 -69
  116. package/lib/module/agent-creator/AgentCreatorBase.js.map +1 -1
  117. package/lib/module/agent-creator/CharacterControls.js +6 -24
  118. package/lib/module/agent-creator/CharacterControls.js.map +1 -1
  119. package/lib/module/agent-creator/EmotionPicker.js +1 -8
  120. package/lib/module/agent-creator/EmotionPicker.js.map +1 -1
  121. package/lib/module/agent-creator/ShapeSilhouette.js +1 -8
  122. package/lib/module/agent-creator/ShapeSilhouette.js.map +1 -1
  123. package/lib/module/agent-creator/constants.js +16 -8
  124. package/lib/module/agent-creator/constants.js.map +1 -1
  125. package/lib/module/agent-creator/messages.js +1 -1
  126. package/lib/module/agent-creator/messages.js.map +1 -1
  127. package/lib/module/app-shell/AppShell.js +3 -2
  128. package/lib/module/app-shell/AppShell.js.map +1 -1
  129. package/lib/module/app-shell/AppShellBars.js +8 -5
  130. package/lib/module/app-shell/AppShellBars.js.map +1 -1
  131. package/lib/module/app-shell/AppShellEngine.js +81 -36
  132. package/lib/module/app-shell/AppShellEngine.js.map +1 -1
  133. package/lib/module/appearance/BloomScope.js +8 -3
  134. package/lib/module/appearance/BloomScope.js.map +1 -1
  135. package/lib/module/appearance/context.js.map +1 -1
  136. package/lib/module/content-panel/ContentPanel.js +35 -24
  137. package/lib/module/content-panel/ContentPanel.js.map +1 -1
  138. package/lib/module/content-panel/ContentPanel.web.js +41 -19
  139. package/lib/module/content-panel/ContentPanel.web.js.map +1 -1
  140. package/lib/module/design-tokens/shapes.js +2 -2
  141. package/lib/module/design-tokens/shapes.js.map +1 -1
  142. package/lib/module/design-tokens/tokens.json +2 -2
  143. package/lib/module/index.js +1 -0
  144. package/lib/module/index.js.map +1 -1
  145. package/lib/module/index.web.js +1 -0
  146. package/lib/module/index.web.js.map +1 -1
  147. package/lib/module/locale/translations/ar.js +1 -1
  148. package/lib/module/locale/translations/ar.js.map +1 -1
  149. package/lib/module/locale/translations/bn.js +1 -1
  150. package/lib/module/locale/translations/bn.js.map +1 -1
  151. package/lib/module/locale/translations/ca.js +1 -1
  152. package/lib/module/locale/translations/ca.js.map +1 -1
  153. package/lib/module/locale/translations/de.js +1 -1
  154. package/lib/module/locale/translations/de.js.map +1 -1
  155. package/lib/module/locale/translations/es.js +1 -1
  156. package/lib/module/locale/translations/es.js.map +1 -1
  157. package/lib/module/locale/translations/fr.js +1 -1
  158. package/lib/module/locale/translations/fr.js.map +1 -1
  159. package/lib/module/locale/translations/hi.js +1 -1
  160. package/lib/module/locale/translations/hi.js.map +1 -1
  161. package/lib/module/locale/translations/id.js +1 -1
  162. package/lib/module/locale/translations/id.js.map +1 -1
  163. package/lib/module/locale/translations/it.js +1 -1
  164. package/lib/module/locale/translations/it.js.map +1 -1
  165. package/lib/module/locale/translations/ja.js +1 -1
  166. package/lib/module/locale/translations/ja.js.map +1 -1
  167. package/lib/module/locale/translations/pt.js +1 -1
  168. package/lib/module/locale/translations/pt.js.map +1 -1
  169. package/lib/module/locale/translations/ru.js +1 -1
  170. package/lib/module/locale/translations/ru.js.map +1 -1
  171. package/lib/module/locale/translations/tr.js +1 -1
  172. package/lib/module/locale/translations/tr.js.map +1 -1
  173. package/lib/module/locale/translations/zh.js +1 -1
  174. package/lib/module/locale/translations/zh.js.map +1 -1
  175. package/lib/module/mail-thread/MailMessage.js +8 -14
  176. package/lib/module/mail-thread/MailMessage.js.map +1 -1
  177. package/lib/module/mail-thread/MailThread.js +6 -2
  178. package/lib/module/mail-thread/MailThread.js.map +1 -1
  179. package/lib/module/mail-thread/shared.js +2 -1
  180. package/lib/module/mail-thread/shared.js.map +1 -1
  181. package/lib/module/page-footer/PageFooter.js +132 -0
  182. package/lib/module/page-footer/PageFooter.js.map +1 -0
  183. package/lib/module/page-footer/PageFooterProvider.js +18 -0
  184. package/lib/module/page-footer/PageFooterProvider.js.map +1 -0
  185. package/lib/module/page-footer/context.js +7 -0
  186. package/lib/module/page-footer/context.js.map +1 -0
  187. package/lib/module/page-footer/index.js +6 -0
  188. package/lib/module/page-footer/index.js.map +1 -0
  189. package/lib/module/page-footer/types.js +4 -0
  190. package/lib/module/page-footer/types.js.map +1 -0
  191. package/lib/module/page-footer/use-page-footer-inset.js +16 -0
  192. package/lib/module/page-footer/use-page-footer-inset.js.map +1 -0
  193. package/lib/module/sidebar/Sidebar.js +6 -5
  194. package/lib/module/sidebar/Sidebar.js.map +1 -1
  195. package/lib/module/styles/panel-chrome.js +14 -1
  196. package/lib/module/styles/panel-chrome.js.map +1 -1
  197. package/lib/typescript/commonjs/agent-avatar/CharacterAvatar.d.ts.map +1 -1
  198. package/lib/typescript/commonjs/agent-avatar/config-character.d.ts +0 -4
  199. package/lib/typescript/commonjs/agent-avatar/config-character.d.ts.map +1 -1
  200. package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts +10 -2
  201. package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts.map +1 -1
  202. package/lib/typescript/commonjs/agent-creator/AgentCreatorBase.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts +1 -2
  204. package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts.map +1 -1
  205. package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts +0 -1
  206. package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts.map +1 -1
  207. package/lib/typescript/commonjs/agent-creator/ShapeSilhouette.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/agent-creator/constants.d.ts +15 -7
  209. package/lib/typescript/commonjs/agent-creator/constants.d.ts.map +1 -1
  210. package/lib/typescript/commonjs/agent-creator/messages.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/app-shell/AppShellBars.d.ts +4 -0
  212. package/lib/typescript/commonjs/app-shell/AppShellBars.d.ts.map +1 -1
  213. package/lib/typescript/commonjs/app-shell/AppShellEngine.d.ts.map +1 -1
  214. package/lib/typescript/commonjs/app-shell/types.d.ts +11 -3
  215. package/lib/typescript/commonjs/app-shell/types.d.ts.map +1 -1
  216. package/lib/typescript/commonjs/appearance/BloomScope.d.ts +1 -1
  217. package/lib/typescript/commonjs/appearance/BloomScope.d.ts.map +1 -1
  218. package/lib/typescript/commonjs/appearance/context.d.ts +2 -2
  219. package/lib/typescript/commonjs/appearance/context.d.ts.map +1 -1
  220. package/lib/typescript/commonjs/appearance/types.d.ts +4 -1
  221. package/lib/typescript/commonjs/appearance/types.d.ts.map +1 -1
  222. package/lib/typescript/commonjs/content-panel/ContentPanel.d.ts +3 -4
  223. package/lib/typescript/commonjs/content-panel/ContentPanel.d.ts.map +1 -1
  224. package/lib/typescript/commonjs/content-panel/ContentPanel.web.d.ts +1 -1
  225. package/lib/typescript/commonjs/content-panel/ContentPanel.web.d.ts.map +1 -1
  226. package/lib/typescript/commonjs/content-panel/types.d.ts +2 -2
  227. package/lib/typescript/commonjs/design-tokens/shapes.d.ts +2 -2
  228. package/lib/typescript/commonjs/index.d.ts +1 -0
  229. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  230. package/lib/typescript/commonjs/index.web.d.ts +1 -0
  231. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  232. package/lib/typescript/commonjs/mail-thread/MailMessage.d.ts.map +1 -1
  233. package/lib/typescript/commonjs/mail-thread/MailThread.d.ts +1 -1
  234. package/lib/typescript/commonjs/mail-thread/MailThread.d.ts.map +1 -1
  235. package/lib/typescript/commonjs/mail-thread/shared.d.ts +1 -1
  236. package/lib/typescript/commonjs/mail-thread/shared.d.ts.map +1 -1
  237. package/lib/typescript/commonjs/mail-thread/types.d.ts +2 -0
  238. package/lib/typescript/commonjs/mail-thread/types.d.ts.map +1 -1
  239. package/lib/typescript/commonjs/page-footer/PageFooter.d.ts +7 -0
  240. package/lib/typescript/commonjs/page-footer/PageFooter.d.ts.map +1 -0
  241. package/lib/typescript/commonjs/page-footer/PageFooterProvider.d.ts +4 -0
  242. package/lib/typescript/commonjs/page-footer/PageFooterProvider.d.ts.map +1 -0
  243. package/lib/typescript/commonjs/page-footer/context.d.ts +3 -0
  244. package/lib/typescript/commonjs/page-footer/context.d.ts.map +1 -0
  245. package/lib/typescript/commonjs/page-footer/index.d.ts +5 -0
  246. package/lib/typescript/commonjs/page-footer/index.d.ts.map +1 -0
  247. package/lib/typescript/commonjs/page-footer/types.d.ts +26 -0
  248. package/lib/typescript/commonjs/page-footer/types.d.ts.map +1 -0
  249. package/lib/typescript/commonjs/page-footer/use-page-footer-inset.d.ts +7 -0
  250. package/lib/typescript/commonjs/page-footer/use-page-footer-inset.d.ts.map +1 -0
  251. package/lib/typescript/commonjs/sidebar/Sidebar.d.ts.map +1 -1
  252. package/lib/typescript/commonjs/sidebar/types.d.ts +1 -1
  253. package/lib/typescript/commonjs/styles/panel-chrome.d.ts +5 -0
  254. package/lib/typescript/commonjs/styles/panel-chrome.d.ts.map +1 -1
  255. package/lib/typescript/module/agent-avatar/CharacterAvatar.d.ts.map +1 -1
  256. package/lib/typescript/module/agent-avatar/config-character.d.ts +0 -4
  257. package/lib/typescript/module/agent-avatar/config-character.d.ts.map +1 -1
  258. package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts +10 -2
  259. package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts.map +1 -1
  260. package/lib/typescript/module/agent-creator/AgentCreatorBase.d.ts.map +1 -1
  261. package/lib/typescript/module/agent-creator/CharacterControls.d.ts +1 -2
  262. package/lib/typescript/module/agent-creator/CharacterControls.d.ts.map +1 -1
  263. package/lib/typescript/module/agent-creator/EmotionPicker.d.ts +0 -1
  264. package/lib/typescript/module/agent-creator/EmotionPicker.d.ts.map +1 -1
  265. package/lib/typescript/module/agent-creator/ShapeSilhouette.d.ts.map +1 -1
  266. package/lib/typescript/module/agent-creator/constants.d.ts +15 -7
  267. package/lib/typescript/module/agent-creator/constants.d.ts.map +1 -1
  268. package/lib/typescript/module/agent-creator/messages.d.ts.map +1 -1
  269. package/lib/typescript/module/app-shell/AppShellBars.d.ts +4 -0
  270. package/lib/typescript/module/app-shell/AppShellBars.d.ts.map +1 -1
  271. package/lib/typescript/module/app-shell/AppShellEngine.d.ts.map +1 -1
  272. package/lib/typescript/module/app-shell/types.d.ts +11 -3
  273. package/lib/typescript/module/app-shell/types.d.ts.map +1 -1
  274. package/lib/typescript/module/appearance/BloomScope.d.ts +1 -1
  275. package/lib/typescript/module/appearance/BloomScope.d.ts.map +1 -1
  276. package/lib/typescript/module/appearance/context.d.ts +2 -2
  277. package/lib/typescript/module/appearance/context.d.ts.map +1 -1
  278. package/lib/typescript/module/appearance/types.d.ts +4 -1
  279. package/lib/typescript/module/appearance/types.d.ts.map +1 -1
  280. package/lib/typescript/module/content-panel/ContentPanel.d.ts +3 -4
  281. package/lib/typescript/module/content-panel/ContentPanel.d.ts.map +1 -1
  282. package/lib/typescript/module/content-panel/ContentPanel.web.d.ts +1 -1
  283. package/lib/typescript/module/content-panel/ContentPanel.web.d.ts.map +1 -1
  284. package/lib/typescript/module/content-panel/types.d.ts +2 -2
  285. package/lib/typescript/module/design-tokens/shapes.d.ts +2 -2
  286. package/lib/typescript/module/index.d.ts +1 -0
  287. package/lib/typescript/module/index.d.ts.map +1 -1
  288. package/lib/typescript/module/index.web.d.ts +1 -0
  289. package/lib/typescript/module/index.web.d.ts.map +1 -1
  290. package/lib/typescript/module/mail-thread/MailMessage.d.ts.map +1 -1
  291. package/lib/typescript/module/mail-thread/MailThread.d.ts +1 -1
  292. package/lib/typescript/module/mail-thread/MailThread.d.ts.map +1 -1
  293. package/lib/typescript/module/mail-thread/shared.d.ts +1 -1
  294. package/lib/typescript/module/mail-thread/shared.d.ts.map +1 -1
  295. package/lib/typescript/module/mail-thread/types.d.ts +2 -0
  296. package/lib/typescript/module/mail-thread/types.d.ts.map +1 -1
  297. package/lib/typescript/module/page-footer/PageFooter.d.ts +7 -0
  298. package/lib/typescript/module/page-footer/PageFooter.d.ts.map +1 -0
  299. package/lib/typescript/module/page-footer/PageFooterProvider.d.ts +4 -0
  300. package/lib/typescript/module/page-footer/PageFooterProvider.d.ts.map +1 -0
  301. package/lib/typescript/module/page-footer/context.d.ts +3 -0
  302. package/lib/typescript/module/page-footer/context.d.ts.map +1 -0
  303. package/lib/typescript/module/page-footer/index.d.ts +5 -0
  304. package/lib/typescript/module/page-footer/index.d.ts.map +1 -0
  305. package/lib/typescript/module/page-footer/types.d.ts +26 -0
  306. package/lib/typescript/module/page-footer/types.d.ts.map +1 -0
  307. package/lib/typescript/module/page-footer/use-page-footer-inset.d.ts +7 -0
  308. package/lib/typescript/module/page-footer/use-page-footer-inset.d.ts.map +1 -0
  309. package/lib/typescript/module/sidebar/Sidebar.d.ts.map +1 -1
  310. package/lib/typescript/module/sidebar/types.d.ts +1 -1
  311. package/lib/typescript/module/styles/panel-chrome.d.ts +5 -0
  312. package/lib/typescript/module/styles/panel-chrome.d.ts.map +1 -1
  313. package/package.json +18 -1
  314. package/src/__tests__/support/adoption-matrix.ts +683 -0
  315. package/src/__tests__/support/card-surface.ts +25 -0
  316. package/src/__tests__/support/collision-fixture-barrel.ts +20 -0
  317. package/src/__tests__/support/commerce-harness.tsx +97 -0
  318. package/src/__tests__/support/composite.ts +68 -0
  319. package/src/__tests__/support/constructed-style-sheets.ts +68 -0
  320. package/src/__tests__/support/messages-in.ts +10 -0
  321. package/src/__tests__/support/press-host.ts +30 -0
  322. package/src/__tests__/support/rendered-style.ts +99 -0
  323. package/src/__tests__/support/unread-hook-fixture.ts +33 -0
  324. package/src/__tests__/support/worklet-capture-fixture.tsx +28 -0
  325. package/src/agent-avatar/AgentAvatar.tsx +1 -1
  326. package/src/agent-avatar/CharacterAvatar.tsx +1 -4
  327. package/src/agent-avatar/__tests__/artwork-golden.json +774 -0
  328. package/src/agent-avatar/config-character.ts +6 -39
  329. package/src/agent-avatar/legacy-recipe.ts +6 -34
  330. package/src/agent-creator/AgentCreatorBase.tsx +152 -121
  331. package/src/agent-creator/CharacterControls.tsx +14 -39
  332. package/src/agent-creator/EmotionPicker.tsx +16 -55
  333. package/src/agent-creator/ShapeSilhouette.tsx +1 -16
  334. package/src/agent-creator/__tests__/support/character-runtime-fixture.tsx +26 -0
  335. package/src/agent-creator/constants.ts +14 -47
  336. package/src/agent-creator/messages.ts +1 -2
  337. package/src/app-shell/AppShell.tsx +2 -2
  338. package/src/app-shell/AppShellBars.tsx +6 -4
  339. package/src/app-shell/AppShellEngine.tsx +51 -18
  340. package/src/app-shell/types.ts +11 -3
  341. package/src/appearance/BloomScope.tsx +5 -2
  342. package/src/appearance/context.ts +2 -2
  343. package/src/appearance/types.ts +4 -1
  344. package/src/content-panel/ContentPanel.tsx +32 -25
  345. package/src/content-panel/ContentPanel.web.tsx +32 -23
  346. package/src/content-panel/types.ts +2 -2
  347. package/src/design-tokens/shapes.ts +1 -1
  348. package/src/design-tokens/tokens.json +2 -2
  349. package/src/index.ts +1 -0
  350. package/src/index.web.ts +1 -0
  351. package/src/locale/translations/ar.ts +1 -1
  352. package/src/locale/translations/bn.ts +1 -1
  353. package/src/locale/translations/ca.ts +1 -1
  354. package/src/locale/translations/de.ts +1 -1
  355. package/src/locale/translations/es.ts +1 -1
  356. package/src/locale/translations/fr.ts +1 -1
  357. package/src/locale/translations/hi.ts +1 -1
  358. package/src/locale/translations/id.ts +1 -1
  359. package/src/locale/translations/it.ts +1 -1
  360. package/src/locale/translations/ja.ts +1 -1
  361. package/src/locale/translations/pt.ts +1 -1
  362. package/src/locale/translations/ru.ts +1 -1
  363. package/src/locale/translations/tr.ts +1 -1
  364. package/src/locale/translations/zh.ts +1 -1
  365. package/src/mail-thread/MailMessage.tsx +9 -11
  366. package/src/mail-thread/MailThread.tsx +3 -1
  367. package/src/mail-thread/shared.ts +2 -1
  368. package/src/mail-thread/types.ts +2 -0
  369. package/src/page-footer/PageFooter.tsx +96 -0
  370. package/src/page-footer/PageFooterProvider.tsx +9 -0
  371. package/src/page-footer/context.ts +6 -0
  372. package/src/page-footer/index.ts +4 -0
  373. package/src/page-footer/types.ts +26 -0
  374. package/src/page-footer/use-page-footer-inset.ts +17 -0
  375. package/src/sidebar/Sidebar.tsx +5 -4
  376. package/src/sidebar/types.ts +1 -1
  377. package/src/styles/panel-chrome.ts +9 -1
  378. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +9346 -0
  379. package/src/theme/__tests__/__fixtures__/tonal-glass-primary-failures.json +69 -0
  380. package/src/theme/__tests__/fixtures/color-engine-golden.json +1 -0
  381. package/assets/character-runtime/authored-parts.mjs +0 -754
  382. package/assets/character-runtime/catalog-parts.mjs +0 -362
  383. package/assets/character-runtime/character-recipe.mjs +0 -247
  384. package/assets/character-runtime/clippo-geometry.mjs +0 -679
  385. package/assets/character-runtime/controller-mode.mjs +0 -208
  386. package/assets/character-runtime/cyclops-geometry.mjs +0 -180
  387. package/assets/character-runtime/migrated-contours.mjs +0 -2067
  388. package/assets/character-runtime/migrated-faces.mjs +0 -59
  389. package/assets/character-runtime/pose-transition.mjs +0 -523
  390. package/assets/character-runtime/preparation-cache.mjs +0 -60
  391. package/assets/character-runtime/render-errors.mjs +0 -180
  392. package/assets/character-runtime/resolution.mjs +0 -10
  393. package/assets/character-runtime/sha256.mjs +0 -44
  394. package/assets/character-runtime/shared-programs.mjs +0 -534
  395. package/assets/character-runtime/shared-surface.mjs +0 -490
  396. package/assets/character-runtime/shared-textures.mjs +0 -420
  397. package/assets/character-runtime/thumbnails/eyes/todd.png +0 -0
  398. package/lib/commonjs/agent-avatar/character-colors.js +0 -19
  399. package/lib/commonjs/agent-avatar/character-colors.js.map +0 -1
  400. package/lib/commonjs/agent-avatar/character-shapes.js +0 -106
  401. package/lib/commonjs/agent-avatar/character-shapes.js.map +0 -1
  402. package/lib/commonjs/agent-creator/ClippoArtwork.js +0 -63
  403. package/lib/commonjs/agent-creator/ClippoArtwork.js.map +0 -1
  404. package/lib/commonjs/agent-creator/CyclopsArtwork.js +0 -45
  405. package/lib/commonjs/agent-creator/CyclopsArtwork.js.map +0 -1
  406. package/lib/commonjs/agent-creator/ToddArtwork.js +0 -29
  407. package/lib/commonjs/agent-creator/ToddArtwork.js.map +0 -1
  408. package/lib/module/agent-avatar/character-colors.js +0 -15
  409. package/lib/module/agent-avatar/character-colors.js.map +0 -1
  410. package/lib/module/agent-avatar/character-shapes.js +0 -97
  411. package/lib/module/agent-avatar/character-shapes.js.map +0 -1
  412. package/lib/module/agent-creator/ClippoArtwork.js +0 -59
  413. package/lib/module/agent-creator/ClippoArtwork.js.map +0 -1
  414. package/lib/module/agent-creator/CyclopsArtwork.js +0 -41
  415. package/lib/module/agent-creator/CyclopsArtwork.js.map +0 -1
  416. package/lib/module/agent-creator/ToddArtwork.js +0 -25
  417. package/lib/module/agent-creator/ToddArtwork.js.map +0 -1
  418. package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts +0 -13
  419. package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts.map +0 -1
  420. package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts +0 -19
  421. package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts.map +0 -1
  422. package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts +0 -6
  423. package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts.map +0 -1
  424. package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts +0 -5
  425. package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts.map +0 -1
  426. package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts +0 -6
  427. package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts.map +0 -1
  428. package/lib/typescript/module/agent-avatar/character-colors.d.ts +0 -13
  429. package/lib/typescript/module/agent-avatar/character-colors.d.ts.map +0 -1
  430. package/lib/typescript/module/agent-avatar/character-shapes.d.ts +0 -19
  431. package/lib/typescript/module/agent-avatar/character-shapes.d.ts.map +0 -1
  432. package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts +0 -6
  433. package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts.map +0 -1
  434. package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts +0 -5
  435. package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts.map +0 -1
  436. package/lib/typescript/module/agent-creator/ToddArtwork.d.ts +0 -6
  437. package/lib/typescript/module/agent-creator/ToddArtwork.d.ts.map +0 -1
  438. package/src/agent-avatar/character-colors.ts +0 -12
  439. package/src/agent-avatar/character-shapes.ts +0 -122
  440. package/src/agent-creator/ClippoArtwork.tsx +0 -49
  441. package/src/agent-creator/CyclopsArtwork.tsx +0 -27
  442. package/src/agent-creator/ToddArtwork.tsx +0 -24
@@ -1,25 +1,14 @@
1
1
  /** Catalog parts extend the existing avatar recipe without discarding its shape or expression fields. */
2
- export type AvatarCharacterCategory =
3
- 'shape' | 'color' | 'eyes' | 'eyewear' | 'accessory';
2
+ export type AvatarCharacterCategory = 'shape' | 'color' | 'eyes' | 'eyewear' | 'accessory';
4
3
 
5
4
  export type AvatarCharacterConfig = {
6
- /** Named catalog preset, including Clippo (`clippo`), or a saved renderer ID. */
7
5
  preset: string;
8
- /** Clippo's open wire body and ring eyes are independently selectable with ID `clippo`. */
9
6
  selections?: Partial<Record<AvatarCharacterCategory, string>>;
10
7
  /** Custom body RGB accepted by the original renderer, stored as lowercase #RRGGBB. */
11
8
  bodyColor?: string;
12
- /** @deprecated Retained when reading saved recipes; ignored by the renderer. Each shape owns its eye layout. */
13
- eyeSpacing?: number;
14
9
  };
15
10
 
16
- const categories: readonly AvatarCharacterCategory[] = [
17
- 'shape',
18
- 'color',
19
- 'eyes',
20
- 'eyewear',
21
- 'accessory',
22
- ];
11
+ const categories: readonly AvatarCharacterCategory[] = ['shape', 'color', 'eyes', 'eyewear', 'accessory'];
23
12
  const validId = (value: unknown): value is string =>
24
13
  typeof value === 'string' && value.length > 0 && value.length <= 63;
25
14
 
@@ -30,44 +19,22 @@ export function parseCharacterConfig(value: unknown): AvatarCharacterConfig {
30
19
  const candidate = value as Record<string, unknown>;
31
20
  if (!validId(candidate.preset)) throw new Error('Invalid character preset.');
32
21
  const result: AvatarCharacterConfig = { preset: candidate.preset };
33
- if (candidate.eyeSpacing !== undefined) {
34
- if (
35
- typeof candidate.eyeSpacing !== 'number' ||
36
- !Number.isFinite(candidate.eyeSpacing) ||
37
- candidate.eyeSpacing < 0.5 ||
38
- candidate.eyeSpacing > 1.5
39
- )
40
- throw new Error('Invalid character eye spacing.');
41
- result.eyeSpacing = candidate.eyeSpacing;
42
- }
43
22
  if (candidate.bodyColor !== undefined) {
44
- if (
45
- typeof candidate.bodyColor !== 'string' ||
46
- candidate.bodyColor.length !== 7 ||
47
- !/^#[0-9a-f]{6}$/i.test(candidate.bodyColor)
48
- )
23
+ if (typeof candidate.bodyColor !== 'string' || candidate.bodyColor.length !== 7 || !/^#[0-9a-f]{6}$/i.test(candidate.bodyColor))
49
24
  throw new Error('Invalid character body color.');
50
25
  result.bodyColor = candidate.bodyColor.toLowerCase();
51
26
  }
52
27
  if (candidate.selections !== undefined) {
53
- if (
54
- !candidate.selections ||
55
- typeof candidate.selections !== 'object' ||
56
- Array.isArray(candidate.selections)
57
- )
28
+ if (!candidate.selections || typeof candidate.selections !== 'object' || Array.isArray(candidate.selections))
58
29
  throw new Error('Invalid character selections.');
59
30
  const selections: NonNullable<AvatarCharacterConfig['selections']> = {};
60
31
  for (const [category, id] of Object.entries(candidate.selections)) {
61
- if (
62
- !categories.includes(category as AvatarCharacterCategory) ||
63
- !validId(id)
64
- )
32
+ if (!categories.includes(category as AvatarCharacterCategory) || !validId(id))
65
33
  throw new Error('Invalid character selection.');
66
34
  selections[category as AvatarCharacterCategory] = id;
67
35
  }
68
36
  result.selections = selections;
69
37
  }
70
- if ('state' in candidate)
71
- throw new Error('Opaque character state is not supported.');
38
+ if ('state' in candidate) throw new Error('Opaque character state is not supported.');
72
39
  return result;
73
40
  }
@@ -1,8 +1,3 @@
1
- import { CHARACTER_COLORS } from './character-colors';
2
- import {
3
- characterShapeGeometry,
4
- isMigratedCharacterShape,
5
- } from './character-shapes';
6
1
  import { avatarHex } from './avatar-color';
7
2
  import { legacyContours } from './legacy-contours';
8
3
  import type { AvatarConfig } from './model';
@@ -14,7 +9,6 @@ export type LegacyRecipe = {
14
9
  points?: Point[];
15
10
  shape?: string;
16
11
  eyes: string;
17
- eyeSpacing?: number;
18
12
  selections?: Pick<
19
13
  NonNullable<AvatarCharacterConfig['selections']>,
20
14
  'eyewear' | 'accessory'
@@ -24,8 +18,6 @@ export type LegacyRecipe = {
24
18
 
25
19
  /** Saved unsupported artwork stays readable without pretending it was migrated. */
26
20
  export function legacyRecipeUnsupported(config: AvatarConfig): boolean {
27
- if (isMigratedCharacterShape(config.character?.selections?.shape))
28
- return false;
29
21
  return (
30
22
  config.family === 'alien' || config.family === 'mascot' || !config.face
31
23
  );
@@ -82,8 +74,6 @@ export function radialContour(polygons: Point[][], samples = 256): Point[] {
82
74
 
83
75
  /** Shared capability identity for the editor and the legacy engine adapter. */
84
76
  export function legacyCharacterRecipe(config: AvatarConfig) {
85
- if (config.character && config.character.preset !== 'bloom')
86
- return config.character;
87
77
  const customization =
88
78
  config.character?.preset === 'bloom' ? config.character : undefined;
89
79
  return {
@@ -98,15 +88,7 @@ export function legacyCharacterRecipe(config: AvatarConfig) {
98
88
  ? { accessory: customization.selections.accessory }
99
89
  : {}),
100
90
  },
101
- bodyColor:
102
- customization?.bodyColor ??
103
- CHARACTER_COLORS[
104
- customization?.selections?.color as keyof typeof CHARACTER_COLORS
105
- ] ??
106
- avatarHex(config),
107
- ...(customization?.eyeSpacing !== undefined
108
- ? { eyeSpacing: customization.eyeSpacing }
109
- : {}),
91
+ bodyColor: customization?.bodyColor ?? avatarHex(config),
110
92
  };
111
93
  }
112
94
 
@@ -120,24 +102,14 @@ export function legacyRecipe(
120
102
  ): LegacyRecipe {
121
103
  if (legacyRecipeUnsupported(config))
122
104
  throw new Error('Unsupported legacy 3D recipe');
123
- const geometry = characterShapeGeometry(config);
124
- const canonical = config.character && config.character.preset !== 'bloom';
125
- const selectedShape = canonical
126
- ? config.character?.selections?.shape
127
- : undefined;
128
- const shape = isMigratedCharacterShape(selectedShape)
129
- ? undefined
130
- : (selectedShape ?? legacyNativeShape(geometry));
105
+ const shape = legacyNativeShape(config);
131
106
  const recipe = legacyCharacterRecipe(config);
132
- const { eyewear, accessory } = recipe.selections ?? {};
107
+ const { eyewear, accessory } = recipe.selections;
133
108
  return {
134
109
  ...(shape
135
110
  ? { shape }
136
- : { points: radialContour(legacyContours(geometry), samples) }),
137
- eyes: recipe.selections?.eyes ?? 'oval',
138
- ...(recipe.eyeSpacing !== undefined
139
- ? { eyeSpacing: recipe.eyeSpacing }
140
- : {}),
111
+ : { points: radialContour(legacyContours(config), samples) }),
112
+ eyes: recipe.selections.eyes,
141
113
  ...(eyewear || accessory
142
114
  ? {
143
115
  selections: {
@@ -146,6 +118,6 @@ export function legacyRecipe(
146
118
  },
147
119
  }
148
120
  : {}),
149
- patch: { bodyColor: recipe.bodyColor ?? avatarHex(config) },
121
+ patch: { bodyColor: recipe.bodyColor },
150
122
  };
151
123
  }
@@ -1,19 +1,15 @@
1
- import { useContext, useMemo, useRef, useState } from 'react';
1
+ import { useContext, useMemo, useState } from 'react';
2
2
  import { Platform } from 'react-native';
3
3
  import { AgentAvatar, type AvatarConfig } from '../agent-avatar';
4
- import {
5
- CHARACTER_SHAPES,
6
- NATIVE_CHARACTER_SHAPES,
7
- createConfigForShape,
8
- currentCharacterShape,
9
- materializeCharacter,
10
- } from '../agent-avatar/character-shapes';
11
4
  import type { AvatarCharacterCategory } from '../agent-avatar/config-character';
12
5
  import {
13
6
  CharacterRuntimeContext,
14
7
  CharacterCapabilitiesContext,
15
8
  } from '../agent-avatar/context';
16
- import { legacyCharacterRecipe } from '../agent-avatar/legacy-recipe';
9
+ import {
10
+ legacyCharacterRecipe,
11
+ legacyNativeShape,
12
+ } from '../agent-avatar/legacy-recipe';
17
13
  import { Button } from '../button/Button';
18
14
  import { CloseButton } from '../button/CloseButton';
19
15
  import { useDirectionProps } from '../hooks/use-is-rtl';
@@ -60,86 +56,58 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
60
56
  );
61
57
  const { runtimeUrl } = runtime;
62
58
  const beta = Boolean(c.character && c.character.preset !== 'bloom');
59
+ const nativeShape = legacyNativeShape(c);
63
60
  const key = JSON.stringify(beta ? c.character : legacyCharacterRecipe(c));
64
- const currentCapabilities =
61
+ const capabilities =
65
62
  catalog.capabilitiesByKey?.get(key) ??
66
63
  (catalog.capabilities?.key === key ? catalog.capabilities : undefined);
67
- const retained = useRef<{ owner: string; selected: Record<string, string> }>({
68
- owner: '',
69
- selected: {},
70
- });
71
- const owner = JSON.stringify([agent.id, c.character?.preset ?? 'bloom']);
72
- if (retained.current.owner !== owner)
73
- retained.current = { owner, selected: {} };
74
- if (currentCapabilities)
75
- retained.current.selected = currentCapabilities.selected;
76
- const capabilities = currentCapabilities ?? {
77
- selected: retained.current.selected,
78
- available: {},
79
- };
80
64
  const betaColor =
81
- c.character?.selections?.color ?? capabilities?.selected.color;
82
- const betaBodyColor =
83
- c.character?.bodyColor ??
84
- (c.character?.preset === 'clippo' && !c.character.selections?.color
85
- ? '#999b9d'
86
- : undefined) ??
87
- (!betaColor ? capabilities?.selected.bodyColor : undefined);
65
+ capabilities?.selected.color ?? c.character?.selections?.color;
88
66
  const customColorValue = beta
89
- ? (betaBodyColor ??
90
- (c.character?.selections?.color
91
- ? CHARACTER_COLORS[
92
- c.character.selections.color as keyof typeof CHARACTER_COLORS
93
- ]
94
- : undefined) ??
95
- capabilities?.selected.bodyColor ??
67
+ ? (c.character?.bodyColor ??
96
68
  CHARACTER_COLORS[betaColor as keyof typeof CHARACTER_COLORS] ??
97
69
  avatarHex(c))
98
- : (c.character?.bodyColor ??
99
- CHARACTER_COLORS[
100
- c.character?.selections?.color as keyof typeof CHARACTER_COLORS
101
- ] ??
102
- avatarHex(c));
70
+ : (c.character?.bodyColor ?? avatarHex(c));
103
71
  const selectedEyes =
104
- c.character?.selections?.eyes ??
105
- capabilities?.selected.eyes ??
106
- (c.character?.preset === 'clippo'
107
- ? 'clippo'
108
- : c.character?.preset === 'lime_frog'
109
- ? 'todd'
110
- : 'oval');
111
- const selectedEyewear =
112
- c.character?.selections?.eyewear ?? capabilities?.selected.eyewear;
113
- const selectedAccessory =
114
- c.character?.selections?.accessory ?? capabilities?.selected.accessory;
115
- const selectedParts = {
116
- ...(c.character?.selections?.eyes ||
117
- capabilities.selected.eyes ||
118
- c.character?.preset === 'clippo' ||
119
- c.character?.preset === 'lime_frog'
120
- ? { eyes: selectedEyes }
121
- : {}),
122
- ...(selectedEyewear ? { eyewear: selectedEyewear } : {}),
123
- ...(selectedAccessory ? { accessory: selectedAccessory } : {}),
124
- };
72
+ capabilities?.selected.eyes ?? c.character?.selections?.eyes ?? 'oval';
125
73
  const characterConfig = (
126
74
  category: AvatarCharacterCategory,
127
75
  id: string,
128
76
  ): AvatarConfig => {
129
- if (category === 'shape')
130
- return createConfigForShape(c, id, capabilities.selected);
131
- const character = materializeCharacter(c, capabilities.selected);
132
- // Choosing a body retains the edited face and the preset's effective parts.
133
- // Presets supply defaults; their catalog restrictions do not own edits.
134
- const selections = {
135
- ...selectedParts,
136
- ...character.selections,
137
- [category]: id,
138
- };
139
- const next = {
140
- ...character,
141
- selections,
142
- };
77
+ if (
78
+ !beta &&
79
+ (category === 'eyes' ||
80
+ category === 'eyewear' ||
81
+ category === 'accessory')
82
+ )
83
+ return {
84
+ ...c,
85
+ character: {
86
+ ...c.character,
87
+ preset: 'bloom',
88
+ selections: { ...c.character?.selections, [category]: id },
89
+ },
90
+ };
91
+ const character = beta
92
+ ? c.character!
93
+ : {
94
+ preset: 'blue_beret',
95
+ bodyColor: customColorValue,
96
+ selections: {
97
+ eyewear:
98
+ c.character?.selections?.eyewear ??
99
+ capabilities?.selected.eyewear ??
100
+ 'none',
101
+ accessory:
102
+ c.character?.selections?.accessory ??
103
+ capabilities?.selected.accessory ??
104
+ 'none',
105
+ eyes: selectedEyes,
106
+ },
107
+ };
108
+ const selections = { ...character.selections, [category]: id };
109
+ if (category === 'shape') delete selections.eyes;
110
+ const next = { ...character, selections };
143
111
  if (category === 'color') delete next.bodyColor;
144
112
  return { ...c, character: next };
145
113
  };
@@ -149,37 +117,103 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
149
117
  ? runtimeUrl.slice(0, runtimeUrl.lastIndexOf('/') + 1)
150
118
  : '';
151
119
  const eyeBackground = customColorValue;
120
+ const migratedShapes = [
121
+ ...(['slender', 'pocket', 'petal', 'star', 'cloud', 'shield'] as const).map(
122
+ (shape) => ({
123
+ family: 'fold' as const,
124
+ shape,
125
+ title: messages.shapes[shape],
126
+ }),
127
+ ),
128
+ ...(
129
+ [
130
+ ['pebble', 'Pebble'],
131
+ ['squircle', 'Squircle'],
132
+ ] as const
133
+ ).map(([shape, title]) => ({
134
+ family: 'blob' as const,
135
+ shape,
136
+ title: messages.characterOption('shape', shape, title),
137
+ })),
138
+ ];
139
+ const migratedConfig = (
140
+ family: 'fold' | 'blob',
141
+ shape: string,
142
+ ): AvatarConfig => {
143
+ const { character: _character, ...existing } = c;
144
+ const color = hexAppearance(customColorValue);
145
+ return {
146
+ ...existing,
147
+ ...color,
148
+ lightEyes: beta ? false : c.lightEyes,
149
+ family,
150
+ ...(family === 'fold'
151
+ ? { foldShape: shape as AvatarConfig['foldShape'] }
152
+ : { shape: shape as AvatarConfig['shape'] }),
153
+ ...(runtimeUrl
154
+ ? {
155
+ character: {
156
+ preset: 'bloom',
157
+ selections: {
158
+ eyes: selectedEyes,
159
+ ...((capabilities?.selected.eyewear ??
160
+ c.character?.selections?.eyewear)
161
+ ? {
162
+ eyewear:
163
+ capabilities?.selected.eyewear ??
164
+ c.character?.selections?.eyewear,
165
+ }
166
+ : {}),
167
+ ...((capabilities?.selected.accessory ??
168
+ c.character?.selections?.accessory)
169
+ ? {
170
+ accessory:
171
+ capabilities?.selected.accessory ??
172
+ c.character?.selections?.accessory,
173
+ }
174
+ : {}),
175
+ },
176
+ },
177
+ }
178
+ : {}),
179
+ };
180
+ };
152
181
  const shapeChoices = runtimeUrl
153
- ? CHARACTER_SHAPES.map(([id, title]) => ({
154
- id,
155
- label:
156
- id in messages.shapes
157
- ? messages.shapes[id as keyof typeof messages.shapes]
158
- : messages.characterOption('shape', id, title),
159
- config: createConfigForShape(c, id, capabilities.selected),
160
- ...(NATIVE_CHARACTER_SHAPES.some(([shape]) => shape === id) &&
161
- id !== 'clippo' &&
162
- id !== 'todd'
163
- ? { thumbnail: `${thumbnailBase}thumbnails/shapes/${id}.png` }
164
- : {}),
165
- }))
182
+ ? [
183
+ ...CHARACTER_OPTIONS.shape.map(([id, title]) => ({
184
+ id,
185
+ label: messages.characterOption('shape', id, title),
186
+ config: characterConfig('shape', id),
187
+ thumbnail: `${thumbnailBase}thumbnails/shapes/${id}.png`,
188
+ })),
189
+ ...migratedShapes.map(({ family, shape, title }) => ({
190
+ id: `legacy:${family}:${shape}`,
191
+ label: title,
192
+ config: migratedConfig(family, shape),
193
+ })),
194
+ ]
166
195
  : undefined;
167
- const shapeValue =
168
- c.character?.selections?.shape ??
169
- (beta
170
- ? (capabilities.selected.shape ??
171
- (c.character?.preset === 'clippo' ? 'clippo' : undefined))
172
- : currentCharacterShape(c));
173
- const selectShape = (id: string) => selectCharacter('shape', id);
196
+ const shapeValue = beta
197
+ ? (capabilities?.selected.shape ?? c.character?.selections?.shape)
198
+ : (nativeShape ??
199
+ `legacy:${c.family}:${c.family === 'fold' ? c.foldShape : c.shape}`);
200
+ const selectShape = (id: string) => {
201
+ if (id.startsWith('legacy:')) {
202
+ const [, family, shape] = id.split(':');
203
+ onChange({
204
+ ...agent,
205
+ avatar: migratedConfig(family as 'fold' | 'blob', shape!),
206
+ });
207
+ } else selectCharacter('shape', id);
208
+ };
174
209
  const eyeChoices = runtimeUrl
175
210
  ? CHARACTER_OPTIONS.eyes.map(([id, title]) => ({
176
211
  id,
177
212
  label: messages.characterOption('eyes', id, title),
178
213
  config: characterConfig('eyes', id),
179
- ...(id === 'clippo' || id === 'cyclops'
180
- ? { artwork: id }
181
- : { thumbnail: `${thumbnailBase}thumbnails/eyes/${id}.png` }),
182
- disabled: false,
214
+ thumbnail: `${thumbnailBase}thumbnails/eyes/${id}.png`,
215
+ disabled:
216
+ !capabilities || capabilities.available[`eyes:${id}`] === false,
183
217
  }))
184
218
  : undefined;
185
219
  const appearance = (patch: Partial<AvatarConfig>) => {
@@ -333,15 +367,8 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
333
367
  </StyledView>
334
368
  )}
335
369
  <CharacterControls
336
- character={
337
- runtimeUrl
338
- ? beta
339
- ? c.character
340
- : materializeCharacter(c, capabilities.selected)
341
- : c.character
342
- }
370
+ character={c.character ?? { preset: 'bloom' }}
343
371
  capabilitiesKey={key}
344
- selected={capabilities.selected}
345
372
  onChange={(character) => {
346
373
  if (character)
347
374
  onChange({ ...agent, avatar: { ...c, character } });
@@ -359,7 +386,7 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
359
386
  boxShadow: '0 1px 2px rgba(0,0,0,.05)',
360
387
  }}
361
388
  >
362
- {!runtimeUrl &&
389
+ {!beta &&
363
390
  AVATAR_COLORS.map(([hue, saturation, name, center, edge]) => {
364
391
  const active =
365
392
  c.hue === hue &&
@@ -388,11 +415,15 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
388
415
  </StyledPressable>
389
416
  );
390
417
  })}
391
- {runtimeUrl &&
418
+ {beta &&
392
419
  CHARACTER_OPTIONS.color.map(([id, title]) => {
393
- const active = !betaBodyColor && betaColor === id;
420
+ const active =
421
+ !c.character?.bodyColor &&
422
+ capabilities?.selected.color === id;
394
423
  const hex = CHARACTER_COLORS[id];
395
- const disabled = false;
424
+ const disabled =
425
+ !capabilities ||
426
+ capabilities.available[`color:${id}`] === false;
396
427
  return (
397
428
  <StyledPressable
398
429
  key={id}
@@ -415,18 +446,18 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
415
446
  <PopoverTrigger asChild label={messages.customColor}>
416
447
  <StyledPressable
417
448
  aria-pressed={
418
- runtimeUrl ? Boolean(betaBodyColor) : undefined
449
+ beta ? Boolean(c.character?.bodyColor) : undefined
419
450
  }
420
451
  accessibilityState={{
421
- selected: Boolean(runtimeUrl) && Boolean(betaBodyColor),
452
+ selected: beta && Boolean(c.character?.bodyColor),
422
453
  }}
423
454
  className="relative size-[26px] shrink-0 overflow-hidden rounded-full"
424
455
  >
425
456
  <GlossArt
426
- rainbow={!runtimeUrl || !betaBodyColor}
427
- center={runtimeUrl ? betaBodyColor : undefined}
428
- edge={runtimeUrl ? betaBodyColor : undefined}
429
- active={Boolean(runtimeUrl) && Boolean(betaBodyColor)}
457
+ rainbow={!beta || !c.character?.bodyColor}
458
+ center={beta ? c.character?.bodyColor : undefined}
459
+ edge={beta ? c.character?.bodyColor : undefined}
460
+ active={beta && Boolean(c.character?.bodyColor)}
430
461
  />
431
462
  </StyledPressable>
432
463
  </PopoverTrigger>
@@ -442,14 +473,14 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
442
473
  onChange={(hex) => {
443
474
  const next = hexAppearance(hex);
444
475
  if (!next) return;
445
- if (runtimeUrl)
476
+ if (beta)
446
477
  onChange({
447
478
  ...agent,
448
479
  avatar: {
449
480
  ...c,
450
481
  ...next,
451
482
  character: {
452
- ...materializeCharacter(c, capabilities.selected),
483
+ ...c.character!,
453
484
  bodyColor: hex.toLowerCase(),
454
485
  },
455
486
  },
@@ -1,4 +1,4 @@
1
- import { useContext, useRef } from 'react';
1
+ import { useContext } from 'react';
2
2
  import {
3
3
  CharacterRuntimeContext,
4
4
  CharacterCapabilitiesContext,
@@ -16,12 +16,10 @@ import { useAgentCreatorBindings, useAgentCreatorMessages } from './context';
16
16
  export function CharacterControls({
17
17
  character,
18
18
  capabilitiesKey,
19
- selected,
20
19
  onChange,
21
20
  }: {
22
21
  character?: AvatarCharacterConfig;
23
22
  capabilitiesKey?: string;
24
- selected?: Readonly<Record<string, string>>;
25
23
  onChange: (character: AvatarCharacterConfig | undefined) => void;
26
24
  }) {
27
25
  const messages = useAgentCreatorMessages();
@@ -38,21 +36,11 @@ export function CharacterControls({
38
36
  SelectItem,
39
37
  SelectItemText,
40
38
  } = useAgentCreatorBindings();
39
+ if (!runtimeUrl) return null;
41
40
  const key = capabilitiesKey ?? JSON.stringify(character);
42
- const current =
41
+ const resolved =
43
42
  capabilitiesByKey?.get(key) ??
44
43
  (character && capabilities?.key === key ? capabilities : undefined);
45
- const retained = useRef<{
46
- preset?: string;
47
- selected: Readonly<Record<string, string>>;
48
- }>({ selected: {} });
49
- if (retained.current.preset !== character?.preset)
50
- retained.current = { preset: character?.preset, selected: {} };
51
- if (current) retained.current.selected = current.selected;
52
- const resolved = {
53
- selected: selected ?? current?.selected ?? retained.current.selected,
54
- };
55
- if (!runtimeUrl) return null;
56
44
  const row = (
57
45
  label: string,
58
46
  value: string,
@@ -102,14 +90,11 @@ export function CharacterControls({
102
90
  if (character && !presets.some((item) => item.id === character.preset))
103
91
  presets.push({
104
92
  id: character.preset,
105
- title:
106
- character.preset === 'legacy'
107
- ? messages.proceduralAvatar
108
- : messages.characterOption(
109
- 'preset',
110
- character.preset,
111
- character.preset,
112
- ),
93
+ title: messages.characterOption(
94
+ 'preset',
95
+ character.preset,
96
+ character.preset,
97
+ ),
113
98
  });
114
99
  const labels: Record<AvatarCharacterCategory, string> = {
115
100
  shape: messages.shape,
@@ -135,8 +120,8 @@ export function CharacterControls({
135
120
  (category) =>
136
121
  row(
137
122
  labels[category],
138
- character.selections?.[category] ??
139
- resolved?.selected[category] ??
123
+ resolved?.selected[category] ??
124
+ character.selections?.[category] ??
140
125
  'none',
141
126
  (category === 'accessory'
142
127
  ? [
@@ -147,24 +132,14 @@ export function CharacterControls({
147
132
  ).map(([id, title]) => ({
148
133
  id,
149
134
  title: messages.characterOption(category, id, title),
150
- disabled: false,
135
+ disabled:
136
+ !resolved ||
137
+ resolved.available[`${category}:${id}`] === false,
151
138
  })),
152
139
  (id) => {
153
140
  onChange({
154
141
  ...character,
155
- selections: {
156
- ...(['eyes', 'eyewear', 'accessory'] as const).reduce(
157
- (parts, part) => ({
158
- ...parts,
159
- ...(resolved?.selected[part]
160
- ? { [part]: resolved.selected[part] }
161
- : {}),
162
- }),
163
- {},
164
- ),
165
- ...character.selections,
166
- [category]: id,
167
- },
142
+ selections: { ...character.selections, [category]: id },
168
143
  });
169
144
  },
170
145
  labels[category],