@kitn.ai/ui 0.20.1 → 0.21.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 (500) hide show
  1. package/README.md +44 -45
  2. package/dist/components/artifact-card.d.ts +51 -0
  3. package/dist/components/artifact.d.ts +1 -1
  4. package/dist/components/attachments.d.ts +2 -2
  5. package/dist/components/audio-visualizer/index.d.ts +3 -3
  6. package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
  7. package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
  8. package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
  9. package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
  10. package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
  11. package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
  12. package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
  13. package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
  14. package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
  15. package/dist/components/card-fallback.d.ts +12 -2
  16. package/dist/components/card-renderer.d.ts +63 -2
  17. package/dist/components/chat-container.d.ts +3 -0
  18. package/dist/components/chat-scope-picker.d.ts +2 -2
  19. package/dist/components/chat-thread.d.ts +68 -18
  20. package/dist/components/choice-card.d.ts +3 -28
  21. package/dist/components/composer-dom.d.ts +1 -1
  22. package/dist/components/composer-highlight.d.ts +1 -1
  23. package/dist/components/composer-history.d.ts +1 -1
  24. package/dist/components/composer.d.ts +1 -1
  25. package/dist/components/confirm-card.d.ts +3 -18
  26. package/dist/components/context.d.ts +8 -4
  27. package/dist/components/conversation-item.d.ts +1 -1
  28. package/dist/components/conversation-list.d.ts +4 -3
  29. package/dist/components/embed.d.ts +3 -3
  30. package/dist/components/file-tree.d.ts +11 -22
  31. package/dist/components/form-widgets.d.ts +1 -1
  32. package/dist/components/form.d.ts +3 -44
  33. package/dist/components/link-preview.d.ts +3 -3
  34. package/dist/components/loader.d.ts +30 -48
  35. package/dist/components/message-skills.d.ts +4 -0
  36. package/dist/components/message.d.ts +84 -21
  37. package/dist/components/model-switcher.d.ts +2 -2
  38. package/dist/components/prompt-input.d.ts +2 -2
  39. package/dist/components/response-compare-types.d.ts +11 -2
  40. package/dist/components/response-compare.d.ts +3 -3
  41. package/dist/components/source.d.ts +12 -3
  42. package/dist/components/tasks-card.d.ts +3 -31
  43. package/dist/components/thread.d.ts +17 -5
  44. package/dist/components/toast.d.ts +2 -2
  45. package/dist/components/tool-classify.d.ts +8 -0
  46. package/dist/components/tool-types.d.ts +29 -1
  47. package/dist/components/tool.d.ts +3 -3
  48. package/dist/components/use-card-resolution.d.ts +1 -1
  49. package/dist/create-tween-D3Y5qiij.js +338 -0
  50. package/dist/create-tween-DGKY1FDY.js +341 -0
  51. package/dist/create-tween-paho5Rh-.js +7 -0
  52. package/dist/custom-elements.json +1681 -454
  53. package/dist/elements/agent-card.js +1 -1
  54. package/dist/elements/artifact.js +1 -1
  55. package/dist/elements/attachments.js +1 -1
  56. package/dist/elements/audio-visualizer.js +1 -1
  57. package/dist/elements/avatar.js +1 -1
  58. package/dist/elements/badge.js +1 -1
  59. package/dist/elements/button.js +1 -1
  60. package/dist/elements/card.js +1 -1
  61. package/dist/elements/cards.js +1 -1
  62. package/dist/elements/chain-of-thought.js +1 -1
  63. package/dist/elements/chat-scope-picker.js +1 -1
  64. package/dist/elements/chat-types.d.ts +70 -10
  65. package/dist/elements/chat-workspace.js +1 -1
  66. package/dist/elements/chat.js +1 -1
  67. package/dist/elements/checkpoint.js +1 -1
  68. package/dist/elements/choice.js +1 -1
  69. package/dist/elements/chunks/{Icon-Tj58ES_d.js → Icon-C-2LvGDG.js} +1 -1
  70. package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-CaYoImEk.js} +1 -1
  71. package/dist/elements/chunks/arrow-left-Bb46H7w9.js +1 -0
  72. package/dist/elements/chunks/artifact-BBIscOxJ.js +1 -0
  73. package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-BB56zoji.js} +1 -1
  74. package/dist/elements/chunks/audio-visualizer-BxOx4THz.js +1 -0
  75. package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-SxLSZ19R.js} +1 -1
  76. package/dist/elements/chunks/{button-ZWNif3--.js → button-CmkUkz6c.js} +1 -1
  77. package/dist/elements/chunks/card-renderer-Db4ffkWv.js +1 -0
  78. package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
  79. package/dist/elements/chunks/chat-thread-B3Ks-cKr.js +1 -0
  80. package/dist/elements/chunks/check-C8desc_h.js +1 -0
  81. package/dist/elements/chunks/chevron-down-DKtc2HNB.js +1 -0
  82. package/dist/elements/chunks/chevron-right-Dw4GPhwL.js +1 -0
  83. package/dist/elements/chunks/choice-card-Q9cYYDyM.js +1 -0
  84. package/dist/elements/chunks/circle-BeokBsvB.js +1 -0
  85. package/dist/elements/chunks/circle-check-wJSqt859.js +1 -0
  86. package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-D0MEfxOM.js} +1 -1
  87. package/dist/elements/chunks/code-block-C8VzAraE.js +1 -0
  88. package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-Cvj61obE.js} +1 -1
  89. package/dist/elements/chunks/{composer-BguS0QL_.js → composer-D86ztyL0.js} +2 -2
  90. package/dist/elements/chunks/confirm-card-BdyDAGLw.js +1 -0
  91. package/dist/elements/chunks/context-WHDl-xSx.js +1 -0
  92. package/dist/elements/chunks/conversation-list-CdR14_Y4.js +1 -0
  93. package/dist/elements/chunks/create-tween-C_A_B638.js +7 -0
  94. package/dist/elements/chunks/{default-input-Cqqilg9t.js → default-input-CSZqUM81.js} +1 -1
  95. package/dist/elements/chunks/define-BzPnNsXg.js +1 -0
  96. package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DVKsoc1F.js} +1 -1
  97. package/dist/elements/chunks/{download-Dsbg3ste.js → download-BjA54IMJ.js} +1 -1
  98. package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-BjVVHWXH.js} +1 -1
  99. package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BNedmqfi.js} +1 -1
  100. package/dist/elements/chunks/embed-DQsl4XEq.js +1 -0
  101. package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-Di-dw2CU.js} +1 -1
  102. package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-B3sAODCV.js} +1 -1
  103. package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-Dgto-bMn.js} +1 -1
  104. package/dist/elements/chunks/{folder-glP5rha4.js → folder-D6rMadFV.js} +1 -1
  105. package/dist/elements/chunks/form-CILxvhQ7.js +1 -0
  106. package/dist/elements/chunks/hover-card-BtiF4XiU.js +1 -0
  107. package/dist/elements/chunks/{icon-BLb8beoi.js → icon-DKkmze3y.js} +1 -1
  108. package/dist/elements/chunks/{info-CIsv92JK.js → info-CWRjZkuy.js} +1 -1
  109. package/dist/elements/chunks/{input-Dds1kFyt.js → input--QJBK6BA.js} +1 -1
  110. package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-C3zuKh8R.js} +1 -1
  111. package/dist/elements/chunks/{link-i4r_k7z4.js → link-BL5JA7Q0.js} +1 -1
  112. package/dist/elements/chunks/link-preview-CU37bbXh.js +1 -0
  113. package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-XmpyxyRH.js} +1 -1
  114. package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-3Gv5UZ_o.js} +1 -1
  115. package/dist/elements/chunks/message-CnBA2OUt.js +1 -0
  116. package/dist/elements/chunks/message-X5NZbq-W.js +1 -0
  117. package/dist/elements/chunks/message-square-CnpAm_P0.js +1 -0
  118. package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-DwyrUTcM.js} +1 -1
  119. package/dist/elements/chunks/{model-switcher-B94YAKsM.js → model-switcher-CclaJEHt.js} +1 -1
  120. package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-Cepd-KcS.js} +1 -1
  121. package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CdwKjrlu.js} +1 -1
  122. package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-DMVXBD3b.js} +1 -1
  123. package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-Di_WZE_5.js} +1 -1
  124. package/dist/elements/chunks/reasoning-D0jMch5u.js +1 -0
  125. package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-1znbL1Gv.js} +1 -1
  126. package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-DVhhgx8n.js} +1 -1
  127. package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-Bs4bFS1P.js} +1 -1
  128. package/dist/elements/chunks/scroll-button-Bet5NLc4.js +1 -0
  129. package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-C5Gh8qGC.js} +1 -1
  130. package/dist/elements/chunks/{settings-B8lmec4D.js → settings-5vmEFg0K.js} +1 -1
  131. package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-BWLB38kz.js} +1 -1
  132. package/dist/elements/chunks/{share-C3lTiYGt.js → share-BZ3G_DaB.js} +1 -1
  133. package/dist/elements/chunks/skeleton-DafPJQTp.js +1 -0
  134. package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
  135. package/dist/elements/chunks/source-D_qj_6uJ.js +1 -0
  136. package/dist/elements/chunks/{star-CSJtGxgv.js → star-Cuv7j2IE.js} +1 -1
  137. package/dist/elements/chunks/{store-CHyW95TP.js → store-C1StPHfW.js} +1 -1
  138. package/dist/elements/chunks/tasks-card-EyoBZfpA.js +1 -0
  139. package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D9gRSh34.js} +1 -1
  140. package/dist/elements/chunks/textarea-DuhtHfcm.js +1 -0
  141. package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-B9hwv43w.js} +1 -1
  142. package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-Bm3DUEDe.js} +1 -1
  143. package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-CDtW7L0z.js} +1 -1
  144. package/dist/elements/chunks/tooltip-eB226mGK.js +1 -0
  145. package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C1SNzTqK.js} +1 -1
  146. package/dist/elements/chunks/use-card-resolution-YZh2MvI5.js +1 -0
  147. package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Cj1F7D0l.js} +2 -2
  148. package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-T9gpt7QE.js} +1 -1
  149. package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-CxU9z-TE.js} +2 -2
  150. package/dist/elements/chunks/{video-B7vmenoC.js → video-CK4R7Rus.js} +1 -1
  151. package/dist/elements/chunks/x-D1qx0aLd.js +1 -0
  152. package/dist/elements/coachmark.js +1 -1
  153. package/dist/elements/code-block.js +1 -1
  154. package/dist/elements/command.js +1 -1
  155. package/dist/elements/compare.js +1 -1
  156. package/dist/elements/composer.js +1 -1
  157. package/dist/elements/confirm-card.js +1 -1
  158. package/dist/elements/context-meter.js +1 -1
  159. package/dist/elements/conversation-list.js +1 -1
  160. package/dist/elements/default-input.d.ts +7 -7
  161. package/dist/elements/define.d.ts +1 -0
  162. package/dist/elements/dialog.js +1 -1
  163. package/dist/elements/disclosure.d.ts +1 -1
  164. package/dist/elements/editable-label.js +1 -1
  165. package/dist/elements/element-data-types.d.ts +107 -0
  166. package/dist/elements/embed.js +1 -1
  167. package/dist/elements/empty.js +1 -1
  168. package/dist/elements/feedback-bar.js +1 -1
  169. package/dist/elements/file-tree.js +1 -1
  170. package/dist/elements/file-upload.js +1 -1
  171. package/dist/elements/form.js +1 -1
  172. package/dist/elements/hover-card.js +1 -1
  173. package/dist/elements/icon.js +1 -1
  174. package/dist/elements/image.js +1 -1
  175. package/dist/elements/input.js +1 -1
  176. package/dist/elements/kbd.js +1 -1
  177. package/dist/elements/link-preview.js +1 -1
  178. package/dist/elements/loader.js +1 -1
  179. package/dist/elements/markdown.js +1 -1
  180. package/dist/elements/menu.js +1 -1
  181. package/dist/elements/message-skills.js +1 -1
  182. package/dist/elements/message.js +1 -1
  183. package/dist/elements/model-switcher.js +1 -1
  184. package/dist/elements/nav.js +1 -1
  185. package/dist/elements/notice.js +1 -1
  186. package/dist/elements/pane-group.js +1 -1
  187. package/dist/elements/pane.js +1 -1
  188. package/dist/elements/popover.js +1 -1
  189. package/dist/elements/progress-bar.js +1 -1
  190. package/dist/elements/prompt-dock.js +1 -1
  191. package/dist/elements/prompt-input.js +1 -1
  192. package/dist/elements/prompt-suggestions.js +1 -1
  193. package/dist/elements/reasoning.js +1 -1
  194. package/dist/elements/register.d.ts +8 -6
  195. package/dist/elements/remote.js +1 -1
  196. package/dist/elements/resizable.js +1 -1
  197. package/dist/elements/response-stream.js +2 -2
  198. package/dist/elements/screen.js +1 -1
  199. package/dist/elements/scroll-area.js +1 -1
  200. package/dist/elements/scroll-button.js +1 -1
  201. package/dist/elements/search.js +1 -1
  202. package/dist/elements/segmented.js +1 -1
  203. package/dist/elements/separator.js +1 -1
  204. package/dist/elements/setting-item.js +1 -1
  205. package/dist/elements/settings-group.js +1 -1
  206. package/dist/elements/skeleton.js +1 -1
  207. package/dist/elements/slots.d.ts +16 -0
  208. package/dist/elements/source.js +1 -1
  209. package/dist/elements/status.js +1 -1
  210. package/dist/elements/switch.js +1 -1
  211. package/dist/elements/tabs.js +1 -1
  212. package/dist/elements/tasks.js +1 -1
  213. package/dist/elements/text-shimmer.js +1 -1
  214. package/dist/elements/thinking-bar.js +1 -1
  215. package/dist/elements/thread.js +1 -1
  216. package/dist/elements/toast.js +1 -1
  217. package/dist/elements/tool.js +1 -1
  218. package/dist/elements/tooltip.js +1 -1
  219. package/dist/elements/validate-messages.d.ts +25 -0
  220. package/dist/elements/voice-input.js +1 -1
  221. package/dist/elements/voice-output.js +1 -1
  222. package/dist/elements.d.ts +2725 -214
  223. package/dist/index.d.ts +163 -125
  224. package/dist/index.js +6336 -5802
  225. package/dist/index.server.d.ts +5 -0
  226. package/dist/index.server.js +5446 -4937
  227. package/dist/kai-provider.es.d.ts +5 -0
  228. package/dist/kai-provider.es.js +79 -77
  229. package/dist/kai.es.d.ts +5 -0
  230. package/dist/kai.es.js +1 -1
  231. package/dist/llms/llms-full.txt +762 -148
  232. package/dist/llms/llms.txt +57 -5
  233. package/dist/mcp.es.js +4010 -770
  234. package/dist/primitives/card-component-types.d.ts +11 -0
  235. package/dist/primitives/card-data-types.d.ts +196 -0
  236. package/dist/primitives/card-host.d.ts +1 -1
  237. package/dist/primitives/card-recovery.d.ts +3 -3
  238. package/dist/primitives/card-registry.d.ts +4 -14
  239. package/dist/primitives/card-resolution.d.ts +1 -1
  240. package/dist/primitives/card-routing.d.ts +1 -1
  241. package/dist/primitives/card-tags.d.ts +11 -0
  242. package/dist/primitives/card-validate-cards.d.ts +57 -0
  243. package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
  244. package/dist/primitives/card-validate-schemas.d.ts +17 -0
  245. package/dist/primitives/card-validate.d.ts +24 -0
  246. package/dist/primitives/create-kai-chat.d.ts +3 -3
  247. package/dist/primitives/embed-providers.d.ts +1 -1
  248. package/dist/primitives/link-preview.d.ts +1 -1
  249. package/dist/primitives/message-feedback.d.ts +2 -2
  250. package/dist/primitives/toast-store.d.ts +1 -1
  251. package/dist/react/index.d.ts +717 -299
  252. package/dist/react/use-kai-chat.d.ts +8 -4
  253. package/dist/react.d.ts +5 -0
  254. package/dist/react.js +417 -316
  255. package/dist/register-impl-bzrZ44ft.js +145 -0
  256. package/dist/remote/host-embed.d.ts +1 -1
  257. package/dist/remote/index.d.ts +2 -2
  258. package/dist/remote/provider-runtime.d.ts +2 -2
  259. package/dist/remote/provider.d.ts +2 -2
  260. package/dist/remote/validate.d.ts +1 -1
  261. package/dist/remote/wire.d.ts +1 -1
  262. package/dist/schemas/artifact.schema.json +92 -0
  263. package/dist/schemas/embed.schema.json +0 -2
  264. package/dist/schemas/from-tool-call.d.ts +48 -0
  265. package/dist/schemas/index.d.ts +48 -0
  266. package/dist/schemas/link.schema.json +0 -2
  267. package/dist/schemas/provider-subsets.d.ts +136 -0
  268. package/dist/schemas/registry.d.ts +140 -0
  269. package/dist/schemas/tool-defs.d.ts +121 -0
  270. package/dist/schemas.d.ts +5 -0
  271. package/dist/schemas.js +717 -0
  272. package/dist/solid-BCJUQqwS.js +22750 -0
  273. package/dist/solid-BdENBcEq.js +20108 -0
  274. package/dist/solid.d.ts +66 -0
  275. package/dist/solid.js +261 -0
  276. package/dist/solid.server.d.ts +5 -0
  277. package/dist/solid.server.js +261 -0
  278. package/dist/state/index.d.ts +14 -4
  279. package/dist/state/messages.d.ts +8 -3
  280. package/dist/state/mock.d.ts +46 -0
  281. package/dist/state/parts.d.ts +85 -0
  282. package/dist/state/stream.d.ts +15 -9
  283. package/dist/state.d.ts +5 -0
  284. package/dist/state.js +253 -84
  285. package/dist/ui/action-icons.d.ts +1 -1
  286. package/dist/ui/collapsible.d.ts +11 -6
  287. package/dist/ui/dropdown.d.ts +47 -42
  288. package/dist/ui/pane-group.d.ts +1 -1
  289. package/dist/variant-aurora-1wMcXRUS.js +381 -0
  290. package/dist/variant-aurora-BKHHiOgL.js +391 -0
  291. package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-DOb_o4pC.js} +1 -1
  292. package/dist/{variant-custom-Dif-IV4u.js → variant-custom-CJGB0Kbw.js} +1 -1
  293. package/dist/variant-custom-Co0CkXJF.js +200 -0
  294. package/dist/variant-custom-DWSSgmd2.js +170 -0
  295. package/dist/variant-wave-C3-45cL6.js +218 -0
  296. package/dist/{variant-wave-DbfNdvSi.js → variant-wave-CEODq-9q.js} +1 -1
  297. package/dist/variant-wave-jdXBnCUZ.js +208 -0
  298. package/dist/wire/chunk.d.ts +171 -0
  299. package/dist/wire/consume.d.ts +26 -0
  300. package/dist/wire/encode.d.ts +148 -0
  301. package/dist/wire/formats/anthropic.d.ts +2 -0
  302. package/dist/wire/formats/openai.d.ts +5 -0
  303. package/dist/wire/index.d.ts +14 -0
  304. package/dist/wire/read.d.ts +26 -0
  305. package/dist/wire/sink-helpers.d.ts +21 -0
  306. package/dist/wire/sse.d.ts +33 -0
  307. package/dist/wire.d.ts +5 -53
  308. package/dist/wire.js +898 -0
  309. package/frameworks/react/index.tsx +183 -154
  310. package/frameworks/react/runtime.tsx +21 -1
  311. package/frameworks/react/use-kai-chat.tsx +11 -1
  312. package/llms-full.txt +762 -148
  313. package/llms.txt +57 -5
  314. package/package.json +61 -8
  315. package/src/agent-tooling/archetypes.ts +96 -0
  316. package/src/agent-tooling/integrations/anthropic.ts +412 -0
  317. package/src/agent-tooling/integrations/cloudflare.ts +136 -52
  318. package/src/agent-tooling/integrations/langgraph.ts +67 -13
  319. package/src/agent-tooling/integrations/mastra.ts +120 -12
  320. package/src/agent-tooling/integrations/mock.ts +43 -8
  321. package/src/agent-tooling/integrations/ollama.ts +61 -24
  322. package/src/agent-tooling/integrations/openai.ts +87 -0
  323. package/src/agent-tooling/integrations/openrouter.ts +56 -8
  324. package/src/agent-tooling/integrations/pi.ts +79 -23
  325. package/src/agent-tooling/integrations/pydantic-ai.ts +24 -2
  326. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +84 -13
  327. package/src/agent-tooling/mcp/manifest.ts +206 -25
  328. package/src/agent-tooling/mcp/tools/debug.ts +13 -7
  329. package/src/agent-tooling/mcp/tools/reference.ts +285 -6
  330. package/src/agent-tooling/mcp/tools/scaffold.ts +3345 -675
  331. package/src/agent-tooling/registry.ts +17 -0
  332. package/src/agent-tooling/types.ts +229 -1
  333. package/src/components/artifact-card.tsx +120 -0
  334. package/src/components/audio-visualizer/index.tsx +9 -0
  335. package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
  336. package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
  337. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
  338. package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
  339. package/src/components/card-fallback.tsx +42 -10
  340. package/src/components/card-renderer.tsx +146 -9
  341. package/src/components/chat-container.tsx +4 -0
  342. package/src/components/chat-thread.tsx +118 -51
  343. package/src/components/choice-card.tsx +17 -29
  344. package/src/components/composer.tsx +12 -2
  345. package/src/components/confirm-card.tsx +24 -20
  346. package/src/components/context.tsx +12 -4
  347. package/src/components/conversation-list.tsx +18 -2
  348. package/src/components/file-tree.tsx +11 -22
  349. package/src/components/file-upload.tsx +14 -8
  350. package/src/components/form.tsx +14 -47
  351. package/src/components/loader.tsx +39 -12
  352. package/src/components/message-skills.tsx +4 -0
  353. package/src/components/message.tsx +294 -46
  354. package/src/components/reasoning.tsx +92 -5
  355. package/src/components/response-compare-types.ts +25 -0
  356. package/src/components/response-compare.tsx +4 -9
  357. package/src/components/source.tsx +50 -24
  358. package/src/components/tasks-card.tsx +10 -33
  359. package/src/components/thread.tsx +84 -42
  360. package/src/components/toast.tsx +11 -5
  361. package/src/components/tool-classify.ts +26 -0
  362. package/src/components/tool-types.ts +31 -1
  363. package/src/elements/agent-card.tsx +11 -11
  364. package/src/elements/artifact.tsx +15 -7
  365. package/src/elements/attachments.tsx +6 -4
  366. package/src/elements/avatar.tsx +1 -1
  367. package/src/elements/button.tsx +3 -3
  368. package/src/elements/card.tsx +2 -2
  369. package/src/elements/cards.tsx +109 -14
  370. package/src/elements/chain-of-thought.tsx +14 -10
  371. package/src/elements/chat-scope-picker.tsx +9 -7
  372. package/src/elements/chat-types.ts +59 -6
  373. package/src/elements/chat-workspace.tsx +50 -9
  374. package/src/elements/chat.tsx +64 -3
  375. package/src/elements/choice.tsx +8 -8
  376. package/src/elements/coachmark.tsx +1 -1
  377. package/src/elements/command.tsx +8 -23
  378. package/src/elements/compare.tsx +7 -6
  379. package/src/elements/compiled.css +1 -1
  380. package/src/elements/composer.tsx +8 -8
  381. package/src/elements/confirm-card.tsx +9 -9
  382. package/src/elements/context-meter.tsx +4 -18
  383. package/src/elements/conversation-list.tsx +14 -9
  384. package/src/elements/default-input.tsx +3 -3
  385. package/src/elements/define.tsx +178 -43
  386. package/src/elements/editable-label.tsx +17 -2
  387. package/src/elements/element-data-types.ts +112 -0
  388. package/src/elements/element-meta.json +1596 -304
  389. package/src/elements/element-types.d.ts +2636 -211
  390. package/src/elements/feedback-bar.tsx +1 -1
  391. package/src/elements/file-tree.tsx +1 -1
  392. package/src/elements/file-upload.tsx +1 -1
  393. package/src/elements/form.tsx +14 -6
  394. package/src/elements/input.tsx +1 -1
  395. package/src/elements/kbd.tsx +1 -1
  396. package/src/elements/menu.tsx +10 -29
  397. package/src/elements/message-skills.tsx +7 -9
  398. package/src/elements/message.tsx +200 -32
  399. package/src/elements/model-switcher.tsx +5 -3
  400. package/src/elements/pane.tsx +1 -1
  401. package/src/elements/prompt-dock.tsx +8 -8
  402. package/src/elements/prompt-input.tsx +10 -10
  403. package/src/elements/prompt-suggestions.tsx +7 -4
  404. package/src/elements/reasoning.tsx +1 -1
  405. package/src/elements/register.ts +9 -0
  406. package/src/elements/resizable.globals.d.ts +36 -0
  407. package/src/elements/resizable.tsx +24 -13
  408. package/src/elements/response-stream.tsx +1 -1
  409. package/src/elements/scroll-button.tsx +1 -1
  410. package/src/elements/search.tsx +6 -1
  411. package/src/elements/segmented.tsx +5 -11
  412. package/src/elements/separator.tsx +1 -1
  413. package/src/elements/slots.ts +57 -24
  414. package/src/elements/source.tsx +21 -22
  415. package/src/elements/switch.tsx +3 -3
  416. package/src/elements/tasks.tsx +5 -4
  417. package/src/elements/thread.tsx +36 -4
  418. package/src/elements/toast.tsx +3 -2
  419. package/src/elements/tool.tsx +1 -1
  420. package/src/elements/validate-messages.ts +76 -0
  421. package/src/elements/voice-input.tsx +7 -7
  422. package/src/elements/voice-output.tsx +4 -4
  423. package/src/index.ts +141 -6
  424. package/src/primitives/card-component-types.ts +63 -0
  425. package/src/primitives/card-data-types.ts +312 -0
  426. package/src/primitives/card-recovery.ts +13 -2
  427. package/src/primitives/card-registry.tsx +34 -23
  428. package/src/primitives/card-schemas/artifact.schema.json +92 -0
  429. package/src/primitives/card-schemas/embed.schema.json +0 -2
  430. package/src/primitives/card-schemas/link.schema.json +0 -2
  431. package/src/primitives/card-tags.ts +61 -0
  432. package/src/primitives/card-validate-cards.ts +255 -0
  433. package/src/primitives/card-validate-generator.testlib.ts +38 -0
  434. package/src/primitives/card-validate-schemas.ts +58 -0
  435. package/src/primitives/card-validate.ts +48 -20
  436. package/src/primitives/create-tween.ts +54 -2
  437. package/src/primitives/message-feedback.ts +3 -2
  438. package/src/primitives/use-audio-analysis.ts +20 -1
  439. package/src/primitives/use-sequencer.ts +20 -1
  440. package/src/schemas/from-tool-call.ts +151 -0
  441. package/src/schemas/index.ts +340 -0
  442. package/src/schemas/provider-subsets.ts +538 -0
  443. package/src/schemas/registry.ts +355 -0
  444. package/src/schemas/tool-defs.ts +492 -0
  445. package/src/solid.ts +150 -0
  446. package/src/state/index.ts +27 -1
  447. package/src/state/messages.ts +21 -4
  448. package/src/state/mock.ts +211 -0
  449. package/src/state/parts.ts +295 -0
  450. package/src/state/stream.ts +56 -58
  451. package/src/ui/collapsible.tsx +17 -5
  452. package/src/ui/dropdown.tsx +46 -12
  453. package/src/ui/overlay.tsx +10 -4
  454. package/src/wire/chunk.ts +201 -0
  455. package/src/wire/consume.ts +440 -0
  456. package/src/wire/encode.ts +474 -0
  457. package/src/wire/formats/anthropic.ts +267 -0
  458. package/src/wire/formats/openai.ts +187 -0
  459. package/src/wire/index.ts +52 -0
  460. package/src/wire/read.ts +152 -0
  461. package/src/wire/sink-helpers.ts +50 -0
  462. package/src/wire/sse.ts +140 -0
  463. package/dist/create-tween-hvpmSuwW.js +0 -7
  464. package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
  465. package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
  466. package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
  467. package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
  468. package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
  469. package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
  470. package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
  471. package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
  472. package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
  473. package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
  474. package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
  475. package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
  476. package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
  477. package/dist/elements/chunks/define-D1din7Ld.js +0 -1
  478. package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
  479. package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
  480. package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
  481. package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
  482. package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
  483. package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
  484. package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
  485. package/dist/elements/chunks/slots--V19HwUb.js +0 -1
  486. package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
  487. package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
  488. package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
  489. package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
  490. package/dist/host-embed.d.ts +0 -33
  491. package/dist/kai-provider.d.ts +0 -2
  492. package/dist/origin.d.ts +0 -5
  493. package/dist/provider-runtime.d.ts +0 -27
  494. package/dist/register-impl-DQyejdfb.js +0 -145
  495. package/dist/validate.d.ts +0 -4
  496. package/dist/version.d.ts +0 -4
  497. package/src/components/component-meta.json +0 -4550
  498. package/src/elements/card-media.jpg +0 -0
  499. package/src/elements/resizable.d.ts +0 -27
  500. package/src/elements/video-poster.jpg +0 -0
