@agent-native/core 0.79.27 → 0.80.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 (346) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +26 -0
  3. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +41 -0
  4. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +51 -0
  5. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +50 -0
  6. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +49 -0
  7. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +44 -0
  8. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +46 -0
  9. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +44 -0
  10. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +48 -0
  11. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +36 -0
  12. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +38 -0
  13. package/corpus/core/docs/content/template-design.mdx +45 -0
  14. package/corpus/core/package.json +2 -1
  15. package/corpus/core/src/agent/engine/index.ts +1 -0
  16. package/corpus/core/src/agent/engine/registry.ts +40 -0
  17. package/corpus/core/src/agent/production-agent.ts +6 -2
  18. package/corpus/core/src/cli/design-connect.ts +490 -0
  19. package/corpus/core/src/cli/index.ts +16 -0
  20. package/corpus/core/src/cli/skills.ts +126 -3
  21. package/corpus/core/src/client/AssistantChat.tsx +43 -7
  22. package/corpus/core/src/client/agent-chat.ts +27 -3
  23. package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +1 -1
  24. package/corpus/core/src/client/blocks/library/diagram.tsx +2 -2
  25. package/corpus/core/src/client/blocks/library/wireframe.tsx +1 -1
  26. package/corpus/core/src/client/chat/message-components.tsx +1 -1
  27. package/corpus/core/src/client/chat-model-groups.ts +1 -2
  28. package/corpus/core/src/client/components/LiveCursorOverlay.tsx +33 -66
  29. package/corpus/core/src/client/composer/TiptapComposer.tsx +99 -24
  30. package/corpus/core/src/client/composer/useVoiceDictation.ts +429 -260
  31. package/corpus/core/src/client/frame-protocol.ts +17 -2
  32. package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +2 -2
  33. package/corpus/core/src/client/sharing/ShareButton.tsx +20 -15
  34. package/corpus/core/src/client/use-agent-engine-configured.ts +80 -28
  35. package/corpus/core/src/server/transcribe-voice.ts +57 -22
  36. package/corpus/core/src/shared/mcp-embed-headers.ts +23 -1
  37. package/corpus/core/src/styles/agent-native.css +56 -7
  38. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  39. package/corpus/core/src/vite/client.ts +2 -0
  40. package/corpus/core/src/voice/index.ts +18 -0
  41. package/corpus/core/src/voice/voice-cleanup-prompt.ts +38 -0
  42. package/corpus/core/src/voice/voice-context.ts +217 -0
  43. package/corpus/core/src/voice/voice-replacements.ts +75 -0
  44. package/corpus/templates/analytics/AGENTS.md +4 -3
  45. package/corpus/templates/analytics/actions/list-session-recordings.ts +6 -1
  46. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +557 -400
  47. package/corpus/templates/analytics/app/global.css +0 -4
  48. package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
  49. package/corpus/templates/analytics/app/i18n-data.ts +20 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +33 -8
  51. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +7 -0
  52. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +7 -0
  53. package/corpus/templates/analytics/changelog/2026-06-28-ask-tab-now-matches-the-darker-app-background.md +6 -0
  54. package/corpus/templates/analytics/changelog/2026-06-28-dashboard-email-reports-now-use-cleaner-light-mode-snapshots.md +6 -0
  55. package/corpus/templates/analytics/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  56. package/corpus/templates/analytics/changelog/2026-06-28-sessions-now-show-only-signed-in-recordings-with-playable-re.md +6 -0
  57. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
  58. package/corpus/templates/analytics/server/lib/dashboard-report.ts +29 -7
  59. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +5 -2
  60. package/corpus/templates/analytics/server/lib/session-replay.ts +24 -4
  61. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -4
  62. package/corpus/templates/assets/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  63. package/corpus/templates/brain/app/components/layout/Layout.tsx +29 -2
  64. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +131 -42
  65. package/corpus/templates/brain/app/i18n/zh-TW.ts +2 -0
  66. package/corpus/templates/brain/app/i18n-data.ts +20 -0
  67. package/corpus/templates/brain/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  68. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +29 -1
  69. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +417 -299
  70. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  71. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  72. package/corpus/templates/calendar/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  73. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +6 -19
  74. package/corpus/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  75. package/corpus/templates/clips/AGENTS.md +4 -0
  76. package/corpus/templates/clips/actions/cleanup-transcript.ts +39 -9
  77. package/corpus/templates/clips/actions/finalize-meeting.ts +81 -12
  78. package/corpus/templates/clips/actions/lib/agents-md-context.ts +4 -1
  79. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
  80. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +1 -1
  81. package/corpus/templates/clips/app/components/player/share-dialog.tsx +2 -2
  82. package/corpus/templates/clips/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  83. package/corpus/templates/clips/desktop/src/lib/personal-vocabulary.ts +13 -8
  84. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +60 -1
  85. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1 -1
  86. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -1
  87. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -5
  88. package/corpus/templates/content/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  89. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +137 -0
  90. package/corpus/templates/design/AGENTS.md +95 -5
  91. package/corpus/templates/design/DESIGN.md +82 -0
  92. package/corpus/templates/design/DEVELOPING.md +43 -0
  93. package/corpus/templates/design/actions/add-localhost-screens.ts +426 -0
  94. package/corpus/templates/design/actions/apply-shader.ts +277 -0
  95. package/corpus/templates/design/actions/apply-visual-edit.ts +303 -0
  96. package/corpus/templates/design/actions/connect-localhost.ts +183 -0
  97. package/corpus/templates/design/actions/edit-design.ts +195 -42
  98. package/corpus/templates/design/actions/generate-design.ts +71 -1
  99. package/corpus/templates/design/actions/generate-screens.ts +193 -0
  100. package/corpus/templates/design/actions/get-code-layer-projection.ts +191 -0
  101. package/corpus/templates/design/actions/get-shader.ts +119 -0
  102. package/corpus/templates/design/actions/list-localhost-connections.ts +95 -0
  103. package/corpus/templates/design/actions/navigate.ts +55 -2
  104. package/corpus/templates/design/actions/view-screen.ts +68 -1
  105. package/corpus/templates/design/agent-native.app-skill.json +10 -0
  106. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +761 -0
  107. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +2057 -103
  108. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +74 -38
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +399 -0
  110. package/corpus/templates/design/app/components/design/EditPanel.tsx +3185 -439
  111. package/corpus/templates/design/app/components/design/LayersPanel.tsx +1124 -0
  112. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3116 -147
  113. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +700 -13
  114. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +107 -63
  115. package/corpus/templates/design/app/components/design/index.ts +0 -5
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +286 -0
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +699 -0
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +461 -0
  119. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +166 -0
  120. package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +1420 -0
  121. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +420 -0
  122. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +215 -0
  123. package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +71 -0
  124. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +518 -0
  125. package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +106 -0
  126. package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +361 -0
  127. package/corpus/templates/design/app/components/design/inspector/index.ts +60 -0
  128. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +201 -0
  129. package/corpus/templates/design/app/components/design/types.ts +23 -0
  130. package/corpus/templates/design/app/components/layout/Layout.tsx +24 -13
  131. package/corpus/templates/design/app/components/layout/Sidebar.tsx +4 -4
  132. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +474 -36
  133. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +22 -5
  134. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +24 -11
  135. package/corpus/templates/design/app/global.css +121 -3
  136. package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -0
  137. package/corpus/templates/design/app/hooks/use-navigation-state.ts +130 -8
  138. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +329 -0
  139. package/corpus/templates/design/app/i18n/zh-TW.ts +264 -0
  140. package/corpus/templates/design/app/i18n-data.ts +2790 -1
  141. package/corpus/templates/design/app/pages/DesignEditor.tsx +5108 -851
  142. package/corpus/templates/design/changelog/2026-06-28-annotate-mode-now-combines-drawing-and-comment-pins-in-one-c.md +6 -0
  143. package/corpus/templates/design/changelog/2026-06-28-design-editor-panel-borders-are-cleaner-so-the-canvas-edge-s.md +6 -0
  144. package/corpus/templates/design/changelog/2026-06-28-drawing-prompts-now-reliably-open-and-submit-to-the-design-a.md +6 -0
  145. package/corpus/templates/design/changelog/2026-06-28-editor-app-menus-now-use-an-outline-agent-native-mark-with-b.md +6 -0
  146. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +6 -0
  147. package/corpus/templates/design/changelog/2026-06-28-layer-selection-now-updates-chat-context-without-opening-the.md +6 -0
  148. package/corpus/templates/design/changelog/2026-06-28-layer-selections-now-preserve-hidden-and-locked-canvas-state.md +6 -0
  149. package/corpus/templates/design/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  150. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +6 -0
  151. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-handles-zooming-drawing-opening-and-dele.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-selects-screens-on-click-and-opens-them-.md +6 -0
  154. package/corpus/templates/design/changelog/2026-06-28-screen-overview-zooms-into-the-active-screen-with-smoother-e.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-28-selected-element-chips-in-chat-are-shorter-and-easier-to-sca.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-28-the-design-editor-toolbar-is-more-compact-and-the-app-menu-m.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-at-the-top-of-the-design-sidebar-instead-of-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-in-the-right-inspector-beside-the-design-tab.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-active-sidebar-rows-use-soft-highlights.md +6 -0
  160. package/corpus/templates/design/changelog/2026-06-29-agents-can-now-open-screen-overview-focus-screens-and-add.md +6 -0
  161. package/corpus/templates/design/changelog/2026-06-29-design-agents-now-edit-broad-copy-changes-more-reliably.md +6 -0
  162. package/corpus/templates/design/changelog/2026-06-29-design-editor-extensions-now-run-inline-beside-the-artboard.md +6 -0
  163. package/corpus/templates/design/changelog/2026-06-29-sidebars-use-darker-chrome-and-chat-warns-immediately.md +6 -0
  164. package/corpus/templates/design/changelog/2026-06-29-visual-edit-can-open-localhost-routes-as-url-backed-screens.md +6 -0
  165. package/corpus/templates/design/package.json +1 -0
  166. package/corpus/templates/design/server/db/schema.ts +26 -0
  167. package/corpus/templates/design/server/lib/design-snapshot.ts +1 -1
  168. package/corpus/templates/design/server/plugins/agent-chat.ts +3 -0
  169. package/corpus/templates/design/shared/api.ts +27 -0
  170. package/corpus/templates/design/shared/canvas-frames.ts +103 -0
  171. package/corpus/templates/design/shared/canvas-math.ts +1058 -0
  172. package/corpus/templates/design/shared/code-layer.ts +2212 -0
  173. package/corpus/templates/design/shared/color-utils.ts +180 -0
  174. package/corpus/templates/design/shared/generation-session.ts +61 -0
  175. package/corpus/templates/design/shared/shader-presets.ts +782 -0
  176. package/corpus/templates/design/shared/shader-safety.ts +137 -0
  177. package/corpus/templates/design/shared/source-mode.ts +237 -0
  178. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +149 -6
  179. package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
  180. package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
  181. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  182. package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
  183. package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
  184. package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
  185. package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
  186. package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
  187. package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
  188. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  189. package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
  190. package/corpus/templates/forms/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  191. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
  192. package/corpus/templates/macros/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
  193. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +408 -247
  194. package/corpus/templates/mail/app/i18n/ar-SA.ts +4 -0
  195. package/corpus/templates/mail/app/i18n/de-DE.ts +4 -0
  196. package/corpus/templates/mail/app/i18n/en-US.ts +4 -0
  197. package/corpus/templates/mail/app/i18n/es-ES.ts +4 -0
  198. package/corpus/templates/mail/app/i18n/fr-FR.ts +4 -0
  199. package/corpus/templates/mail/app/i18n/hi-IN.ts +4 -0
  200. package/corpus/templates/mail/app/i18n/ja-JP.ts +4 -0
  201. package/corpus/templates/mail/app/i18n/ko-KR.ts +4 -0
  202. package/corpus/templates/mail/app/i18n/pt-BR.ts +4 -0
  203. package/corpus/templates/mail/app/i18n/zh-CN.ts +4 -0
  204. package/corpus/templates/mail/app/i18n/zh-TW.ts +4 -0
  205. package/corpus/templates/mail/changelog/2026-06-28-pinned-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  206. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +6 -8
  207. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
  208. package/corpus/templates/plan/app/global.css +61 -78
  209. package/corpus/templates/plan/app/pages/PlansPage.tsx +8 -0
  210. package/corpus/templates/plan/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  211. package/corpus/templates/plan/changelog/2026-06-28-plans-use-the-shared-neutral-light-and-dark-theme.md +6 -0
  212. package/corpus/templates/plan/changelog/2026-06-28-sending-open-feedback-from-a-plan-now-opens-the-inline-plan-.md +6 -0
  213. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +5 -5
  214. package/corpus/templates/slides/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
  215. package/corpus/templates/videos/app/components/Sidebar.tsx +2 -2
  216. package/corpus/templates/videos/app/components/layout/Layout.tsx +29 -2
  217. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +113 -30
  218. package/corpus/templates/videos/app/i18n/ar-SA.ts +2 -0
  219. package/corpus/templates/videos/app/i18n/de-DE.ts +2 -0
  220. package/corpus/templates/videos/app/i18n/en-US.ts +2 -0
  221. package/corpus/templates/videos/app/i18n/es-ES.ts +2 -0
  222. package/corpus/templates/videos/app/i18n/fr-FR.ts +2 -0
  223. package/corpus/templates/videos/app/i18n/hi-IN.ts +2 -0
  224. package/corpus/templates/videos/app/i18n/ja-JP.ts +2 -0
  225. package/corpus/templates/videos/app/i18n/ko-KR.ts +2 -0
  226. package/corpus/templates/videos/app/i18n/pt-BR.ts +2 -0
  227. package/corpus/templates/videos/app/i18n/zh-CN.ts +2 -0
  228. package/corpus/templates/videos/app/i18n/zh-TW.ts +2 -0
  229. package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
  230. package/dist/agent/engine/index.d.ts +1 -1
  231. package/dist/agent/engine/index.d.ts.map +1 -1
  232. package/dist/agent/engine/index.js +1 -1
  233. package/dist/agent/engine/index.js.map +1 -1
  234. package/dist/agent/engine/registry.d.ts +9 -0
  235. package/dist/agent/engine/registry.d.ts.map +1 -1
  236. package/dist/agent/engine/registry.js +37 -0
  237. package/dist/agent/engine/registry.js.map +1 -1
  238. package/dist/agent/production-agent.d.ts.map +1 -1
  239. package/dist/agent/production-agent.js +4 -3
  240. package/dist/agent/production-agent.js.map +1 -1
  241. package/dist/cli/design-connect.d.ts +52 -0
  242. package/dist/cli/design-connect.d.ts.map +1 -0
  243. package/dist/cli/design-connect.js +409 -0
  244. package/dist/cli/design-connect.js.map +1 -0
  245. package/dist/cli/index.js +15 -0
  246. package/dist/cli/index.js.map +1 -1
  247. package/dist/cli/skills.d.ts +3 -0
  248. package/dist/cli/skills.d.ts.map +1 -1
  249. package/dist/cli/skills.js +121 -3
  250. package/dist/cli/skills.js.map +1 -1
  251. package/dist/client/AssistantChat.d.ts.map +1 -1
  252. package/dist/client/AssistantChat.js +38 -8
  253. package/dist/client/AssistantChat.js.map +1 -1
  254. package/dist/client/agent-chat.d.ts +6 -0
  255. package/dist/client/agent-chat.d.ts.map +1 -1
  256. package/dist/client/agent-chat.js +17 -3
  257. package/dist/client/agent-chat.js.map +1 -1
  258. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  259. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  260. package/dist/client/blocks/library/diagram.js +1 -1
  261. package/dist/client/blocks/library/diagram.js.map +1 -1
  262. package/dist/client/blocks/library/wireframe.js +1 -1
  263. package/dist/client/blocks/library/wireframe.js.map +1 -1
  264. package/dist/client/chat/message-components.js +1 -1
  265. package/dist/client/chat/message-components.js.map +1 -1
  266. package/dist/client/chat-model-groups.d.ts.map +1 -1
  267. package/dist/client/chat-model-groups.js +1 -2
  268. package/dist/client/chat-model-groups.js.map +1 -1
  269. package/dist/client/components/LiveCursorOverlay.d.ts +1 -2
  270. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
  271. package/dist/client/components/LiveCursorOverlay.js +19 -40
  272. package/dist/client/components/LiveCursorOverlay.js.map +1 -1
  273. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  274. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  275. package/dist/client/composer/TiptapComposer.js +86 -24
  276. package/dist/client/composer/TiptapComposer.js.map +1 -1
  277. package/dist/client/composer/useVoiceDictation.d.ts +9 -0
  278. package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
  279. package/dist/client/composer/useVoiceDictation.js +154 -32
  280. package/dist/client/composer/useVoiceDictation.js.map +1 -1
  281. package/dist/client/frame-protocol.d.ts +17 -2
  282. package/dist/client/frame-protocol.d.ts.map +1 -1
  283. package/dist/client/frame-protocol.js.map +1 -1
  284. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +2 -2
  285. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  286. package/dist/client/sharing/ShareButton.d.ts +2 -0
  287. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  288. package/dist/client/sharing/ShareButton.js +7 -6
  289. package/dist/client/sharing/ShareButton.js.map +1 -1
  290. package/dist/client/use-agent-engine-configured.d.ts +5 -0
  291. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  292. package/dist/client/use-agent-engine-configured.js +51 -25
  293. package/dist/client/use-agent-engine-configured.js.map +1 -1
  294. package/dist/collab/awareness.d.ts +2 -2
  295. package/dist/collab/awareness.d.ts.map +1 -1
  296. package/dist/collab/routes.d.ts +1 -1
  297. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  298. package/dist/notifications/routes.d.ts +3 -3
  299. package/dist/observability/routes.d.ts +8 -8
  300. package/dist/progress/routes.d.ts +1 -1
  301. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  302. package/dist/server/transcribe-voice.d.ts.map +1 -1
  303. package/dist/server/transcribe-voice.js +40 -24
  304. package/dist/server/transcribe-voice.js.map +1 -1
  305. package/dist/shared/mcp-embed-headers.d.ts +1 -0
  306. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  307. package/dist/shared/mcp-embed-headers.js +20 -1
  308. package/dist/shared/mcp-embed-headers.js.map +1 -1
  309. package/dist/styles/agent-native.css +56 -7
  310. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  311. package/dist/vite/client.d.ts.map +1 -1
  312. package/dist/vite/client.js +2 -0
  313. package/dist/vite/client.js.map +1 -1
  314. package/dist/voice/index.d.ts +5 -0
  315. package/dist/voice/index.d.ts.map +1 -0
  316. package/dist/voice/index.js +4 -0
  317. package/dist/voice/index.js.map +1 -0
  318. package/dist/voice/voice-cleanup-prompt.d.ts +6 -0
  319. package/dist/voice/voice-cleanup-prompt.d.ts.map +1 -0
  320. package/dist/voice/voice-cleanup-prompt.js +26 -0
  321. package/dist/voice/voice-cleanup-prompt.js.map +1 -0
  322. package/dist/voice/voice-context.d.ts +25 -0
  323. package/dist/voice/voice-context.d.ts.map +1 -0
  324. package/dist/voice/voice-context.js +156 -0
  325. package/dist/voice/voice-context.js.map +1 -0
  326. package/dist/voice/voice-replacements.d.ts +4 -0
  327. package/dist/voice/voice-replacements.d.ts.map +1 -0
  328. package/dist/voice/voice-replacements.js +52 -0
  329. package/dist/voice/voice-replacements.js.map +1 -0
  330. package/docs/content/locales/ar-SA/template-design.mdx +41 -0
  331. package/docs/content/locales/de-DE/template-design.mdx +51 -0
  332. package/docs/content/locales/es-ES/template-design.mdx +50 -0
  333. package/docs/content/locales/fr-FR/template-design.mdx +49 -0
  334. package/docs/content/locales/hi-IN/template-design.mdx +44 -0
  335. package/docs/content/locales/ja-JP/template-design.mdx +46 -0
  336. package/docs/content/locales/ko-KR/template-design.mdx +44 -0
  337. package/docs/content/locales/pt-BR/template-design.mdx +48 -0
  338. package/docs/content/locales/zh-CN/template-design.mdx +36 -0
  339. package/docs/content/locales/zh-TW/template-design.mdx +38 -0
  340. package/docs/content/template-design.mdx +45 -0
  341. package/package.json +2 -1
  342. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
  343. package/corpus/templates/design/app/components/design/DesignToolbar.tsx +0 -339
  344. package/corpus/templates/design/app/components/design/PresentMode.tsx +0 -68
  345. package/corpus/templates/design/app/components/design/ViewportTabs.tsx +0 -149
  346. package/corpus/templates/design/app/components/design/ZoomControls.tsx +0 -157
