@kitn.ai/ui 0.20.0 → 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.
- package/README.md +44 -45
- package/dist/components/artifact-card.d.ts +51 -0
- package/dist/components/artifact.d.ts +1 -1
- package/dist/components/attachments.d.ts +2 -2
- package/dist/components/audio-visualizer/index.d.ts +3 -3
- package/dist/components/audio-visualizer/labs/lab-choreography.d.ts +59 -0
- package/dist/components/audio-visualizer/labs/lab-shaders.d.ts +22 -0
- package/dist/components/audio-visualizer/labs/lab-visualizer.d.ts +18 -0
- package/dist/components/audio-visualizer/variant-aurora.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-bar.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-custom.d.ts +2 -2
- package/dist/components/audio-visualizer/variant-grid.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-radial.d.ts +1 -1
- package/dist/components/audio-visualizer/variant-wave.d.ts +1 -1
- package/dist/components/card-fallback.d.ts +12 -2
- package/dist/components/card-renderer.d.ts +63 -2
- package/dist/components/chat-container.d.ts +3 -0
- package/dist/components/chat-scope-picker.d.ts +2 -2
- package/dist/components/chat-thread.d.ts +68 -18
- package/dist/components/choice-card.d.ts +3 -28
- package/dist/components/composer-dom.d.ts +1 -1
- package/dist/components/composer-highlight.d.ts +1 -1
- package/dist/components/composer-history.d.ts +1 -1
- package/dist/components/composer.d.ts +1 -1
- package/dist/components/confirm-card.d.ts +3 -18
- package/dist/components/context.d.ts +8 -4
- package/dist/components/conversation-item.d.ts +1 -1
- package/dist/components/conversation-list.d.ts +4 -3
- package/dist/components/embed.d.ts +3 -3
- package/dist/components/file-tree.d.ts +11 -22
- package/dist/components/form-widgets.d.ts +1 -1
- package/dist/components/form.d.ts +3 -44
- package/dist/components/link-preview.d.ts +3 -3
- package/dist/components/loader.d.ts +30 -48
- package/dist/components/message-skills.d.ts +4 -0
- package/dist/components/message.d.ts +84 -21
- package/dist/components/model-switcher.d.ts +2 -2
- package/dist/components/prompt-input.d.ts +2 -2
- package/dist/components/response-compare-types.d.ts +11 -2
- package/dist/components/response-compare.d.ts +3 -3
- package/dist/components/source.d.ts +12 -3
- package/dist/components/tasks-card.d.ts +3 -31
- package/dist/components/thread.d.ts +17 -5
- package/dist/components/toast.d.ts +2 -2
- package/dist/components/tool-classify.d.ts +8 -0
- package/dist/components/tool-types.d.ts +29 -1
- package/dist/components/tool.d.ts +3 -3
- package/dist/components/use-card-resolution.d.ts +1 -1
- package/dist/create-tween-D3Y5qiij.js +338 -0
- package/dist/create-tween-DGKY1FDY.js +341 -0
- package/dist/create-tween-paho5Rh-.js +7 -0
- package/dist/custom-elements.json +1681 -454
- package/dist/elements/agent-card.js +1 -1
- package/dist/elements/artifact.js +1 -1
- package/dist/elements/attachments.js +1 -1
- package/dist/elements/audio-visualizer.js +1 -1
- package/dist/elements/avatar.js +1 -1
- package/dist/elements/badge.js +1 -1
- package/dist/elements/button.js +1 -1
- package/dist/elements/card.js +1 -1
- package/dist/elements/cards.js +1 -1
- package/dist/elements/chain-of-thought.js +1 -1
- package/dist/elements/chat-scope-picker.js +1 -1
- package/dist/elements/chat-types.d.ts +70 -10
- package/dist/elements/chat-workspace.js +1 -1
- package/dist/elements/chat.js +1 -1
- package/dist/elements/checkpoint.js +1 -1
- package/dist/elements/choice.js +1 -1
- package/dist/elements/chunks/{Icon-Tj58ES_d.js → Icon-C-2LvGDG.js} +1 -1
- package/dist/elements/chunks/{action-icons-ns1Fnedj.js → action-icons-CaYoImEk.js} +1 -1
- package/dist/elements/chunks/arrow-left-Bb46H7w9.js +1 -0
- package/dist/elements/chunks/artifact-BBIscOxJ.js +1 -0
- package/dist/elements/chunks/{attachments-mCB5F1Fq.js → attachments-BB56zoji.js} +1 -1
- package/dist/elements/chunks/audio-visualizer-BxOx4THz.js +1 -0
- package/dist/elements/chunks/{badge-B4Zuajl2.js → badge-SxLSZ19R.js} +1 -1
- package/dist/elements/chunks/{button-ZWNif3--.js → button-CmkUkz6c.js} +1 -1
- package/dist/elements/chunks/card-renderer-Db4ffkWv.js +1 -0
- package/dist/elements/chunks/card-tags-D8lZ-C_U.js +1 -0
- package/dist/elements/chunks/chat-thread-B3Ks-cKr.js +1 -0
- package/dist/elements/chunks/check-C8desc_h.js +1 -0
- package/dist/elements/chunks/chevron-down-DKtc2HNB.js +1 -0
- package/dist/elements/chunks/chevron-right-Dw4GPhwL.js +1 -0
- package/dist/elements/chunks/choice-card-Q9cYYDyM.js +1 -0
- package/dist/elements/chunks/circle-BeokBsvB.js +1 -0
- package/dist/elements/chunks/circle-check-wJSqt859.js +1 -0
- package/dist/elements/chunks/{circle-x-B7faJFlY.js → circle-x-D0MEfxOM.js} +1 -1
- package/dist/elements/chunks/code-block-C8VzAraE.js +1 -0
- package/dist/elements/chunks/{collapsible-DM1Ckd4e.js → collapsible-Cvj61obE.js} +1 -1
- package/dist/elements/chunks/{composer-BguS0QL_.js → composer-D86ztyL0.js} +2 -2
- package/dist/elements/chunks/confirm-card-BdyDAGLw.js +1 -0
- package/dist/elements/chunks/context-WHDl-xSx.js +1 -0
- package/dist/elements/chunks/conversation-list-CdR14_Y4.js +1 -0
- package/dist/elements/chunks/create-tween-C_A_B638.js +7 -0
- package/dist/elements/chunks/{default-input-Cqqilg9t.js → default-input-CSZqUM81.js} +1 -1
- package/dist/elements/chunks/define-BzPnNsXg.js +1 -0
- package/dist/elements/chunks/{disclosure-CIZ5c8nO.js → disclosure-DVKsoc1F.js} +1 -1
- package/dist/elements/chunks/{download-Dsbg3ste.js → download-BjA54IMJ.js} +1 -1
- package/dist/elements/chunks/{dropdown-BDd1-Zgi.js → dropdown-BjVVHWXH.js} +1 -1
- package/dist/elements/chunks/{ellipsis-Dw6qrss-.js → ellipsis-BNedmqfi.js} +1 -1
- package/dist/elements/chunks/embed-DQsl4XEq.js +1 -0
- package/dist/elements/chunks/{external-link-Vt74zAoL.js → external-link-Di-dw2CU.js} +1 -1
- package/dist/elements/chunks/{file-text-CZrZF6_v.js → file-text-B3sAODCV.js} +1 -1
- package/dist/elements/chunks/{file-tree-DF4okKyo.js → file-tree-Dgto-bMn.js} +1 -1
- package/dist/elements/chunks/{folder-glP5rha4.js → folder-D6rMadFV.js} +1 -1
- package/dist/elements/chunks/form-CILxvhQ7.js +1 -0
- package/dist/elements/chunks/hover-card-BtiF4XiU.js +1 -0
- package/dist/elements/chunks/{icon-BLb8beoi.js → icon-DKkmze3y.js} +1 -1
- package/dist/elements/chunks/{info-CIsv92JK.js → info-CWRjZkuy.js} +1 -1
- package/dist/elements/chunks/{input-Dds1kFyt.js → input--QJBK6BA.js} +1 -1
- package/dist/elements/chunks/{kbd-De_xbgi9.js → kbd-C3zuKh8R.js} +1 -1
- package/dist/elements/chunks/{link-i4r_k7z4.js → link-BL5JA7Q0.js} +1 -1
- package/dist/elements/chunks/link-preview-CU37bbXh.js +1 -0
- package/dist/elements/chunks/{loader-BmQH4s3V.js → loader-XmpyxyRH.js} +1 -1
- package/dist/elements/chunks/{markdown-Zi21WhUz.js → markdown-3Gv5UZ_o.js} +1 -1
- package/dist/elements/chunks/message-CnBA2OUt.js +1 -0
- package/dist/elements/chunks/message-X5NZbq-W.js +1 -0
- package/dist/elements/chunks/message-square-CnpAm_P0.js +1 -0
- package/dist/elements/chunks/{minimize-2--ifeCGrl.js → minimize-2-DwyrUTcM.js} +1 -1
- package/dist/elements/chunks/{model-switcher-B94YAKsM.js → model-switcher-CclaJEHt.js} +1 -1
- package/dist/elements/chunks/{overlay-kD8dwRv_.js → overlay-Cepd-KcS.js} +1 -1
- package/dist/elements/chunks/{paperclip-q21dYOSK.js → paperclip-CdwKjrlu.js} +1 -1
- package/dist/elements/chunks/{progress-bar-BrAIIaaJ.js → progress-bar-DMVXBD3b.js} +1 -1
- package/dist/elements/chunks/{prompt-suggestion-Bjn2K-fR.js → prompt-suggestion-Di_WZE_5.js} +1 -1
- package/dist/elements/chunks/reasoning-D0jMch5u.js +1 -0
- package/dist/elements/chunks/{resizable-Dp4JExql.js → resizable-1znbL1Gv.js} +1 -1
- package/dist/elements/chunks/{rotate-cw-CFWWkpj2.js → rotate-cw-DVhhgx8n.js} +1 -1
- package/dist/elements/chunks/{scroll-area-Bb0kHH1j.js → scroll-area-Bs4bFS1P.js} +1 -1
- package/dist/elements/chunks/scroll-button-Bet5NLc4.js +1 -0
- package/dist/elements/chunks/{separator-9kRgr1X9.js → separator-C5Gh8qGC.js} +1 -1
- package/dist/elements/chunks/{settings-B8lmec4D.js → settings-5vmEFg0K.js} +1 -1
- package/dist/elements/chunks/{settings-group-I0hEuXiN.js → settings-group-BWLB38kz.js} +1 -1
- package/dist/elements/chunks/{share-C3lTiYGt.js → share-BZ3G_DaB.js} +1 -1
- package/dist/elements/chunks/skeleton-DafPJQTp.js +1 -0
- package/dist/elements/chunks/slots-CIw9RlAe.js +1 -0
- package/dist/elements/chunks/source-D_qj_6uJ.js +1 -0
- package/dist/elements/chunks/{star-CSJtGxgv.js → star-Cuv7j2IE.js} +1 -1
- package/dist/elements/chunks/{store-CHyW95TP.js → store-C1StPHfW.js} +1 -1
- package/dist/elements/chunks/tasks-card-EyoBZfpA.js +1 -0
- package/dist/elements/chunks/{text-shimmer-Cn9TmNpI.js → text-shimmer-D9gRSh34.js} +1 -1
- package/dist/elements/chunks/textarea-DuhtHfcm.js +1 -0
- package/dist/elements/chunks/{thumbs-up-PNVVThEF.js → thumbs-up-B9hwv43w.js} +1 -1
- package/dist/elements/chunks/{toast-store-DKbQn3Wn.js → toast-store-Bm3DUEDe.js} +1 -1
- package/dist/elements/chunks/{tool-DjTRpIpl.js → tool-CDtW7L0z.js} +1 -1
- package/dist/elements/chunks/tooltip-eB226mGK.js +1 -0
- package/dist/elements/chunks/{triangle-alert-DsHTHCPm.js → triangle-alert-C1SNzTqK.js} +1 -1
- package/dist/elements/chunks/use-card-resolution-YZh2MvI5.js +1 -0
- package/dist/elements/chunks/{variant-aurora-Dc4nQUia.js → variant-aurora-Cj1F7D0l.js} +2 -2
- package/dist/elements/chunks/{variant-custom-y_3kVQhS.js → variant-custom-T9gpt7QE.js} +1 -1
- package/dist/elements/chunks/{variant-wave-D5OR1-9Z.js → variant-wave-CxU9z-TE.js} +2 -2
- package/dist/elements/chunks/{video-B7vmenoC.js → video-CK4R7Rus.js} +1 -1
- package/dist/elements/chunks/x-D1qx0aLd.js +1 -0
- package/dist/elements/coachmark.js +1 -1
- package/dist/elements/code-block.js +1 -1
- package/dist/elements/command.js +1 -1
- package/dist/elements/compare.js +1 -1
- package/dist/elements/composer.js +1 -1
- package/dist/elements/confirm-card.js +1 -1
- package/dist/elements/context-meter.js +1 -1
- package/dist/elements/conversation-list.js +1 -1
- package/dist/elements/default-input.d.ts +7 -7
- package/dist/elements/define.d.ts +1 -0
- package/dist/elements/dialog.js +1 -1
- package/dist/elements/disclosure.d.ts +1 -1
- package/dist/elements/editable-label.js +1 -1
- package/dist/elements/element-data-types.d.ts +107 -0
- package/dist/elements/embed.js +1 -1
- package/dist/elements/empty.js +1 -1
- package/dist/elements/feedback-bar.js +1 -1
- package/dist/elements/file-tree.js +1 -1
- package/dist/elements/file-upload.js +1 -1
- package/dist/elements/form.js +1 -1
- package/dist/elements/hover-card.js +1 -1
- package/dist/elements/icon.js +1 -1
- package/dist/elements/image.js +1 -1
- package/dist/elements/input.js +1 -1
- package/dist/elements/kbd.js +1 -1
- package/dist/elements/link-preview.js +1 -1
- package/dist/elements/loader.js +1 -1
- package/dist/elements/markdown.js +1 -1
- package/dist/elements/menu.js +1 -1
- package/dist/elements/message-skills.js +1 -1
- package/dist/elements/message.js +1 -1
- package/dist/elements/model-switcher.js +1 -1
- package/dist/elements/nav.js +1 -1
- package/dist/elements/notice.js +1 -1
- package/dist/elements/pane-group.js +1 -1
- package/dist/elements/pane.js +1 -1
- package/dist/elements/popover.js +1 -1
- package/dist/elements/progress-bar.js +1 -1
- package/dist/elements/prompt-dock.js +1 -1
- package/dist/elements/prompt-input.js +1 -1
- package/dist/elements/prompt-suggestions.js +1 -1
- package/dist/elements/reasoning.js +1 -1
- package/dist/elements/register.d.ts +8 -6
- package/dist/elements/remote.js +1 -1
- package/dist/elements/resizable.js +1 -1
- package/dist/elements/response-stream.js +2 -2
- package/dist/elements/screen.js +1 -1
- package/dist/elements/scroll-area.js +1 -1
- package/dist/elements/scroll-button.js +1 -1
- package/dist/elements/search.js +1 -1
- package/dist/elements/segmented.js +1 -1
- package/dist/elements/separator.js +1 -1
- package/dist/elements/setting-item.js +1 -1
- package/dist/elements/settings-group.js +1 -1
- package/dist/elements/skeleton.js +1 -1
- package/dist/elements/slots.d.ts +16 -0
- package/dist/elements/source.js +1 -1
- package/dist/elements/status.js +1 -1
- package/dist/elements/switch.js +1 -1
- package/dist/elements/tabs.js +1 -1
- package/dist/elements/tasks.js +1 -1
- package/dist/elements/text-shimmer.js +1 -1
- package/dist/elements/thinking-bar.js +1 -1
- package/dist/elements/thread.js +1 -1
- package/dist/elements/toast.js +1 -1
- package/dist/elements/tool.js +1 -1
- package/dist/elements/tooltip.js +1 -1
- package/dist/elements/validate-messages.d.ts +25 -0
- package/dist/elements/voice-input.js +1 -1
- package/dist/elements/voice-output.js +1 -1
- package/dist/elements.d.ts +2725 -214
- package/dist/index.d.ts +163 -125
- package/dist/index.js +6336 -5802
- package/dist/index.server.d.ts +5 -0
- package/dist/index.server.js +16913 -0
- package/dist/kai-provider.es.d.ts +5 -0
- package/dist/kai-provider.es.js +79 -77
- package/dist/kai.es.d.ts +5 -0
- package/dist/kai.es.js +1 -1
- package/dist/llms/llms-full.txt +762 -148
- package/dist/llms/llms.txt +57 -5
- package/dist/mcp.es.js +4010 -770
- package/dist/primitives/card-component-types.d.ts +11 -0
- package/dist/primitives/card-data-types.d.ts +196 -0
- package/dist/primitives/card-host.d.ts +1 -1
- package/dist/primitives/card-recovery.d.ts +3 -3
- package/dist/primitives/card-registry.d.ts +4 -14
- package/dist/primitives/card-resolution.d.ts +1 -1
- package/dist/primitives/card-routing.d.ts +1 -1
- package/dist/primitives/card-tags.d.ts +11 -0
- package/dist/primitives/card-validate-cards.d.ts +57 -0
- package/dist/primitives/card-validate-generator.testlib.d.ts +20 -0
- package/dist/primitives/card-validate-schemas.d.ts +17 -0
- package/dist/primitives/card-validate.d.ts +24 -0
- package/dist/primitives/create-kai-chat.d.ts +3 -3
- package/dist/primitives/embed-providers.d.ts +1 -1
- package/dist/primitives/link-preview.d.ts +1 -1
- package/dist/primitives/message-feedback.d.ts +2 -2
- package/dist/primitives/toast-store.d.ts +1 -1
- package/dist/react/index.d.ts +717 -299
- package/dist/react/use-kai-chat.d.ts +8 -4
- package/dist/react.d.ts +5 -0
- package/dist/react.js +417 -316
- package/dist/register-impl-bzrZ44ft.js +145 -0
- package/dist/remote/host-embed.d.ts +1 -1
- package/dist/remote/index.d.ts +2 -2
- package/dist/remote/provider-runtime.d.ts +2 -2
- package/dist/remote/provider.d.ts +2 -2
- package/dist/remote/validate.d.ts +1 -1
- package/dist/remote/wire.d.ts +1 -1
- package/dist/schemas/artifact.schema.json +92 -0
- package/dist/schemas/embed.schema.json +0 -2
- package/dist/schemas/from-tool-call.d.ts +48 -0
- package/dist/schemas/index.d.ts +48 -0
- package/dist/schemas/link.schema.json +0 -2
- package/dist/schemas/provider-subsets.d.ts +136 -0
- package/dist/schemas/registry.d.ts +140 -0
- package/dist/schemas/tool-defs.d.ts +121 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.js +717 -0
- package/dist/solid-BCJUQqwS.js +22750 -0
- package/dist/solid-BdENBcEq.js +20108 -0
- package/dist/solid.d.ts +66 -0
- package/dist/solid.js +261 -0
- package/dist/solid.server.d.ts +5 -0
- package/dist/solid.server.js +261 -0
- package/dist/state/index.d.ts +14 -4
- package/dist/state/messages.d.ts +8 -3
- package/dist/state/mock.d.ts +46 -0
- package/dist/state/parts.d.ts +85 -0
- package/dist/state/stream.d.ts +15 -9
- package/dist/state.d.ts +5 -0
- package/dist/state.js +253 -84
- package/dist/ui/action-icons.d.ts +1 -1
- package/dist/ui/collapsible.d.ts +11 -6
- package/dist/ui/dropdown.d.ts +47 -42
- package/dist/ui/pane-group.d.ts +1 -1
- package/dist/variant-aurora-1wMcXRUS.js +381 -0
- package/dist/variant-aurora-BKHHiOgL.js +391 -0
- package/dist/{variant-aurora-DVtGqVH6.js → variant-aurora-DOb_o4pC.js} +1 -1
- package/dist/{variant-custom-Dif-IV4u.js → variant-custom-CJGB0Kbw.js} +1 -1
- package/dist/variant-custom-Co0CkXJF.js +200 -0
- package/dist/variant-custom-DWSSgmd2.js +170 -0
- package/dist/variant-wave-C3-45cL6.js +218 -0
- package/dist/{variant-wave-DbfNdvSi.js → variant-wave-CEODq-9q.js} +1 -1
- package/dist/variant-wave-jdXBnCUZ.js +208 -0
- package/dist/wire/chunk.d.ts +171 -0
- package/dist/wire/consume.d.ts +26 -0
- package/dist/wire/encode.d.ts +148 -0
- package/dist/wire/formats/anthropic.d.ts +2 -0
- package/dist/wire/formats/openai.d.ts +5 -0
- package/dist/wire/index.d.ts +14 -0
- package/dist/wire/read.d.ts +26 -0
- package/dist/wire/sink-helpers.d.ts +21 -0
- package/dist/wire/sse.d.ts +33 -0
- package/dist/wire.d.ts +5 -53
- package/dist/wire.js +898 -0
- package/frameworks/react/index.tsx +183 -154
- package/frameworks/react/runtime.tsx +21 -1
- package/frameworks/react/use-kai-chat.tsx +11 -1
- package/llms-full.txt +762 -148
- package/llms.txt +57 -5
- package/package.json +65 -7
- package/src/agent-tooling/archetypes.ts +96 -0
- package/src/agent-tooling/integrations/anthropic.ts +412 -0
- package/src/agent-tooling/integrations/cloudflare.ts +136 -52
- package/src/agent-tooling/integrations/langgraph.ts +67 -13
- package/src/agent-tooling/integrations/mastra.ts +120 -12
- package/src/agent-tooling/integrations/mock.ts +43 -8
- package/src/agent-tooling/integrations/ollama.ts +61 -24
- package/src/agent-tooling/integrations/openai.ts +87 -0
- package/src/agent-tooling/integrations/openrouter.ts +56 -8
- package/src/agent-tooling/integrations/pi.ts +79 -23
- package/src/agent-tooling/integrations/pydantic-ai.ts +24 -2
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +84 -13
- package/src/agent-tooling/mcp/manifest.ts +206 -25
- package/src/agent-tooling/mcp/tools/debug.ts +13 -7
- package/src/agent-tooling/mcp/tools/reference.ts +285 -6
- package/src/agent-tooling/mcp/tools/scaffold.ts +3345 -675
- package/src/agent-tooling/registry.ts +17 -0
- package/src/agent-tooling/types.ts +229 -1
- package/src/components/artifact-card.tsx +120 -0
- package/src/components/audio-visualizer/index.tsx +9 -0
- package/src/components/audio-visualizer/labs/lab-choreography.ts +187 -0
- package/src/components/audio-visualizer/labs/lab-shaders.ts +363 -0
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +102 -0
- package/src/components/audio-visualizer/shader-canvas.tsx +31 -1
- package/src/components/card-fallback.tsx +42 -10
- package/src/components/card-renderer.tsx +146 -9
- package/src/components/chat-container.tsx +4 -0
- package/src/components/chat-thread.tsx +118 -51
- package/src/components/choice-card.tsx +17 -29
- package/src/components/composer.tsx +12 -2
- package/src/components/confirm-card.tsx +24 -20
- package/src/components/context.tsx +12 -4
- package/src/components/conversation-list.tsx +18 -2
- package/src/components/file-tree.tsx +11 -22
- package/src/components/file-upload.tsx +14 -8
- package/src/components/form.tsx +14 -47
- package/src/components/loader.tsx +39 -12
- package/src/components/message-skills.tsx +4 -0
- package/src/components/message.tsx +294 -46
- package/src/components/reasoning.tsx +92 -5
- package/src/components/response-compare-types.ts +25 -0
- package/src/components/response-compare.tsx +4 -9
- package/src/components/source.tsx +50 -24
- package/src/components/tasks-card.tsx +10 -33
- package/src/components/thread.tsx +84 -42
- package/src/components/toast.tsx +11 -5
- package/src/components/tool-classify.ts +26 -0
- package/src/components/tool-types.ts +31 -1
- package/src/elements/agent-card.tsx +11 -11
- package/src/elements/artifact.tsx +15 -7
- package/src/elements/attachments.tsx +6 -4
- package/src/elements/avatar.tsx +1 -1
- package/src/elements/button.tsx +3 -3
- package/src/elements/card.tsx +2 -2
- package/src/elements/cards.tsx +109 -14
- package/src/elements/chain-of-thought.tsx +14 -10
- package/src/elements/chat-scope-picker.tsx +9 -7
- package/src/elements/chat-types.ts +59 -6
- package/src/elements/chat-workspace.tsx +50 -9
- package/src/elements/chat.tsx +64 -3
- package/src/elements/choice.tsx +8 -8
- package/src/elements/coachmark.tsx +1 -1
- package/src/elements/command.tsx +8 -23
- package/src/elements/compare.tsx +7 -6
- package/src/elements/compiled.css +1 -1
- package/src/elements/composer.tsx +8 -8
- package/src/elements/confirm-card.tsx +9 -9
- package/src/elements/context-meter.tsx +4 -18
- package/src/elements/conversation-list.tsx +14 -9
- package/src/elements/default-input.tsx +3 -3
- package/src/elements/define.tsx +178 -43
- package/src/elements/editable-label.tsx +17 -2
- package/src/elements/element-data-types.ts +112 -0
- package/src/elements/element-meta.json +1596 -304
- package/src/elements/element-types.d.ts +2636 -211
- package/src/elements/feedback-bar.tsx +1 -1
- package/src/elements/file-tree.tsx +1 -1
- package/src/elements/file-upload.tsx +1 -1
- package/src/elements/form.tsx +14 -6
- package/src/elements/input.tsx +1 -1
- package/src/elements/kbd.tsx +1 -1
- package/src/elements/menu.tsx +10 -29
- package/src/elements/message-skills.tsx +7 -9
- package/src/elements/message.tsx +200 -32
- package/src/elements/model-switcher.tsx +5 -3
- package/src/elements/pane.tsx +1 -1
- package/src/elements/prompt-dock.tsx +8 -8
- package/src/elements/prompt-input.tsx +10 -10
- package/src/elements/prompt-suggestions.tsx +7 -4
- package/src/elements/reasoning.tsx +1 -1
- package/src/elements/register.ts +9 -0
- package/src/elements/resizable.globals.d.ts +36 -0
- package/src/elements/resizable.tsx +24 -13
- package/src/elements/response-stream.tsx +1 -1
- package/src/elements/scroll-button.tsx +1 -1
- package/src/elements/search.tsx +6 -1
- package/src/elements/segmented.tsx +5 -11
- package/src/elements/separator.tsx +1 -1
- package/src/elements/slots.ts +57 -24
- package/src/elements/source.tsx +21 -22
- package/src/elements/switch.tsx +3 -3
- package/src/elements/tasks.tsx +5 -4
- package/src/elements/thread.tsx +36 -4
- package/src/elements/toast.tsx +3 -2
- package/src/elements/tool.tsx +1 -1
- package/src/elements/validate-messages.ts +76 -0
- package/src/elements/voice-input.tsx +7 -7
- package/src/elements/voice-output.tsx +4 -4
- package/src/index.ts +141 -6
- package/src/primitives/card-component-types.ts +63 -0
- package/src/primitives/card-data-types.ts +312 -0
- package/src/primitives/card-recovery.ts +13 -2
- package/src/primitives/card-registry.tsx +34 -23
- package/src/primitives/card-schemas/artifact.schema.json +92 -0
- package/src/primitives/card-schemas/embed.schema.json +0 -2
- package/src/primitives/card-schemas/link.schema.json +0 -2
- package/src/primitives/card-tags.ts +61 -0
- package/src/primitives/card-validate-cards.ts +255 -0
- package/src/primitives/card-validate-generator.testlib.ts +38 -0
- package/src/primitives/card-validate-schemas.ts +58 -0
- package/src/primitives/card-validate.ts +48 -20
- package/src/primitives/create-tween.ts +54 -2
- package/src/primitives/message-feedback.ts +3 -2
- package/src/primitives/use-audio-analysis.ts +20 -1
- package/src/primitives/use-sequencer.ts +20 -1
- package/src/schemas/from-tool-call.ts +151 -0
- package/src/schemas/index.ts +340 -0
- package/src/schemas/provider-subsets.ts +538 -0
- package/src/schemas/registry.ts +355 -0
- package/src/schemas/tool-defs.ts +492 -0
- package/src/solid.ts +150 -0
- package/src/state/index.ts +27 -1
- package/src/state/messages.ts +21 -4
- package/src/state/mock.ts +211 -0
- package/src/state/parts.ts +295 -0
- package/src/state/stream.ts +56 -58
- package/src/ui/collapsible.tsx +17 -5
- package/src/ui/dropdown.tsx +46 -12
- package/src/ui/overlay.tsx +10 -4
- package/src/wire/chunk.ts +201 -0
- package/src/wire/consume.ts +440 -0
- package/src/wire/encode.ts +474 -0
- package/src/wire/formats/anthropic.ts +267 -0
- package/src/wire/formats/openai.ts +187 -0
- package/src/wire/index.ts +52 -0
- package/src/wire/read.ts +152 -0
- package/src/wire/sink-helpers.ts +50 -0
- package/src/wire/sse.ts +140 -0
- package/dist/create-tween-hvpmSuwW.js +0 -7
- package/dist/elements/chunks/arrow-left-DQocUFvy.js +0 -1
- package/dist/elements/chunks/audio-visualizer-BqNy7dfm.js +0 -1
- package/dist/elements/chunks/card-BkHbp4BA.js +0 -1
- package/dist/elements/chunks/chat-thread-CkRN6pZ7.js +0 -1
- package/dist/elements/chunks/check-B9-gn6SS.js +0 -1
- package/dist/elements/chunks/chevron-down-BNsxc2hk.js +0 -1
- package/dist/elements/chunks/chevron-right-Hv00StBO.js +0 -1
- package/dist/elements/chunks/circle-0e3KJTDr.js +0 -1
- package/dist/elements/chunks/circle-check-BNAS0JEy.js +0 -1
- package/dist/elements/chunks/code-block-BFUHn6Va.js +0 -1
- package/dist/elements/chunks/context-Cb7k4F-v.js +0 -1
- package/dist/elements/chunks/conversation-list-CvoAkWhN.js +0 -1
- package/dist/elements/chunks/create-tween-oVvAIG8r.js +0 -7
- package/dist/elements/chunks/define-D1din7Ld.js +0 -1
- package/dist/elements/chunks/hover-card-Cmm6Q53m.js +0 -1
- package/dist/elements/chunks/message-BqyXDN3-.js +0 -1
- package/dist/elements/chunks/message-feedback-Djr3z6Yb.js +0 -1
- package/dist/elements/chunks/message-square-vFAgbDaX.js +0 -1
- package/dist/elements/chunks/reasoning-DTpCGtnY.js +0 -1
- package/dist/elements/chunks/scroll-button-B0cH5fXf.js +0 -1
- package/dist/elements/chunks/skeleton-DSXW5Yya.js +0 -1
- package/dist/elements/chunks/slots--V19HwUb.js +0 -1
- package/dist/elements/chunks/textarea-CUwqAX0G.js +0 -1
- package/dist/elements/chunks/tooltip-CgBZCVKp.js +0 -1
- package/dist/elements/chunks/use-card-resolution-BSu_XHjH.js +0 -1
- package/dist/elements/chunks/x-GRUeeQFT.js +0 -1
- package/dist/host-embed.d.ts +0 -33
- package/dist/kai-provider.d.ts +0 -2
- package/dist/origin.d.ts +0 -5
- package/dist/provider-runtime.d.ts +0 -27
- package/dist/register-impl-DQyejdfb.js +0 -145
- package/dist/validate.d.ts +0 -4
- package/dist/version.d.ts +0 -4
- package/src/components/component-meta.json +0 -4550
- package/src/elements/card-media.jpg +0 -0
- package/src/elements/resizable.d.ts +0 -27
- package/src/elements/video-poster.jpg +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
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
|
+
|
|
14
|
+
/** Value-noise fbm. Non-integer lacunarity so octaves do not align into grids. */
|
|
15
|
+
const NOISE = `
|
|
16
|
+
float labHash(vec2 q) {
|
|
17
|
+
return fract(sin(dot(q, vec2(127.1, 311.7))) * 43758.5453);
|
|
18
|
+
}
|
|
19
|
+
float labNoise(vec2 q) {
|
|
20
|
+
vec2 i = floor(q);
|
|
21
|
+
vec2 f = fract(q);
|
|
22
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
23
|
+
float a = labHash(i);
|
|
24
|
+
float b = labHash(i + vec2(1.0, 0.0));
|
|
25
|
+
float c = labHash(i + vec2(0.0, 1.0));
|
|
26
|
+
float d = labHash(i + vec2(1.0, 1.0));
|
|
27
|
+
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
|
|
28
|
+
}
|
|
29
|
+
float labFbm(vec2 q) {
|
|
30
|
+
float sum = 0.0;
|
|
31
|
+
float amp = 0.5;
|
|
32
|
+
for (int i = 0; i < 4; i++) {
|
|
33
|
+
sum += amp * labNoise(q);
|
|
34
|
+
q *= 2.03;
|
|
35
|
+
amp *= 0.5;
|
|
36
|
+
}
|
|
37
|
+
return sum;
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Fractal lightning: five sites firing on independent rhythms; each firing
|
|
43
|
+
* strikes a noise-displaced arc (re-seeded per strike, so no two bolts share
|
|
44
|
+
* a shape) plus a fainter fork, from its previous site to its new one.
|
|
45
|
+
*/
|
|
46
|
+
const LIGHTNING = `
|
|
47
|
+
float labSegDist(vec2 q, vec2 a, vec2 b) {
|
|
48
|
+
vec2 ab = b - a;
|
|
49
|
+
float h = clamp(dot(q - a, ab) / max(dot(ab, ab), 1.0e-6), 0.0, 1.0);
|
|
50
|
+
return length(q - a - ab * h);
|
|
51
|
+
}
|
|
52
|
+
vec2 labSparkPos(float k, float i, float R) {
|
|
53
|
+
float h1 = labHash(vec2(k * 7.31 + 1.13, i * 3.71 + 0.17));
|
|
54
|
+
float h2 = labHash(vec2(i * 9.13 + 2.29, k * 5.77 + 0.53));
|
|
55
|
+
float av = 6.2831853 * h1;
|
|
56
|
+
float rad = R * 0.85 * sqrt(h2);
|
|
57
|
+
return vec2(cos(av), sin(av)) * rad;
|
|
58
|
+
}
|
|
59
|
+
float labBolt(vec2 q, vec2 A, vec2 B, float seed, float R, float life) {
|
|
60
|
+
vec2 ab = B - A;
|
|
61
|
+
float len = max(length(ab), 1.0e-4);
|
|
62
|
+
vec2 dir = ab / len;
|
|
63
|
+
vec2 nrm = vec2(-dir.y, dir.x);
|
|
64
|
+
vec2 w = q - A;
|
|
65
|
+
float u = dot(w, dir) / len;
|
|
66
|
+
float v = dot(w, nrm);
|
|
67
|
+
if (u < -0.05 || u > 1.05 || abs(v) > R * 0.30) return 0.0;
|
|
68
|
+
float uu = clamp(u, 0.0, 1.0);
|
|
69
|
+
float taper = sin(uu * 3.14159265);
|
|
70
|
+
float off1 = (labFbm(vec2(uu * 9.0 + seed * 13.1, seed * 7.7)) - 0.5) * 0.55 * uBoltJag;
|
|
71
|
+
float off2 = (labFbm(vec2(uu * 23.0 + seed * 5.3, seed * 3.9 + 4.2)) - 0.5) * 0.22 * uBoltJag;
|
|
72
|
+
float mainArc = abs(v - (off1 + off2) * len * taper);
|
|
73
|
+
float forkArc = abs(v - (off1 * 0.6 - off2 * 1.8) * len * taper);
|
|
74
|
+
float wdt = R * (0.006 + 0.010 * life) * uBoltWidth;
|
|
75
|
+
float bolt = exp(-pow(mainArc / wdt, 2.0))
|
|
76
|
+
+ 0.45 * exp(-pow(mainArc / (wdt * 3.0), 2.0))
|
|
77
|
+
+ 0.5 * exp(-pow(forkArc / (wdt * 0.8), 2.0))
|
|
78
|
+
+ 0.25 * exp(-pow(forkArc / (wdt * 2.5), 2.0));
|
|
79
|
+
return bolt * taper;
|
|
80
|
+
}
|
|
81
|
+
float labNeural(vec2 q, float t, float R) {
|
|
82
|
+
if (uNeural < 0.01) return 0.0;
|
|
83
|
+
float acc = 0.0;
|
|
84
|
+
for (int k = 0; k < 5; k++) {
|
|
85
|
+
float fk = float(k);
|
|
86
|
+
float period = (1.1 + 1.3 * labHash(vec2(fk, 3.3))) / max(uBoltRate, 0.05);
|
|
87
|
+
float cyc = t / period + labHash(vec2(fk, 7.7)) * 7.0;
|
|
88
|
+
float i = floor(cyc);
|
|
89
|
+
float life = fract(cyc);
|
|
90
|
+
float env = smoothstep(0.0, 0.04, life) * exp(-5.0 * life);
|
|
91
|
+
if (env >= 0.004) {
|
|
92
|
+
vec2 pos = labSparkPos(fk, i, R);
|
|
93
|
+
vec2 prev = labSparkPos(fk, i - 1.0, R);
|
|
94
|
+
float seed = labHash(vec2(fk * 3.1, i * 1.7));
|
|
95
|
+
float bolt = labBolt(q, prev, pos, seed, R, life) * env;
|
|
96
|
+
vec2 dp = q - pos;
|
|
97
|
+
vec2 dq = q - prev;
|
|
98
|
+
float tips = (exp(-dot(dp, dp) / (2.0 * R * R * 0.0016))
|
|
99
|
+
+ 0.6 * exp(-dot(dq, dq) / (2.0 * R * R * 0.0012))) * env;
|
|
100
|
+
acc += bolt * 1.2 + tips * 0.8;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return acc * uNeural;
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
/** Super-gaussian stroke: flat solid core, fast but feathered falloff. */
|
|
108
|
+
const STROKE = `
|
|
109
|
+
float labStroke(float d, float sigma) {
|
|
110
|
+
float q = d / sigma;
|
|
111
|
+
float q2 = q * q;
|
|
112
|
+
float core = exp(-q2 * q2);
|
|
113
|
+
float bq = d / (sigma * uBloomMul);
|
|
114
|
+
float bloom = exp(-bq * bq) * uBloomGain;
|
|
115
|
+
return core + bloom;
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
/** Shared ring color pipeline: accent brightness ramp with a capped white lift. */
|
|
120
|
+
const RING_COLOR = `
|
|
121
|
+
vec4 labRingColor(float glow, float bfloor, float bscale, float wcap, vec2 fragCoord) {
|
|
122
|
+
float bright = bfloor + bscale * min(glow, 1.2);
|
|
123
|
+
float white = smoothstep(uWhiteLo, uWhiteHi, glow) * wcap;
|
|
124
|
+
vec3 col = mix(uColor * bright, vec3(1.0), white);
|
|
125
|
+
float alpha = clamp(glow, 0.0, 1.0);
|
|
126
|
+
float n = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);
|
|
127
|
+
alpha = clamp(alpha + (n - 0.5) / 255.0, 0.0, 1.0);
|
|
128
|
+
return vec4(col * alpha, alpha);
|
|
129
|
+
}
|
|
130
|
+
`;
|
|
131
|
+
|
|
132
|
+
/** Three woven strands sharing one wave family; pileups soft-compressed. */
|
|
133
|
+
export const BRAID_FRAGMENT = `${STROKE}${RING_COLOR}
|
|
134
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
135
|
+
vec2 hres = iResolution.xy * 0.5;
|
|
136
|
+
vec2 p = (fragCoord - hres) / hres.y;
|
|
137
|
+
float r = length(p);
|
|
138
|
+
float th = atan(p.y, p.x);
|
|
139
|
+
float t = uT;
|
|
140
|
+
|
|
141
|
+
float amp = uAmpIdle + uAmpVoice * uLvl;
|
|
142
|
+
float baseR = uBaseR + uRadVoice * uLvl;
|
|
143
|
+
float env = 0.62 + 0.38 * sin(th * 2.0 + t * uEnvSpd + 2.0);
|
|
144
|
+
|
|
145
|
+
float glow = 0.0;
|
|
146
|
+
for (int i = 0; i < 3; i++) {
|
|
147
|
+
float fi = float(i);
|
|
148
|
+
float a = th + fi * uDelta;
|
|
149
|
+
float tt = t + fi * 1.3;
|
|
150
|
+
float wob = sin(a * uF1 + tt * uS1) * 0.55 + sin(a * uF2 - tt * uS2) * 0.45;
|
|
151
|
+
float ampi = amp * (0.65 + 0.35 * fi);
|
|
152
|
+
float sepMod = 0.5 + 0.5 * sin(th + t * uSepSpd + fi * 1.9);
|
|
153
|
+
float ringR = baseR + (fi - 1.0) * uOff * (0.35 + 1.5 * sepMod) + wob * ampi * env;
|
|
154
|
+
glow += uGain * (0.8 + 0.35 * env) * labStroke(abs(r - ringR), uSigma);
|
|
155
|
+
}
|
|
156
|
+
// three overlapping strands can sum past every threshold; compress so
|
|
157
|
+
// crossings brighten without blowing out to a solid white tube
|
|
158
|
+
glow = glow / (1.0 + 0.35 * glow);
|
|
159
|
+
fragColor = labRingColor(glow, 0.55, 0.65, 0.45, fragCoord);
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
/** One ribbon whose width pinches to zero at traveling twist points. */
|
|
164
|
+
export const RIBBON_FRAGMENT = `${STROKE}${RING_COLOR}
|
|
165
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
166
|
+
vec2 hres = iResolution.xy * 0.5;
|
|
167
|
+
vec2 p = (fragCoord - hres) / hres.y;
|
|
168
|
+
float r = length(p);
|
|
169
|
+
float th = atan(p.y, p.x);
|
|
170
|
+
float t = uT;
|
|
171
|
+
|
|
172
|
+
float amp = uAmpIdle + uAmpVoice * uLvl;
|
|
173
|
+
float baseR = uBaseR + uRadVoice * uLvl;
|
|
174
|
+
float env = 0.62 + 0.38 * sin(th * 2.0 + t * uEnvSpd + 2.0);
|
|
175
|
+
|
|
176
|
+
float wRaw = sin(th * 2.0 + t * uTwistSpd) * 0.6
|
|
177
|
+
+ sin(th * 3.0 - t * uTwistSpd * 0.7 + 1.7) * 0.4;
|
|
178
|
+
float w = (abs(wRaw) * uWWidth + uWMin) * (0.55 + 0.45 * env);
|
|
179
|
+
|
|
180
|
+
float c = baseR
|
|
181
|
+
+ (sin(th * uF1 + t * uS1) * 0.6
|
|
182
|
+
+ sin(th * (uF1 + 2.0) - t * uS1 * 0.63 + 2.3) * 0.4) * amp;
|
|
183
|
+
|
|
184
|
+
float fl = uFlut * (0.5 + 0.9 * uLvl);
|
|
185
|
+
float e1 = c - w + sin(th * uF2 + t * uS2) * fl;
|
|
186
|
+
float e2 = c + w + sin(th * uF2 * 1.3 - t * uS2 * 0.8 + 2.0) * fl;
|
|
187
|
+
|
|
188
|
+
float lo = min(e1, e2), hi = max(e1, e2);
|
|
189
|
+
float ww = max(hi - lo, 0.004);
|
|
190
|
+
float dens = clamp(uWWidth * 1.2 / ww, 0.4, 2.0);
|
|
191
|
+
|
|
192
|
+
float box = smoothstep(-uSigma, uSigma, r - lo)
|
|
193
|
+
* (1.0 - smoothstep(-uSigma, uSigma, r - hi));
|
|
194
|
+
float u = clamp((r - lo) / ww, 0.0, 1.0);
|
|
195
|
+
float rim = smoothstep(0.5, 1.0, abs(u - 0.5) * 2.0);
|
|
196
|
+
|
|
197
|
+
float outside = max(max(lo - r, r - hi), 0.0);
|
|
198
|
+
float bs = uSigma * uBloomMul;
|
|
199
|
+
float halo = exp(-(outside * outside) / (2.0 * bs * bs)) * uBloomGain * dens;
|
|
200
|
+
|
|
201
|
+
float glow = uGain * uFillGain
|
|
202
|
+
* (box * dens * (1.0 + uEdgeGain * rim) + halo * (1.0 - box));
|
|
203
|
+
fragColor = labRingColor(glow, 0.75, 0.45, 0.55, fragCoord);
|
|
204
|
+
}
|
|
205
|
+
`;
|
|
206
|
+
|
|
207
|
+
/** Dense churning cloud cover on a stationary glass sphere. */
|
|
208
|
+
export const PLANET_FRAGMENT = `${NOISE}${LIGHTNING}${RING_COLOR}
|
|
209
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
210
|
+
vec2 hres = iResolution.xy * 0.5;
|
|
211
|
+
vec2 p = (fragCoord - hres) / hres.y;
|
|
212
|
+
float t = uT;
|
|
213
|
+
float R = uBaseR * 2.0;
|
|
214
|
+
float d = length(p);
|
|
215
|
+
float mask = 1.0 - smoothstep(R - 0.012, R + 0.004, d);
|
|
216
|
+
float zn = sqrt(max(R * R - d * d, 0.0)) / max(R, 1.0e-4);
|
|
217
|
+
vec2 ps = p / (R * mix(1.0, 0.35 + 0.65 * zn, uLens));
|
|
218
|
+
|
|
219
|
+
float tt = t * uTwistSpd;
|
|
220
|
+
float sc = uF2 * 0.35;
|
|
221
|
+
float turb = uWarpAmp * (0.5 + 0.8 * uLvl);
|
|
222
|
+
|
|
223
|
+
float dens = 0.0;
|
|
224
|
+
for (int k = 0; k < 3; k++) {
|
|
225
|
+
float fk = float(k);
|
|
226
|
+
vec2 o = vec2(fk * 7.31, fk * 3.77);
|
|
227
|
+
vec2 pk = ps * (1.0 + fk * 0.18 * (1.0 - zn));
|
|
228
|
+
vec2 q = vec2(
|
|
229
|
+
labFbm(pk * sc * 0.6 + o + vec2(tt * uS1 * 0.55, 0.0)),
|
|
230
|
+
labFbm(pk * sc * 0.6 + o + vec2(5.2, 1.3) - vec2(0.0, tt * uS2 * 0.45)));
|
|
231
|
+
float n = labFbm(pk * sc + turb * 2.0 * (q - 0.5) + o + vec2(tt * 0.28, tt * 0.18));
|
|
232
|
+
dens += (0.45 - fk * 0.1) * n;
|
|
233
|
+
}
|
|
234
|
+
dens = smoothstep(0.30 + (1.0 - uPresence) * 0.40, 0.78, dens);
|
|
235
|
+
dens *= 0.12 + 0.88 * uPresence;
|
|
236
|
+
|
|
237
|
+
vec2 lp = vec2(cos(tt * 0.23), sin(tt * 0.31)) * R * 0.35;
|
|
238
|
+
vec2 dl = p - lp;
|
|
239
|
+
float smoke = dens * (0.5 + 0.9 * exp(-dot(dl, dl) / (2.0 * R * R * 0.16))) * (0.55 + 0.65 * zn)
|
|
240
|
+
+ 0.05 * zn;
|
|
241
|
+
|
|
242
|
+
float rim = pow(smoothstep(R * 0.62, R, d), 3.0);
|
|
243
|
+
vec2 hp = p - vec2(-0.38, 0.42) * R;
|
|
244
|
+
float spec = exp(-dot(hp, hp) / (2.0 * R * R * 0.004)) * uSpec;
|
|
245
|
+
float core = uCore * exp(-(d * d) / (2.0 * R * R * 0.026));
|
|
246
|
+
float nrl = labNeural(p, tt * 0.6, R);
|
|
247
|
+
|
|
248
|
+
float glow = uGain * mask
|
|
249
|
+
* (uFillGain * 1.6 * smoke + uEdgeGain * 0.8 * rim + spec + core * 1.3 + nrl * 1.2);
|
|
250
|
+
fragColor = labRingColor(glow, 0.75, 0.45, 0.55, fragCoord);
|
|
251
|
+
}
|
|
252
|
+
`;
|
|
253
|
+
|
|
254
|
+
/** Luminous smoke sealed in a stationary glass sphere, lit from within. */
|
|
255
|
+
export const ORB_FRAGMENT = `${NOISE}${LIGHTNING}
|
|
256
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
257
|
+
vec2 hres = iResolution.xy * 0.5;
|
|
258
|
+
vec2 p = (fragCoord - hres) / hres.y;
|
|
259
|
+
float t = uT;
|
|
260
|
+
float R = uBaseR * 2.0;
|
|
261
|
+
float d = length(p);
|
|
262
|
+
float mask = 1.0 - smoothstep(R - 0.010, R + 0.004, d);
|
|
263
|
+
float zn = sqrt(max(R * R - d * d, 0.0)) / max(R, 1.0e-4);
|
|
264
|
+
float inner = 1.0 - clamp(d / max(R, 1.0e-4), 0.0, 1.0);
|
|
265
|
+
vec2 ps = p / (R * mix(1.0, 0.35 + 0.65 * zn, uLens));
|
|
266
|
+
|
|
267
|
+
float tt = t * uTwistSpd;
|
|
268
|
+
// rigid drift plus a BOUNDED oscillating stir: shear that accumulates
|
|
269
|
+
// forever winds any pattern into a spiral
|
|
270
|
+
float ang = tt * 0.04
|
|
271
|
+
+ (sin(tt * 0.11) * 0.55 + sin(tt * 0.047 + 1.7) * 0.35) * inner;
|
|
272
|
+
float ca = cos(ang), sa = sin(ang);
|
|
273
|
+
ps = mat2(ca, -sa, sa, ca) * ps;
|
|
274
|
+
|
|
275
|
+
float sc = uF2 * 0.18;
|
|
276
|
+
float tau0 = 0.50 + 0.06 * uLvl;
|
|
277
|
+
float bw = mix(0.16, 0.12, uLvl);
|
|
278
|
+
|
|
279
|
+
vec2 lp = vec2(cos(tt * 0.21), sin(tt * 0.27)) * R * 0.42;
|
|
280
|
+
vec2 L = normalize(lp - p + vec2(1.0e-4, 0.0));
|
|
281
|
+
|
|
282
|
+
float dens = 0.0;
|
|
283
|
+
float lit = 0.0;
|
|
284
|
+
for (int k = 0; k < 2; k++) {
|
|
285
|
+
float fk = float(k);
|
|
286
|
+
vec2 o = vec2(fk * 9.17, fk * 5.13);
|
|
287
|
+
float scale = sc * (1.0 + 0.7 * fk);
|
|
288
|
+
vec2 pk = ps * (1.0 + fk * 0.24 * (1.0 - zn)) + o;
|
|
289
|
+
|
|
290
|
+
// bounded orbit, never a straight scroll: the coverage pattern wanders
|
|
291
|
+
// around home instead of migrating off one side of the vessel
|
|
292
|
+
float cn = labFbm(pk * 0.9 + vec2(sin(tt * 0.041), -cos(tt * 0.033)) * 0.8);
|
|
293
|
+
float covLo = 0.62 - 0.30 * uFillGain + 0.03 * uLvl
|
|
294
|
+
+ (1.0 - uPresence) * 0.45;
|
|
295
|
+
float bottomness = clamp(-p.y / max(R, 1.0e-4) * 1.3 - 0.1, 0.0, 1.0);
|
|
296
|
+
float gBias = 0.16 * inner * uPresence
|
|
297
|
+
+ max(uGather, 0.0) * 0.30 * inner
|
|
298
|
+
+ max(-uGather, 0.0) * 0.38 * bottomness;
|
|
299
|
+
float cov = smoothstep(covLo, covLo + 0.28, cn + gBias);
|
|
300
|
+
|
|
301
|
+
vec2 flow = vec2(-pk.y, pk.x) * 0.5 + vec2(0.0, 0.4);
|
|
302
|
+
float cyc = tt * 0.10 * uS1 * (1.0 + 0.6 * fk);
|
|
303
|
+
float ph0 = fract(cyc + 0.35 * cn);
|
|
304
|
+
float ph1 = fract(cyc + 0.35 * cn + 0.5);
|
|
305
|
+
float w0 = 1.0 - abs(1.0 - 2.0 * ph0);
|
|
306
|
+
|
|
307
|
+
vec2 w2 = vec2(labFbm(pk * scale * 0.5 + vec2(sin(tt * 0.09 * uS2), cos(tt * 0.075 * uS2)) * 0.9),
|
|
308
|
+
labFbm(pk * scale * 0.5 + vec2(3.7, 8.1) + vec2(cos(tt * 0.065 * uS2), sin(tt * 0.083 * uS2)) * 0.9));
|
|
309
|
+
vec2 qw = pk * scale + uWarpAmp * 3.0 * (w2 - 0.5);
|
|
310
|
+
|
|
311
|
+
float n = mix(labFbm(qw - flow * 1.2 * ph1), labFbm(qw - flow * 1.2 * ph0), w0);
|
|
312
|
+
float sgn = 2.0 * n - 1.0;
|
|
313
|
+
float ridge = 1.0 - abs(sgn);
|
|
314
|
+
ridge *= ridge;
|
|
315
|
+
float band = smoothstep(tau0 - bw, tau0, n) * (1.0 - smoothstep(tau0, tau0 + bw, n));
|
|
316
|
+
float dk = cov * (band * (0.6 + 0.5 * ridge) + 0.12 * n * cov);
|
|
317
|
+
dens += (0.60 - 0.22 * fk) * dk;
|
|
318
|
+
|
|
319
|
+
float nL = labFbm(qw + L * 0.5);
|
|
320
|
+
lit += clamp((nL - n) * 3.0, 0.0, 1.0) * dk;
|
|
321
|
+
}
|
|
322
|
+
dens *= 1.0 - smoothstep(0.72, 0.97, d / max(R, 1.0e-4));
|
|
323
|
+
dens *= (0.45 + 1.25 * uFillGain) * (1.0 + 0.25 * uLvl);
|
|
324
|
+
dens *= 0.08 + 0.92 * uPresence;
|
|
325
|
+
float dEff = clamp(dens, 0.0, 1.5) * (0.5 + 0.5 * zn);
|
|
326
|
+
float aSmoke = 1.0 - exp(-2.6 * dEff);
|
|
327
|
+
|
|
328
|
+
float rL = length(p - lp) / R;
|
|
329
|
+
float G = 1.0 / (1.0 + 2.0 * rL + 8.0 * rL * rL);
|
|
330
|
+
float act = 0.7 + 0.8 * uLvl;
|
|
331
|
+
|
|
332
|
+
vec3 albedo = mix(vec3(0.84, 0.87, 0.92), uColor, uTint);
|
|
333
|
+
vec3 body = albedo * (0.30 + 0.55 * exp(-1.4 * dEff))
|
|
334
|
+
+ uColor * (lit * 0.5 + dEff * G * 1.1) * act;
|
|
335
|
+
vec3 bgIn = uColor * 0.05 * zn;
|
|
336
|
+
vec3 col = mix(bgIn, body, aSmoke)
|
|
337
|
+
+ uColor * G * act * 0.18 * zn;
|
|
338
|
+
|
|
339
|
+
float rim = pow(smoothstep(R * 0.66, R, d), 3.0);
|
|
340
|
+
vec2 hp = p - vec2(-0.38, 0.42) * R;
|
|
341
|
+
float spec = exp(-dot(hp, hp) / (2.0 * R * R * 0.004)) * uSpec;
|
|
342
|
+
float core = uCore * exp(-(d * d) / (2.0 * R * R * 0.022));
|
|
343
|
+
float nrl = labNeural(p, tt * 0.6, R);
|
|
344
|
+
col += uColor * rim * uEdgeGain * 0.7 + vec3(spec) + uColor * core * 1.5
|
|
345
|
+
+ uColor * nrl * (0.7 + 0.6 * aSmoke);
|
|
346
|
+
|
|
347
|
+
col *= uGain * mask;
|
|
348
|
+
float alpha = clamp((aSmoke * 0.9 + G * act * 0.15 * zn + core + nrl * 0.55
|
|
349
|
+
+ rim * uEdgeGain * 0.5 + spec + 0.03 * zn) * uGain, 0.0, 1.0) * mask;
|
|
350
|
+
float nz = fract(sin(dot(fragCoord, vec2(12.9898, 78.233))) * 43758.5453);
|
|
351
|
+
alpha = clamp(alpha + (nz - 0.5) / 255.0, 0.0, 1.0);
|
|
352
|
+
fragColor = vec4(col, alpha);
|
|
353
|
+
}
|
|
354
|
+
`;
|
|
355
|
+
|
|
356
|
+
export type LabLook = 'braid' | 'ribbon' | 'planet' | 'orb';
|
|
357
|
+
|
|
358
|
+
export const LAB_FRAGMENTS: Record<LabLook, string> = {
|
|
359
|
+
braid: BRAID_FRAGMENT,
|
|
360
|
+
ribbon: RIBBON_FRAGMENT,
|
|
361
|
+
planet: PLANET_FRAGMENT,
|
|
362
|
+
orb: ORB_FRAGMENT,
|
|
363
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createSignal, onCleanup, onMount, type JSX } from 'solid-js';
|
|
2
|
+
import { ShaderCanvas, hexToRgb, type UniformSpec } from '../shader-canvas';
|
|
3
|
+
import { LAB_FRAGMENTS, type LabLook } from './lab-shaders';
|
|
4
|
+
import { createChoreography, LOOK_DEFAULTS, type LabParams, type LabState } from './lab-choreography';
|
|
5
|
+
|
|
6
|
+
export interface LabVisualizerProps {
|
|
7
|
+
look: LabLook;
|
|
8
|
+
state?: LabState;
|
|
9
|
+
color?: string;
|
|
10
|
+
/** Square canvas edge in px. */
|
|
11
|
+
size?: number;
|
|
12
|
+
/** Overrides on the look's tuned defaults. */
|
|
13
|
+
params?: Partial<LabParams>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Runs one lab look through the same `ShaderCanvas` the shipped variants use,
|
|
18
|
+
* with the playground's state choreography driving the uniforms per frame.
|
|
19
|
+
* While `speaking`, a baked loudness loop stands in for a live voice.
|
|
20
|
+
*/
|
|
21
|
+
export function LabVisualizer(props: LabVisualizerProps): JSX.Element {
|
|
22
|
+
const merged = (): LabParams => {
|
|
23
|
+
const out: LabParams = { ...LOOK_DEFAULTS[props.look] };
|
|
24
|
+
for (const [key, value] of Object.entries(props.params ?? {})) {
|
|
25
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
26
|
+
(out as unknown as Record<string, number>)[key] = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
};
|
|
31
|
+
const chor = createChoreography(() => props.look, () => props.state ?? 'manual', merged);
|
|
32
|
+
const [frame, setFrame] = createSignal(chor.step(0));
|
|
33
|
+
|
|
34
|
+
onMount(() => {
|
|
35
|
+
// Captured at SETUP and closed over, never re-resolved as a global inside
|
|
36
|
+
// `onCleanup`: cleanup can run after the host removed the DOM globals (a
|
|
37
|
+
// `kai-*` release is deferred one microtask past detachment, so an
|
|
38
|
+
// environment teardown gets in between), and a bare `cancelAnimationFrame`
|
|
39
|
+
// there throws -- from a promise nobody holds, so it lands as an unhandled
|
|
40
|
+
// rejection that fails the run while every test passes.
|
|
41
|
+
// See tests/components/teardown-without-dom-globals.test.tsx.
|
|
42
|
+
//
|
|
43
|
+
// The FUNCTION, not the view. The `const win = window` capture that fixes a
|
|
44
|
+
// bare `document` does nothing here: `window === globalThis` -- measured, in
|
|
45
|
+
// jsdom and in real Chromium/WebKit alike -- and the teardown deletes these
|
|
46
|
+
// keys off that very object, so `win.cancelAnimationFrame` is undefined by
|
|
47
|
+
// the time cleanup runs. It only trades the ReferenceError for a TypeError.
|
|
48
|
+
// `.bind` pins the receiver the WebIDL operation is specified on; Chromium
|
|
49
|
+
// and WebKit both accept a detached call (measured), so the bind is belt and
|
|
50
|
+
// braces against an engine that does not, at zero cost.
|
|
51
|
+
const cancelFrame = cancelAnimationFrame.bind(globalThis);
|
|
52
|
+
|
|
53
|
+
let raf = 0;
|
|
54
|
+
let last = performance.now();
|
|
55
|
+
const loop = (): void => {
|
|
56
|
+
const now = performance.now();
|
|
57
|
+
const dt = Math.min((now - last) / 1000, 0.1);
|
|
58
|
+
last = now;
|
|
59
|
+
setFrame(chor.step(dt));
|
|
60
|
+
raf = requestAnimationFrame(loop);
|
|
61
|
+
};
|
|
62
|
+
raf = requestAnimationFrame(loop);
|
|
63
|
+
onCleanup(() => cancelFrame(raf));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const uniforms = (): Record<string, UniformSpec> => {
|
|
67
|
+
const f = frame();
|
|
68
|
+
const v = f.values;
|
|
69
|
+
const one = (value: number): UniformSpec => ({ type: '1f', value });
|
|
70
|
+
return {
|
|
71
|
+
uColor: { type: '3fv', value: hexToRgb(props.color ?? '#1fd5f9') },
|
|
72
|
+
uT: one(f.t),
|
|
73
|
+
uLvl: one(f.level),
|
|
74
|
+
uBaseR: one(v.baseR), uAmpIdle: one(v.ampIdle), uAmpVoice: one(v.ampVoice),
|
|
75
|
+
uRadVoice: one(v.radVoice), uSigma: one(v.sigma), uGain: one(v.gain),
|
|
76
|
+
uF1: one(v.f1), uF2: one(v.f2), uS1: one(v.s1), uS2: one(v.s2),
|
|
77
|
+
uEnvSpd: one(v.envSpd), uSepSpd: one(v.sepSpd),
|
|
78
|
+
uWhiteLo: one(v.whiteLo), uWhiteHi: one(v.whiteHi),
|
|
79
|
+
uBloomMul: one(v.bloomMul), uBloomGain: one(v.bloomGain),
|
|
80
|
+
uDelta: one(v.delta), uOff: one(v.off),
|
|
81
|
+
uWWidth: one(v.wWidth), uWMin: one(v.wMin),
|
|
82
|
+
uFillGain: one(v.fillGain), uEdgeGain: one(v.edgeGain), uFlut: one(v.flut),
|
|
83
|
+
uTwistSpd: one(v.twistSpd), uWarpAmp: one(v.warpAmp),
|
|
84
|
+
uLens: one(v.lens), uSpec: one(v.spec), uTint: one(v.tint),
|
|
85
|
+
uPresence: one(v.presence), uGather: one(v.gather), uCore: one(v.core),
|
|
86
|
+
uNeural: one(v.neural), uBoltJag: one(v.boltJag),
|
|
87
|
+
uBoltWidth: one(v.boltWidth), uBoltRate: one(v.boltRate),
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const edge = (): string => `${props.size ?? 320}px`;
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div style={{ width: edge(), height: edge() }}>
|
|
95
|
+
<ShaderCanvas
|
|
96
|
+
fragment={LAB_FRAGMENTS[props.look]}
|
|
97
|
+
uniforms={uniforms()}
|
|
98
|
+
onError={(message) => console.warn(`lab visualizer (${props.look}):`, message)}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -382,6 +382,35 @@ export function ShaderCanvas(props: ShaderCanvasProps): JSX.Element {
|
|
|
382
382
|
let drawFrame: ((now: number) => void) | null = null;
|
|
383
383
|
/** The pending animation frame id, or 0 when the loop is stopped. */
|
|
384
384
|
let raf = 0;
|
|
385
|
+
/**
|
|
386
|
+
* `cancelAnimationFrame`, captured at SETUP.
|
|
387
|
+
*
|
|
388
|
+
* `stopLoop()` below runs at dispose (via `release()`), and dispose is not
|
|
389
|
+
* guaranteed to happen while the page that mounted this canvas is still
|
|
390
|
+
* standing -- `component-register`'s `disconnectedCallback` defers a
|
|
391
|
+
* microtask, and a test environment tears its DOM globals down in between.
|
|
392
|
+
* A bare `cancelAnimationFrame` there throws from a promise nobody holds, so
|
|
393
|
+
* it surfaces as an unhandled rejection that fails a run in which every test
|
|
394
|
+
* passed. See tests/components/teardown-without-dom-globals.test.tsx.
|
|
395
|
+
*
|
|
396
|
+
* The FUNCTION, not the view. The `const win = window` capture that fixes a
|
|
397
|
+
* bare `document` does nothing here: `window === globalThis` -- measured, in
|
|
398
|
+
* jsdom and in real Chromium/WebKit alike -- and the teardown deletes these
|
|
399
|
+
* keys off that very object, so `win.cancelAnimationFrame` is undefined by
|
|
400
|
+
* the time cleanup runs. It only trades the ReferenceError for a TypeError.
|
|
401
|
+
* `.bind` pins the receiver the WebIDL operation is specified on; Chromium
|
|
402
|
+
* and WebKit both accept a detached call (measured), so the bind is belt and
|
|
403
|
+
* braces against an engine that does not, at zero cost.
|
|
404
|
+
*
|
|
405
|
+
* GUARDED because "setup" for this component is its body, and a server render
|
|
406
|
+
* executes component bodies. Node has no `cancelAnimationFrame` at all, so an
|
|
407
|
+
* unguarded capture here would trade the disposal crash for an SSR crash --
|
|
408
|
+
* measured, not hypothesised. Nothing can be scheduled without
|
|
409
|
+
* `requestAnimationFrame` either, so the no-op fallback is exactly right.
|
|
410
|
+
*/
|
|
411
|
+
const cancelFrame = typeof cancelAnimationFrame === 'function'
|
|
412
|
+
? cancelAnimationFrame.bind(globalThis)
|
|
413
|
+
: () => {};
|
|
385
414
|
|
|
386
415
|
/** The assembled source and the uniform snapshot it was assembled from. */
|
|
387
416
|
let build: { source: string; uniforms: Record<string, UniformSpec> } | null = null;
|
|
@@ -460,7 +489,8 @@ export function ShaderCanvas(props: ShaderCanvasProps): JSX.Element {
|
|
|
460
489
|
|
|
461
490
|
const stopLoop = () => {
|
|
462
491
|
if (raf === 0) return;
|
|
463
|
-
|
|
492
|
+
// Captured at setup -- see `cancelFrame`. This line runs at dispose.
|
|
493
|
+
cancelFrame(raf);
|
|
464
494
|
raf = 0;
|
|
465
495
|
// Bank what was drawn so `iTime` resumes from here, not from zero.
|
|
466
496
|
elapsedMs += Math.max(0, performance.now() - runStartedAt);
|
|
@@ -1,28 +1,60 @@
|
|
|
1
1
|
// src/components/card-fallback.tsx
|
|
2
|
-
// Rendered by the dispatcher when an envelope
|
|
2
|
+
// Rendered by the dispatcher when an envelope cannot be rendered: its `type` has no
|
|
3
|
+
// registered card, or its `data` failed HARD validation against the built-in schema
|
|
4
|
+
// for that type (see primitives/card-validate-cards.ts for what "hard" means).
|
|
3
5
|
// Visual: reuses the Card chrome so it sits naturally in a card stream.
|
|
4
|
-
import type
|
|
6
|
+
import { Show, type JSX } from 'solid-js';
|
|
5
7
|
import { Card } from './card';
|
|
6
8
|
import { AlertTriangle } from 'lucide-solid';
|
|
7
9
|
|
|
8
10
|
export interface CardFallbackProps {
|
|
9
|
-
/** The
|
|
11
|
+
/** The envelope type, shown to aid debugging. */
|
|
10
12
|
type: string;
|
|
11
13
|
/** The envelope id (for parity with cards; not displayed). */
|
|
12
14
|
cardId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Why this card could not render, when the type WAS known but the data was not
|
|
17
|
+
* usable. Carries the failing field paths verbatim, e.g.
|
|
18
|
+
* `(root).actions: fewer than minItems 1`.
|
|
19
|
+
*
|
|
20
|
+
* Absent means the older case: an unrecognized type. The two are told apart by
|
|
21
|
+
* this prop rather than by a mode flag so a caller cannot ask for the diagnostic
|
|
22
|
+
* and forget to supply the diagnosis.
|
|
23
|
+
*/
|
|
24
|
+
reason?: string;
|
|
13
25
|
}
|
|
14
26
|
|
|
15
|
-
/** Inert, themed fallback for
|
|
27
|
+
/** Inert, themed fallback for a card that cannot render. Emits nothing itself:
|
|
16
28
|
* the dispatcher emits the contract `error` event alongside rendering this. */
|
|
17
29
|
export function CardFallback(props: CardFallbackProps): JSX.Element {
|
|
18
30
|
return (
|
|
19
31
|
<Card>
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
<Show
|
|
33
|
+
when={props.reason}
|
|
34
|
+
fallback={
|
|
35
|
+
<div data-card-fallback role="alert" class="flex items-center gap-2 p-4 text-sm text-muted-foreground">
|
|
36
|
+
<AlertTriangle class="size-4 shrink-0 text-destructive dark:text-red-400" aria-hidden="true" />
|
|
37
|
+
<span>
|
|
38
|
+
Unsupported card type: <code class="font-mono">{props.type}</code>
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
}
|
|
42
|
+
>
|
|
43
|
+
{(reason) => (
|
|
44
|
+
<div
|
|
45
|
+
data-card-fallback
|
|
46
|
+
data-card-invalid
|
|
47
|
+
role="alert"
|
|
48
|
+
class="flex items-start gap-2 p-4 text-sm text-muted-foreground"
|
|
49
|
+
>
|
|
50
|
+
<AlertTriangle class="size-4 shrink-0 translate-y-0.5 text-destructive dark:text-red-400" aria-hidden="true" />
|
|
51
|
+
<span class="min-w-0">
|
|
52
|
+
Invalid <code class="font-mono">{props.type}</code> card:{' '}
|
|
53
|
+
<code data-card-invalid-reason class="font-mono break-words">{reason()}</code>
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</Show>
|
|
26
58
|
</Card>
|
|
27
59
|
);
|
|
28
60
|
}
|