package/README.md CHANGED
@@ -49,9 +49,10 @@ npm run build # emits dist/kai.es.js
49
49
 
50
50
  const chat = document.querySelector('kai-chat');
51
51
 
52
- // Rich data is set as JS properties (not HTML attributes)
52
+ // Rich data is set as JS properties (not HTML attributes). A message's
53
+ // content is an ordered `parts` array.
53
54
  chat.messages = [
54
- { id: '1', role: 'assistant', content: 'Hello! How can I help?' },
55
+ { id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Hello! How can I help?' }] },
55
56
  ];
56
57
 
57
58
  // Events are non-bubbling kai-* CustomEvents dispatched on the element
@@ -130,6 +131,8 @@ The components are deliberately **transport-agnostic**: `<kai-chat>` just render
130
131
 
131
132
  <script type="module">
132
133
  import '@kitn.ai/ui/elements';
134
+ import { createAssistantStream } from '@kitn.ai/ui/state';
135
+ import { readOpenAIStream, toOpenAIMessages } from '@kitn.ai/ui/wire';
133
136
 
134
137
  // Registration is async (SSR-safe) — wait for the element before using it.
135
138
  await customElements.whenDefined('kai-chat');
@@ -142,14 +145,17 @@ The components are deliberately **transport-agnostic**: `<kai-chat>` just render
142
145
  if (!text) return;
143
146
 
144
147
  // 1. Show the user message immediately
145
- const history = [...chat.messages, { id: crypto.randomUUID(), role: 'user', content: text }];
148
+ const history = [...chat.messages,
149
+ { id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text }] }];
146
150
  chat.messages = history;
