@agent-native/core 0.90.1 → 0.90.3
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/agent-native-toolkit.mdx +87 -80
- package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +89 -80
- package/corpus/core/docs/content/toolkit-agent-ux.mdx +43 -0
- package/corpus/core/docs/content/toolkit-app-adapters.mdx +9 -0
- package/corpus/core/docs/content/toolkit-collaboration-ui.mdx +12 -0
- package/corpus/core/docs/content/toolkit-collaboration.mdx +74 -0
- package/corpus/core/docs/content/toolkit-command-navigation.mdx +106 -0
- package/corpus/core/docs/content/toolkit-comments-review.mdx +98 -0
- package/corpus/core/docs/content/toolkit-history.mdx +95 -0
- package/corpus/core/docs/content/toolkit-observability.mdx +41 -0
- package/corpus/core/docs/content/toolkit-org-team.mdx +80 -0
- package/corpus/core/docs/content/toolkit-resources.mdx +57 -0
- package/corpus/core/docs/content/toolkit-settings.mdx +65 -0
- package/corpus/core/docs/content/toolkit-setup-connections.mdx +109 -0
- package/corpus/core/docs/content/toolkit-sharing-ui.mdx +18 -6
- package/corpus/core/docs/content/toolkit-sharing.mdx +81 -0
- package/corpus/core/docs/content/toolkit-shell-hooks.mdx +9 -0
- package/corpus/core/docs/content/toolkit-ui.mdx +9 -0
- package/corpus/core/package.json +35 -1
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +19 -1
- package/corpus/core/src/agent/engine/anthropic-engine.ts +25 -1
- package/corpus/core/src/agent/engine/registry.ts +23 -16
- package/corpus/core/src/agent/production-agent.ts +37 -6
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/command-navigation/index.ts +15 -0
- package/corpus/core/src/client/comments-review/index.ts +1 -0
- package/corpus/core/src/client/history/VersionHistoryPanel.tsx +145 -0
- package/corpus/core/src/client/history/index.ts +18 -0
- package/corpus/core/src/client/history/use-history.ts +86 -0
- package/corpus/core/src/client/index.ts +76 -9
- package/corpus/core/src/client/org/OrgSwitcher.tsx +6 -6
- package/corpus/core/src/client/org/RequireActiveOrg.tsx +2 -2
- package/corpus/core/src/client/org/TeamPage.tsx +3 -3
- package/corpus/core/src/client/org/hooks.ts +32 -0
- package/corpus/core/src/client/org/index.ts +30 -1
- package/corpus/core/src/client/org-team/index.ts +1 -0
- package/corpus/core/src/client/review/ReviewStatusBadge.tsx +39 -0
- package/corpus/core/src/client/review/ReviewThreadPanel.tsx +278 -0
- package/corpus/core/src/client/review/index.ts +25 -0
- package/corpus/core/src/client/review/use-review.ts +114 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
- package/corpus/core/src/client/settings/index.ts +11 -1
- package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +94 -0
- package/corpus/core/src/client/setup-connections/ProviderReadinessBadge.tsx +73 -0
- package/corpus/core/src/client/setup-connections/SetupConnectionsPage.tsx +94 -0
- package/corpus/core/src/client/setup-connections/index.ts +46 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +20 -14
- package/corpus/core/src/client/sharing/ShareDialog.tsx +3 -3
- package/corpus/core/src/client/use-action.ts +39 -2
- package/corpus/core/src/client/use-db-sync.ts +44 -18
- package/corpus/core/src/command-navigation/actions.ts +100 -0
- package/corpus/core/src/command-navigation/index.ts +12 -0
- package/corpus/core/src/comments-review/index.ts +1 -0
- package/corpus/core/src/db/create-get-db.ts +32 -2
- package/corpus/core/src/file-upload/builder.ts +24 -3
- package/corpus/core/src/file-upload/types.ts +3 -1
- package/corpus/core/src/history/actions/create-resource-version.ts +89 -0
- package/corpus/core/src/history/actions/get-resource-version.ts +60 -0
- package/corpus/core/src/history/actions/list-resource-history.ts +53 -0
- package/corpus/core/src/history/actions/list-resource-versions.ts +43 -0
- package/corpus/core/src/history/actions/restore-resource-version.ts +96 -0
- package/corpus/core/src/history/index.ts +27 -0
- package/corpus/core/src/history/registry.ts +99 -0
- package/corpus/core/src/history/store.ts +348 -0
- package/corpus/core/src/history/types.ts +69 -0
- package/corpus/core/src/index.ts +10 -0
- package/corpus/core/src/navigation/index.ts +170 -0
- package/corpus/core/src/org/index.ts +8 -0
- package/corpus/core/src/org/permissions.ts +30 -0
- package/corpus/core/src/org-team/index.ts +1 -0
- package/corpus/core/src/private-blob/registry.ts +1 -0
- package/corpus/core/src/review/actions/consume-review-feedback.ts +38 -0
- package/corpus/core/src/review/actions/create-review-comment.ts +107 -0
- package/corpus/core/src/review/actions/delete-review-comment.ts +55 -0
- package/corpus/core/src/review/actions/get-review-feedback.ts +54 -0
- package/corpus/core/src/review/actions/list-review-comments.ts +53 -0
- package/corpus/core/src/review/actions/reply-review-comment.ts +107 -0
- package/corpus/core/src/review/actions/resolve-review-thread.ts +60 -0
- package/corpus/core/src/review/actions/set-review-status.ts +58 -0
- package/corpus/core/src/review/index.ts +36 -0
- package/corpus/core/src/review/mentions.ts +44 -0
- package/corpus/core/src/review/registry.ts +99 -0
- package/corpus/core/src/review/store.ts +687 -0
- package/corpus/core/src/review/types.ts +97 -0
- package/corpus/core/src/server/action-discovery.ts +54 -0
- package/corpus/core/src/server/agent-engine-api-key-route.ts +5 -0
- package/corpus/core/src/server/credential-provider.ts +108 -0
- package/corpus/core/src/server/framework-request-handler.ts +52 -4
- package/corpus/core/src/setup-connections/index.ts +89 -0
- package/corpus/core/src/setup-connections/onboarding.ts +47 -0
- package/corpus/core/src/transcription/builder-transcription.ts +9 -2
- package/corpus/core/src/vite/action-types-plugin.ts +52 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +2 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/analytics/app/global.css +22 -10
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +6 -1
- package/corpus/templates/analytics/app/i18n-data.ts +81 -13
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +528 -108
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +466 -183
- package/corpus/templates/analytics/changelog/2026-07-07-session-replays-load-sooner-show-clearer-activity-timelines-.md +6 -0
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
- package/corpus/templates/assets/AGENTS.md +23 -4
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
- package/corpus/templates/assets/actions/_helpers.ts +8 -1
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
- package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
- package/corpus/templates/assets/actions/generate-image.ts +342 -25
- package/corpus/templates/assets/actions/get-library.ts +4 -3
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
- package/corpus/templates/assets/actions/update-asset.ts +1 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
- package/corpus/templates/assets/actions/view-screen.ts +8 -1
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
- package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
- package/corpus/templates/assets/app/i18n-data.ts +650 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
- package/corpus/templates/assets/app/routes/library.tsx +43 -1
- package/corpus/templates/assets/server/lib/generation.ts +366 -44
- package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
- package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
- package/corpus/templates/assets/shared/api.ts +47 -0
- package/corpus/templates/brain/app/routes/settings.tsx +2 -2
- package/corpus/templates/calendar/app/components/calendar/AttendeeAutocomplete.tsx +32 -6
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +120 -40
- package/corpus/templates/calendar/app/hooks/use-people.ts +55 -0
- package/corpus/templates/calendar/changelog/2026-07-07-guest-suggestions-now-find-coworkers-from-your-google-worksp.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-07-zoom-stays-selected-after-connecting-it-from-a-draft-event.md +6 -0
- package/corpus/templates/clips/actions/create-recording.ts +5 -1
- package/corpus/templates/clips/actions/finalize-recording.ts +140 -1
- package/corpus/templates/clips/actions/import-loom-recording.ts +1 -0
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +1 -0
- package/corpus/templates/clips/actions/request-transcript.ts +31 -0
- package/corpus/templates/clips/actions/set-thumbnail.ts +2 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
- package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/player/scrubber-position.ts +9 -0
- package/corpus/templates/clips/app/components/player/scrubber.tsx +5 -2
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +69 -41
- package/corpus/templates/clips/app/components/player/video-player.tsx +38 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +3 -3
- package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +9 -19
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +9 -3
- package/corpus/templates/clips/app/routes/record.tsx +178 -80
- package/corpus/templates/clips/changelog/2026-07-02-recordings-now-wait-for-storage-media-to-serve-before-finishing.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-a-pending-app-update-no-longer-blocks-screen-recording-updat.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-chrome-extension-recordings-keep-audio-after-refreshing-tab.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-clip-playback-progress-now-starts-and-finishes-at-the-right-times.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-sharing-public-clips-now-stays-focused-on-the-normal-link-wi.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +18 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +23 -8
- package/corpus/templates/clips/desktop/src/app.tsx +40 -3
- package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +19 -7
- package/corpus/templates/clips/desktop/src/lib/permissions.ts +2 -0
- package/corpus/templates/clips/desktop/src/lib/updater.ts +25 -2
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +7 -0
- package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +1 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +23 -6
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +28 -3
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +13 -6
- package/corpus/templates/clips/shared/finalize-recovery.ts +35 -3
- package/corpus/templates/content/AGENTS.md +52 -52
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
- package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
- package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
- package/corpus/templates/content/actions/_database-utils.ts +44 -4
- package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
- package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
- package/corpus/templates/content/actions/delete-content-database.ts +1 -0
- package/corpus/templates/content/actions/delete-document.ts +337 -52
- package/corpus/templates/content/actions/get-document.ts +11 -2
- package/corpus/templates/content/actions/list-content-databases.ts +57 -9
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
- package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
- package/corpus/templates/content/actions/restore-content-database.ts +1 -0
- package/corpus/templates/content/actions/update-document.ts +43 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
- package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
- package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
- package/corpus/templates/content/app/global.css +41 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
- package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
- package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
- package/corpus/templates/content/app/i18n-data.ts +355 -0
- package/corpus/templates/content/app/root.tsx +22 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
- package/corpus/templates/content/changelog/2026-07-07-permanently-deleting-trashed-databases-now-finishes-reliably.md +6 -0
- package/corpus/templates/content/shared/api.ts +13 -0
- package/corpus/templates/content/shared/builder-mdx.ts +16 -3
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
- package/corpus/templates/design/AGENTS.md +9 -2
- package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
- package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
- package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
- package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
- package/corpus/templates/design/actions/create-component.ts +29 -60
- package/corpus/templates/design/actions/create-file.ts +9 -2
- package/corpus/templates/design/actions/duplicate-design.ts +31 -2
- package/corpus/templates/design/actions/edit-design.ts +36 -38
- package/corpus/templates/design/actions/generate-design-title.ts +87 -0
- package/corpus/templates/design/actions/generate-design.ts +53 -18
- package/corpus/templates/design/actions/generate-screens.ts +108 -4
- package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
- package/corpus/templates/design/actions/insert-asset.ts +34 -29
- package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
- package/corpus/templates/design/actions/update-file.ts +190 -75
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
- package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
- package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
- package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
- package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
- package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
- package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
- package/corpus/templates/design/app/components/design/types.ts +15 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
- package/corpus/templates/design/app/global.css +8 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
- package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
- package/corpus/templates/design/app/i18n-data.ts +1664 -152
- package/corpus/templates/design/app/i18n-motion.ts +563 -0
- package/corpus/templates/design/app/lib/design-import.ts +73 -0
- package/corpus/templates/design/app/pages/Index.tsx +41 -22
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
- package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
- package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
- package/corpus/templates/design/server/source-workspace.ts +139 -59
- package/corpus/templates/design/shared/board-file.ts +11 -2
- package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
- package/corpus/templates/design/shared/canvas-math.ts +354 -35
- package/corpus/templates/design/shared/code-layer.ts +277 -8
- package/corpus/templates/design/shared/design-state.ts +11 -4
- package/corpus/templates/design/shared/interaction-states.ts +548 -0
- package/corpus/templates/design/shared/motion-compiler.ts +186 -23
- package/corpus/templates/design/shared/motion-easing.ts +294 -0
- package/corpus/templates/design/shared/motion-timeline.ts +400 -34
- package/corpus/templates/design/shared/prompt-title.ts +95 -0
- package/corpus/templates/design/shared/responsive-classes.ts +448 -10
- package/corpus/templates/design/shared/screen-annotation.ts +46 -0
- package/corpus/templates/design/shared/shader-fills.ts +1009 -0
- package/corpus/templates/design/shared/shader-presets.ts +852 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
- package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +2 -2
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +15 -1
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +20 -1
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +22 -14
- 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 +27 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/command-navigation/index.d.ts +4 -0
- package/dist/client/command-navigation/index.d.ts.map +1 -0
- package/dist/client/command-navigation/index.js +4 -0
- package/dist/client/command-navigation/index.js.map +1 -0
- package/dist/client/comments-review/index.d.ts +2 -0
- package/dist/client/comments-review/index.d.ts.map +1 -0
- package/dist/client/comments-review/index.js +2 -0
- package/dist/client/comments-review/index.js.map +1 -0
- package/dist/client/history/VersionHistoryPanel.d.ts +18 -0
- package/dist/client/history/VersionHistoryPanel.d.ts.map +1 -0
- package/dist/client/history/VersionHistoryPanel.js +24 -0
- package/dist/client/history/VersionHistoryPanel.js.map +1 -0
- package/dist/client/history/index.d.ts +3 -0
- package/dist/client/history/index.d.ts.map +1 -0
- package/dist/client/history/index.js +3 -0
- package/dist/client/history/index.js.map +1 -0
- package/dist/client/history/use-history.d.ts +46 -0
- package/dist/client/history/use-history.d.ts.map +1 -0
- package/dist/client/history/use-history.js +18 -0
- package/dist/client/history/use-history.js.map +1 -0
- package/dist/client/index.d.ts +6 -4
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -4
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.js +5 -5
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/RequireActiveOrg.js +2 -2
- package/dist/client/org/RequireActiveOrg.js.map +1 -1
- package/dist/client/org/TeamPage.js +3 -3
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/org/hooks.d.ts +12 -1
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +15 -0
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +4 -2
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +3 -1
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/org-team/index.d.ts +2 -0
- package/dist/client/org-team/index.d.ts.map +1 -0
- package/dist/client/org-team/index.js +2 -0
- package/dist/client/org-team/index.js.map +1 -0
- package/dist/client/review/ReviewStatusBadge.d.ts +7 -0
- package/dist/client/review/ReviewStatusBadge.d.ts.map +1 -0
- package/dist/client/review/ReviewStatusBadge.js +19 -0
- package/dist/client/review/ReviewStatusBadge.js.map +1 -0
- package/dist/client/review/ReviewThreadPanel.d.ts +20 -0
- package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -0
- package/dist/client/review/ReviewThreadPanel.js +84 -0
- package/dist/client/review/ReviewThreadPanel.js.map +1 -0
- package/dist/client/review/index.d.ts +4 -0
- package/dist/client/review/index.d.ts.map +1 -0
- package/dist/client/review/index.js +4 -0
- package/dist/client/review/index.js.map +1 -0
- package/dist/client/review/use-review.d.ts +68 -0
- package/dist/client/review/use-review.d.ts.map +1 -0
- package/dist/client/review/use-review.js +22 -0
- package/dist/client/review/use-review.js.map +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/settings/index.d.ts +1 -1
- package/dist/client/settings/index.d.ts.map +1 -1
- package/dist/client/settings/index.js +1 -1
- package/dist/client/settings/index.js.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.d.ts +9 -0
- package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -0
- package/dist/client/setup-connections/BuilderConnectCard.js +25 -0
- package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -0
- package/dist/client/setup-connections/ProviderReadinessBadge.d.ts +8 -0
- package/dist/client/setup-connections/ProviderReadinessBadge.d.ts.map +1 -0
- package/dist/client/setup-connections/ProviderReadinessBadge.js +32 -0
- package/dist/client/setup-connections/ProviderReadinessBadge.js.map +1 -0
- package/dist/client/setup-connections/SetupConnectionsPage.d.ts +17 -0
- package/dist/client/setup-connections/SetupConnectionsPage.d.ts.map +1 -0
- package/dist/client/setup-connections/SetupConnectionsPage.js +10 -0
- package/dist/client/setup-connections/SetupConnectionsPage.js.map +1 -0
- package/dist/client/setup-connections/index.d.ts +7 -0
- package/dist/client/setup-connections/index.d.ts.map +1 -0
- package/dist/client/setup-connections/index.js +7 -0
- package/dist/client/setup-connections/index.js.map +1 -0
- package/dist/client/sharing/ShareButton.d.ts +4 -4
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +13 -7
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.js +3 -3
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/client/use-action.d.ts +3 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +34 -3
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +37 -18
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/command-navigation/actions.d.ts +25 -0
- package/dist/command-navigation/actions.d.ts.map +1 -0
- package/dist/command-navigation/actions.js +64 -0
- package/dist/command-navigation/actions.js.map +1 -0
- package/dist/command-navigation/index.d.ts +4 -0
- package/dist/command-navigation/index.d.ts.map +1 -0
- package/dist/command-navigation/index.js +4 -0
- package/dist/command-navigation/index.js.map +1 -0
- package/dist/comments-review/index.d.ts +2 -0
- package/dist/comments-review/index.d.ts.map +1 -0
- package/dist/comments-review/index.js +2 -0
- package/dist/comments-review/index.js.map +1 -0
- package/dist/db/create-get-db.d.ts +25 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +25 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +18 -2
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/file-upload/types.d.ts +3 -0
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/history/actions/create-resource-version.d.ts +10 -0
- package/dist/history/actions/create-resource-version.d.ts.map +1 -0
- package/dist/history/actions/create-resource-version.js +65 -0
- package/dist/history/actions/create-resource-version.js.map +1 -0
- package/dist/history/actions/get-resource-version.d.ts +10 -0
- package/dist/history/actions/get-resource-version.d.ts.map +1 -0
- package/dist/history/actions/get-resource-version.js +38 -0
- package/dist/history/actions/get-resource-version.js.map +1 -0
- package/dist/history/actions/list-resource-history.d.ts +10 -0
- package/dist/history/actions/list-resource-history.d.ts.map +1 -0
- package/dist/history/actions/list-resource-history.js +45 -0
- package/dist/history/actions/list-resource-history.js.map +1 -0
- package/dist/history/actions/list-resource-versions.d.ts +10 -0
- package/dist/history/actions/list-resource-versions.d.ts.map +1 -0
- package/dist/history/actions/list-resource-versions.js +35 -0
- package/dist/history/actions/list-resource-versions.js.map +1 -0
- package/dist/history/actions/restore-resource-version.d.ts +11 -0
- package/dist/history/actions/restore-resource-version.d.ts.map +1 -0
- package/dist/history/actions/restore-resource-version.js +59 -0
- package/dist/history/actions/restore-resource-version.js.map +1 -0
- package/dist/history/index.d.ts +4 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +3 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/registry.d.ts +10 -0
- package/dist/history/registry.d.ts.map +1 -0
- package/dist/history/registry.js +61 -0
- package/dist/history/registry.js.map +1 -0
- package/dist/history/store.d.ts +34 -0
- package/dist/history/store.d.ts.map +1 -0
- package/dist/history/store.js +265 -0
- package/dist/history/store.js.map +1 -0
- package/dist/history/types.d.ts +55 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/history/types.js +2 -0
- package/dist/history/types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/navigation/index.d.ts +53 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +105 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/index.d.ts +1 -0
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +1 -0
- package/dist/org/index.js.map +1 -1
- package/dist/org/permissions.d.ts +7 -0
- package/dist/org/permissions.d.ts.map +1 -0
- package/dist/org/permissions.js +21 -0
- package/dist/org/permissions.js.map +1 -0
- package/dist/org-team/index.d.ts +2 -0
- package/dist/org-team/index.d.ts.map +1 -0
- package/dist/org-team/index.js +2 -0
- package/dist/org-team/index.js.map +1 -0
- package/dist/private-blob/registry.d.ts.map +1 -1
- package/dist/private-blob/registry.js +1 -0
- package/dist/private-blob/registry.js.map +1 -1
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/review/actions/consume-review-feedback.d.ts +9 -0
- package/dist/review/actions/consume-review-feedback.d.ts.map +1 -0
- package/dist/review/actions/consume-review-feedback.js +29 -0
- package/dist/review/actions/consume-review-feedback.js.map +1 -0
- package/dist/review/actions/create-review-comment.d.ts +18 -0
- package/dist/review/actions/create-review-comment.d.ts.map +1 -0
- package/dist/review/actions/create-review-comment.js +81 -0
- package/dist/review/actions/create-review-comment.js.map +1 -0
- package/dist/review/actions/delete-review-comment.d.ts +10 -0
- package/dist/review/actions/delete-review-comment.d.ts.map +1 -0
- package/dist/review/actions/delete-review-comment.js +45 -0
- package/dist/review/actions/delete-review-comment.js.map +1 -0
- package/dist/review/actions/get-review-feedback.d.ts +10 -0
- package/dist/review/actions/get-review-feedback.d.ts.map +1 -0
- package/dist/review/actions/get-review-feedback.js +45 -0
- package/dist/review/actions/get-review-feedback.js.map +1 -0
- package/dist/review/actions/list-review-comments.d.ts +13 -0
- package/dist/review/actions/list-review-comments.d.ts.map +1 -0
- package/dist/review/actions/list-review-comments.js +44 -0
- package/dist/review/actions/list-review-comments.js.map +1 -0
- package/dist/review/actions/reply-review-comment.d.ts +16 -0
- package/dist/review/actions/reply-review-comment.d.ts.map +1 -0
- package/dist/review/actions/reply-review-comment.js +84 -0
- package/dist/review/actions/reply-review-comment.js.map +1 -0
- package/dist/review/actions/resolve-review-thread.d.ts +11 -0
- package/dist/review/actions/resolve-review-thread.d.ts.map +1 -0
- package/dist/review/actions/resolve-review-thread.js +46 -0
- package/dist/review/actions/resolve-review-thread.js.map +1 -0
- package/dist/review/actions/set-review-status.d.ts +9 -0
- package/dist/review/actions/set-review-status.d.ts.map +1 -0
- package/dist/review/actions/set-review-status.js +43 -0
- package/dist/review/actions/set-review-status.js.map +1 -0
- package/dist/review/index.d.ts +5 -0
- package/dist/review/index.d.ts.map +1 -0
- package/dist/review/index.js +4 -0
- package/dist/review/index.js.map +1 -0
- package/dist/review/mentions.d.ts +4 -0
- package/dist/review/mentions.d.ts.map +1 -0
- package/dist/review/mentions.js +39 -0
- package/dist/review/mentions.js.map +1 -0
- package/dist/review/registry.d.ts +10 -0
- package/dist/review/registry.d.ts.map +1 -0
- package/dist/review/registry.js +61 -0
- package/dist/review/registry.js.map +1 -0
- package/dist/review/store.d.ts +63 -0
- package/dist/review/store.d.ts.map +1 -0
- package/dist/review/store.js +558 -0
- package/dist/review/store.js.map +1 -0
- package/dist/review/types.d.ts +77 -0
- package/dist/review/types.d.ts.map +1 -0
- package/dist/review/types.js +2 -0
- package/dist/review/types.js.map +1 -0
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +54 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts.map +1 -1
- package/dist/server/agent-engine-api-key-route.js +5 -0
- package/dist/server/agent-engine-api-key-route.js.map +1 -1
- package/dist/server/credential-provider.d.ts +26 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +82 -0
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +37 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/setup-connections/index.d.ts +6 -0
- package/dist/setup-connections/index.d.ts.map +1 -0
- package/dist/setup-connections/index.js +6 -0
- package/dist/setup-connections/index.js.map +1 -0
- package/dist/setup-connections/onboarding.d.ts +14 -0
- package/dist/setup-connections/onboarding.d.ts.map +1 -0
- package/dist/setup-connections/onboarding.js +23 -0
- package/dist/setup-connections/onboarding.js.map +1 -0
- package/dist/transcription/builder-transcription.d.ts +1 -0
- package/dist/transcription/builder-transcription.d.ts.map +1 -1
- package/dist/transcription/builder-transcription.js +5 -2
- package/dist/transcription/builder-transcription.js.map +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +52 -0
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/docs/content/agent-native-toolkit.mdx +87 -80
- package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/de-DE/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/es-ES/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +89 -80
- package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +89 -80
- package/docs/content/toolkit-agent-ux.mdx +43 -0
- package/docs/content/toolkit-app-adapters.mdx +9 -0
- package/docs/content/toolkit-collaboration-ui.mdx +12 -0
- package/docs/content/toolkit-collaboration.mdx +74 -0
- package/docs/content/toolkit-command-navigation.mdx +106 -0
- package/docs/content/toolkit-comments-review.mdx +98 -0
- package/docs/content/toolkit-history.mdx +95 -0
- package/docs/content/toolkit-observability.mdx +41 -0
- package/docs/content/toolkit-org-team.mdx +80 -0
- package/docs/content/toolkit-resources.mdx +57 -0
- package/docs/content/toolkit-settings.mdx +65 -0
- package/docs/content/toolkit-setup-connections.mdx +109 -0
- package/docs/content/toolkit-sharing-ui.mdx +18 -6
- package/docs/content/toolkit-sharing.mdx +81 -0
- package/docs/content/toolkit-shell-hooks.mdx +9 -0
- package/docs/content/toolkit-ui.mdx +9 -0
- package/package.json +36 -2
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
- package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
|
@@ -0,0 +1,1009 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-backed GLSL shader fills + effects — canonical persisted format.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the preset-only `shader-presets.ts` catalog (which approximates
|
|
5
|
+
* shaders as CSS gradients when persisting), this module defines a fully
|
|
6
|
+
* code-backed representation: the GLSL fragment source lives IN the screen
|
|
7
|
+
* HTML, readable and editable in the Code panel, and a small self-contained
|
|
8
|
+
* WebGL runtime (embedded in the same HTML) renders it live — in the editor,
|
|
9
|
+
* in shared links, and in exported standalone HTML.
|
|
10
|
+
*
|
|
11
|
+
* ── Persisted format (v1) ────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* 1. One definition block per shader, anywhere in the document (by
|
|
14
|
+
* convention just before `</body>`):
|
|
15
|
+
*
|
|
16
|
+
* <script type="application/x-agent-native-shader"
|
|
17
|
+
* data-shader-id="an-shader-x1y2z3"
|
|
18
|
+
* data-shader-name="Water Caustics"
|
|
19
|
+
* data-shader-mode="fill">
|
|
20
|
+
* (leading GLSL block comment opened with slash-star-bang)
|
|
21
|
+
* an-shader v1
|
|
22
|
+
* { "uniforms": { "u_speed": { "type": "float", "value": 1,
|
|
23
|
+
* "min": 0, "max": 4, "step": 0.01, "label": "Speed" } } }
|
|
24
|
+
* (star-slash closes the comment)
|
|
25
|
+
* precision highp float;
|
|
26
|
+
* uniform vec2 u_resolution;
|
|
27
|
+
* uniform float u_time;
|
|
28
|
+
* uniform float u_speed;
|
|
29
|
+
* void main() { ... gl_FragColor = vec4(...); }
|
|
30
|
+
* </script>
|
|
31
|
+
*
|
|
32
|
+
* The uniforms manifest rides inside a leading GLSL block comment — valid
|
|
33
|
+
* GLSL, so the whole block body is directly compilable, and the Code panel
|
|
34
|
+
* shows one readable, self-documenting artifact.
|
|
35
|
+
*
|
|
36
|
+
* 2. Elements reference a shader by id:
|
|
37
|
+
* data-an-shader-fill="an-shader-x1y2z3" (canvas behind content)
|
|
38
|
+
* data-an-shader-effect="an-shader-x1y2z3" (overlay above content)
|
|
39
|
+
* Optional per-element uniform overrides (Figma's paint-instance
|
|
40
|
+
* properties): data-an-shader-uniforms='{"u_speed":2}'
|
|
41
|
+
* For fills, the element's inline `background` holds a static fallback
|
|
42
|
+
* color so the artifact still renders without JS/WebGL.
|
|
43
|
+
*
|
|
44
|
+
* 3. The runtime is embedded once per document:
|
|
45
|
+
* <script data-agent-native-shader-runtime data-runtime-version="1">…
|
|
46
|
+
* (source of truth: app/components/design/bridge/shader-runtime.bridge.ts,
|
|
47
|
+
* compiled by bridge/codegen.ts — `ensureShaderRuntime()` injects/upgrades
|
|
48
|
+
* it.)
|
|
49
|
+
*
|
|
50
|
+
* Built-in uniforms every shader may declare (auto-driven by the runtime):
|
|
51
|
+
* uniform float u_time; // seconds, 0 under prefers-reduced-motion
|
|
52
|
+
* uniform vec2 u_resolution; // canvas size in physical pixels
|
|
53
|
+
*
|
|
54
|
+
* Keep the manifest parsing in shader-runtime.bridge.ts in sync with this
|
|
55
|
+
* module.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
import { shaderRuntimeBridgeScript } from "../.generated/bridge/shader-runtime.generated";
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Types
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
export type GlslUniformType = "float" | "vec2" | "color";
|
|
65
|
+
|
|
66
|
+
export type GlslUniformValue = number | [number, number] | string;
|
|
67
|
+
|
|
68
|
+
export interface GlslUniformDef {
|
|
69
|
+
type: GlslUniformType;
|
|
70
|
+
/** float → number; vec2 → [x, y]; color → "#rrggbb". */
|
|
71
|
+
value: GlslUniformValue;
|
|
72
|
+
/** Knob range — only for type "float". */
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
step?: number;
|
|
76
|
+
/** Human-readable knob label shown in the inspector. */
|
|
77
|
+
label?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export type GlslUniformManifest = Record<string, GlslUniformDef>;
|
|
81
|
+
|
|
82
|
+
export type GlslShaderMode = "fill" | "effect";
|
|
83
|
+
|
|
84
|
+
/** One code-backed shader as persisted in the screen HTML. */
|
|
85
|
+
export interface GlslShaderDef {
|
|
86
|
+
id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
mode: GlslShaderMode;
|
|
89
|
+
glsl: string;
|
|
90
|
+
uniforms: GlslUniformManifest;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** One element ↔ shader reference parsed back out of the HTML. */
|
|
94
|
+
export interface GlslShaderMountRef {
|
|
95
|
+
nodeId: string | null;
|
|
96
|
+
shaderId: string;
|
|
97
|
+
mode: GlslShaderMode;
|
|
98
|
+
/** Per-element uniform value overrides, when present. */
|
|
99
|
+
values?: Record<string, GlslUniformValue>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Constants
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
export const SHADER_SCRIPT_TYPE = "application/x-agent-native-shader";
|
|
107
|
+
export const SHADER_FILL_ATTR = "data-an-shader-fill";
|
|
108
|
+
export const SHADER_EFFECT_ATTR = "data-an-shader-effect";
|
|
109
|
+
export const SHADER_UNIFORMS_ATTR = "data-an-shader-uniforms";
|
|
110
|
+
/**
|
|
111
|
+
* Per-element uniform overrides for the EFFECT mount. Fills and effects can
|
|
112
|
+
* coexist on one element (Figma stacks them), so each mode gets its own
|
|
113
|
+
* override attribute.
|
|
114
|
+
*/
|
|
115
|
+
export const SHADER_EFFECT_UNIFORMS_ATTR = "data-an-shader-effect-uniforms";
|
|
116
|
+
export const SHADER_RUNTIME_ATTR = "data-agent-native-shader-runtime";
|
|
117
|
+
export const SHADER_RUNTIME_VERSION = "1";
|
|
118
|
+
export const SHADER_MANIFEST_VERSION = 1;
|
|
119
|
+
|
|
120
|
+
/** Uniform names the runtime provides automatically — reserved. */
|
|
121
|
+
export const SHADER_BUILTIN_UNIFORMS = ["u_time", "u_resolution"] as const;
|
|
122
|
+
|
|
123
|
+
const MAX_GLSL_LENGTH = 20000;
|
|
124
|
+
const ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
125
|
+
const UNIFORM_NAME_RE = /^u_[A-Za-z0-9_]{1,48}$/;
|
|
126
|
+
const VOID_TAGS = new Set([
|
|
127
|
+
"area",
|
|
128
|
+
"base",
|
|
129
|
+
"br",
|
|
130
|
+
"col",
|
|
131
|
+
"embed",
|
|
132
|
+
"hr",
|
|
133
|
+
"img",
|
|
134
|
+
"input",
|
|
135
|
+
"link",
|
|
136
|
+
"meta",
|
|
137
|
+
"param",
|
|
138
|
+
"source",
|
|
139
|
+
"track",
|
|
140
|
+
"wbr",
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Small utilities
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
function escapeAttr(value: string): string {
|
|
148
|
+
return value
|
|
149
|
+
.replace(/&/g, "&")
|
|
150
|
+
.replace(/"/g, """)
|
|
151
|
+
.replace(/'/g, "'")
|
|
152
|
+
.replace(/</g, "<")
|
|
153
|
+
.replace(/>/g, ">");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function unescapeAttr(value: string): string {
|
|
157
|
+
return value
|
|
158
|
+
.replace(/"/g, '"')
|
|
159
|
+
.replace(/'/g, "'")
|
|
160
|
+
.replace(/</g, "<")
|
|
161
|
+
.replace(/>/g, ">")
|
|
162
|
+
.replace(/&/g, "&");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function escapeRegExp(value: string): string {
|
|
166
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Generate a fresh shader id: an-shader-<8 base36 chars>. */
|
|
170
|
+
export function newShaderId(): string {
|
|
171
|
+
let suffix = "";
|
|
172
|
+
while (suffix.length < 8) {
|
|
173
|
+
suffix += Math.random().toString(36).slice(2);
|
|
174
|
+
}
|
|
175
|
+
return "an-shader-" + suffix.slice(0, 8);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Validation
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
const GLSL_TYPE_FOR_UNIFORM: Record<GlslUniformType, string> = {
|
|
183
|
+
float: "float",
|
|
184
|
+
vec2: "vec2",
|
|
185
|
+
color: "vec3",
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const SAFE_COLOR_RE =
|
|
189
|
+
/^(#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgba?\([\d.,\s%/]*\)|hsla?\([\d.,\s%/deg]*\)|oklch\([\d.,\s%/deg]*\)|[a-zA-Z]{3,25})$/;
|
|
190
|
+
|
|
191
|
+
/** True when a CSS color literal is safe to embed in an inline style. */
|
|
192
|
+
export function isSafeShaderFallbackColor(value: string): boolean {
|
|
193
|
+
const trimmed = value.trim();
|
|
194
|
+
if (trimmed.length === 0 || trimmed.length > 64) return false;
|
|
195
|
+
if (/[;{}<>]|url\s*\(/i.test(trimmed)) return false;
|
|
196
|
+
return SAFE_COLOR_RE.test(trimmed);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Neutralize an unsafe fallback color instead of failing the whole apply. */
|
|
200
|
+
export function sanitizeShaderFallbackColor(value: string | undefined): string {
|
|
201
|
+
if (value && isSafeShaderFallbackColor(value)) return value.trim();
|
|
202
|
+
return "#808080";
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface ShaderValidationResult {
|
|
206
|
+
valid: boolean;
|
|
207
|
+
errors: string[];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** String-level sanity checks on a GLSL fragment source. */
|
|
211
|
+
export function validateGlslSource(glsl: string): ShaderValidationResult {
|
|
212
|
+
const errors: string[] = [];
|
|
213
|
+
if (typeof glsl !== "string" || glsl.trim().length === 0) {
|
|
214
|
+
return { valid: false, errors: ["GLSL source is empty"] };
|
|
215
|
+
}
|
|
216
|
+
if (glsl.length > MAX_GLSL_LENGTH) {
|
|
217
|
+
errors.push(
|
|
218
|
+
`GLSL source is ${glsl.length} chars — max is ${MAX_GLSL_LENGTH}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (!/void\s+main\s*\(/.test(glsl)) {
|
|
222
|
+
errors.push("GLSL source must define void main()");
|
|
223
|
+
}
|
|
224
|
+
if (!/gl_FragColor/.test(glsl)) {
|
|
225
|
+
errors.push("GLSL source must write gl_FragColor");
|
|
226
|
+
}
|
|
227
|
+
// An opening `<script` tag is a real injection vector (it starts a brand
|
|
228
|
+
// new, arbitrary script rather than merely closing the current block), so
|
|
229
|
+
// it stays a hard rejection. A closing `</script` on its own — e.g. inside
|
|
230
|
+
// a GLSL line comment describing script-tag breakouts — is no longer
|
|
231
|
+
// rejected here: serializeShaderScriptBlock escapes it
|
|
232
|
+
// (escapeShaderScriptBreakout) before embedding, and parseShaderBlockBody
|
|
233
|
+
// reverses that escape, so the literal sequence never reaches the emitted
|
|
234
|
+
// HTML unescaped.
|
|
235
|
+
if (/<script/i.test(glsl)) {
|
|
236
|
+
errors.push("GLSL source must not contain an opening script tag");
|
|
237
|
+
}
|
|
238
|
+
// eslint-disable-next-line no-control-regex
|
|
239
|
+
if (/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/.test(glsl)) {
|
|
240
|
+
errors.push("GLSL source contains control characters");
|
|
241
|
+
}
|
|
242
|
+
return { valid: errors.length === 0, errors };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Validate a uniforms manifest (names, types, values, ranges). */
|
|
246
|
+
export function validateUniformManifest(
|
|
247
|
+
uniforms: GlslUniformManifest,
|
|
248
|
+
): ShaderValidationResult {
|
|
249
|
+
const errors: string[] = [];
|
|
250
|
+
if (!uniforms || typeof uniforms !== "object") {
|
|
251
|
+
return { valid: false, errors: ["uniforms manifest must be an object"] };
|
|
252
|
+
}
|
|
253
|
+
const names = Object.keys(uniforms);
|
|
254
|
+
if (names.length > 16) {
|
|
255
|
+
errors.push(`too many uniforms (${names.length}) — max is 16`);
|
|
256
|
+
}
|
|
257
|
+
for (const name of names) {
|
|
258
|
+
const def = uniforms[name];
|
|
259
|
+
if (!UNIFORM_NAME_RE.test(name)) {
|
|
260
|
+
errors.push(
|
|
261
|
+
`uniform "${name}" must match u_[A-Za-z0-9_]+ (max 50 chars)`,
|
|
262
|
+
);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if ((SHADER_BUILTIN_UNIFORMS as readonly string[]).includes(name)) {
|
|
266
|
+
errors.push(
|
|
267
|
+
`uniform "${name}" is a built-in provided by the runtime — ` +
|
|
268
|
+
"do not declare it in the manifest",
|
|
269
|
+
);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (!def || typeof def !== "object") {
|
|
273
|
+
errors.push(`uniform "${name}" definition must be an object`);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (def.type === "float") {
|
|
277
|
+
if (typeof def.value !== "number" || !isFinite(def.value)) {
|
|
278
|
+
errors.push(`uniform "${name}" value must be a finite number`);
|
|
279
|
+
} else {
|
|
280
|
+
if (def.min !== undefined && def.value < def.min) {
|
|
281
|
+
errors.push(`uniform "${name}" value is below its min`);
|
|
282
|
+
}
|
|
283
|
+
if (def.max !== undefined && def.value > def.max) {
|
|
284
|
+
errors.push(`uniform "${name}" value is above its max`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (
|
|
288
|
+
def.min !== undefined &&
|
|
289
|
+
def.max !== undefined &&
|
|
290
|
+
!(def.min < def.max)
|
|
291
|
+
) {
|
|
292
|
+
errors.push(`uniform "${name}" needs min < max`);
|
|
293
|
+
}
|
|
294
|
+
if (def.step !== undefined && !(def.step > 0)) {
|
|
295
|
+
errors.push(`uniform "${name}" step must be > 0`);
|
|
296
|
+
}
|
|
297
|
+
} else if (def.type === "vec2") {
|
|
298
|
+
const v = def.value;
|
|
299
|
+
if (
|
|
300
|
+
!Array.isArray(v) ||
|
|
301
|
+
v.length !== 2 ||
|
|
302
|
+
typeof v[0] !== "number" ||
|
|
303
|
+
typeof v[1] !== "number" ||
|
|
304
|
+
!isFinite(v[0]) ||
|
|
305
|
+
!isFinite(v[1])
|
|
306
|
+
) {
|
|
307
|
+
errors.push(`uniform "${name}" value must be [x, y] finite numbers`);
|
|
308
|
+
}
|
|
309
|
+
} else if (def.type === "color") {
|
|
310
|
+
if (
|
|
311
|
+
typeof def.value !== "string" ||
|
|
312
|
+
!/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(def.value)
|
|
313
|
+
) {
|
|
314
|
+
errors.push(
|
|
315
|
+
`uniform "${name}" value must be a hex color like "#1a2b3c"`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
} else {
|
|
319
|
+
errors.push(
|
|
320
|
+
`uniform "${name}" has unknown type "${String(
|
|
321
|
+
(def as { type?: unknown }).type,
|
|
322
|
+
)}" — use float, vec2, or color`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
if (def.label !== undefined) {
|
|
326
|
+
if (typeof def.label !== "string" || def.label.length > 40) {
|
|
327
|
+
errors.push(`uniform "${name}" label must be a string ≤ 40 chars`);
|
|
328
|
+
} else if (def.label.includes("*/") || /<\/?script/i.test(def.label)) {
|
|
329
|
+
errors.push(`uniform "${name}" label contains forbidden sequences`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return { valid: errors.length === 0, errors };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Validate a full shader definition, including the cross-check that every
|
|
338
|
+
* manifest uniform is actually declared in the GLSL with the matching type
|
|
339
|
+
* (float → float, vec2 → vec2, color → vec3) so every knob provably drives
|
|
340
|
+
* the shader.
|
|
341
|
+
*/
|
|
342
|
+
export function validateShaderDef(def: GlslShaderDef): ShaderValidationResult {
|
|
343
|
+
const errors: string[] = [];
|
|
344
|
+
if (!def || typeof def !== "object") {
|
|
345
|
+
return { valid: false, errors: ["shader definition must be an object"] };
|
|
346
|
+
}
|
|
347
|
+
if (typeof def.id !== "string" || !ID_RE.test(def.id)) {
|
|
348
|
+
errors.push(
|
|
349
|
+
'shader id must match [A-Za-z0-9_-]{1,64} (e.g. "an-shader-x1y2z3")',
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
if (
|
|
353
|
+
typeof def.name !== "string" ||
|
|
354
|
+
def.name.trim().length === 0 ||
|
|
355
|
+
def.name.length > 80
|
|
356
|
+
) {
|
|
357
|
+
errors.push("shader name must be a non-empty string ≤ 80 chars");
|
|
358
|
+
} else if (def.name.includes("*/") || /<\/?script/i.test(def.name)) {
|
|
359
|
+
errors.push("shader name contains forbidden sequences");
|
|
360
|
+
}
|
|
361
|
+
if (def.mode !== "fill" && def.mode !== "effect") {
|
|
362
|
+
errors.push('shader mode must be "fill" or "effect"');
|
|
363
|
+
}
|
|
364
|
+
const glslResult = validateGlslSource(def.glsl);
|
|
365
|
+
errors.push(...glslResult.errors);
|
|
366
|
+
const manifestResult = validateUniformManifest(def.uniforms ?? {});
|
|
367
|
+
errors.push(...manifestResult.errors);
|
|
368
|
+
|
|
369
|
+
if (glslResult.valid && manifestResult.valid) {
|
|
370
|
+
for (const [name, u] of Object.entries(def.uniforms ?? {})) {
|
|
371
|
+
const glslType = GLSL_TYPE_FOR_UNIFORM[u.type];
|
|
372
|
+
const declRe = new RegExp(
|
|
373
|
+
"uniform\\s+(?:lowp\\s+|mediump\\s+|highp\\s+)?" +
|
|
374
|
+
glslType +
|
|
375
|
+
"\\s+" +
|
|
376
|
+
escapeRegExp(name) +
|
|
377
|
+
"\\s*;",
|
|
378
|
+
);
|
|
379
|
+
if (!declRe.test(def.glsl)) {
|
|
380
|
+
errors.push(
|
|
381
|
+
`uniform "${name}" (${u.type}) is not declared in the GLSL as ` +
|
|
382
|
+
`"uniform ${glslType} ${name};" — every knob must drive the shader`,
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return { valid: errors.length === 0, errors };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ---------------------------------------------------------------------------
|
|
391
|
+
// Manifest comment + script block serialization
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
|
|
394
|
+
const MANIFEST_COMMENT_RE = /^\s*\/\*!\s*an-shader\s+v(\d+)\s*([\s\S]*?)\*\//;
|
|
395
|
+
|
|
396
|
+
/** Serialize the manifest as the leading GLSL block comment. */
|
|
397
|
+
export function serializeManifestComment(
|
|
398
|
+
uniforms: GlslUniformManifest,
|
|
399
|
+
): string {
|
|
400
|
+
const json = JSON.stringify({ uniforms }, null, 2);
|
|
401
|
+
if (json.includes("*/")) {
|
|
402
|
+
throw new Error("uniforms manifest must not contain */");
|
|
403
|
+
}
|
|
404
|
+
return "/*! an-shader v" + SHADER_MANIFEST_VERSION + "\n" + json + "\n*/";
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Escape/unescape pair guarding against a `</script` breakout inside a
|
|
409
|
+
* serialized GLSL body.
|
|
410
|
+
*
|
|
411
|
+
* `def.glsl` is caller-controlled (agent/user-edited GLSL source) and is
|
|
412
|
+
* embedded RAW inside a `<script type="application/x-agent-native-shader">`
|
|
413
|
+
* block. `validateGlslSource` already rejects a literal `</script` at the
|
|
414
|
+
* point a shader definition is validated/applied — but `serializeShaderScriptBlock`
|
|
415
|
+
* is also reachable with defs that were constructed without going through
|
|
416
|
+
* that validation (e.g. directly in tests, or future callers), and stored
|
|
417
|
+
* legacy content may already contain the substring. Escaping here is
|
|
418
|
+
* defense in depth: even if an unescaped `</script` reaches this function,
|
|
419
|
+
* the emitted HTML never contains a literal closing-script-tag sequence
|
|
420
|
+
* inside the block body, so the surrounding document can't be corrupted.
|
|
421
|
+
*
|
|
422
|
+
* Approach: replace `</script` (case-insensitive) with `<\/script` — the
|
|
423
|
+
* same backslash-escape idiom used for embedding JS strings inside
|
|
424
|
+
* `<script>` blocks. It's a minimal, transform-invariant edit (inserts one
|
|
425
|
+
* `\` character) that is trivial to reverse exactly on parse.
|
|
426
|
+
*/
|
|
427
|
+
export function escapeShaderScriptBreakout(glsl: string): string {
|
|
428
|
+
return glsl.replace(
|
|
429
|
+
/<\/script/gi,
|
|
430
|
+
(match) => match.slice(0, 1) + "\\" + match.slice(1),
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** Reverse {@link escapeShaderScriptBreakout} — restores the original GLSL. */
|
|
435
|
+
export function unescapeShaderScriptBreakout(glsl: string): string {
|
|
436
|
+
return glsl.replace(
|
|
437
|
+
/<\\\/script/gi,
|
|
438
|
+
(match) => match.slice(0, 1) + match.slice(2),
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Split a script-block body into { uniforms, glsl }. Missing/malformed
|
|
444
|
+
* manifests degrade to an empty manifest with the full body as GLSL — the
|
|
445
|
+
* shader still renders, it just has no knobs.
|
|
446
|
+
*
|
|
447
|
+
* The raw captured body may contain an escaped `</script` breakout marker
|
|
448
|
+
* (see {@link escapeShaderScriptBreakout}); it is unescaped here, after
|
|
449
|
+
* manifest-comment splitting, so callers always get back the original,
|
|
450
|
+
* editable GLSL source.
|
|
451
|
+
*/
|
|
452
|
+
export function parseShaderBlockBody(body: string): {
|
|
453
|
+
uniforms: GlslUniformManifest;
|
|
454
|
+
glsl: string;
|
|
455
|
+
} {
|
|
456
|
+
const match = MANIFEST_COMMENT_RE.exec(body);
|
|
457
|
+
if (!match) {
|
|
458
|
+
return {
|
|
459
|
+
uniforms: {},
|
|
460
|
+
glsl: unescapeShaderScriptBreakout(
|
|
461
|
+
body.replace(/^[ \t]*\r?\n/, "").trim(),
|
|
462
|
+
),
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
let uniforms: GlslUniformManifest = {};
|
|
466
|
+
try {
|
|
467
|
+
const meta = JSON.parse(match[2]) as { uniforms?: GlslUniformManifest };
|
|
468
|
+
if (meta && typeof meta === "object" && meta.uniforms) {
|
|
469
|
+
uniforms = meta.uniforms;
|
|
470
|
+
}
|
|
471
|
+
} catch {
|
|
472
|
+
uniforms = {};
|
|
473
|
+
}
|
|
474
|
+
const glsl = unescapeShaderScriptBreakout(
|
|
475
|
+
body
|
|
476
|
+
.slice(match.index + match[0].length)
|
|
477
|
+
.replace(/^[ \t]*\r?\n/, "")
|
|
478
|
+
.trim(),
|
|
479
|
+
);
|
|
480
|
+
return { uniforms, glsl };
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/** Serialize a full `<script type="application/x-agent-native-shader">` block. */
|
|
484
|
+
export function serializeShaderScriptBlock(def: GlslShaderDef): string {
|
|
485
|
+
const validation = validateShaderDef(def);
|
|
486
|
+
if (!validation.valid) {
|
|
487
|
+
throw new Error(
|
|
488
|
+
"Invalid shader definition: " + validation.errors.join("; "),
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
return (
|
|
492
|
+
`<script type="${SHADER_SCRIPT_TYPE}"` +
|
|
493
|
+
` data-shader-id="${escapeAttr(def.id)}"` +
|
|
494
|
+
` data-shader-name="${escapeAttr(def.name)}"` +
|
|
495
|
+
` data-shader-mode="${def.mode}">\n` +
|
|
496
|
+
serializeManifestComment(def.uniforms) +
|
|
497
|
+
"\n" +
|
|
498
|
+
escapeShaderScriptBreakout(def.glsl.trim()) +
|
|
499
|
+
"\n</script>"
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const SHADER_BLOCK_RE = new RegExp(
|
|
504
|
+
'<script\\b([^>]*type\\s*=\\s*"' +
|
|
505
|
+
escapeRegExp(SHADER_SCRIPT_TYPE) +
|
|
506
|
+
'"[^>]*)>([\\s\\S]*?)<\\/script\\s*>',
|
|
507
|
+
"gi",
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
function readAttrFrom(attrs: string, name: string): string | null {
|
|
511
|
+
const match = new RegExp(name + '\\s*=\\s*"([^"]*)"', "i").exec(attrs);
|
|
512
|
+
return match ? unescapeAttr(match[1]) : null;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** Parse every shader definition block out of a screen HTML document. */
|
|
516
|
+
export function listShadersInHtml(html: string): GlslShaderDef[] {
|
|
517
|
+
const defs: GlslShaderDef[] = [];
|
|
518
|
+
if (typeof html !== "string" || html.length === 0) return defs;
|
|
519
|
+
SHADER_BLOCK_RE.lastIndex = 0;
|
|
520
|
+
let match: RegExpExecArray | null;
|
|
521
|
+
while ((match = SHADER_BLOCK_RE.exec(html))) {
|
|
522
|
+
const attrs = match[1];
|
|
523
|
+
const id = readAttrFrom(attrs, "data-shader-id");
|
|
524
|
+
if (!id || !ID_RE.test(id)) continue;
|
|
525
|
+
const body = parseShaderBlockBody(match[2]);
|
|
526
|
+
defs.push({
|
|
527
|
+
id,
|
|
528
|
+
name: readAttrFrom(attrs, "data-shader-name") || id,
|
|
529
|
+
mode:
|
|
530
|
+
readAttrFrom(attrs, "data-shader-mode") === "effect"
|
|
531
|
+
? "effect"
|
|
532
|
+
: "fill",
|
|
533
|
+
glsl: body.glsl,
|
|
534
|
+
uniforms: body.uniforms,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return defs;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Find one shader definition by id. */
|
|
541
|
+
export function getShaderFromHtml(
|
|
542
|
+
html: string,
|
|
543
|
+
id: string,
|
|
544
|
+
): GlslShaderDef | undefined {
|
|
545
|
+
return listShadersInHtml(html).find((def) => def.id === id);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function findShaderBlockSpan(
|
|
549
|
+
html: string,
|
|
550
|
+
id: string,
|
|
551
|
+
): { start: number; end: number } | null {
|
|
552
|
+
SHADER_BLOCK_RE.lastIndex = 0;
|
|
553
|
+
let match: RegExpExecArray | null;
|
|
554
|
+
while ((match = SHADER_BLOCK_RE.exec(html))) {
|
|
555
|
+
if (readAttrFrom(match[1], "data-shader-id") === id) {
|
|
556
|
+
return { start: match.index, end: match.index + match[0].length };
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/** Insert or replace a shader definition block in the document. */
|
|
563
|
+
export function upsertShaderInHtml(html: string, def: GlslShaderDef): string {
|
|
564
|
+
const block = serializeShaderScriptBlock(def);
|
|
565
|
+
const existing = findShaderBlockSpan(html, def.id);
|
|
566
|
+
if (existing) {
|
|
567
|
+
return html.slice(0, existing.start) + block + html.slice(existing.end);
|
|
568
|
+
}
|
|
569
|
+
const bodyClose = html.toLowerCase().lastIndexOf("</body>");
|
|
570
|
+
if (bodyClose !== -1) {
|
|
571
|
+
return html.slice(0, bodyClose) + block + "\n" + html.slice(bodyClose);
|
|
572
|
+
}
|
|
573
|
+
const htmlClose = html.toLowerCase().lastIndexOf("</html>");
|
|
574
|
+
if (htmlClose !== -1) {
|
|
575
|
+
return html.slice(0, htmlClose) + block + "\n" + html.slice(htmlClose);
|
|
576
|
+
}
|
|
577
|
+
return html + "\n" + block + "\n";
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/** Remove a shader definition block (references are left untouched). */
|
|
581
|
+
export function removeShaderFromHtml(html: string, id: string): string {
|
|
582
|
+
const span = findShaderBlockSpan(html, id);
|
|
583
|
+
if (!span) return html;
|
|
584
|
+
let start = span.start;
|
|
585
|
+
// Also consume the preceding line's indentation/newline for tidiness.
|
|
586
|
+
while (start > 0 && (html[start - 1] === " " || html[start - 1] === "\t")) {
|
|
587
|
+
start--;
|
|
588
|
+
}
|
|
589
|
+
let end = span.end;
|
|
590
|
+
if (html[end] === "\r") end++;
|
|
591
|
+
if (html[end] === "\n") end++;
|
|
592
|
+
return html.slice(0, start) + html.slice(end);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// ---------------------------------------------------------------------------
|
|
596
|
+
// Runtime embedding
|
|
597
|
+
// ---------------------------------------------------------------------------
|
|
598
|
+
|
|
599
|
+
/** The compiled, self-contained WebGL runtime (see shader-runtime.bridge.ts). */
|
|
600
|
+
export const SHADER_RUNTIME_SOURCE: string = shaderRuntimeBridgeScript;
|
|
601
|
+
|
|
602
|
+
export function buildShaderRuntimeScriptTag(): string {
|
|
603
|
+
return (
|
|
604
|
+
`<script ${SHADER_RUNTIME_ATTR} data-runtime-version="${SHADER_RUNTIME_VERSION}">\n` +
|
|
605
|
+
SHADER_RUNTIME_SOURCE +
|
|
606
|
+
"\n</script>"
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const RUNTIME_BLOCK_RE = new RegExp(
|
|
611
|
+
"<script\\s+" + SHADER_RUNTIME_ATTR + "[^>]*>[\\s\\S]*?<\\/script\\s*>",
|
|
612
|
+
"i",
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Ensure the document embeds the current shader runtime exactly once,
|
|
617
|
+
* upgrading any previously-embedded copy in place. Idempotent.
|
|
618
|
+
*/
|
|
619
|
+
export function ensureShaderRuntime(html: string): string {
|
|
620
|
+
const tag = buildShaderRuntimeScriptTag();
|
|
621
|
+
const existing = RUNTIME_BLOCK_RE.exec(html);
|
|
622
|
+
if (existing) {
|
|
623
|
+
if (existing[0] === tag) return html;
|
|
624
|
+
return (
|
|
625
|
+
html.slice(0, existing.index) +
|
|
626
|
+
tag +
|
|
627
|
+
html.slice(existing.index + existing[0].length)
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
const bodyClose = html.toLowerCase().lastIndexOf("</body>");
|
|
631
|
+
if (bodyClose !== -1) {
|
|
632
|
+
return html.slice(0, bodyClose) + tag + "\n" + html.slice(bodyClose);
|
|
633
|
+
}
|
|
634
|
+
const htmlClose = html.toLowerCase().lastIndexOf("</html>");
|
|
635
|
+
if (htmlClose !== -1) {
|
|
636
|
+
return html.slice(0, htmlClose) + tag + "\n" + html.slice(htmlClose);
|
|
637
|
+
}
|
|
638
|
+
return html + "\n" + tag + "\n";
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/** True when the document has no shader references left. */
|
|
642
|
+
export function htmlHasShaderReferences(html: string): boolean {
|
|
643
|
+
return (
|
|
644
|
+
html.includes(SHADER_FILL_ATTR + '="') ||
|
|
645
|
+
html.includes(SHADER_EFFECT_ATTR + '="')
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** Remove definition blocks that no element references any more. */
|
|
650
|
+
export function pruneUnusedShaders(html: string): string {
|
|
651
|
+
let out = html;
|
|
652
|
+
for (const def of listShadersInHtml(html)) {
|
|
653
|
+
const fillRef = `${SHADER_FILL_ATTR}="${escapeAttr(def.id)}"`;
|
|
654
|
+
const effectRef = `${SHADER_EFFECT_ATTR}="${escapeAttr(def.id)}"`;
|
|
655
|
+
if (!out.includes(fillRef) && !out.includes(effectRef)) {
|
|
656
|
+
out = removeShaderFromHtml(out, def.id);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return out;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// ---------------------------------------------------------------------------
|
|
663
|
+
// Element annotation (pure string transforms, no DOM)
|
|
664
|
+
// ---------------------------------------------------------------------------
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Locate the bounds of the open tag containing the given index. Scans
|
|
668
|
+
* backward for "<" and forward for ">" while respecting quoted attribute
|
|
669
|
+
* values. Returns null when the index isn't inside a plausible tag.
|
|
670
|
+
*/
|
|
671
|
+
function findTagBounds(
|
|
672
|
+
html: string,
|
|
673
|
+
indexInsideTag: number,
|
|
674
|
+
): { start: number; end: number } | null {
|
|
675
|
+
let start = -1;
|
|
676
|
+
for (let i = indexInsideTag; i >= 0; i--) {
|
|
677
|
+
const ch = html[i];
|
|
678
|
+
if (ch === "<") {
|
|
679
|
+
start = i;
|
|
680
|
+
break;
|
|
681
|
+
}
|
|
682
|
+
if (ch === ">") return null;
|
|
683
|
+
}
|
|
684
|
+
if (start === -1) return null;
|
|
685
|
+
if (!/[a-zA-Z]/.test(html[start + 1] ?? "")) return null;
|
|
686
|
+
let quote: string | null = null;
|
|
687
|
+
for (let i = start + 1; i < html.length; i++) {
|
|
688
|
+
const ch = html[i];
|
|
689
|
+
if (quote) {
|
|
690
|
+
if (ch === quote) quote = null;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (ch === '"' || ch === "'") {
|
|
694
|
+
quote = ch;
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
if (ch === ">") return { start, end: i + 1 };
|
|
698
|
+
}
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function tagNameOf(tagText: string): string {
|
|
703
|
+
const match = /^<\s*([a-zA-Z][a-zA-Z0-9-]*)/.exec(tagText);
|
|
704
|
+
return match ? match[1].toLowerCase() : "";
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function removeAttr(tagText: string, name: string): string {
|
|
708
|
+
return tagText.replace(
|
|
709
|
+
new RegExp("\\s+" + name + "\\s*=\\s*(\"[^\"]*\"|'[^']*'|[^\\s/>]+)", "gi"),
|
|
710
|
+
"",
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/** Upsert one declaration inside an inline style attribute. */
|
|
715
|
+
function upsertStyleProperty(
|
|
716
|
+
tagText: string,
|
|
717
|
+
property: string,
|
|
718
|
+
value: string,
|
|
719
|
+
): string {
|
|
720
|
+
const styleRe = /(\sstyle\s*=\s*")([^"]*)(")/i;
|
|
721
|
+
const styleMatch = styleRe.exec(tagText);
|
|
722
|
+
const decl = `${property}: ${value}`;
|
|
723
|
+
if (!styleMatch) {
|
|
724
|
+
const insertAt = tagText.endsWith("/>")
|
|
725
|
+
? tagText.length - 2
|
|
726
|
+
: tagText.length - 1;
|
|
727
|
+
return (
|
|
728
|
+
tagText.slice(0, insertAt) +
|
|
729
|
+
` style="${escapeAttr(decl)}"` +
|
|
730
|
+
tagText.slice(insertAt)
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
const existing = unescapeAttr(styleMatch[2]);
|
|
734
|
+
const kept = existing
|
|
735
|
+
.split(";")
|
|
736
|
+
.map((part) => part.trim())
|
|
737
|
+
.filter(
|
|
738
|
+
(part) =>
|
|
739
|
+
part.length > 0 &&
|
|
740
|
+
!new RegExp("^" + escapeRegExp(property) + "\\s*:", "i").test(part),
|
|
741
|
+
);
|
|
742
|
+
kept.push(decl);
|
|
743
|
+
const next = kept.join("; ");
|
|
744
|
+
return (
|
|
745
|
+
tagText.slice(0, styleMatch.index) +
|
|
746
|
+
styleMatch[1] +
|
|
747
|
+
escapeAttr(next) +
|
|
748
|
+
styleMatch[3] +
|
|
749
|
+
tagText.slice(styleMatch.index + styleMatch[0].length)
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function locateNodeTag(
|
|
754
|
+
html: string,
|
|
755
|
+
nodeId: string,
|
|
756
|
+
): { start: number; end: number; tagText: string } | null {
|
|
757
|
+
const marker = new RegExp(
|
|
758
|
+
'data-agent-native-node-id\\s*=\\s*"' + escapeRegExp(nodeId) + '"',
|
|
759
|
+
).exec(html);
|
|
760
|
+
if (!marker) return null;
|
|
761
|
+
const bounds = findTagBounds(html, marker.index);
|
|
762
|
+
if (!bounds) return null;
|
|
763
|
+
return {
|
|
764
|
+
start: bounds.start,
|
|
765
|
+
end: bounds.end,
|
|
766
|
+
tagText: html.slice(bounds.start, bounds.end),
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export interface AnnotateShaderNodeOptions {
|
|
771
|
+
nodeId: string;
|
|
772
|
+
shaderId: string;
|
|
773
|
+
mode: GlslShaderMode;
|
|
774
|
+
/** Per-element uniform overrides serialized to data-an-shader-uniforms. */
|
|
775
|
+
values?: Record<string, GlslUniformValue>;
|
|
776
|
+
/**
|
|
777
|
+
* Static fallback background written to the element's inline style
|
|
778
|
+
* (fill mode only). Unsafe values are neutralized to #808080. When
|
|
779
|
+
* omitted, the element's existing background is left untouched — pass it
|
|
780
|
+
* on the initial apply, omit it for knob-value-only updates.
|
|
781
|
+
*/
|
|
782
|
+
fallbackColor?: string;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export interface HtmlTransformResult {
|
|
786
|
+
html: string;
|
|
787
|
+
changed: boolean;
|
|
788
|
+
errors: string[];
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Point an element (located by its stable data-agent-native-node-id) at a
|
|
793
|
+
* shader definition. Replaces any previous shader annotation OF THE SAME
|
|
794
|
+
* MODE on the node — a fill and an effect can coexist on one element,
|
|
795
|
+
* mirroring Figma's paint/effect stacking.
|
|
796
|
+
*/
|
|
797
|
+
export function annotateNodeWithShader(
|
|
798
|
+
html: string,
|
|
799
|
+
options: AnnotateShaderNodeOptions,
|
|
800
|
+
): HtmlTransformResult {
|
|
801
|
+
const errors: string[] = [];
|
|
802
|
+
if (!ID_RE.test(options.shaderId)) {
|
|
803
|
+
return { html, changed: false, errors: ["invalid shader id"] };
|
|
804
|
+
}
|
|
805
|
+
const located = locateNodeTag(html, options.nodeId);
|
|
806
|
+
if (!located) {
|
|
807
|
+
return {
|
|
808
|
+
html,
|
|
809
|
+
changed: false,
|
|
810
|
+
errors: [
|
|
811
|
+
`no element with data-agent-native-node-id="${options.nodeId}" found`,
|
|
812
|
+
],
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
const tagName = tagNameOf(located.tagText);
|
|
816
|
+
if (VOID_TAGS.has(tagName)) {
|
|
817
|
+
return {
|
|
818
|
+
html,
|
|
819
|
+
changed: false,
|
|
820
|
+
errors: [
|
|
821
|
+
`<${tagName}> cannot host a shader canvas — wrap it in a container ` +
|
|
822
|
+
"element and apply the shader there",
|
|
823
|
+
],
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const isEffect = options.mode === "effect";
|
|
828
|
+
const refAttr = isEffect ? SHADER_EFFECT_ATTR : SHADER_FILL_ATTR;
|
|
829
|
+
const valuesAttr = isEffect
|
|
830
|
+
? SHADER_EFFECT_UNIFORMS_ATTR
|
|
831
|
+
: SHADER_UNIFORMS_ATTR;
|
|
832
|
+
|
|
833
|
+
let tagText = located.tagText;
|
|
834
|
+
tagText = removeAttr(tagText, refAttr);
|
|
835
|
+
tagText = removeAttr(tagText, valuesAttr);
|
|
836
|
+
|
|
837
|
+
let insertion = ` ${refAttr}="${escapeAttr(options.shaderId)}"`;
|
|
838
|
+
if (options.values && Object.keys(options.values).length > 0) {
|
|
839
|
+
const json = JSON.stringify(options.values);
|
|
840
|
+
insertion += ` ${valuesAttr}="${escapeAttr(json)}"`;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const selfClosing = tagText.endsWith("/>");
|
|
844
|
+
const insertAt = selfClosing ? tagText.length - 2 : tagText.length - 1;
|
|
845
|
+
tagText = tagText.slice(0, insertAt) + insertion + tagText.slice(insertAt);
|
|
846
|
+
|
|
847
|
+
if (options.mode === "fill" && options.fallbackColor !== undefined) {
|
|
848
|
+
tagText = upsertStyleProperty(
|
|
849
|
+
tagText,
|
|
850
|
+
"background",
|
|
851
|
+
sanitizeShaderFallbackColor(options.fallbackColor),
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
const nextHtml =
|
|
856
|
+
html.slice(0, located.start) + tagText + html.slice(located.end);
|
|
857
|
+
return { html: nextHtml, changed: nextHtml !== html, errors };
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Remove shader annotations from an element (fallback background stays).
|
|
862
|
+
* Pass `mode` to clear only the fill or only the effect; omit to clear both.
|
|
863
|
+
*/
|
|
864
|
+
export function clearNodeShader(
|
|
865
|
+
html: string,
|
|
866
|
+
nodeId: string,
|
|
867
|
+
mode?: GlslShaderMode,
|
|
868
|
+
): HtmlTransformResult {
|
|
869
|
+
const located = locateNodeTag(html, nodeId);
|
|
870
|
+
if (!located) {
|
|
871
|
+
return {
|
|
872
|
+
html,
|
|
873
|
+
changed: false,
|
|
874
|
+
errors: [`no element with data-agent-native-node-id="${nodeId}" found`],
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
let tagText = located.tagText;
|
|
878
|
+
if (mode !== "effect") {
|
|
879
|
+
tagText = removeAttr(tagText, SHADER_FILL_ATTR);
|
|
880
|
+
tagText = removeAttr(tagText, SHADER_UNIFORMS_ATTR);
|
|
881
|
+
}
|
|
882
|
+
if (mode !== "fill") {
|
|
883
|
+
tagText = removeAttr(tagText, SHADER_EFFECT_ATTR);
|
|
884
|
+
tagText = removeAttr(tagText, SHADER_EFFECT_UNIFORMS_ATTR);
|
|
885
|
+
}
|
|
886
|
+
const nextHtml =
|
|
887
|
+
html.slice(0, located.start) + tagText + html.slice(located.end);
|
|
888
|
+
return { html: nextHtml, changed: nextHtml !== html, errors: [] };
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/** Parse every element ↔ shader reference out of the document. */
|
|
892
|
+
export function listShaderMounts(html: string): GlslShaderMountRef[] {
|
|
893
|
+
const mounts: GlslShaderMountRef[] = [];
|
|
894
|
+
if (typeof html !== "string" || html.length === 0) return mounts;
|
|
895
|
+
const refRe = new RegExp(
|
|
896
|
+
"\\s(" +
|
|
897
|
+
SHADER_FILL_ATTR +
|
|
898
|
+
"|" +
|
|
899
|
+
SHADER_EFFECT_ATTR +
|
|
900
|
+
')\\s*=\\s*"([^"]*)"',
|
|
901
|
+
"g",
|
|
902
|
+
);
|
|
903
|
+
let match: RegExpExecArray | null;
|
|
904
|
+
while ((match = refRe.exec(html))) {
|
|
905
|
+
const bounds = findTagBounds(html, match.index + 1);
|
|
906
|
+
if (!bounds) continue;
|
|
907
|
+
const tagText = html.slice(bounds.start, bounds.end);
|
|
908
|
+
const shaderId = unescapeAttr(match[2]);
|
|
909
|
+
if (!ID_RE.test(shaderId)) continue;
|
|
910
|
+
const mode: GlslShaderMode =
|
|
911
|
+
match[1] === SHADER_EFFECT_ATTR ? "effect" : "fill";
|
|
912
|
+
const valuesRaw = readAttrFrom(
|
|
913
|
+
tagText,
|
|
914
|
+
mode === "effect" ? SHADER_EFFECT_UNIFORMS_ATTR : SHADER_UNIFORMS_ATTR,
|
|
915
|
+
);
|
|
916
|
+
let values: Record<string, GlslUniformValue> | undefined;
|
|
917
|
+
if (valuesRaw) {
|
|
918
|
+
try {
|
|
919
|
+
const parsed = JSON.parse(valuesRaw) as Record<
|
|
920
|
+
string,
|
|
921
|
+
GlslUniformValue
|
|
922
|
+
>;
|
|
923
|
+
if (parsed && typeof parsed === "object") values = parsed;
|
|
924
|
+
} catch {
|
|
925
|
+
values = undefined;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
mounts.push({
|
|
929
|
+
nodeId: readAttrFrom(tagText, "data-agent-native-node-id"),
|
|
930
|
+
shaderId,
|
|
931
|
+
mode,
|
|
932
|
+
values,
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
return mounts;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// ---------------------------------------------------------------------------
|
|
939
|
+
// High-level apply (the one-call transform the inspector + agent use)
|
|
940
|
+
// ---------------------------------------------------------------------------
|
|
941
|
+
|
|
942
|
+
export interface ApplyShaderOptions {
|
|
943
|
+
nodeId: string;
|
|
944
|
+
def: GlslShaderDef;
|
|
945
|
+
/** Per-element uniform value overrides. */
|
|
946
|
+
values?: Record<string, GlslUniformValue>;
|
|
947
|
+
/** Fill-mode static fallback background color. */
|
|
948
|
+
fallbackColor?: string;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* The complete persistence transform: upsert the definition block, embed or
|
|
953
|
+
* upgrade the runtime, and annotate the target element. Pure string → string;
|
|
954
|
+
* callers persist the result through their normal write path
|
|
955
|
+
* (apply-source-edit / edit-design / collab).
|
|
956
|
+
*/
|
|
957
|
+
export function applyShaderToHtml(
|
|
958
|
+
html: string,
|
|
959
|
+
options: ApplyShaderOptions,
|
|
960
|
+
): HtmlTransformResult {
|
|
961
|
+
const validation = validateShaderDef(options.def);
|
|
962
|
+
if (!validation.valid) {
|
|
963
|
+
return { html, changed: false, errors: validation.errors };
|
|
964
|
+
}
|
|
965
|
+
let next = upsertShaderInHtml(html, options.def);
|
|
966
|
+
next = ensureShaderRuntime(next);
|
|
967
|
+
const annotated = annotateNodeWithShader(next, {
|
|
968
|
+
nodeId: options.nodeId,
|
|
969
|
+
shaderId: options.def.id,
|
|
970
|
+
mode: options.def.mode,
|
|
971
|
+
values: options.values,
|
|
972
|
+
fallbackColor: options.fallbackColor,
|
|
973
|
+
});
|
|
974
|
+
if (annotated.errors.length > 0) {
|
|
975
|
+
return { html, changed: false, errors: annotated.errors };
|
|
976
|
+
}
|
|
977
|
+
return {
|
|
978
|
+
html: annotated.html,
|
|
979
|
+
changed: annotated.html !== html,
|
|
980
|
+
errors: [],
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Remove a shader from an element and garbage-collect any now-unreferenced
|
|
986
|
+
* definition blocks (the runtime tag stays — it is inert without mounts).
|
|
987
|
+
* Pass `mode` to remove only the fill or only the effect; omit for both.
|
|
988
|
+
*/
|
|
989
|
+
export function removeShaderFromNode(
|
|
990
|
+
html: string,
|
|
991
|
+
nodeId: string,
|
|
992
|
+
mode?: GlslShaderMode,
|
|
993
|
+
): HtmlTransformResult {
|
|
994
|
+
const cleared = clearNodeShader(html, nodeId, mode);
|
|
995
|
+
if (cleared.errors.length > 0) return cleared;
|
|
996
|
+
const pruned = pruneUnusedShaders(cleared.html);
|
|
997
|
+
return { html: pruned, changed: pruned !== html, errors: [] };
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/** Default uniform values (manifest values) for fresh knob state. */
|
|
1001
|
+
export function defaultUniformValues(
|
|
1002
|
+
def: GlslShaderDef,
|
|
1003
|
+
): Record<string, GlslUniformValue> {
|
|
1004
|
+
const out: Record<string, GlslUniformValue> = {};
|
|
1005
|
+
for (const [name, u] of Object.entries(def.uniforms)) {
|
|
1006
|
+
out[name] = u.value;
|
|
1007
|
+
}
|
|
1008
|
+
return out;
|
|
1009
|
+
}
|