@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.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +26 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +41 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +51 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +50 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +49 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +44 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +46 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +44 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +48 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +36 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +38 -0
- package/corpus/core/docs/content/template-design.mdx +45 -0
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/engine/index.ts +1 -0
- package/corpus/core/src/agent/engine/registry.ts +40 -0
- package/corpus/core/src/agent/production-agent.ts +6 -2
- package/corpus/core/src/cli/design-connect.ts +490 -0
- package/corpus/core/src/cli/index.ts +16 -0
- package/corpus/core/src/cli/skills.ts +126 -3
- package/corpus/core/src/client/AssistantChat.tsx +43 -7
- package/corpus/core/src/client/agent-chat.ts +27 -3
- package/corpus/core/src/client/blocks/library/MermaidBlock.tsx +1 -1
- package/corpus/core/src/client/blocks/library/diagram.tsx +2 -2
- package/corpus/core/src/client/blocks/library/wireframe.tsx +1 -1
- package/corpus/core/src/client/chat/message-components.tsx +1 -1
- package/corpus/core/src/client/chat-model-groups.ts +1 -2
- package/corpus/core/src/client/components/LiveCursorOverlay.tsx +33 -66
- package/corpus/core/src/client/composer/TiptapComposer.tsx +99 -24
- package/corpus/core/src/client/composer/useVoiceDictation.ts +429 -260
- package/corpus/core/src/client/frame-protocol.ts +17 -2
- package/corpus/core/src/client/rich-markdown-editor/RegistryBlockNode.tsx +2 -2
- package/corpus/core/src/client/sharing/ShareButton.tsx +20 -15
- package/corpus/core/src/client/use-agent-engine-configured.ts +80 -28
- package/corpus/core/src/server/transcribe-voice.ts +57 -22
- package/corpus/core/src/shared/mcp-embed-headers.ts +23 -1
- package/corpus/core/src/styles/agent-native.css +56 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
- package/corpus/core/src/vite/client.ts +2 -0
- package/corpus/core/src/voice/index.ts +18 -0
- package/corpus/core/src/voice/voice-cleanup-prompt.ts +38 -0
- package/corpus/core/src/voice/voice-context.ts +217 -0
- package/corpus/core/src/voice/voice-replacements.ts +75 -0
- package/corpus/templates/analytics/AGENTS.md +4 -3
- package/corpus/templates/analytics/actions/list-session-recordings.ts +6 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +557 -400
- package/corpus/templates/analytics/app/global.css +0 -4
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +20 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +33 -8
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +7 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +7 -0
- package/corpus/templates/analytics/changelog/2026-06-28-ask-tab-now-matches-the-darker-app-background.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-28-dashboard-email-reports-now-use-cleaner-light-mode-snapshots.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-28-sessions-now-show-only-signed-in-recordings-with-playable-re.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +3 -3
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +29 -7
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +5 -2
- package/corpus/templates/analytics/server/lib/session-replay.ts +24 -4
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +4 -4
- package/corpus/templates/assets/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +29 -2
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +131 -42
- package/corpus/templates/brain/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/brain/app/i18n-data.ts +20 -0
- package/corpus/templates/brain/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +29 -1
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +417 -299
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/calendar/app/i18n-data.ts +20 -0
- package/corpus/templates/calendar/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +6 -19
- package/corpus/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/cleanup-transcript.ts +39 -9
- package/corpus/templates/clips/actions/finalize-meeting.ts +81 -12
- package/corpus/templates/clips/actions/lib/agents-md-context.ts +4 -1
- package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
- package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +1 -1
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +2 -2
- package/corpus/templates/clips/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/personal-vocabulary.ts +13 -8
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +60 -1
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +1 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -5
- package/corpus/templates/content/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +137 -0
- package/corpus/templates/design/AGENTS.md +95 -5
- package/corpus/templates/design/DESIGN.md +82 -0
- package/corpus/templates/design/DEVELOPING.md +43 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +426 -0
- package/corpus/templates/design/actions/apply-shader.ts +277 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +303 -0
- package/corpus/templates/design/actions/connect-localhost.ts +183 -0
- package/corpus/templates/design/actions/edit-design.ts +195 -42
- package/corpus/templates/design/actions/generate-design.ts +71 -1
- package/corpus/templates/design/actions/generate-screens.ts +193 -0
- package/corpus/templates/design/actions/get-code-layer-projection.ts +191 -0
- package/corpus/templates/design/actions/get-shader.ts +119 -0
- package/corpus/templates/design/actions/list-localhost-connections.ts +95 -0
- package/corpus/templates/design/actions/navigate.ts +55 -2
- package/corpus/templates/design/actions/view-screen.ts +68 -1
- package/corpus/templates/design/agent-native.app-skill.json +10 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +761 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +2057 -103
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +74 -38
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +399 -0
- package/corpus/templates/design/app/components/design/EditPanel.tsx +3185 -439
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +1124 -0
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3116 -147
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +700 -13
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +107 -63
- package/corpus/templates/design/app/components/design/index.ts +0 -5
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +286 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +699 -0
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +461 -0
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +166 -0
- package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +1420 -0
- package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +420 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +215 -0
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +71 -0
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +518 -0
- package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +106 -0
- package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +361 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +60 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +201 -0
- package/corpus/templates/design/app/components/design/types.ts +23 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +24 -13
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +4 -4
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +474 -36
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +22 -5
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +24 -11
- package/corpus/templates/design/app/global.css +121 -3
- package/corpus/templates/design/app/hooks/use-agent-generating.ts +4 -0
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +130 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +329 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +264 -0
- package/corpus/templates/design/app/i18n-data.ts +2790 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +5108 -851
- package/corpus/templates/design/changelog/2026-06-28-annotate-mode-now-combines-drawing-and-comment-pins-in-one-c.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-design-editor-panel-borders-are-cleaner-so-the-canvas-edge-s.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-drawing-prompts-now-reliably-open-and-submit-to-the-design-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-editor-app-menus-now-use-an-outline-agent-native-mark-with-b.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-layer-selection-now-updates-chat-context-without-opening-the.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-layer-selections-now-preserve-hidden-and-locked-canvas-state.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-handles-zooming-drawing-opening-and-dele.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-screen-overview-now-selects-screens-on-click-and-opens-them-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-screen-overview-zooms-into-the-active-screen-with-smoother-e.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-selected-element-chips-in-chat-are-shorter-and-easier-to-sca.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-the-design-editor-toolbar-is-more-compact-and-the-app-menu-m.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-at-the-top-of-the-design-sidebar-instead-of-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-28-tweaks-now-live-in-the-right-inspector-beside-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-active-sidebar-rows-use-soft-highlights.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-agents-can-now-open-screen-overview-focus-screens-and-add.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-agents-now-edit-broad-copy-changes-more-reliably.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-editor-extensions-now-run-inline-beside-the-artboard.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-sidebars-use-darker-chrome-and-chat-warns-immediately.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-visual-edit-can-open-localhost-routes-as-url-backed-screens.md +6 -0
- package/corpus/templates/design/package.json +1 -0
- package/corpus/templates/design/server/db/schema.ts +26 -0
- package/corpus/templates/design/server/lib/design-snapshot.ts +1 -1
- package/corpus/templates/design/server/plugins/agent-chat.ts +3 -0
- package/corpus/templates/design/shared/api.ts +27 -0
- package/corpus/templates/design/shared/canvas-frames.ts +103 -0
- package/corpus/templates/design/shared/canvas-math.ts +1058 -0
- package/corpus/templates/design/shared/code-layer.ts +2212 -0
- package/corpus/templates/design/shared/color-utils.ts +180 -0
- package/corpus/templates/design/shared/generation-session.ts +61 -0
- package/corpus/templates/design/shared/shader-presets.ts +782 -0
- package/corpus/templates/design/shared/shader-safety.ts +137 -0
- package/corpus/templates/design/shared/source-mode.ts +237 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +149 -6
- package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
- package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
- package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
- package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
- package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
- package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
- package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
- package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
- package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
- package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
- package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/forms/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/macros/changelog/2026-06-28-left-sidebar-footer-controls-use-less-divider-chrome.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +408 -247
- package/corpus/templates/mail/app/i18n/ar-SA.ts +4 -0
- package/corpus/templates/mail/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +4 -0
- package/corpus/templates/mail/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/mail/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/mail/app/i18n/hi-IN.ts +4 -0
- package/corpus/templates/mail/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/mail/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/mail/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/mail/app/i18n/zh-CN.ts +4 -0
- package/corpus/templates/mail/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/mail/changelog/2026-06-28-pinned-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +6 -8
- package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
- package/corpus/templates/plan/app/global.css +61 -78
- package/corpus/templates/plan/app/pages/PlansPage.tsx +8 -0
- package/corpus/templates/plan/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/plan/changelog/2026-06-28-plans-use-the-shared-neutral-light-and-dark-theme.md +6 -0
- package/corpus/templates/plan/changelog/2026-06-28-sending-open-feedback-from-a-plan-now-opens-the-inline-plan-.md +6 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +5 -5
- package/corpus/templates/slides/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +6 -0
- package/corpus/templates/videos/app/components/Sidebar.tsx +2 -2
- package/corpus/templates/videos/app/components/layout/Layout.tsx +29 -2
- package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +113 -30
- package/corpus/templates/videos/app/i18n/ar-SA.ts +2 -0
- package/corpus/templates/videos/app/i18n/de-DE.ts +2 -0
- package/corpus/templates/videos/app/i18n/en-US.ts +2 -0
- package/corpus/templates/videos/app/i18n/es-ES.ts +2 -0
- package/corpus/templates/videos/app/i18n/fr-FR.ts +2 -0
- package/corpus/templates/videos/app/i18n/hi-IN.ts +2 -0
- package/corpus/templates/videos/app/i18n/ja-JP.ts +2 -0
- package/corpus/templates/videos/app/i18n/ko-KR.ts +2 -0
- package/corpus/templates/videos/app/i18n/pt-BR.ts +2 -0
- package/corpus/templates/videos/app/i18n/zh-CN.ts +2 -0
- package/corpus/templates/videos/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +6 -0
- package/dist/agent/engine/index.d.ts +1 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +1 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +9 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +37 -0
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/design-connect.d.ts +52 -0
- package/dist/cli/design-connect.d.ts.map +1 -0
- package/dist/cli/design-connect.js +409 -0
- package/dist/cli/design-connect.js.map +1 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +121 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +38 -8
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts +6 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +17 -3
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/blocks/library/MermaidBlock.js +1 -1
- package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
- package/dist/client/blocks/library/diagram.js +1 -1
- package/dist/client/blocks/library/diagram.js.map +1 -1
- package/dist/client/blocks/library/wireframe.js +1 -1
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/client/chat/message-components.js +1 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +1 -2
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/components/LiveCursorOverlay.d.ts +1 -2
- package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
- package/dist/client/components/LiveCursorOverlay.js +19 -40
- package/dist/client/components/LiveCursorOverlay.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +3 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +86 -24
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/useVoiceDictation.d.ts +9 -0
- package/dist/client/composer/useVoiceDictation.d.ts.map +1 -1
- package/dist/client/composer/useVoiceDictation.js +154 -32
- package/dist/client/composer/useVoiceDictation.js.map +1 -1
- package/dist/client/frame-protocol.d.ts +17 -2
- package/dist/client/frame-protocol.d.ts.map +1 -1
- package/dist/client/frame-protocol.js.map +1 -1
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js +2 -2
- package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +2 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +7 -6
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts +5 -0
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +51 -25
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +8 -8
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts.map +1 -1
- package/dist/server/transcribe-voice.js +40 -24
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -0
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +20 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/styles/agent-native.css +56 -7
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +2 -0
- package/dist/vite/client.js.map +1 -1
- package/dist/voice/index.d.ts +5 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/index.js +4 -0
- package/dist/voice/index.js.map +1 -0
- package/dist/voice/voice-cleanup-prompt.d.ts +6 -0
- package/dist/voice/voice-cleanup-prompt.d.ts.map +1 -0
- package/dist/voice/voice-cleanup-prompt.js +26 -0
- package/dist/voice/voice-cleanup-prompt.js.map +1 -0
- package/dist/voice/voice-context.d.ts +25 -0
- package/dist/voice/voice-context.d.ts.map +1 -0
- package/dist/voice/voice-context.js +156 -0
- package/dist/voice/voice-context.js.map +1 -0
- package/dist/voice/voice-replacements.d.ts +4 -0
- package/dist/voice/voice-replacements.d.ts.map +1 -0
- package/dist/voice/voice-replacements.js +52 -0
- package/dist/voice/voice-replacements.js.map +1 -0
- package/docs/content/locales/ar-SA/template-design.mdx +41 -0
- package/docs/content/locales/de-DE/template-design.mdx +51 -0
- package/docs/content/locales/es-ES/template-design.mdx +50 -0
- package/docs/content/locales/fr-FR/template-design.mdx +49 -0
- package/docs/content/locales/hi-IN/template-design.mdx +44 -0
- package/docs/content/locales/ja-JP/template-design.mdx +46 -0
- package/docs/content/locales/ko-KR/template-design.mdx +44 -0
- package/docs/content/locales/pt-BR/template-design.mdx +48 -0
- package/docs/content/locales/zh-CN/template-design.mdx +36 -0
- package/docs/content/locales/zh-TW/template-design.mdx +38 -0
- package/docs/content/template-design.mdx +45 -0
- package/package.json +2 -1
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +10 -0
- package/corpus/templates/design/app/components/design/DesignToolbar.tsx +0 -339
- package/corpus/templates/design/app/components/design/PresentMode.tsx +0 -68
- package/corpus/templates/design/app/components/design/ViewportTabs.tsx +0 -149
- 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
|
+
}
|