147
151
  chat.value = ''; // clear the input
148
152
  chat.loading = true;
149
153
 
150
- // 2. Add an empty assistant message we'll stream into
151
- const assistantId = crypto.randomUUID();
152
- chat.messages = [...history, { id: assistantId, role: 'assistant', content: '' }];
154
+ // 2. Open the assistant message. createAssistantStream appends it and folds
155
+ // each delta onto the right part, reassigning `messages` every time.
156
+ const stream = createAssistantStream((update) => {
157
+ chat.messages = update(chat.messages);
158
+ });
153
159
 
154
160
  try {
155
161
  // In production, replace this URL with your own proxy endpoint.
@@ -162,59 +168,41 @@ The components are deliberately **transport-agnostic**: `<kai-chat>` just render
162
168
  body: JSON.stringify({
163
169
  model: 'anthropic/claude-sonnet-4',
164
170
  stream: true,
165
- messages: history.map((m) => ({ role: m.role, content: m.content })),
171
+ // The encoder turns the thread into the OpenAI `messages` array,
172
+ // keeping tool calls and their results in the order the model needs.
173
+ messages: toOpenAIMessages(history),
166
174
  }),
167
175
  });
168
176
 
169
- const reader = res.body.getReader();
170
- const decoder = new TextDecoder();
171
- let buffer = '';
172
- let answer = '';
173
-
174
- while (true) {
175
- const { value, done } = await reader.read();
176
- if (done) break;
177
- buffer += decoder.decode(value, { stream: true });
178
-
179
- // SSE frames are separated by newlines; each data line is JSON
180
- const lines = buffer.split('\n');
181
- buffer = lines.pop(); // keep the partial last line
182
- for (const line of lines) {
183
- const s = line.trim();
184
- if (!s.startsWith('data:')) continue; // skip ": keep-alive" comments
185
- const payload = s.slice(5).trim();
186
- if (payload === '[DONE]') continue;
187
- try {
188
- const delta = JSON.parse(payload).choices?.[0]?.delta?.content;
189
- if (!delta) continue;
190
- answer += delta;
191
- // Replace the assistant message with a NEW object so the row re-renders
192
- chat.messages = chat.messages.map((m) =>
193
- m.id === assistantId ? { ...m, content: answer } : m
194
- );
195
- } catch { /* ignore non-JSON keep-alive lines */ }
196
- }
197
- }
177
+ // Parses the whole stream: keep-alive comments, multi-line frames,
178
+ // codepoints split across a socket boundary, tool calls, reasoning.
179
+ await readOpenAIStream(res, stream);
198
180
  } catch (err) {
199
- chat.messages = chat.messages.map((m) =>
200
- m.id === assistantId ? { ...m, content: '⚠️ ' + err.message } : m
201
- );
181
+ // A non-ok response throws WireError before a single chunk is read, so put
182
+ // the reason in the bubble rather than leaving an empty one.
183
+ stream.appendText('Request failed: ' + err.message);
202
184
  } finally {
185
+ stream.done();
203
186
  chat.loading = false;
204
187
  }