@@ -0,0 +1,518 @@
1
+ import {
2
+ Dithering,
3
+ GodRays,
4
+ GrainGradient,
5
+ MeshGradient,
6
+ Metaballs,
7
+ PaperTexture,
8
+ Voronoi,
9
+ Warp,
10
+ } from "@paper-design/shaders-react";
11
+ import {
12
+ SHADER_PRESET_MAP,
13
+ SHADER_PRESETS,
14
+ type ParamDef,
15
+ type ShaderDescriptor,
16
+ type ShaderPresetDef,
17
+ type ShaderPresetName,
18
+ } from "@shared/shader-presets";
19
+ import { useMemo, useState } from "react";
20
+
21
+ import { Button } from "@/components/ui/button";
22
+ import { Label } from "@/components/ui/label";
23
+ import {
24
+ Select,
25
+ SelectContent,
26
+ SelectItem,
27
+ SelectTrigger,
28
+ SelectValue,
29
+ } from "@/components/ui/select";
30
+ import { Switch } from "@/components/ui/switch";
31
+ import {
32
+ Tooltip,
33
+ TooltipContent,
34
+ TooltipTrigger,
35
+ } from "@/components/ui/tooltip";
36
+ import { cn } from "@/lib/utils";
37
+
38
+ import { ScrubInput } from "./ScrubInput";
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Dynamic shader component map
42
+ // ---------------------------------------------------------------------------
43
+
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ type AnyShaderComponent = React.ComponentType<Record<string, any>>;
46
+
47
+ const SHADER_COMPONENTS: Record<ShaderPresetName, AnyShaderComponent> = {
48
+ MeshGradient: MeshGradient as AnyShaderComponent,
49
+ GrainGradient: GrainGradient as AnyShaderComponent,
50
+ Voronoi: Voronoi as AnyShaderComponent,
51
+ Metaballs: Metaballs as AnyShaderComponent,
52
+ Warp: Warp as AnyShaderComponent,
53
+ GodRays: GodRays as AnyShaderComponent,
54
+ Dithering: Dithering as AnyShaderComponent,
55
+ PaperTexture: PaperTexture as AnyShaderComponent,
56
+ };
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // Reduced-motion helper (inline, SSR-safe)
60
+ // ---------------------------------------------------------------------------
61
+
62
+ function getPreferreducedMotion(): boolean {
63
+ if (typeof window === "undefined") return false;
64
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // ShaderPreview sub-component
69
+ // ---------------------------------------------------------------------------
70
+
71
+ interface ShaderPreviewProps {
72
+ descriptor: ShaderDescriptor;
73
+ animated: boolean;
74
+ }
75
+
76
+ function ShaderPreview({ descriptor, animated }: ShaderPreviewProps) {
77
+ const preset = SHADER_PRESET_MAP[descriptor.preset];
78
+ const ShaderComponent = SHADER_COMPONENTS[descriptor.preset];
79
+
80
+ // Build props — memoized to avoid identity churn on the WebGL layer
81
+ const shaderProps = useMemo(() => {
82
+ const p: Record<string, unknown> = { ...descriptor.params };
83
+ if (descriptor.colors !== undefined) p.colors = descriptor.colors;
84
+ if (descriptor.fit !== undefined) p.fit = descriptor.fit;
85
+ if (descriptor.scale !== undefined) p.scale = descriptor.scale;
86
+ if (descriptor.rotation !== undefined) p.rotation = descriptor.rotation;
87
+ if (descriptor.offsetX !== undefined) p.offsetX = descriptor.offsetX;
88
+ if (descriptor.offsetY !== undefined) p.offsetY = descriptor.offsetY;
89
+ p.speed = animated ? (descriptor.speed ?? 1) : 0;
90
+ if (!animated) p.frame = descriptor.frame ?? 0;
91
+ return p;
92
+ }, [descriptor, animated]);
93
+
94
+ // Fallback gradient from the preset's default colors
95
+ const fallbackColors =
96
+ (preset?.defaultColors ?? preset?.defaultColorBack)
97
+ ? [preset.defaultColorBack ?? "#555", preset.defaultColors?.[0] ?? "#888"]
98
+ : ["#555555", "#888888"];
99
+
100
+ const fallbackStyle = {
101
+ background: `linear-gradient(135deg, ${fallbackColors.join(", ")})`,
102
+ };
103
+
104
+ try {
105
+ return (
106
+ <div
107
+ className="relative overflow-hidden rounded"
108
+ style={{ width: 120, height: 80 }}
109
+ >
110
+ <ShaderComponent
111
+ {...shaderProps}
112
+ style={{
113
+ position: "absolute",
114
+ inset: 0,
115
+ width: "100%",
116
+ height: "100%",
117
+ }}
118
+ />
119
+ </div>
120
+ );
121
+ } catch {
122
+ return (
123
+ <Tooltip>
124
+ <TooltipTrigger asChild>
125
+ <div
126
+ className="rounded"
127
+ style={{ width: 120, height: 80, ...fallbackStyle }}
128
+ />
129
+ </TooltipTrigger>
130
+ <TooltipContent>
131
+ {
132
+ "WebGL unavailable - showing fallback" /* i18n-ignore shader tooltip */
133
+ }
134
+ </TooltipContent>
135
+ </Tooltip>
136
+ );
137
+ }
138
+ }
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // Param row renderers
142
+ // ---------------------------------------------------------------------------
143
+
144
+ interface ParamRowProps {
145
+ paramDef: ParamDef;
146
+ value: number | boolean | string | string[];
147
+ onChange: (key: string, value: number | boolean | string | string[]) => void;
148
+ }
149
+
150
+ function ParamRow({ paramDef, value, onChange }: ParamRowProps) {
151
+ const { key, kind, label, min, max, step, options, maxCount } = paramDef;
152
+
153
+ if (kind === "number") {
154
+ const numVal = typeof value === "number" ? value : Number(paramDef.default);
155
+ return (
156
+ <ScrubInput
157
+ label={label}
158
+ value={numVal}
159
+ min={min}
160
+ max={max}
161
+ step={step ?? 1}
162
+ onChange={(v) => onChange(key, v)}
163
+ className="w-full"
164
+ />
165
+ );
166
+ }
167
+
168
+ if (kind === "enum") {
169
+ const strVal = typeof value === "string" ? value : String(paramDef.default);
170
+ return (
171
+ <div className="flex items-center gap-2">
172
+ <span className="w-20 shrink-0 truncate text-xs text-muted-foreground">
173
+ {label}
174
+ </span>
175
+ <Select value={strVal} onValueChange={(v) => onChange(key, v)}>
176
+ <SelectTrigger className="h-7 flex-1 text-xs">
177
+ <SelectValue />
178
+ </SelectTrigger>
179
+ <SelectContent>
180
+ {(options ?? []).map((opt: string) => (
181
+ <SelectItem key={opt} value={opt} className="text-xs">
182
+ {opt}
183
+ </SelectItem>
184
+ ))}
185
+ </SelectContent>
186
+ </Select>
187
+ </div>
188
+ );
189
+ }
190
+
191
+ if (kind === "bool") {
192
+ const boolVal =
193
+ typeof value === "boolean" ? value : Boolean(paramDef.default);
194
+ const switchId = `shader-param-${key}`;
195
+ return (
196
+ <div className="flex items-center justify-between gap-2">
197
+ <Label htmlFor={switchId} className="text-xs text-muted-foreground">
198
+ {label}
199
+ </Label>
200
+ <Switch
201
+ id={switchId}
202
+ checked={boolVal}
203
+ onCheckedChange={(checked) => onChange(key, checked)}
204
+ className="scale-90"
205
+ />
206
+ </div>
207
+ );
208
+ }
209
+
210
+ if (kind === "color") {
211
+ const strVal = typeof value === "string" ? value : String(paramDef.default);
212
+ return (
213
+ <div className="flex items-center gap-2">
214
+ <span className="w-20 shrink-0 truncate text-xs text-muted-foreground">
215
+ {label}
216
+ </span>
217
+ <Tooltip>
218
+ <TooltipTrigger asChild>
219
+ <input
220
+ type="color"
221
+ value={strVal}
222
+ onChange={(e) => onChange(key, e.target.value)}
223
+ className="h-7 w-8 cursor-pointer rounded border border-border bg-transparent p-0.5"
224
+ aria-label={label}
225
+ />
226
+ </TooltipTrigger>
227
+ <TooltipContent>{label}</TooltipContent>
228
+ </Tooltip>
229
+ <span className="text-[10px] text-muted-foreground">{strVal}</span>
230
+ </div>
231
+ );
232
+ }
233
+
234
+ if (kind === "colors") {
235
+ const arrVal = Array.isArray(value)
236
+ ? value
237
+ : (paramDef.default as string[]);
238
+ const limit = maxCount ?? 10;
239
+ return (
240
+ <div className="flex flex-col gap-1">
241
+ <span className="text-xs text-muted-foreground">{label}</span>
242
+ <div className="flex flex-wrap gap-1">
243
+ {arrVal.map((color, i) => {
244
+ const colorLabel = `Color ${i + 1}`;
245
+ return (
246
+ <div key={i} className="flex items-center gap-0.5">
247
+ <Tooltip>
248
+ <TooltipTrigger asChild>
249
+ <input
250
+ type="color"
251
+ value={color}
252
+ onChange={(e) => {
253
+ const next = [...arrVal];
254
+ next[i] = e.target.value;
255
+ onChange(key, next);
256
+ }}
257
+ className="h-6 w-6 cursor-pointer rounded border border-border bg-transparent p-0"
258
+ aria-label={colorLabel}
259
+ />
260
+ </TooltipTrigger>
261
+ <TooltipContent>{colorLabel}</TooltipContent>
262
+ </Tooltip>
263
+ {arrVal.length > 1 && (
264
+ <Tooltip>
265
+ <TooltipTrigger asChild>
266
+ <button
267
+ type="button"
268
+ onClick={() => {
269
+ const next = arrVal.filter((_, idx) => idx !== i);
270
+ onChange(key, next);
271
+ }}
272
+ className="text-[10px] leading-none text-muted-foreground hover:text-destructive"
273
+ aria-label={
274
+ "Remove color" /* i18n-ignore shader tooltip */
275
+ }
276
+ >
277
+ x
278
+ </button>
279
+ </TooltipTrigger>
280
+ <TooltipContent>
281
+ {"Remove color" /* i18n-ignore shader tooltip */}
282
+ </TooltipContent>
283
+ </Tooltip>
284
+ )}
285
+ </div>
286
+ );
287
+ })}
288
+ {arrVal.length < limit && (
289
+ <Button
290
+ variant="ghost"
291
+ size="sm"
292
+ className="h-6 px-2 text-[10px]"
293
+ onClick={() => onChange(key, [...arrVal, "#ffffff"])}
294
+ >
295
+ {"+ Add" /* i18n-ignore shader compact add button */}
296
+ </Button>
297
+ )}
298
+ </div>
299
+ </div>
300
+ );
301
+ }
302
+
303
+ return null;
304
+ }
305
+
306
+ // ---------------------------------------------------------------------------
307
+ // Main ShaderControls component
308
+ // ---------------------------------------------------------------------------
309
+
310
+ export interface ShaderControlsProps {
311
+ descriptor: ShaderDescriptor;
312
+ onChange: (descriptor: ShaderDescriptor) => void;
313
+ className?: string;
314
+ }
315
+
316
+ export function ShaderControls({
317
+ descriptor,
318
+ onChange,
319
+ className,
320
+ }: ShaderControlsProps) {
321
+ const prefersReducedMotion = getPreferreducedMotion();
322
+
323
+ const [animated, setAnimated] = useState(
324
+ () => (descriptor.speed ?? 0) !== 0 && !prefersReducedMotion,
325
+ );
326
+
327
+ const preset = SHADER_PRESET_MAP[descriptor.preset];
328
+
329
+ // Check if any expensive param is non-zero
330
+ const hasExpensiveParam = preset?.params.some(
331
+ (p: ParamDef) =>
332
+ p.isExpensive && Number(descriptor.params[p.key] ?? p.default) > 0,
333
+ );
334
+
335
+ function handlePresetChange(name: string) {
336
+ const newPreset = SHADER_PRESET_MAP[name as ShaderPresetName];
337
+ if (!newPreset) return;
338
+
339
+ const defaults: Record<string, number | boolean | string> = {};
340
+ for (const p of newPreset.params) {
341
+ if (p.kind !== "colors" && !Array.isArray(p.default)) {
342
+ defaults[p.key] = p.default as number | boolean | string;
343
+ }
344
+ }
345
+
346
+ onChange({
347
+ preset: newPreset.name,
348
+ params: defaults,
349
+ colors: newPreset.defaultColors ?? undefined,
350
+ speed: descriptor.speed,
351
+ frame: descriptor.frame,
352
+ });
353
+ }
354
+
355
+ function handleParamChange(
356
+ key: string,
357
+ value: number | boolean | string | string[],
358
+ ) {
359
+ if (Array.isArray(value)) {
360
+ // colors-kind param
361
+ onChange({
362
+ ...descriptor,
363
+ params: { ...descriptor.params, [key]: value as unknown as string },
364
+ });
365
+ } else {
366
+ onChange({
367
+ ...descriptor,
368
+ params: { ...descriptor.params, [key]: value },
369
+ });
370
+ }
371
+ }
372
+
373
+ function handleColorsParamChange(key: string, value: string[]) {
374
+ // The shader-specific colors[] key may differ from the universal one;
375
+ // for now store on descriptor.colors when the param key matches "colors".
376
+ if (key === "colors") {
377
+ onChange({ ...descriptor, colors: value });
378
+ } else {
379
+ // Store as JSON string in params for non-standard color arrays
380
+ onChange({
381
+ ...descriptor,
382
+ params: { ...descriptor.params, [key]: JSON.stringify(value) },
383
+ });
384
+ }
385
+ }
386
+
387
+ function handleAnimatedChange(on: boolean) {
388
+ setAnimated(on);
389
+ if (!on) {
390
+ onChange({ ...descriptor, speed: 0 });
391
+ } else {
392
+ onChange({
393
+ ...descriptor,
394
+ speed:
395
+ descriptor.speed && descriptor.speed !== 0 ? descriptor.speed : 1,
396
+ });
397
+ }
398
+ }
399
+
400
+ function handleSpeedChange(v: number) {
401
+ onChange({ ...descriptor, speed: v });
402
+ }
403
+
404
+ const animateSwitchId = "shader-animate";
405
+
406
+ return (
407
+ <div
408
+ className={cn(
409
+ "flex flex-col gap-3 rounded-md bg-[#1a1a1a] p-3 text-xs",
410
+ className,
411
+ )}
412
+ >
413
+ {/* Preset picker */}
414
+ <div className="flex flex-col gap-1.5">
415
+ <span className="text-[10px] uppercase tracking-wider text-muted-foreground">
416
+ Preset
417
+ </span>
418
+ <Select value={descriptor.preset} onValueChange={handlePresetChange}>
419
+ <SelectTrigger className="h-7 text-xs">
420
+ <SelectValue />
421
+ </SelectTrigger>
422
+ <SelectContent>
423
+ {(SHADER_PRESETS as readonly ShaderPresetDef[]).map((p) => (
424
+ <SelectItem key={p.name} value={p.name} className="text-xs">
425
+ {p.label}
426
+ </SelectItem>
427
+ ))}
428
+ </SelectContent>
429
+ </Select>
430
+ </div>
431
+
432
+ {/* Live preview */}
433
+ <div className="flex justify-center">
434
+ <ShaderPreview descriptor={descriptor} animated={animated} />
435
+ </div>
436
+
437
+ {/* Animate toggle */}
438
+ <div className="flex items-center justify-between gap-2">
439
+ <Label
440
+ htmlFor={animateSwitchId}
441
+ className={cn(
442
+ "text-xs text-muted-foreground",
443
+ prefersReducedMotion && "opacity-50",
444
+ )}
445
+ >
446
+ Animate
447
+ {prefersReducedMotion && (
448
+ <span className="ml-1 text-[10px]">(reduced motion)</span>
449
+ )}
450
+ </Label>
451
+ <Switch
452
+ id={animateSwitchId}
453
+ checked={animated}
454
+ onCheckedChange={handleAnimatedChange}
455
+ disabled={prefersReducedMotion}
456
+ className="scale-90"
457
+ />
458
+ </div>
459
+
460
+ {/* Speed scrub — only when animating */}
461
+ {animated && (
462
+ <ScrubInput
463
+ label="Speed"
464
+ value={descriptor.speed ?? 1}
465
+ min={-5}
466
+ max={5}
467
+ step={0.1}
468
+ onChange={handleSpeedChange}
469
+ className="w-full"
470
+ />
471
+ )}
472
+
473
+ {/* Shader-specific params */}
474
+ {preset && preset.params.length > 0 && (
475
+ <div className="flex flex-col gap-2">
476
+ <span className="text-[10px] uppercase tracking-wider text-muted-foreground">
477
+ Parameters
478
+ </span>
479
+ {preset.params.map((paramDef: ParamDef) => {
480
+ if (paramDef.kind === "colors") {
481
+ // Resolve the current color array
482
+ const val: string[] =
483
+ descriptor.colors ?? preset.defaultColors ?? [];
484
+ return (
485
+ <ParamRow
486
+ key={paramDef.key}
487
+ paramDef={paramDef}
488
+ value={val}
489
+ onChange={(k, v) => handleColorsParamChange(k, v as string[])}
490
+ />
491
+ );
492
+ }
493
+
494
+ const val = descriptor.params[paramDef.key] ?? paramDef.default;
495
+
496
+ return (
497
+ <ParamRow
498
+ key={paramDef.key}
499
+ paramDef={paramDef}
500
+ value={val as number | boolean | string}
501
+ onChange={handleParamChange}
502
+ />
503
+ );
504
+ })}
505
+ </div>
506
+ )}
507
+
508
+ {/* Expensive param performance warning */}
509
+ {hasExpensiveParam && (
510
+ <p className="rounded bg-yellow-950/50 px-2 py-1 text-[10px] text-yellow-400">
511
+ {
512
+ "grainMixer / grainOverlay may impact performance on mobile" /* i18n-ignore shader performance warning */
513
+ }
514
+ </p>
515
+ )}
516
+ </div>
517
+ );
518
+ }
@@ -0,0 +1,106 @@
1
+ import {
2
+ SHADER_PRESET_MAP,
3
+ type ShaderDescriptor,
4
+ } from "@shared/shader-presets";
5
+ import { IconTrash } from "@tabler/icons-react";
6
+
7
+ import { Button } from "@/components/ui/button";
8
+ import {
9
+ Popover,
10
+ PopoverContent,
11
+ PopoverTrigger,
12
+ } from "@/components/ui/popover";
13
+ import {
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipTrigger,
17
+ } from "@/components/ui/tooltip";
18
+ import { cn } from "@/lib/utils";
19
+
20
+ import { ShaderControls } from "./ShaderControls";
21
+
22
+ export interface ShaderEffectRowProps {
23
+ descriptor: ShaderDescriptor;
24
+ onChange: (descriptor: ShaderDescriptor) => void;
25
+ onRemove: () => void;
26
+ className?: string;
27
+ }
28
+
29
+ export function ShaderEffectRow({
30
+ descriptor,
31
+ onChange,
32
+ onRemove,
33
+ className,
34
+ }: ShaderEffectRowProps) {
35
+ const preset = SHADER_PRESET_MAP[descriptor.preset];
36
+
37
+ // Resolve swatch color: first color in the palette, or preset default, or gray
38
+ const swatchColor =
39
+ descriptor.colors?.[0] ??
40
+ preset?.defaultColors?.[0] ??
41
+ preset?.defaultColorBack ??
42
+ "#888888";
43
+
44
+ const label = preset?.label ?? descriptor.preset;
45
+
46
+ return (
47
+ <div
48
+ className={cn(
49
+ "flex h-8 items-center gap-2 rounded px-1 hover:bg-accent/50",
50
+ className,
51
+ )}
52
+ >
53
+ {/* Color swatch */}
54
+ <div
55
+ className="size-4 shrink-0 rounded-sm border border-border/40"
56
+ style={{ background: swatchColor }}
57
+ aria-hidden="true"
58
+ />
59
+
60
+ {/* Preset label — click to open controls popover */}
61
+ <Popover>
62
+ <Tooltip>
63
+ <TooltipTrigger asChild>
64
+ <PopoverTrigger asChild>
65
+ <button
66
+ type="button"
67
+ className="flex-1 truncate text-left text-xs text-foreground hover:text-foreground/80 focus:outline-none"
68
+ >
69
+ {label}
70
+ </button>
71
+ </PopoverTrigger>
72
+ </TooltipTrigger>
73
+ {preset?.description ? (
74
+ <TooltipContent>{preset.description}</TooltipContent>
75
+ ) : null}
76
+ </Tooltip>
77
+ <PopoverContent
78
+ side="left"
79
+ align="start"
80
+ className="w-72 p-0"
81
+ sideOffset={8}
82
+ >
83
+ <ShaderControls descriptor={descriptor} onChange={onChange} />
84
+ </PopoverContent>
85
+ </Popover>
86
+
87
+ {/* Remove button */}
88
+ <Tooltip>
89
+ <TooltipTrigger asChild>
90
+ <Button
91
+ variant="ghost"
92
+ size="icon"
93
+ className="size-5 shrink-0 text-muted-foreground hover:text-destructive"
94
+ onClick={onRemove}
95
+ aria-label={"Remove shader effect" /* i18n-ignore shader tooltip */}
96
+ >
97
+ <IconTrash className="size-3" />
98
+ </Button>
99
+ </TooltipTrigger>
100
+ <TooltipContent>
101
+ {"Remove shader effect" /* i18n-ignore shader tooltip */}
102
+ </TooltipContent>
103
+ </Tooltip>
104
+ </div>
105
+ );
106
+ }