@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,420 @@
1
+ # Shader Feature Integration Guide
2
+
3
+ This guide covers the five seam files that need edits to wire the GPU shader feature
4
+ into the design template. Each section gives the exact search string to locate the
5
+ right spot plus copy-pasteable code to insert or replace.
6
+
7
+ Do NOT rely on line numbers — they drift. Use the search strings instead.
8
+
9
+ ---
10
+
11
+ ## (a) FigmaColorPicker.tsx — Add `"shader"` fill type
12
+
13
+ **File:** `app/components/design/inspector/FigmaColorPicker.tsx`
14
+
15
+ ### 1. Extend `FigmaFillType`
16
+
17
+ Search for:
18
+
19
+ ```ts
20
+ export type FigmaFillType = "solid" | "gradient" | "image";
21
+ ```
22
+
23
+ Replace with:
24
+
25
+ ```ts
26
+ export type FigmaFillType = "solid" | "gradient" | "image" | "shader";
27
+ ```
28
+
29
+ ### 2. Extend `FigmaPaintType`
30
+
31
+ Search for:
32
+
33
+ ```ts
34
+ export type FigmaPaintType =
35
+ | "solid"
36
+ | "linear"
37
+ | "radial"
38
+ | "angular"
39
+ | "diamond"
40
+ | "none";
41
+ ```
42
+
43
+ Replace with:
44
+
45
+ ```ts
46
+ export type FigmaPaintType =
47
+ | "solid"
48
+ | "linear"
49
+ | "radial"
50
+ | "angular"
51
+ | "diamond"
52
+ | "none"
53
+ | "shader";
54
+ ```
55
+
56
+ ### 3. Add `canUseShaders` prop to `FigmaColorPickerProps`
57
+
58
+ Search for:
59
+
60
+ ```ts
61
+ canUseGradients?: boolean
62
+ ```
63
+
64
+ After that line, add:
65
+
66
+ ```ts
67
+ canUseShaders?: boolean
68
+ ```
69
+
70
+ ### 4. Add shader button to the paint-type button row
71
+
72
+ Search for:
73
+
74
+ ```tsx
75
+ {canUseGradients && (
76
+ ```
77
+
78
+ After the closing `)}` of that block, add:
79
+
80
+ ```tsx
81
+ {
82
+ canUseShaders && (
83
+ <button
84
+ type="button"
85
+ className={cn(
86
+ "flex h-6 w-6 items-center justify-center rounded transition-colors",
87
+ paintType === "shader"
88
+ ? "bg-white/20 text-white"
89
+ : "text-white/50 hover:text-white",
90
+ )}
91
+ onClick={() => onPaintTypeChange?.("shader")}
92
+ title="Shader"
93
+ >
94
+ <IconSparkles size={14} />
95
+ </button>
96
+ );
97
+ }
98
+ ```
99
+
100
+ Add the import at the top of the file alongside the existing Tabler icon imports:
101
+
102
+ ```ts
103
+ import { IconSparkles } from "@tabler/icons-react";
104
+ ```
105
+
106
+ ### 5. Render `ShaderControls` when `paintType === "shader"`
107
+
108
+ Search for the block that renders gradient or color controls based on `paintType`.
109
+ It will look something like:
110
+
111
+ ```tsx
112
+ {paintType === "gradient" ? (
113
+ // gradient controls
114
+ ) : (
115
+ // solid color controls
116
+ )}
117
+ ```
118
+
119
+ Extend it to a three-way branch:
120
+
121
+ ```tsx
122
+ {paintType === "shader" ? (
123
+ <ShaderControls
124
+ descriptor={
125
+ (() => {
126
+ try {
127
+ return JSON.parse(value ?? "{}");
128
+ } catch {
129
+ return { preset: "MeshGradient", params: {}, colors: [], speed: 1, frame: 0, fit: "contain" };
130
+ }
131
+ })()
132
+ }
133
+ onChange={(descriptor) => {
134
+ onValueChange?.(JSON.stringify(descriptor));
135
+ }}
136
+ />
137
+ ) : paintType === "gradient" ? (
138
+ // existing gradient controls
139
+ ) : (
140
+ // existing solid color controls
141
+ )}
142
+ ```
143
+
144
+ Add the import near the other local inspector imports:
145
+
146
+ ```ts
147
+ import { ShaderControls } from "./ShaderControls";
148
+ ```
149
+
150
+ The fill row's `value` field holds the serialized `ShaderDescriptor` JSON when
151
+ `type === "shader"`. No schema change is needed — it reuses the existing `value: string`
152
+ slot.
153
+
154
+ ---
155
+
156
+ ## (b) EditPanel.tsx — Add `ShaderEffectRow` to `EffectsProperties`
157
+
158
+ **File:** `app/components/design/inspector/EditPanel.tsx`
159
+
160
+ ### 1. Add imports
161
+
162
+ Search for the block that imports `ShadowEffectRow` (or the effects-related imports).
163
+ Add alongside those:
164
+
165
+ ```ts
166
+ import { ShaderEffectRow } from "./inspector/ShaderEffectRow";
167
+ import type { ShaderDescriptor } from "../../shared/shader-presets";
168
+ ```
169
+
170
+ If `EditPanel.tsx` is itself inside the `inspector/` folder, drop the `inspector/` prefix:
171
+
172
+ ```ts
173
+ import { ShaderEffectRow } from "./ShaderEffectRow";
174
+ ```
175
+
176
+ ### 2. Extend `EffectsProperties` props
177
+
178
+ Search for the `EffectsProperties` function signature. It will include props like
179
+ `shadowLayers` and `blurLayers`. Add:
180
+
181
+ ```ts
182
+ shaderLayers?: ShaderDescriptor[];
183
+ onShaderLayersChange?: (layers: ShaderDescriptor[]) => void;
184
+ ```
185
+
186
+ ### 3. Render shader effect rows
187
+
188
+ Search for:
189
+
190
+ ```tsx
191
+ {shadowLayers.map(
192
+ ```
193
+
194
+ After the `shadowLayers.map(...)` block and the `blurLayers.map(...)` block
195
+ (whichever comes last), add:
196
+
197
+ ```tsx
198
+ {
199
+ (shaderLayers ?? []).map((layer, i) => (
200
+ <ShaderEffectRow
201
+ key={layer.id ?? i}
202
+ descriptor={layer}
203
+ onChange={(updated) => {
204
+ const next = [...(shaderLayers ?? [])];
205
+ next[i] = updated;
206
+ onShaderLayersChange?.(next);
207
+ }}
208
+ onRemove={() => {
209
+ const next = (shaderLayers ?? []).filter((_, j) => j !== i);
210
+ onShaderLayersChange?.(next);
211
+ }}
212
+ />
213
+ ));
214
+ }
215
+ ```
216
+
217
+ ### 4. Add "Add Shader" option to the effects dropdown
218
+
219
+ Search for the "Add effect" button or the dropdown that lets users add shadow/blur.
220
+ It will contain strings like `"Drop Shadow"` or `"Add Shadow"`. Add a shader option:
221
+
222
+ ```tsx
223
+ <DropdownMenuItem
224
+ onSelect={() => {
225
+ onShaderLayersChange?.([
226
+ ...(shaderLayers ?? []),
227
+ {
228
+ preset: "MeshGradient",
229
+ params: { distortion: 0.8, swirl: 0.1 },
230
+ colors: ["#e0eaff", "#241d9a", "#f75092", "#9f50d3"],
231
+ speed: 1,
232
+ frame: 0,
233
+ fit: "contain",
234
+ },
235
+ ]);
236
+ }}
237
+ >
238
+ Shader
239
+ </DropdownMenuItem>
240
+ ```
241
+
242
+ ---
243
+
244
+ ## (c) Register apply-shader and get-shader actions
245
+
246
+ No registration step is required. The actions directory is auto-discovered by the
247
+ framework at startup. Confirm both files exist:
248
+
249
+ ```
250
+ templates/design/actions/apply-shader.ts ✓
251
+ templates/design/actions/get-shader.ts ✓
252
+ ```
253
+
254
+ If either is missing, the agent won't have access to shader tools. The `defineAction`
255
+ export at the top of each file is all that's needed for automatic discovery.
256
+
257
+ ---
258
+
259
+ ## (d) DesignCanvas.tsx — Alpine/inline artboard shader bridge
260
+
261
+ **File:** `app/components/design/canvas/DesignCanvas.tsx` (or similar canvas file)
262
+
263
+ ### 1. Locate the bridge scripts injection point
264
+
265
+ Search for:
266
+
267
+ ```
268
+ // === BRIDGE SCRIPTS ===
269
+ ```
270
+
271
+ Or search for the injected HTML string that wires up the Alpine bridge. It will
272
+ contain `<script` tags being concatenated into a string that gets injected into the
273
+ artboard iframe.
274
+
275
+ ### 2. Add the shader mount script
276
+
277
+ Append the following after the existing bridge scripts (inside the same injected
278
+ content string):
279
+
280
+ ```js
281
+ const shaderBridgeScript = `
282
+ <script type="module">
283
+ import { ShaderMount } from 'https://esm.sh/@paper-design/shaders@0.0.76/dist/index.js';
284
+
285
+ function mountShaders() {
286
+ document.querySelectorAll('[data-shader]').forEach(el => {
287
+ if (el.__shaderMounted) return;
288
+ el.__shaderMounted = true;
289
+ try {
290
+ const descriptor = JSON.parse(el.getAttribute('data-shader') || '{}');
291
+ if (!descriptor.preset) return;
292
+ const canvas = document.createElement('canvas');
293
+ canvas.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;pointer-events:none;';
294
+ el.style.position = 'relative';
295
+ el.prepend(canvas);
296
+ // ShaderMount takes { canvas, preset, uniforms } — map descriptor.params to uniforms:
297
+ new ShaderMount({
298
+ canvas,
299
+ preset: descriptor.preset,
300
+ uniforms: {
301
+ ...(descriptor.params ?? {}),
302
+ colors: descriptor.colors ?? [],
303
+ speed: descriptor.speed ?? 1,
304
+ },
305
+ });
306
+ console.log('[shader bridge] mounted', descriptor.preset, 'on', el);
307
+ } catch (e) {
308
+ console.warn('[shader bridge] mount failed:', e);
309
+ }
310
+ });
311
+ }
312
+
313
+ document.addEventListener('DOMContentLoaded', mountShaders);
314
+ // Re-run on mutations (new elements added dynamically):
315
+ new MutationObserver(mountShaders).observe(document.body, { childList: true, subtree: true });
316
+ <\/script>
317
+ `;
318
+ ```
319
+
320
+ Concatenate `shaderBridgeScript` into the injected HTML alongside the other bridge
321
+ scripts. The exact concatenation point depends on how the existing bridge is assembled
322
+ — look for where the other `<script>` strings are joined.
323
+
324
+ ### 3. Add vanilla shaders package dependency
325
+
326
+ The bridge imports from `esm.sh` at runtime, so no local dep is strictly required
327
+ for the iframe bridge. However, if you want type-safe access in the canvas component
328
+ itself, add:
329
+
330
+ ```bash
331
+ pnpm add @paper-design/shaders
332
+ ```
333
+
334
+ in the `templates/design/` directory. The package provides both the React components
335
+ (already used via `@paper-design/shaders-react`) and the vanilla `ShaderMount` class.
336
+
337
+ ### 4. Ensure artboard elements carry `data-shader`
338
+
339
+ When the canvas renders an element whose fill type is `"shader"`, it must serialize
340
+ the `ShaderDescriptor` onto the DOM element as `data-shader`. Search for the artboard
341
+ render path (likely a function that serializes fills to inline styles or HTML
342
+ attributes) and add:
343
+
344
+ ```ts
345
+ if (fill.type === "shader") {
346
+ attrs["data-shader"] = JSON.stringify(fill.descriptor);
347
+ // Optionally set a placeholder background so the element is visible before mount:
348
+ styles["background"] = fill.descriptor.colors?.[0] ?? "transparent";
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ ## (e) Changelog entry (DEFERRED)
355
+
356
+ The shader feature is not yet user-reachable — it still needs all seam files wired.
357
+ Do NOT add a changelog entry yet.
358
+
359
+ Once the seam files are integrated and the feature is accessible from the UI (a user
360
+ can apply a shader fill from the fill picker or add a shader effect from the effects
361
+ panel), run:
362
+
363
+ ```bash
364
+ agent-native changelog add "Add GPU shader fills and effects — 8 presets (MeshGradient, GrainGradient, Voronoi, Metaballs, Warp, GodRays, Dithering, PaperTexture) with live preview and agent-tunable params" --type added
365
+ ```
366
+
367
+ from the `templates/design/` directory.
368
+
369
+ ---
370
+
371
+ ## (f) Design-system token shape (for Phase 6)
372
+
373
+ The design system `data` blob (returned by the `get-design-system` action) can be
374
+ extended to store shader tokens without any migration — `data` is already an untyped
375
+ JSON blob.
376
+
377
+ Search for `update-design-system.ts` and locate the `DesignSystemData` interface (or
378
+ wherever the `data` field is typed). Add:
379
+
380
+ ```ts
381
+ interface DesignSystemData {
382
+ // ... existing fields (colors, typography, spacing, etc.) ...
383
+ tokens?: {
384
+ shaders?: Array<{
385
+ id: string;
386
+ name: string;
387
+ descriptor: ShaderDescriptor;
388
+ }>;
389
+ };
390
+ }
391
+ ```
392
+
393
+ Import `ShaderDescriptor` from:
394
+
395
+ ```ts
396
+ import type { ShaderDescriptor } from "../shared/shader-presets";
397
+ ```
398
+
399
+ (Adjust the relative path based on where `update-design-system.ts` lives relative to
400
+ the `shared/` folder — typically `../../shared/shader-presets` from inside `actions/`.)
401
+
402
+ This shape lets the agent call `update-design-system` to persist named shader presets
403
+ as reusable design tokens, and `get-design-system` to retrieve them for display in a
404
+ shader token picker.
405
+
406
+ ---
407
+
408
+ ## Integration Checklist
409
+
410
+ - [ ] `FigmaColorPicker.tsx` — `FigmaFillType` includes `"shader"`
411
+ - [ ] `FigmaColorPicker.tsx` — `FigmaPaintType` includes `"shader"`
412
+ - [ ] `FigmaColorPicker.tsx` — shader button renders in paint-type row
413
+ - [ ] `FigmaColorPicker.tsx` — `ShaderControls` renders when `paintType === "shader"`
414
+ - [ ] `EditPanel.tsx` — `ShaderEffectRow` renders in `EffectsProperties`
415
+ - [ ] `EditPanel.tsx` — "Add Shader" option in effects dropdown
416
+ - [ ] `actions/apply-shader.ts` exists
417
+ - [ ] `actions/get-shader.ts` exists
418
+ - [ ] `DesignCanvas.tsx` — shader bridge script injected into artboard
419
+ - [ ] `DesignCanvas.tsx` — `data-shader` attribute serialized for shader fills
420
+ - [ ] Changelog entry added (after feature is user-reachable)
@@ -0,0 +1,215 @@
1
+ import { IconArrowsHorizontal } from "@tabler/icons-react";
2
+ import {
3
+ useEffect,
4
+ useId,
5
+ useRef,
6
+ useState,
7
+ type ComponentType,
8
+ type KeyboardEvent,
9
+ type PointerEvent,
10
+ } from "react";
11
+
12
+ import { Input } from "@/components/ui/input";
13
+ import { Label } from "@/components/ui/label";
14
+ import {
15
+ Tooltip,
16
+ TooltipContent,
17
+ TooltipTrigger,
18
+ } from "@/components/ui/tooltip";
19
+ import { cn } from "@/lib/utils";
20
+
21
+ import {
22
+ formatScrubValue,
23
+ getScrubStepFromEvent,
24
+ normalizeScrubNumber,
25
+ parseScrubExpression,
26
+ type ScrubExpressionOptions,
27
+ } from "./scrub-input-utils";
28
+
29
+ type ScrubInputIcon = ComponentType<{ className?: string }>;
30
+
31
+ export interface ScrubInputChangeMeta {
32
+ source: "commit" | "keyboard" | "scrub";
33
+ expression?: string;
34
+ }
35
+
36
+ export interface ScrubInputProps extends ScrubExpressionOptions {
37
+ label: string;
38
+ value: number;
39
+ onChange: (value: number, meta: ScrubInputChangeMeta) => void;
40
+ id?: string;
41
+ step?: number;
42
+ icon?: ScrubInputIcon;
43
+ disabled?: boolean;
44
+ placeholder?: string;
45
+ className?: string;
46
+ inputClassName?: string;
47
+ labelClassName?: string;
48
+ ariaLabel?: string;
49
+ }
50
+
51
+ export function ScrubInput({
52
+ label,
53
+ value,
54
+ onChange,
55
+ id,
56
+ step = 1,
57
+ unit,
58
+ min,
59
+ max,
60
+ precision,
61
+ icon: Icon = IconArrowsHorizontal,
62
+ disabled = false,
63
+ placeholder,
64
+ className,
65
+ inputClassName,
66
+ labelClassName,
67
+ ariaLabel,
68
+ }: ScrubInputProps) {
69
+ const generatedId = useId();
70
+ const inputId = id ?? generatedId;
71
+ const [draft, setDraft] = useState(() =>
72
+ formatScrubValue(value, { unit, precision }),
73
+ );
74
+ const [focused, setFocused] = useState(false);
75
+ const [dragging, setDragging] = useState(false);
76
+ const skipNextBlurCommitRef = useRef(false);
77
+ const dragRef = useRef({
78
+ pointerId: -1,
79
+ startX: 0,
80
+ startValue: value,
81
+ });
82
+
83
+ useEffect(() => {
84
+ if (!focused) setDraft(formatScrubValue(value, { unit, precision }));
85
+ }, [focused, precision, unit, value]);
86
+
87
+ const options = { unit, min, max, precision };
88
+
89
+ const setNextValue = (nextValue: number, meta: ScrubInputChangeMeta) => {
90
+ const normalized = normalizeScrubNumber(nextValue, options);
91
+ onChange(normalized, meta);
92
+ setDraft(formatScrubValue(normalized, options));
93
+ };
94
+
95
+ const commitDraft = () => {
96
+ const parsed = parseScrubExpression(draft, value, options);
97
+ if (!parsed) {
98
+ setDraft(formatScrubValue(value, options));
99
+ return;
100
+ }
101
+
102
+ setDraft(parsed.normalized);
103
+ if (parsed.value !== value) {
104
+ onChange(parsed.value, { source: "commit", expression: draft });
105
+ }
106
+ };
107
+
108
+ const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
109
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
110
+ event.preventDefault();
111
+ const direction = event.key === "ArrowUp" ? 1 : -1;
112
+ setNextValue(value + direction * getScrubStepFromEvent(event, step), {
113
+ source: "keyboard",
114
+ });
115
+ return;
116
+ }
117
+
118
+ if (event.key === "Enter") {
119
+ event.preventDefault();
120
+ commitDraft();
121
+ skipNextBlurCommitRef.current = true;
122
+ event.currentTarget.blur();
123
+ return;
124
+ }
125
+
126
+ if (event.key === "Escape") {
127
+ event.preventDefault();
128
+ setDraft(formatScrubValue(value, options));
129
+ skipNextBlurCommitRef.current = true;
130
+ event.currentTarget.blur();
131
+ }
132
+ };
133
+
134
+ const handlePointerDown = (event: PointerEvent<HTMLLabelElement>) => {
135
+ if (disabled || event.button !== 0) return;
136
+ event.preventDefault();
137
+ dragRef.current = {
138
+ pointerId: event.pointerId,
139
+ startX: event.clientX,
140
+ startValue: value,
141
+ };
142
+ event.currentTarget.setPointerCapture(event.pointerId);
143
+ setDragging(true);
144
+ };
145
+
146
+ const handlePointerMove = (event: PointerEvent<HTMLLabelElement>) => {
147
+ if (!dragging || dragRef.current.pointerId !== event.pointerId) return;
148
+ const delta = event.clientX - dragRef.current.startX;
149
+ if (delta === 0) return;
150
+ const next =
151
+ dragRef.current.startValue +
152
+ delta *
153
+ getScrubStepFromEvent(
154
+ { altKey: event.altKey, shiftKey: event.shiftKey },
155
+ step,
156
+ );
157
+ setNextValue(next, { source: "scrub" });
158
+ };
159
+
160
+ const endDrag = (event: PointerEvent<HTMLLabelElement>) => {
161
+ if (dragRef.current.pointerId !== event.pointerId) return;
162
+ event.currentTarget.releasePointerCapture(event.pointerId);
163
+ setDragging(false);
164
+ };
165
+
166
+ return (
167
+ <div className={cn("flex items-center gap-1.5", className)}>
168
+ <Tooltip>
169
+ <TooltipTrigger asChild>
170
+ <Label
171
+ htmlFor={inputId}
172
+ onPointerDown={handlePointerDown}
173
+ onPointerMove={handlePointerMove}
174
+ onPointerUp={endDrag}
175
+ onPointerCancel={endDrag}
176
+ className={cn(
177
+ "flex h-6 w-20 shrink-0 cursor-ew-resize select-none items-center gap-1 text-[11px] text-muted-foreground",
178
+ "hover:bg-[var(--design-editor-control-bg)] hover:rounded-sm",
179
+ dragging && "text-foreground",
180
+ disabled && "pointer-events-none cursor-not-allowed opacity-50",
181
+ labelClassName,
182
+ )}
183
+ >
184
+ <Icon className="size-3 shrink-0" />
185
+ <span className="truncate">{label}</span>
186
+ </Label>
187
+ </TooltipTrigger>
188
+ <TooltipContent>{`${label}. Drag to scrub, use arrows to step.`}</TooltipContent>
189
+ </Tooltip>
190
+ <Input
191
+ id={inputId}
192
+ value={draft}
193
+ disabled={disabled}
194
+ placeholder={placeholder}
195
+ inputMode="decimal"
196
+ aria-label={ariaLabel ?? label}
197
+ onFocus={(event) => {
198
+ setFocused(true);
199
+ event.target.select();
200
+ }}
201
+ onBlur={() => {
202
+ setFocused(false);
203
+ if (skipNextBlurCommitRef.current) {
204
+ skipNextBlurCommitRef.current = false;
205
+ return;
206
+ }
207
+ commitDraft();
208
+ }}
209
+ onChange={(event) => setDraft(event.target.value)}
210
+ onKeyDown={handleKeyDown}
211
+ className={cn("h-6 text-[11px] tabular-nums", inputClassName)}
212
+ />
213
+ </div>
214
+ );
215
+ }
@@ -0,0 +1,71 @@
1
+ import type { ShaderDescriptor } from "@shared/shader-presets";
2
+ import React, { useState } from "react";
3
+
4
+ import { ShaderControls } from "./ShaderControls";
5
+
6
+ const defaultMesh: ShaderDescriptor = {
7
+ preset: "MeshGradient",
8
+ params: { distortion: 0.8, swirl: 0.1 },
9
+ colors: ["#e0eaff", "#241d9a", "#f75092", "#9f50d3"],
10
+ speed: 1,
11
+ frame: 0,
12
+ fit: "contain",
13
+ };
14
+
15
+ const defaultGrain: ShaderDescriptor = {
16
+ preset: "GrainGradient",
17
+ params: { softness: 0.5, intensity: 0.5, noise: 0.25, shape: "corners" },
18
+ colors: ["#7300ff", "#eba8ff", "#00bfff"],
19
+ speed: 0,
20
+ frame: 0,
21
+ fit: "contain",
22
+ };
23
+
24
+ export function ShaderControlsDemo() {
25
+ const [mesh, setMesh] = useState<ShaderDescriptor>(defaultMesh);
26
+ const [grain, setGrain] = useState<ShaderDescriptor>(defaultGrain);
27
+ return (
28
+ <div
29
+ style={{
30
+ display: "flex",
31
+ gap: 24,
32
+ padding: 24,
33
+ background: "#111",
34
+ minHeight: "100vh",
35
+ }}
36
+ >
37
+ <div style={{ width: 280 }}>
38
+ <h3 style={{ color: "white", marginBottom: 12, fontSize: 12 }}>
39
+ MeshGradient
40
+ </h3>
41
+ <ShaderControls descriptor={mesh} onChange={setMesh} />
42
+ <pre
43
+ style={{
44
+ color: "#888",
45
+ fontSize: 10,
46
+ marginTop: 8,
47
+ overflow: "auto",
48
+ }}
49
+ >
50
+ {JSON.stringify(mesh, null, 2)}
51
+ </pre>
52
+ </div>
53
+ <div style={{ width: 280 }}>
54
+ <h3 style={{ color: "white", marginBottom: 12, fontSize: 12 }}>
55
+ GrainGradient
56
+ </h3>
57
+ <ShaderControls descriptor={grain} onChange={setGrain} />
58
+ <pre
59
+ style={{
60
+ color: "#888",
61
+ fontSize: 10,
62
+ marginTop: 8,
63
+ overflow: "auto",
64
+ }}
65
+ >
66
+ {JSON.stringify(grain, null, 2)}
67
+ </pre>
68
+ </div>
69
+ </div>
70
+ );
71
+ }