205
188
  });
206
189
  </script>
207
190
  ```
208
191
 
209
- Key point: reassign `chat.messages` with a **new array containing a new object** for the streaming message on each chunk — that's what triggers the re-render. Mutating the existing object in place won't update the view.
192
+ Key point: `chat.messages` has to be reassigned with a **new array containing a new object** for the streaming message on each chunk. That's what triggers the re-render. Mutating the existing object in place won't update the view. `createAssistantStream` is what satisfies that rule for you; if you drive `messages` by hand, you own it.
193
+
194
+ `@kitn.ai/ui/wire` also ships `readAnthropicStream`, the helpers for a multi-round tool loop, and a seam for a custom wire format. See the [wire adapter recipe](https://ui.kitn.ai/guides/recipes/wire-adapter/).
210
195
 
211
196
  ### Text-to-speech (TTS)
212
197
 
213
198
  #### Option 1 — Browser-native (zero dependencies)
214
199
 
215
- The Web Speech API speaks text with no network call. Speak each assistant reply once it finishes streaming — call `speak(answer)` right before `chat.loading = false` in the example above:
200
+ The Web Speech API speaks text with no network call. `readOpenAIStream` resolves with the finished turn, so speak `turn.text` in the example above:
216
201
 
217
202
  ```js
203
+ const turn = await readOpenAIStream(res, stream);
204
+ speak(turn.text);
205
+
218
206
  function speak(text) {
219
207
  if (!('speechSynthesis' in window)) return;
220
208
  const utter = new SpeechSynthesisUtterance(text);
@@ -236,7 +224,19 @@ function speakIncremental(fullText) {
236
224
  spokenUpTo = lastBreak + 1;
237
225
  }
238
226
  }
239
- // call speakIncremental(answer) inside the streaming loop
227
+
228
+ // A sink is a plain object, so wrap it to see the text as it arrives. Everything
229
+ // else passes through untouched.
230
+ let sofar = '';
231
+ const speaking = {
232
+ ...stream,
233
+ appendText(delta) {
234
+ sofar += delta;
235
+ speakIncremental(sofar);
236
+ return stream.appendText(delta);
237
+ },
238
+ };
239
+ await readOpenAIStream(res, speaking);
240
240
  ```
241
241
 
242
242
  #### Option 2 — Cloud TTS (OpenAI, ElevenLabs, …)
@@ -268,16 +268,15 @@ You can trigger either option from the streaming completion (auto-read replies)
268
268
 
269
269
  ## State helpers & hooks
270
270
 
271
- `@kitn.ai/ui/state` ships immutable helpers (`appendMessage`, `upsertMessage`, `updateMessage`, `removeMessage`, `appendContent`) and a streaming handle (`createAssistantStream`) so you don't hand-roll array mutations. React apps get `useKaiChat` (from `@kitn.ai/ui/react`); SolidJS apps get `createKaiChat` (from `@kitn.ai/ui`). Both return a `bind` object to spread directly onto the element:
271
+ `@kitn.ai/ui/state` ships immutable helpers (`appendMessage`, `upsertMessage`, `updateMessage`, `removeMessage`, `appendText`, `textMessage`), the part-level folds they build on (`appendTextPart`, `appendReasoningPart`, `upsertToolPart`, `upsertCardPart`), and a streaming handle (`createAssistantStream`) so you don't hand-roll array mutations. React apps get `useKaiChat` (from `@kitn.ai/ui/react`); SolidJS apps get `createKaiChat` (from `@kitn.ai/ui`). Both return a `bind` object to spread directly onto the element:
272
272
 
273
273
  ```tsx
274
274
  import { Chat, useKaiChat } from '@kitn.ai/ui/react';
275
- import { createAssistantStream } from '@kitn.ai/ui/state';
276
275
 
277
276
  function App() {
278
277
  const chat = useKaiChat({
279
278
  async onSubmit({ value }) {
280
- chat.append({ id: crypto.randomUUID(), role: 'user', content: value });
279
+ chat.append({ id: crypto.randomUUID(), role: 'user', parts: [{ type: 'text', text: value }] });
281
280
  const s = chat.streamAssistant();
282
281
  for await (const part of backend(value)) s.appendText(part);
283
282
  s.done();
@@ -0,0 +1,51 @@
1
+ import { JSX } from 'solid-js';
2
+ import { CardHost } from '../primitives/card-contract.js';
3
+ import { ArtifactCardData } from '../primitives/card-data-types.js';
4
+ export type { ArtifactCardData, ArtifactCardEnvelope, ArtifactCardFile, ArtifactCardTab, } from '../primitives/card-data-types.js';
5
+ /** Height the artifact card falls back to. Tall enough that a framed page is
6
+ * actually legible in a thread, short enough to leave the conversation visible. */
7
+ export declare const DEFAULT_ARTIFACT_CARD_HEIGHT = "420px";
8
+ export interface ArtifactCardProps {
9
+ data: ArtifactCardData;
10
+ cardId: string;
11
+ heading?: string;
12
+ host?: CardHost;
13
+ }
14
+ /** Chrome + sizing around `<Artifact>` for the `artifact` card type.
15
+ *
16
+ * WHY A WRAPPER IS REQUIRED, not cosmetic. `<Artifact>`'s root is
17
+ * `flex h-full w-full flex-col` — it is built to FILL a container that already
18
+ * has a height (a resizable panel, a split view). A message thread gives its
19
+ * parts no height at all, so `h-full` resolves against an auto-height parent,
20
+ * the frame computes to ZERO, and the card renders as an invisible nothing.
21
+ * The explicit `height` here is what makes the card visible; `data.height`
22
+ * overrides it.
23
+ *
24
+ * `part`/`data-card-type` are stable handles. `CardRenderer` renders card
25
+ * components bare, and in the web-component path `cardComponentsFromTags` maps a
26
+ * non-overridden built-in straight to its Solid component — so there is no
27
+ * `<kai-artifact>` tag in the DOM to point at. This wrapper is the only stable
28
+ * thing to select, which is what lets a test count rendered artifacts inside
29
+ * `<kai-thread>`'s shadow root.
30
+ *
31
+ * `part="card"` matches the other chromed cards, which get it from `<Card>`;
32
+ * this one hand-rolls its chrome and so states it directly. The artifact-specific
33
+ * handle is `data-card-type`, NOT a second part token: every `::part` name has to
34
+ * be declared in `elements/slots.ts` (the drift guard in `slots.test.ts` enforces
35
+ * it), so adding an `artifact` part is a deliberate public-API decision to make
36
+ * there, not something to smuggle in from a component.
37
+ *
38
+ * `envelope.title` renders as a HEADING above the frame rather than being folded
39
+ * into `displayUrl`: the address field states where the preview is pointing, and
40
+ * overwriting it with a title would make it lie. A heading is also what the four
41
+ * other chromed cards (form/confirm/tasks/choice) already do with `title`.
42
+ *
43
+ * `tab`/`activeFile` are SEEDS, never re-asserted — see their notes on
44
+ * `ArtifactCardData`. A revised envelope must not undo what the user did.
45
+ *
46
+ * The three observation callbacks emit the contract's EXISTING `state` verb —
47
+ * the contract is frozen, and a new kind would force a CARD_CONTRACT_VERSION
48
+ * bump. Each patch key mirrors a `data` field name, so a host can merge the
49
+ * patch straight back into `envelope.data` and re-send it; `addCard` upserts on
50
+ * `envelope.id`, so that round-trip revises the card instead of duplicating it. */
51
+ export declare function ArtifactCard(props: ArtifactCardProps): JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'solid-js';
2
- import { FileTreeFile } from './file-tree';
2
+ import { FileTreeFile } from './file-tree.js';
3
3
  export type ArtifactTab = 'preview' | 'code';
4
4
  /** A file the artifact can preview + show source for. */
5
5
  export type ArtifactFile = FileTreeFile;
@@ -1,6 +1,6 @@
1
1
  import { JSX } from 'solid-js';
2
- import { AttachmentData, AttachmentMediaCategory, AttachmentVariant } from './attachment-types';
3
- export type { AttachmentData, AttachmentMediaCategory, AttachmentVariant } from './attachment-types';
2
+ import { AttachmentData, AttachmentMediaCategory, AttachmentVariant } from './attachment-types.js';
3
+ export type { AttachmentData, AttachmentMediaCategory, AttachmentVariant } from './attachment-types.js';
4
4
  export declare const getMediaCategory: (data: AttachmentData) => AttachmentMediaCategory;
5
5
  export declare const getAttachmentLabel: (data: AttachmentData) => string;
6
6
  interface AttachmentsContextValue {
@@ -1,7 +1,7 @@
1
1
  import { Accessor, JSX } from 'solid-js';
2
- import { VariantProps } from './variant-bar';
3
- import { VisualizerSize } from './sizes';
4
- import { UniformType } from './shader-canvas';
2
+ import { VariantProps } from './variant-bar.js';
3
+ import { VisualizerSize } from './sizes.js';
4
+ import { UniformType } from './shader-canvas.js';
5
5
  export type VisualizerVariant = 'bar' | 'grid' | 'radial' | 'wave' | 'aurora' | 'custom';
6
6
  export declare function normalizeVariant(input: string | undefined): VisualizerVariant;
7
7
  /** A consumer-supplied fragment shader, for `variant="custom"`. */
@@ -0,0 +1,59 @@
1
+ import { LabLook } from './lab-shaders.js';
2
+ /** The agent states the kit's visualizers respond to, plus manual free play. */
3
+ export type LabState = 'manual' | 'idle' | 'connecting' | 'listening' | 'thinking' | 'speaking';
4
+ export declare const LAB_STATES: LabState[];
5
+ /** Every tunable the lab shaders read. Flat on purpose: story args map 1:1. */
6
+ export interface LabParams {
7
+ baseR: number;
8
+ ampIdle: number;
9
+ ampVoice: number;
10
+ radVoice: number;
11
+ sigma: number;
12
+ gain: number;
13
+ f1: number;
14
+ f2: number;
15
+ s1: number;
16
+ s2: number;
17
+ envSpd: number;
18
+ sepSpd: number;
19
+ whiteLo: number;
20
+ whiteHi: number;
21
+ bloomMul: number;
22
+ bloomGain: number;
23
+ delta: number;
24
+ off: number;
25
+ wWidth: number;
26
+ wMin: number;
27
+ fillGain: number;
28
+ edgeGain: number;
29
+ flut: number;
30
+ twistSpd: number;
31
+ warpAmp: number;
32
+ lens: number;
33
+ spec: number;
34
+ tint: number;
35
+ vSpeed: number;
36
+ presence: number;
37
+ gather: number;
38
+ core: number;
39
+ neural: number;
40
+ boltJag: number;
41
+ boltWidth: number;
42
+ boltRate: number;
43
+ }
44
+ /** Hand-tuned in the aurora playground; per-look starting points. */
45
+ export declare const LOOK_DEFAULTS: Record<LabLook, LabParams>;
46
+ export interface LabFrame {
47
+ t: number;
48
+ level: number;
49
+ values: LabParams;
50
+ }
51
+ /**
52
+ * The state choreography from the playground, per frame. Slow targets glide
53
+ * over seconds (presence slowest, so smoke visibly forms and dissipates);
54
+ * tempo runs on an accumulated warped clock, so state changes never jump the
55
+ * animation phase; the ember beats and the bolts fire in real time.
56
+ */
57
+ export declare function createChoreography(getLook: () => LabLook, getState: () => LabState, getParams: () => LabParams): {
58
+ step: (dt: number) => LabFrame;
59
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The four lab looks, written for `ShaderCanvas` in the same `mainImage`
3
+ * convention the `custom` variant documents. Every uniform is declared by
4
+ * the canvas from the uniform map (`lab-visualizer.tsx`), never in the body.
5
+ *
6
+ * All four are original clean-room work from the aurora prototyping sessions
7
+ * (see `examples/internal/aurora-playground`, the tuning playground these were
8
+ * born in). Braid and ribbon read the accent through the shared ring pipeline;
9
+ * planet and orb are stationary vessels whose CONTENTS react to state and
10
+ * voice: presence materializes the smoke, gather settles or centers it, the
11
+ * ember pulses while connecting, and thinking fires fractal lightning.
12
+ */
13
+ /** Three woven strands sharing one wave family; pileups soft-compressed. */
14
+ export declare const BRAID_FRAGMENT = "\nfloat labStroke(float d, float sigma) {\n float q = d / sigma;\n float q2 = q * q;\n float core = exp(-q2 * q2);\n float bq = d / (sigma * uBloomMul);\n float bloom = exp(-bq * bq) * uBloomGain;\n return core + bloom;\n}\n\nvec4 labRingColor(float glow, float bfloor, float bscale, float wcap, vec2 fragCoord) {\n float bright = bfloor + bscale * min(glow, 1.2);\n float white = smoothstep(uWhiteLo, uWhiteHi, glow) * wcap;\n vec3 col = mix(uColor * bright, vec3(1.0), white);\n float alpha = clamp(glow, 0.0, 1.0);\n float n = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);\n alpha = clamp(alpha + (n - 0.5) / 255.0, 0.0, 1.0);\n return vec4(col * alpha, alpha);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 hres = iResolution.xy * 0.5;\n vec2 p = (fragCoord - hres) / hres.y;\n float r = length(p);\n float th = atan(p.y, p.x);\n float t = uT;\n\n float amp = uAmpIdle + uAmpVoice * uLvl;\n float baseR = uBaseR + uRadVoice * uLvl;\n float env = 0.62 + 0.38 * sin(th * 2.0 + t * uEnvSpd + 2.0);\n\n float glow = 0.0;\n for (int i = 0; i < 3; i++) {\n float fi = float(i);\n float a = th + fi * uDelta;\n float tt = t + fi * 1.3;\n float wob = sin(a * uF1 + tt * uS1) * 0.55 + sin(a * uF2 - tt * uS2) * 0.45;\n float ampi = amp * (0.65 + 0.35 * fi);\n float sepMod = 0.5 + 0.5 * sin(th + t * uSepSpd + fi * 1.9);\n float ringR = baseR + (fi - 1.0) * uOff * (0.35 + 1.5 * sepMod) + wob * ampi * env;\n glow += uGain * (0.8 + 0.35 * env) * labStroke(abs(r - ringR), uSigma);\n }\n // three overlapping strands can sum past every threshold; compress so\n // crossings brighten without blowing out to a solid white tube\n glow = glow / (1.0 + 0.35 * glow);\n fragColor = labRingColor(glow, 0.55, 0.65, 0.45, fragCoord);\n}\n";
15
+ /** One ribbon whose width pinches to zero at traveling twist points. */
16
+ export declare const RIBBON_FRAGMENT = "\nfloat labStroke(float d, float sigma) {\n float q = d / sigma;\n float q2 = q * q;\n float core = exp(-q2 * q2);\n float bq = d / (sigma * uBloomMul);\n float bloom = exp(-bq * bq) * uBloomGain;\n return core + bloom;\n}\n\nvec4 labRingColor(float glow, float bfloor, float bscale, float wcap, vec2 fragCoord) {\n float bright = bfloor + bscale * min(glow, 1.2);\n float white = smoothstep(uWhiteLo, uWhiteHi, glow) * wcap;\n vec3 col = mix(uColor * bright, vec3(1.0), white);\n float alpha = clamp(glow, 0.0, 1.0);\n float n = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);\n alpha = clamp(alpha + (n - 0.5) / 255.0, 0.0, 1.0);\n return vec4(col * alpha, alpha);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 hres = iResolution.xy * 0.5;\n vec2 p = (fragCoord - hres) / hres.y;\n float r = length(p);\n float th = atan(p.y, p.x);\n float t = uT;\n\n float amp = uAmpIdle + uAmpVoice * uLvl;\n float baseR = uBaseR + uRadVoice * uLvl;\n float env = 0.62 + 0.38 * sin(th * 2.0 + t * uEnvSpd + 2.0);\n\n float wRaw = sin(th * 2.0 + t * uTwistSpd) * 0.6\n + sin(th * 3.0 - t * uTwistSpd * 0.7 + 1.7) * 0.4;\n float w = (abs(wRaw) * uWWidth + uWMin) * (0.55 + 0.45 * env);\n\n float c = baseR\n + (sin(th * uF1 + t * uS1) * 0.6\n + sin(th * (uF1 + 2.0) - t * uS1 * 0.63 + 2.3) * 0.4) * amp;\n\n float fl = uFlut * (0.5 + 0.9 * uLvl);\n float e1 = c - w + sin(th * uF2 + t * uS2) * fl;\n float e2 = c + w + sin(th * uF2 * 1.3 - t * uS2 * 0.8 + 2.0) * fl;\n\n float lo = min(e1, e2), hi = max(e1, e2);\n float ww = max(hi - lo, 0.004);\n float dens = clamp(uWWidth * 1.2 / ww, 0.4, 2.0);\n\n float box = smoothstep(-uSigma, uSigma, r - lo)\n * (1.0 - smoothstep(-uSigma, uSigma, r - hi));\n float u = clamp((r - lo) / ww, 0.0, 1.0);\n float rim = smoothstep(0.5, 1.0, abs(u - 0.5) * 2.0);\n\n float outside = max(max(lo - r, r - hi), 0.0);\n float bs = uSigma * uBloomMul;\n float halo = exp(-(outside * outside) / (2.0 * bs * bs)) * uBloomGain * dens;\n\n float glow = uGain * uFillGain\n * (box * dens * (1.0 + uEdgeGain * rim) + halo * (1.0 - box));\n fragColor = labRingColor(glow, 0.75, 0.45, 0.55, fragCoord);\n}\n";
17
+ /** Dense churning cloud cover on a stationary glass sphere. */
18
+ export declare const PLANET_FRAGMENT = "\nfloat labHash(vec2 q) {\n return fract(sin(dot(q, vec2(127.1, 311.7))) * 43758.5453);\n}\nfloat labNoise(vec2 q) {\n vec2 i = floor(q);\n vec2 f = fract(q);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = labHash(i);\n float b = labHash(i + vec2(1.0, 0.0));\n float c = labHash(i + vec2(0.0, 1.0));\n float d = labHash(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\nfloat labFbm(vec2 q) {\n float sum = 0.0;\n float amp = 0.5;\n for (int i = 0; i < 4; i++) {\n sum += amp * labNoise(q);\n q *= 2.03;\n amp *= 0.5;\n }\n return sum;\n}\n\nfloat labSegDist(vec2 q, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float h = clamp(dot(q - a, ab) / max(dot(ab, ab), 1.0e-6), 0.0, 1.0);\n return length(q - a - ab * h);\n}\nvec2 labSparkPos(float k, float i, float R) {\n float h1 = labHash(vec2(k * 7.31 + 1.13, i * 3.71 + 0.17));\n float h2 = labHash(vec2(i * 9.13 + 2.29, k * 5.77 + 0.53));\n float av = 6.2831853 * h1;\n float rad = R * 0.85 * sqrt(h2);\n return vec2(cos(av), sin(av)) * rad;\n}\nfloat labBolt(vec2 q, vec2 A, vec2 B, float seed, float R, float life) {\n vec2 ab = B - A;\n float len = max(length(ab), 1.0e-4);\n vec2 dir = ab / len;\n vec2 nrm = vec2(-dir.y, dir.x);\n vec2 w = q - A;\n float u = dot(w, dir) / len;\n float v = dot(w, nrm);\n if (u < -0.05 || u > 1.05 || abs(v) > R * 0.30) return 0.0;\n float uu = clamp(u, 0.0, 1.0);\n float taper = sin(uu * 3.14159265);\n float off1 = (labFbm(vec2(uu * 9.0 + seed * 13.1, seed * 7.7)) - 0.5) * 0.55 * uBoltJag;\n float off2 = (labFbm(vec2(uu * 23.0 + seed * 5.3, seed * 3.9 + 4.2)) - 0.5) * 0.22 * uBoltJag;\n float mainArc = abs(v - (off1 + off2) * len * taper);\n float forkArc = abs(v - (off1 * 0.6 - off2 * 1.8) * len * taper);\n float wdt = R * (0.006 + 0.010 * life) * uBoltWidth;\n float bolt = exp(-pow(mainArc / wdt, 2.0))\n + 0.45 * exp(-pow(mainArc / (wdt * 3.0), 2.0))\n + 0.5 * exp(-pow(forkArc / (wdt * 0.8), 2.0))\n + 0.25 * exp(-pow(forkArc / (wdt * 2.5), 2.0));\n return bolt * taper;\n}\nfloat labNeural(vec2 q, float t, float R) {\n if (uNeural < 0.01) return 0.0;\n float acc = 0.0;\n for (int k = 0; k < 5; k++) {\n float fk = float(k);\n float period = (1.1 + 1.3 * labHash(vec2(fk, 3.3))) / max(uBoltRate, 0.05);\n float cyc = t / period + labHash(vec2(fk, 7.7)) * 7.0;\n float i = floor(cyc);\n float life = fract(cyc);\n float env = smoothstep(0.0, 0.04, life) * exp(-5.0 * life);\n if (env >= 0.004) {\n vec2 pos = labSparkPos(fk, i, R);\n vec2 prev = labSparkPos(fk, i - 1.0, R);\n float seed = labHash(vec2(fk * 3.1, i * 1.7));\n float bolt = labBolt(q, prev, pos, seed, R, life) * env;\n vec2 dp = q - pos;\n vec2 dq = q - prev;\n float tips = (exp(-dot(dp, dp) / (2.0 * R * R * 0.0016))\n + 0.6 * exp(-dot(dq, dq) / (2.0 * R * R * 0.0012))) * env;\n acc += bolt * 1.2 + tips * 0.8;\n }\n }\n return acc * uNeural;\n}\n\nvec4 labRingColor(float glow, float bfloor, float bscale, float wcap, vec2 fragCoord) {\n float bright = bfloor + bscale * min(glow, 1.2);\n float white = smoothstep(uWhiteLo, uWhiteHi, glow) * wcap;\n vec3 col = mix(uColor * bright, vec3(1.0), white);\n float alpha = clamp(glow, 0.0, 1.0);\n float n = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);\n alpha = clamp(alpha + (n - 0.5) / 255.0, 0.0, 1.0);\n return vec4(col * alpha, alpha);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 hres = iResolution.xy * 0.5;\n vec2 p = (fragCoord - hres) / hres.y;\n float t = uT;\n float R = uBaseR * 2.0;\n float d = length(p);\n float mask = 1.0 - smoothstep(R - 0.012, R + 0.004, d);\n float zn = sqrt(max(R * R - d * d, 0.0)) / max(R, 1.0e-4);\n vec2 ps = p / (R * mix(1.0, 0.35 + 0.65 * zn, uLens));\n\n float tt = t * uTwistSpd;\n float sc = uF2 * 0.35;\n float turb = uWarpAmp * (0.5 + 0.8 * uLvl);\n\n float dens = 0.0;\n for (int k = 0; k < 3; k++) {\n float fk = float(k);\n vec2 o = vec2(fk * 7.31, fk * 3.77);\n vec2 pk = ps * (1.0 + fk * 0.18 * (1.0 - zn));\n vec2 q = vec2(\n labFbm(pk * sc * 0.6 + o + vec2(tt * uS1 * 0.55, 0.0)),\n labFbm(pk * sc * 0.6 + o + vec2(5.2, 1.3) - vec2(0.0, tt * uS2 * 0.45)));\n float n = labFbm(pk * sc + turb * 2.0 * (q - 0.5) + o + vec2(tt * 0.28, tt * 0.18));\n dens += (0.45 - fk * 0.1) * n;\n }\n dens = smoothstep(0.30 + (1.0 - uPresence) * 0.40, 0.78, dens);\n dens *= 0.12 + 0.88 * uPresence;\n\n vec2 lp = vec2(cos(tt * 0.23), sin(tt * 0.31)) * R * 0.35;\n vec2 dl = p - lp;\n float smoke = dens * (0.5 + 0.9 * exp(-dot(dl, dl) / (2.0 * R * R * 0.16))) * (0.55 + 0.65 * zn)\n + 0.05 * zn;\n\n float rim = pow(smoothstep(R * 0.62, R, d), 3.0);\n vec2 hp = p - vec2(-0.38, 0.42) * R;\n float spec = exp(-dot(hp, hp) / (2.0 * R * R * 0.004)) * uSpec;\n float core = uCore * exp(-(d * d) / (2.0 * R * R * 0.026));\n float nrl = labNeural(p, tt * 0.6, R);\n\n float glow = uGain * mask\n * (uFillGain * 1.6 * smoke + uEdgeGain * 0.8 * rim + spec + core * 1.3 + nrl * 1.2);\n fragColor = labRingColor(glow, 0.75, 0.45, 0.55, fragCoord);\n}\n";
19
+ /** Luminous smoke sealed in a stationary glass sphere, lit from within. */
20
+ export declare const ORB_FRAGMENT = "\nfloat labHash(vec2 q) {\n return fract(sin(dot(q, vec2(127.1, 311.7))) * 43758.5453);\n}\nfloat labNoise(vec2 q) {\n vec2 i = floor(q);\n vec2 f = fract(q);\n vec2 u = f * f * (3.0 - 2.0 * f);\n float a = labHash(i);\n float b = labHash(i + vec2(1.0, 0.0));\n float c = labHash(i + vec2(0.0, 1.0));\n float d = labHash(i + vec2(1.0, 1.0));\n return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\nfloat labFbm(vec2 q) {\n float sum = 0.0;\n float amp = 0.5;\n for (int i = 0; i < 4; i++) {\n sum += amp * labNoise(q);\n q *= 2.03;\n amp *= 0.5;\n }\n return sum;\n}\n\nfloat labSegDist(vec2 q, vec2 a, vec2 b) {\n vec2 ab = b - a;\n float h = clamp(dot(q - a, ab) / max(dot(ab, ab), 1.0e-6), 0.0, 1.0);\n return length(q - a - ab * h);\n}\nvec2 labSparkPos(float k, float i, float R) {\n float h1 = labHash(vec2(k * 7.31 + 1.13, i * 3.71 + 0.17));\n float h2 = labHash(vec2(i * 9.13 + 2.29, k * 5.77 + 0.53));\n float av = 6.2831853 * h1;\n float rad = R * 0.85 * sqrt(h2);\n return vec2(cos(av), sin(av)) * rad;\n}\nfloat labBolt(vec2 q, vec2 A, vec2 B, float seed, float R, float life) {\n vec2 ab = B - A;\n float len = max(length(ab), 1.0e-4);\n vec2 dir = ab / len;\n vec2 nrm = vec2(-dir.y, dir.x);\n vec2 w = q - A;\n float u = dot(w, dir) / len;\n float v = dot(w, nrm);\n if (u < -0.05 || u > 1.05 || abs(v) > R * 0.30) return 0.0;\n float uu = clamp(u, 0.0, 1.0);\n float taper = sin(uu * 3.14159265);\n float off1 = (labFbm(vec2(uu * 9.0 + seed * 13.1, seed * 7.7)) - 0.5) * 0.55 * uBoltJag;\n float off2 = (labFbm(vec2(uu * 23.0 + seed * 5.3, seed * 3.9 + 4.2)) - 0.5) * 0.22 * uBoltJag;\n float mainArc = abs(v - (off1 + off2) * len * taper);\n float forkArc = abs(v - (off1 * 0.6 - off2 * 1.8) * len * taper);\n float wdt = R * (0.006 + 0.010 * life) * uBoltWidth;\n float bolt = exp(-pow(mainArc / wdt, 2.0))\n + 0.45 * exp(-pow(mainArc / (wdt * 3.0), 2.0))\n + 0.5 * exp(-pow(forkArc / (wdt * 0.8), 2.0))\n + 0.25 * exp(-pow(forkArc / (wdt * 2.5), 2.0));\n return bolt * taper;\n}\nfloat labNeural(vec2 q, float t, float R) {\n if (uNeural < 0.01) return 0.0;\n float acc = 0.0;\n for (int k = 0; k < 5; k++) {\n float fk = float(k);\n float period = (1.1 + 1.3 * labHash(vec2(fk, 3.3))) / max(uBoltRate, 0.05);\n float cyc = t / period + labHash(vec2(fk, 7.7)) * 7.0;\n float i = floor(cyc);\n float life = fract(cyc);\n float env = smoothstep(0.0, 0.04, life) * exp(-5.0 * life);\n if (env >= 0.004) {\n vec2 pos = labSparkPos(fk, i, R);\n vec2 prev = labSparkPos(fk, i - 1.0, R);\n float seed = labHash(vec2(fk * 3.1, i * 1.7));\n float bolt = labBolt(q, prev, pos, seed, R, life) * env;\n vec2 dp = q - pos;\n vec2 dq = q - prev;\n float tips = (exp(-dot(dp, dp) / (2.0 * R * R * 0.0016))\n + 0.6 * exp(-dot(dq, dq) / (2.0 * R * R * 0.0012))) * env;\n acc += bolt * 1.2 + tips * 0.8;\n }\n }\n return acc * uNeural;\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n vec2 hres = iResolution.xy * 0.5;\n vec2 p = (fragCoord - hres) / hres.y;\n float t = uT;\n float R = uBaseR * 2.0;\n float d = length(p);\n float mask = 1.0 - smoothstep(R - 0.010, R + 0.004, d);\n float zn = sqrt(max(R * R - d * d, 0.0)) / max(R, 1.0e-4);\n float inner = 1.0 - clamp(d / max(R, 1.0e-4), 0.0, 1.0);\n vec2 ps = p / (R * mix(1.0, 0.35 + 0.65 * zn, uLens));\n\n float tt = t * uTwistSpd;\n // rigid drift plus a BOUNDED oscillating stir: shear that accumulates\n // forever winds any pattern into a spiral\n float ang = tt * 0.04\n + (sin(tt * 0.11) * 0.55 + sin(tt * 0.047 + 1.7) * 0.35) * inner;\n float ca = cos(ang), sa = sin(ang);\n ps = mat2(ca, -sa, sa, ca) * ps;\n\n float sc = uF2 * 0.18;\n float tau0 = 0.50 + 0.06 * uLvl;\n float bw = mix(0.16, 0.12, uLvl);\n\n vec2 lp = vec2(cos(tt * 0.21), sin(tt * 0.27)) * R * 0.42;\n vec2 L = normalize(lp - p + vec2(1.0e-4, 0.0));\n\n float dens = 0.0;\n float lit = 0.0;\n for (int k = 0; k < 2; k++) {\n float fk = float(k);\n vec2 o = vec2(fk * 9.17, fk * 5.13);\n float scale = sc * (1.0 + 0.7 * fk);\n vec2 pk = ps * (1.0 + fk * 0.24 * (1.0 - zn)) + o;\n\n // bounded orbit, never a straight scroll: the coverage pattern wanders\n // around home instead of migrating off one side of the vessel\n float cn = labFbm(pk * 0.9 + vec2(sin(tt * 0.041), -cos(tt * 0.033)) * 0.8);\n float covLo = 0.62 - 0.30 * uFillGain + 0.03 * uLvl\n + (1.0 - uPresence) * 0.45;\n float bottomness = clamp(-p.y / max(R, 1.0e-4) * 1.3 - 0.1, 0.0, 1.0);\n float gBias = 0.16 * inner * uPresence\n + max(uGather, 0.0) * 0.30 * inner\n + max(-uGather, 0.0) * 0.38 * bottomness;\n float cov = smoothstep(covLo, covLo + 0.28, cn + gBias);\n\n vec2 flow = vec2(-pk.y, pk.x) * 0.5 + vec2(0.0, 0.4);\n float cyc = tt * 0.10 * uS1 * (1.0 + 0.6 * fk);\n float ph0 = fract(cyc + 0.35 * cn);\n float ph1 = fract(cyc + 0.35 * cn + 0.5);\n float w0 = 1.0 - abs(1.0 - 2.0 * ph0);\n\n vec2 w2 = vec2(labFbm(pk * scale * 0.5 + vec2(sin(tt * 0.09 * uS2), cos(tt * 0.075 * uS2)) * 0.9),\n labFbm(pk * scale * 0.5 + vec2(3.7, 8.1) + vec2(cos(tt * 0.065 * uS2), sin(tt * 0.083 * uS2)) * 0.9));\n vec2 qw = pk * scale + uWarpAmp * 3.0 * (w2 - 0.5);\n\n float n = mix(labFbm(qw - flow * 1.2 * ph1), labFbm(qw - flow * 1.2 * ph0), w0);\n float sgn = 2.0 * n - 1.0;\n float ridge = 1.0 - abs(sgn);\n ridge *= ridge;\n float band = smoothstep(tau0 - bw, tau0, n) * (1.0 - smoothstep(tau0, tau0 + bw, n));\n float dk = cov * (band * (0.6 + 0.5 * ridge) + 0.12 * n * cov);\n dens += (0.60 - 0.22 * fk) * dk;\n\n float nL = labFbm(qw + L * 0.5);\n lit += clamp((nL - n) * 3.0, 0.0, 1.0) * dk;\n }\n dens *= 1.0 - smoothstep(0.72, 0.97, d / max(R, 1.0e-4));\n dens *= (0.45 + 1.25 * uFillGain) * (1.0 + 0.25 * uLvl);\n dens *= 0.08 + 0.92 * uPresence;\n float dEff = clamp(dens, 0.0, 1.5) * (0.5 + 0.5 * zn);\n float aSmoke = 1.0 - exp(-2.6 * dEff);\n\n float rL = length(p - lp) / R;\n float G = 1.0 / (1.0 + 2.0 * rL + 8.0 * rL * rL);\n float act = 0.7 + 0.8 * uLvl;\n\n vec3 albedo = mix(vec3(0.84, 0.87, 0.92), uColor, uTint);\n vec3 body = albedo * (0.30 + 0.55 * exp(-1.4 * dEff))\n + uColor * (lit * 0.5 + dEff * G * 1.1) * act;\n vec3 bgIn = uColor * 0.05 * zn;\n vec3 col = mix(bgIn, body, aSmoke)\n + uColor * G * act * 0.18 * zn;\n\n float rim = pow(smoothstep(R * 0.66, R, d), 3.0);\n vec2 hp = p - vec2(-0.38, 0.42) * R;\n float spec = exp(-dot(hp, hp) / (2.0 * R * R * 0.004)) * uSpec;\n float core = uCore * exp(-(d * d) / (2.0 * R * R * 0.022));\n float nrl = labNeural(p, tt * 0.6, R);\n col += uColor * rim * uEdgeGain * 0.7 + vec3(spec) + uColor * core * 1.5\n + uColor * nrl * (0.7 + 0.6 * aSmoke);\n\n col *= uGain * mask;\n float alpha = clamp((aSmoke * 0.9 + G * act * 0.15 * zn + core + nrl * 0.55\n + rim * uEdgeGain * 0.5 + spec + 0.03 * zn) * uGain, 0.0, 1.0) * mask;\n float nz = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);\n alpha = clamp(alpha + (nz - 0.5) / 255.0, 0.0, 1.0);\n fragColor = vec4(col, alpha);\n}\n";
21
+ export type LabLook = 'braid' | 'ribbon' | 'planet' | 'orb';
22
+ export declare const LAB_FRAGMENTS: Record<LabLook, string>;
@@ -0,0 +1,18 @@
1
+ import { JSX } from 'solid-js';
2
+ import { LabLook } from './lab-shaders.js';
3
+ import { LabParams, LabState } from './lab-choreography.js';
4
+ export interface LabVisualizerProps {
5
+ look: LabLook;
6
+ state?: LabState;
7
+ color?: string;
8
+ /** Square canvas edge in px. */
9
+ size?: number;
10
+ /** Overrides on the look's tuned defaults. */
11
+ params?: Partial<LabParams>;
12
+ }
13
+ /**
14
+ * Runs one lab look through the same `ShaderCanvas` the shipped variants use,
15
+ * with the playground's state choreography driving the uniforms per frame.
16
+ * While `speaking`, a baked loudness loop stands in for a live voice.
17
+ */
18
+ export declare function LabVisualizer(props: LabVisualizerProps): JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { JSX } from 'solid-js';
2
- import { VisualizerState } from '../../primitives/visualizer-sequences';
3
- import { ShaderVariantProps } from './index';
2
+ import { VisualizerState } from '../../primitives/visualizer-sequences.js';
3
+ import { ShaderVariantProps } from './index.js';
4
4
  /**
5
5
  * Per-state uniform targets, straight from fact sheet section 5's measured
6
6
  * table (`.superpowers/sdd/2026-08-07-audio-visualizers/reference/
@@ -1,6 +1,6 @@
1
1
  import { JSX } from 'solid-js';
2
- import { VisualizerState } from '../../primitives/visualizer-sequences';
3
- import { VisualizerSize } from './sizes';
2
+ import { VisualizerState } from '../../primitives/visualizer-sequences.js';
3
+ import { VisualizerSize } from './sizes.js';
4
4
  /** Props every DOM variant takes. The dispatcher supplies all of them. */
5
5
  export interface VariantProps {
6
6
  state: VisualizerState;
@@ -1,6 +1,6 @@
1
1
  import { JSX } from 'solid-js';
2
- import { UniformSpec } from './shader-canvas';
3
- import { ShaderVariantProps } from './index';
2
+ import { UniformSpec } from './shader-canvas.js';
3
+ import { ShaderVariantProps } from './index.js';
4
4
  /**
5
5
  * Uniforms every custom shader receives without asking: the standard set
6
6
  * (`uColor`, `uIntensity`, `uSpeed`, `uComplexity`) plus the audio pair that
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'solid-js';
2
- import { VariantProps } from './variant-bar';
2
+ import { VariantProps } from './variant-bar.js';
3
3
  /**
4
4
  * A grid of dots that pulses with the audio.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'solid-js';
2
- import { VariantProps } from './variant-bar';
2
+ import { VariantProps } from './variant-bar.js';
3
3
  /**
4
4
  * Bars arranged around a circle, growing outward with the audio.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  import { JSX } from 'solid-js';
2
- import { ShaderVariantProps } from './index';
2
+ import { ShaderVariantProps } from './index.js';
3
3
  /**
4
4
  * A flowing oscilloscope line.
5
5
  *
@@ -1,10 +1,20 @@
1
1
  import { JSX } from 'solid-js';
2
2
  export interface CardFallbackProps {
3
- /** The unrecognized envelope type, shown to aid debugging. */
3
+ /** The envelope type, shown to aid debugging. */
4
4
  type: string;
5
5
  /** The envelope id (for parity with cards; not displayed). */
6
6
  cardId?: string;
7
+ /**
8
+ * Why this card could not render, when the type WAS known but the data was not
9
+ * usable. Carries the failing field paths verbatim, e.g.
10
+ * `(root).actions: fewer than minItems 1`.
11
+ *
12
+ * Absent means the older case: an unrecognized type. The two are told apart by
13
+ * this prop rather than by a mode flag so a caller cannot ask for the diagnostic
14
+ * and forget to supply the diagnosis.
15
+ */
16
+ reason?: string;
7
17
  }
8
- /** Inert, themed fallback for an unsupported card type. Emits nothing itself
18
+ /** Inert, themed fallback for a card that cannot render. Emits nothing itself:
9
19
  * the dispatcher emits the contract `error` event alongside rendering this. */
10
20
  export declare function CardFallback(props: CardFallbackProps): JSX.Element;
@@ -1,13 +1,74 @@
1
1
  import { JSX } from 'solid-js';
2
- import { CardEnvelope } from '../primitives/card-contract';
3
- import { CardComponentMap } from '../primitives/card-registry';
2
+ import { CardEnvelope } from '../primitives/card-contract.js';
3
+ import { CardComponentMap } from '../primitives/card-registry.js';
4
+ /**
5
+ * Consumer card schemas by envelope type: `{ 'pricing-table': pricingSchema }`.
6
+ *
7
+ * `object`, NOT `JsonSchema`, and that is measured rather than lazy. A real schema
8
+ * is either imported from a `.json` file — where TypeScript widens `"type": "object"`
9
+ * to `string`, which `JsonSchema`'s literal union rejects — or written out with the
10
+ * `$schema` / `title` / `description` / `additionalProperties` keywords that
11
+ * `JsonSchema` does not describe at all, which excess-property checking rejects.
12
+ * Both are the ordinary case, so the tighter type would make the normal way of
13
+ * supplying a schema a compile error. `src/schemas/index.ts` widens `CardSchema`
14
+ * for exactly this reason and says so at length (lines 92-110 there).
15
+ *
16
+ * The value is handed straight to `validateCardData`, which reads only the keywords
17
+ * `validateAgainstSchema` implements and ignores the rest.
18
+ */
19
+ export type CardSchemaMap = Record<string, object>;
4
20
  export interface CardRendererProps {
5
21
  envelope: CardEnvelope;
6
22
  /** Add/override type→component entries (merged over the built-ins). */
7
23
  types?: CardComponentMap;
24
+ /**
25
+ * JSON Schemas for the card types this app renders, keyed by `envelope.type`.
26
+ * `createCardRegistry(...).validationSchemas` is exactly this shape.
27
+ *
28
+ * The companion of `types`, and the half that was missing: `types` says WHAT
29
+ * draws a `pricing-table`, `schemas` says what a VALID one looks like. Without it
30
+ * the kit checks its own seven built-ins and leaves the developer's own card —
31
+ * the one the app actually cares about — as the only unvalidated thing on screen.
32
+ *
33
+ * A schema given here WINS over a built-in of the same name, matching
34
+ * `mergeCardComponents`, where the consumer's entry is spread over ours.
35
+ */
36
+ schemas?: CardSchemaMap;
37
+ /**
38
+ * Validate `envelope.data` against the built-in schema for `envelope.type` before
39
+ * rendering. Default `true`.
40
+ *
41
+ * ON IN PRODUCTION TOO, DELIBERATELY. The obvious alternative, stripping the check
42
+ * from production builds, inverts the point: a model emitting a bad shape is a
43
+ * production failure mode, so stripping it means the developer's USERS get the
44
+ * broken card while the developer's laptop looks fine. The cost is the projected
45
+ * schema data for all seven card types, measured by building this package twice
46
+ * (once with the projection stubbed to `{}`) rather than estimated: +834 B gzip on
47
+ * `dist/index.js` and +775 B gzip on the elements register bundle. That is below
48
+ * the noise floor of a package that already ships a Solid runtime and `marked`.
49
+ *
50
+ * Set `false` to opt out. A type with no schema at all — no built-in, and none
51
+ * supplied through `schemas` — is never validated either way.
52
+ */
53
+ validateCards?: boolean;
8
54
  }
55
+ /**
56
+ * True when the consumer registered a schema for this type.
57
+ *
58
+ * Spelled out rather than left to `validateCardData` because it is a GATE, not a
59
+ * lookup: a consumer schema is the one thing that authorises validating a renderer
60
+ * that is not ours. `hasOwnProperty` (not `in`) so a type named `toString` cannot
61
+ * pick up `Object.prototype`, and the `typeof` check so a `{ 'x': null }` entry
62
+ * reads as "not registered" instead of matching and then validating against
63
+ * nothing. The same predicate lives in elements/cards.tsx for `<kai-cards>`; the
64
+ * two dispatchers already duplicate this rule (they compare component identity vs
65
+ * tag identity), so keep them in step.
66
+ */
67
+ export declare function hasConsumerSchema(schemas: CardSchemaMap | undefined, type: string): boolean;
9
68
  export declare function CardRenderer(props: CardRendererProps): JSX.Element;
10
69
  /** Function sugar: renderCard(env) ≡ <CardRenderer envelope={env} />. */
11
70
  export declare function renderCard(envelope: CardEnvelope, opts?: {
12
71
  types?: CardComponentMap;
72
+ schemas?: CardSchemaMap;
73
+ validateCards?: boolean;
13
74
  }): JSX.Element;
@@ -16,4 +16,7 @@ export interface ChatContainerScrollAnchorProps extends JSX.HTMLAttributes<HTMLD
16
16
  ref?: HTMLDivElement | ((el: HTMLDivElement) => void);
17
17
  }
18
18
  declare function ChatContainerScrollAnchor(props: ChatContainerScrollAnchorProps): JSX.Element;
19
+ /** `ChatContainer` is the exported alias of `ChatContainerRoot`; its props type
20
+ * is aliased too, so the name a consumer imports always has a matching Props. */
21
+ export type ChatContainerProps = ChatContainerRootProps;
19
22
  export { ChatContainerRoot as ChatContainer, ChatContainerRoot, ChatContainerContent, ChatContainerScrollAnchor, };
@@ -1,5 +1,5 @@
1
- import { DropdownController } from '../ui/dropdown';
2
- import { SearchFilters } from '../types';
1
+ import { DropdownController } from '../ui/dropdown.js';
2
+ import { SearchFilters } from '../types.js';
3
3
  export interface ChatScopePickerProps {
4
4
  currentLabel: string;
5
5
  onScopeChange: (filters: SearchFilters | undefined) => void;