@agent-native/core 0.85.6 → 0.86.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +130 -1
- package/corpus/core/README.md +0 -11
- package/corpus/core/docs/content/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/plan-plugin.mdx +12 -11
- package/corpus/core/docs/content/sharing.mdx +1 -2
- package/corpus/core/docs/content/skills-guide.mdx +4 -3
- package/corpus/core/docs/content/template-plan.mdx +37 -6
- package/corpus/core/docs/content/tracking.mdx +1 -1
- package/corpus/core/docs/content/workspace-connections.mdx +1 -1
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/agent/run-store.ts +1 -1
- package/corpus/core/src/chat-threads/store.ts +73 -11
- package/corpus/core/src/checkpoints/store.ts +13 -2
- package/corpus/core/src/cli/create.ts +3 -4
- package/corpus/core/src/cli/design-connect.ts +469 -9
- package/corpus/core/src/cli/index.ts +13 -0
- package/corpus/core/src/cli/plan-local.ts +281 -24
- package/corpus/core/src/cli/skills.ts +177 -21
- package/corpus/core/src/cli/templates-meta.ts +0 -13
- package/corpus/core/src/cli/visualize-repo.ts +715 -0
- package/corpus/core/src/client/AssistantChat.tsx +126 -17
- package/corpus/core/src/client/agent-chat-adapter.ts +6 -5
- package/corpus/core/src/client/app-providers.tsx +2 -2
- package/corpus/core/src/client/collab/index.ts +31 -0
- package/corpus/core/src/client/components/LiveCursorOverlay.tsx +16 -1
- package/corpus/core/src/client/components/PresenceBar.tsx +14 -1
- package/corpus/core/src/client/components/RecentEditHighlights.tsx +219 -0
- package/corpus/core/src/client/components/RemoteSelectionRings.tsx +40 -6
- package/corpus/core/src/client/index.ts +48 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +0 -4
- package/corpus/core/src/client/rich-markdown-editor/SharedRichEditor.tsx +49 -32
- package/corpus/core/src/client/rich-markdown-editor/index.ts +6 -0
- package/corpus/core/src/client/rich-markdown-editor/surgical-apply.ts +192 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +59 -8
- package/corpus/core/src/client/session-replay.ts +181 -15
- package/corpus/core/src/client/sse-event-processor.ts +90 -1
- package/corpus/core/src/client/use-action.ts +123 -25
- package/corpus/core/src/client/use-agent-engine-configured.ts +7 -1
- package/corpus/core/src/client/use-chat-threads.ts +18 -7
- package/corpus/core/src/client/use-db-sync.ts +104 -19
- package/corpus/core/src/client/use-pinch-zoom.ts +76 -11
- package/corpus/core/src/client/visual-style-controls.tsx +475 -0
- package/corpus/core/src/collab/agent-presence.ts +191 -62
- package/corpus/core/src/collab/awareness.ts +83 -6
- package/corpus/core/src/collab/client.ts +89 -146
- package/corpus/core/src/collab/index.ts +34 -0
- package/corpus/core/src/collab/presence.ts +63 -3
- package/corpus/core/src/collab/recent-edits.ts +171 -0
- package/corpus/core/src/collab/undo.ts +432 -0
- package/corpus/core/src/collab/ydoc-manager.ts +68 -0
- package/corpus/core/src/connections/catalog.ts +2 -3
- package/corpus/core/src/db/create-get-db.ts +86 -1
- package/corpus/core/src/db/ensure-additive-columns.ts +430 -0
- package/corpus/core/src/db/index.ts +6 -0
- package/corpus/core/src/db/migrations.ts +236 -35
- package/corpus/core/src/jobs/scheduler.ts +17 -14
- package/corpus/core/src/observability/traces.ts +182 -1
- package/corpus/core/src/org/context.ts +79 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +10 -6
- package/corpus/core/src/server/auth-marketing.ts +0 -11
- package/corpus/core/src/server/auth.ts +11 -4
- package/corpus/core/src/server/collab-plugin.ts +56 -13
- package/corpus/core/src/server/design-token-utils.ts +1 -1
- package/corpus/core/src/server/fusion-app.ts +447 -0
- package/corpus/core/src/server/index.ts +13 -0
- package/corpus/core/src/server/onboarding-html.ts +3 -4
- package/corpus/core/src/server/poll-events.ts +14 -2
- package/corpus/core/src/server/poll.ts +219 -12
- package/corpus/core/src/server/schema-prompt.ts +28 -9
- package/corpus/core/src/settings/store.ts +33 -2
- package/corpus/core/src/sharing/actions/set-resource-visibility.ts +2 -0
- package/corpus/core/src/sharing/actions/share-resource.ts +3 -0
- package/corpus/core/src/sharing/actions/unshare-resource.ts +2 -0
- package/corpus/core/src/styles/agent-native.css +0 -5
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/default/package.json +3 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/src/tracking/providers.ts +22 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +20 -5
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/analytics/AGENTS.md +33 -6
- package/corpus/templates/analytics/actions/navigate.ts +14 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/view-screen.ts +57 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +23 -1
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +15 -1
- package/corpus/templates/analytics/app/i18n-data.ts +151 -10
- package/corpus/templates/analytics/app/pages/Agents.tsx +118 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +11 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +76 -40
- package/corpus/templates/analytics/app/pages/sessions/session-replay-devtools.ts +5 -0
- package/corpus/templates/analytics/app/routes/agents.tsx +10 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-admin-tools-page.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-llm-observability-dashboard.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-session-recordings-now-include-response-bodies-for-5xx-error.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +34 -0
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +6 -0
- package/corpus/templates/analytics/package.json +3 -3
- package/corpus/templates/analytics/seeds/dashboards/agent-observability-llm.json +173 -0
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +23 -5
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +58 -13
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +23 -0
- package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +5 -0
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +120 -8
- package/corpus/templates/analytics/server/lib/session-replay.ts +3 -2
- package/corpus/templates/analytics/server/plugins/db.ts +93 -2
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +45 -1
- package/corpus/templates/analytics/shared/session-replay-diagnostics.ts +10 -0
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/assets/package.json +3 -3
- package/corpus/templates/assets/server/plugins/db.ts +63 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/brain/package.json +3 -3
- package/corpus/templates/brain/server/plugins/db.ts +75 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/calendar/package.json +3 -3
- package/corpus/templates/calendar/server/plugins/db.ts +64 -2
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/chat/package.json +3 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +50 -40
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +8 -6
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -3
- package/corpus/templates/clips/changelog/2026-07-03-mobile-recording-pages-keep-videos-in-a-16-9-player-with-act.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +245 -77
- package/corpus/templates/clips/package.json +3 -3
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +56 -0
- package/corpus/templates/clips/server/plugins/db.ts +68 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +27 -3
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/content/actions/edit-document.ts +48 -1
- package/corpus/templates/content/actions/list-documents.ts +101 -94
- package/corpus/templates/content/actions/search-documents.ts +19 -3
- package/corpus/templates/content/actions/update-document.ts +54 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -7
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +97 -2
- package/corpus/templates/content/changelog/2026-07-03-agent-document-edits-now-appear-as-a-live-collaborator-prese.md +6 -0
- package/corpus/templates/content/changelog/2026-07-03-document-search-and-list-views-load-faster-on-large-workspac.md +6 -0
- package/corpus/templates/content/package.json +3 -3
- package/corpus/templates/content/server/plugins/db.ts +57 -1
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +190 -13
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +16 -4
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +46 -3
- package/corpus/templates/design/.agents/skills/full-app-build/SKILL.md +140 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +20 -0
- package/corpus/templates/design/AGENTS.md +83 -13
- package/corpus/templates/design/actions/add-fusion-screens.ts +91 -0
- package/corpus/templates/design/actions/apply-a11y-fix.ts +5 -1
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +24 -69
- package/corpus/templates/design/actions/apply-fusion-edits.ts +161 -0
- package/corpus/templates/design/actions/apply-motion-edit.ts +29 -2
- package/corpus/templates/design/actions/apply-visual-edit.ts +38 -3
- package/corpus/templates/design/actions/connect-localhost.ts +25 -18
- package/corpus/templates/design/actions/create-component.ts +5 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +202 -0
- package/corpus/templates/design/actions/deploy-fusion-app.ts +123 -0
- package/corpus/templates/design/actions/edit-design.ts +13 -16
- package/corpus/templates/design/actions/export-pdf.ts +8 -1
- package/corpus/templates/design/actions/export-zip.ts +10 -1
- package/corpus/templates/design/actions/get-fusion-deploy-status.ts +86 -0
- package/corpus/templates/design/actions/get-motion-timeline.ts +26 -20
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +10 -0
- package/corpus/templates/design/actions/insert-asset.ts +190 -7
- package/corpus/templates/design/actions/list-fusion-edits.ts +96 -0
- package/corpus/templates/design/actions/list-local-files.ts +133 -0
- package/corpus/templates/design/actions/open-visual-edit.ts +27 -5
- package/corpus/templates/design/actions/present-design-variants.ts +2 -2
- package/corpus/templates/design/actions/push-fusion-app.ts +62 -0
- package/corpus/templates/design/actions/queue-fusion-edit.ts +112 -0
- package/corpus/templates/design/actions/read-local-file.ts +139 -0
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +18 -14
- package/corpus/templates/design/actions/run-design-audit.ts +7 -4
- package/corpus/templates/design/actions/send-fusion-message.ts +69 -0
- package/corpus/templates/design/actions/sync-fusion-app.ts +196 -0
- package/corpus/templates/design/actions/write-local-file.ts +162 -36
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +12 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +600 -66
- package/corpus/templates/design/app/components/design/EditPanel.tsx +793 -304
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +328 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +671 -154
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +1 -1
- package/corpus/templates/design/app/components/design/MotionDock.tsx +234 -46
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2070 -420
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +25 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -98
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +640 -72
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +605 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +50 -26
- package/corpus/templates/design/app/components/design/code-workbench/ActivityBar.tsx +85 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +466 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +53 -0
- package/corpus/templates/design/app/components/design/code-workbench/commands.ts +339 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/Breadcrumbs.tsx +42 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/BufferSync.tsx +128 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/EditorTabs.tsx +363 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +268 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/StatusBar.tsx +208 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +61 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme-palette.ts +191 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme.ts +29 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/status-bar-lang.ts +21 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/tab-drag.ts +27 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +155 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +551 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/file-icons.tsx +115 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +65 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/prettier-format.ts +182 -0
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +133 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +563 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/fuzzy.ts +170 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +508 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +280 -0
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +734 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +39 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +196 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +177 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/tree.ts +110 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +103 -0
- package/corpus/templates/design/app/components/design/code-workbench-theme.ts +68 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +16 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +217 -113
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +111 -5
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +79 -16
- package/corpus/templates/design/app/components/design/inspector/index.ts +9 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +67 -2
- package/corpus/templates/design/app/components/design/types.ts +16 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +80 -1
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +24 -6
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +15 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +6 -16
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +77 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/design/app/i18n-data.ts +31 -0
- package/corpus/templates/design/app/lib/design-import.ts +95 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +5586 -1112
- package/corpus/templates/design/app/pages/Index.tsx +90 -17
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-inspector-fixes-mixed-selections-show-mixed-instead-of-wrong.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-keyframe-timeline-works-reliably-drag-keyframes-smoothly-pic.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-much-faster-editor-smooth-dragging-zooming-and-panel-updates.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-pen-tool-refinements-click-the-first-point-to-close-with-a-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-text-editing-enter-adds-a-line-break-international-ime-typin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-ai-now-edits-like-a-collaborator-on-canvas-its-cursor-gl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-code-panel-is-now-a-full-vs-code-style-editor-with-a-fil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-undo-and-redo-are-dependable-across-agent-edits-screen-switc.md +6 -0
- package/corpus/templates/design/package.json +4 -3
- package/corpus/templates/design/server/db/schema.ts +31 -0
- package/corpus/templates/design/server/lib/design-export.ts +43 -1
- package/corpus/templates/design/server/lib/fusion-screens.ts +246 -0
- package/corpus/templates/design/server/plugins/db.ts +89 -2
- package/corpus/templates/design/shared/board-file.ts +25 -5
- package/corpus/templates/design/shared/canvas-math.ts +754 -9
- package/corpus/templates/design/shared/code-layer.ts +304 -26
- package/corpus/templates/design/shared/collab-selection.ts +52 -0
- package/corpus/templates/design/shared/color-utils.ts +84 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +16 -7
- package/corpus/templates/design/shared/full-app.ts +126 -0
- package/corpus/templates/design/shared/motion-compiler.ts +75 -31
- package/corpus/templates/design/shared/motion-timeline.ts +335 -0
- package/corpus/templates/design/shared/pen-path.ts +496 -23
- package/corpus/templates/dispatch/package.json +3 -3
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/forms/package.json +3 -3
- package/corpus/templates/forms/server/plugins/db.ts +62 -2
- package/corpus/templates/macros/package.json +3 -3
- package/corpus/templates/macros/server/plugins/db.ts +63 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/mail/package.json +3 -3
- package/corpus/templates/mail/server/lib/contact-frequency.ts +42 -15
- package/corpus/templates/mail/server/plugins/db.ts +63 -2
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +9 -3
- package/corpus/templates/plan/.agents/skills/visualize-repo/SKILL.md +92 -0
- package/corpus/templates/plan/actions/export-visual-plan.ts +5 -0
- package/corpus/templates/plan/actions/get-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/get-plan-version.ts +6 -16
- package/corpus/templates/plan/actions/list-plan-versions.ts +48 -20
- package/corpus/templates/plan/actions/patch-visual-plan-source.ts +41 -1
- package/corpus/templates/plan/actions/promote-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-local-plan-comments.ts +4 -2
- package/corpus/templates/plan/actions/update-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-visual-plan.ts +60 -1
- package/corpus/templates/plan/agent-native.app-skill.json +10 -0
- package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +138 -39
- package/corpus/templates/plan/app/components/editor/usePlanUndoStack.ts +165 -23
- package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +80 -4
- package/corpus/templates/plan/app/global.css +11 -9
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +10 -1
- package/corpus/templates/plan/app/hooks/use-plan-presence.ts +66 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +215 -63
- package/corpus/templates/plan/changelog/2026-07-03-local-visual-plans-and-recaps-can-save-comments-without-sign.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plan-tabs-render-nested-text-instead-of-raw-json.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-are-now-fully-real-time-collaborative-multiple-people-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-open-and-refresh-faster-especially-long-lived-plans-wi.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-undo-now-survives-agent-edits-cmd-z-keeps-working-on-your-ow.md +6 -0
- package/corpus/templates/plan/package.json +5 -3
- package/corpus/templates/plan/server/db/schema.ts +12 -0
- package/corpus/templates/plan/server/lib/local-plan-kind.ts +25 -0
- package/corpus/templates/plan/server/lib/plan-versions.ts +83 -1
- package/corpus/templates/plan/server/lib/public-action-paths.ts +0 -2
- package/corpus/templates/plan/server/plans.ts +26 -3
- package/corpus/templates/plan/server/plugins/db.ts +105 -2
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +8 -4
- package/corpus/templates/slides/AGENTS.md +4 -0
- package/corpus/templates/slides/actions/_agent-presence.ts +48 -0
- package/corpus/templates/slides/actions/add-slide.ts +16 -18
- package/corpus/templates/slides/actions/patch-deck.ts +4 -2
- package/corpus/templates/slides/actions/update-slide.ts +114 -77
- package/corpus/templates/slides/actions/view-screen.ts +39 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +47 -3
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +32 -35
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +625 -199
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +342 -0
- package/corpus/templates/slides/app/components/editor/TweaksPanel.tsx +46 -96
- package/corpus/templates/slides/app/components/visual-editor/SaveStatusIndicator.tsx +8 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +589 -176
- package/corpus/templates/slides/app/hooks/use-deck-presence.ts +84 -42
- package/corpus/templates/slides/app/i18n/ar-SA.ts +46 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +46 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +46 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +46 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +46 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +46 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +46 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +46 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +46 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +46 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +46 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +25 -13
- package/corpus/templates/slides/changelog/2026-07-03-figma-style-slide-editing.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-see-the-ai-working-with-you-when-the-agent-edits-a-slide-it-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-undo-redo-is-now-precise-and-safe-with-collaborators-it-only.md +6 -0
- package/corpus/templates/slides/package.json +3 -3
- package/corpus/templates/slides/server/handlers/decks.ts +31 -3
- package/corpus/templates/slides/server/plugins/db.ts +65 -2
- package/corpus/templates/videos/netlify.toml +1 -12
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +9 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +63 -11
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +10 -2
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +3 -5
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts +49 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +414 -9
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plan-local.d.ts +24 -0
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +188 -20
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +173 -21
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +0 -14
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/visualize-repo.d.ts +49 -0
- package/dist/cli/visualize-repo.d.ts.map +1 -0
- package/dist/cli/visualize-repo.js +561 -0
- package/dist/cli/visualize-repo.js.map +1 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +120 -15
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +6 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/app-providers.d.ts +2 -2
- package/dist/client/app-providers.js.map +1 -1
- package/dist/client/collab/index.d.ts +4 -1
- package/dist/client/collab/index.d.ts.map +1 -1
- package/dist/client/collab/index.js +3 -0
- package/dist/client/collab/index.js.map +1 -1
- package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
- package/dist/client/components/LiveCursorOverlay.js +11 -3
- package/dist/client/components/LiveCursorOverlay.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +6 -1
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/components/RecentEditHighlights.d.ts +43 -0
- package/dist/client/components/RecentEditHighlights.d.ts.map +1 -0
- package/dist/client/components/RecentEditHighlights.js +146 -0
- package/dist/client/components/RecentEditHighlights.js.map +1 -0
- package/dist/client/components/RemoteSelectionRings.d.ts +9 -0
- package/dist/client/components/RemoteSelectionRings.d.ts.map +1 -1
- package/dist/client/components/RemoteSelectionRings.js +22 -8
- package/dist/client/components/RemoteSelectionRings.js.map +1 -1
- package/dist/client/index.d.ts +6 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +7 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -3
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +8 -2
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/index.d.ts +1 -0
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +1 -0
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts +66 -0
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js +147 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js.map +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +18 -2
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +39 -8
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/session-replay.d.ts +10 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +134 -7
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +81 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-action.d.ts +24 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +109 -27
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +7 -1
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +11 -3
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +36 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +68 -12
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-pinch-zoom.d.ts.map +1 -1
- package/dist/client/use-pinch-zoom.js +76 -11
- package/dist/client/use-pinch-zoom.js.map +1 -1
- package/dist/client/visual-style-controls.d.ts +79 -0
- package/dist/client/visual-style-controls.d.ts.map +1 -0
- package/dist/client/visual-style-controls.js +150 -0
- package/dist/client/visual-style-controls.js.map +1 -0
- package/dist/collab/agent-presence.d.ts +51 -5
- package/dist/collab/agent-presence.d.ts.map +1 -1
- package/dist/collab/agent-presence.js +144 -58
- package/dist/collab/agent-presence.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +32 -0
- package/dist/collab/awareness-store.d.ts.map +1 -0
- package/dist/collab/awareness-store.js +0 -0
- package/dist/collab/awareness-store.js.map +1 -0
- package/dist/collab/awareness.d.ts +14 -3
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +53 -5
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts +2 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +79 -119
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +3 -1
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +5 -1
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/presence.d.ts.map +1 -1
- package/dist/collab/presence.js +54 -3
- package/dist/collab/presence.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +87 -0
- package/dist/collab/recent-edits.d.ts.map +1 -0
- package/dist/collab/recent-edits.js +116 -0
- package/dist/collab/recent-edits.js.map +1 -0
- package/dist/collab/undo.d.ts +121 -0
- package/dist/collab/undo.d.ts.map +1 -0
- package/dist/collab/undo.js +244 -0
- package/dist/collab/undo.js.map +1 -0
- package/dist/collab/ydoc-manager.d.ts +10 -0
- package/dist/collab/ydoc-manager.d.ts.map +1 -1
- package/dist/collab/ydoc-manager.js +57 -0
- package/dist/collab/ydoc-manager.js.map +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +1 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/db/create-get-db.d.ts +22 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +73 -1
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts +93 -0
- package/dist/db/ensure-additive-columns.d.ts.map +1 -0
- package/dist/db/ensure-additive-columns.js +355 -0
- package/dist/db/ensure-additive-columns.js.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +70 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +196 -33
- package/dist/db/migrations.js.map +1 -1
- package/dist/jobs/scheduler.js +17 -10
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +155 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/org/context.d.ts +7 -0
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +54 -2
- package/dist/org/context.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +10 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +0 -10
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -4
- package/dist/server/auth.js.map +1 -1
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +45 -13
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +1 -1
- package/dist/server/design-token-utils.js +1 -1
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/server/fusion-app.d.ts +107 -0
- package/dist/server/fusion-app.d.ts.map +1 -0
- package/dist/server/fusion-app.js +371 -0
- package/dist/server/fusion-app.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +3 -4
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll-events.d.ts +2 -0
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +7 -2
- package/dist/server/poll-events.js.map +1 -1
- package/dist/server/poll.d.ts +47 -3
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +176 -10
- package/dist/server/poll.js.map +1 -1
- package/dist/server/schema-prompt.d.ts.map +1 -1
- package/dist/server/schema-prompt.js +24 -7
- package/dist/server/schema-prompt.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +32 -3
- package/dist/settings/store.js.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +2 -0
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +3 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/actions/unshare-resource.js +2 -0
- package/dist/sharing/actions/unshare-resource.js.map +1 -1
- package/dist/styles/agent-native.css +0 -5
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/default/package.json +3 -3
- package/dist/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +17 -1
- package/dist/tracking/providers.js.map +1 -1
- package/docs/content/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/docs/content/plan-plugin.mdx +12 -11
- package/docs/content/sharing.mdx +1 -2
- package/docs/content/skills-guide.mdx +4 -3
- package/docs/content/template-plan.mdx +37 -6
- package/docs/content/tracking.mdx +1 -1
- package/docs/content/workspace-connections.mdx +1 -1
- package/package.json +6 -6
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/default/package.json +3 -3
- package/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/corpus/core/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/corpus/core/docs/content/template-videos.mdx +0 -332
- package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +0 -697
- package/corpus/templates/slides/app/components/editor/CodeEditor.tsx +0 -49
- package/corpus/templates/videos/.agents/skills/actions/SKILL.md +0 -432
- package/corpus/templates/videos/.agents/skills/animation-tracks/SKILL.md +0 -99
- package/corpus/templates/videos/.agents/skills/capture-learnings/SKILL.md +0 -76
- package/corpus/templates/videos/.agents/skills/composition-management/SKILL.md +0 -106
- package/corpus/templates/videos/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/templates/videos/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/frontend-design/SKILL.md +0 -112
- package/corpus/templates/videos/.agents/skills/security/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/self-modifying-code/SKILL.md +0 -88
- package/corpus/templates/videos/.agents/skills/shadcn-ui/SKILL.md +0 -95
- package/corpus/templates/videos/.builder/ANIMATED_PROPERTIES.md +0 -335
- package/corpus/templates/videos/.builder/KEYFRAME_SYNC.md +0 -166
- package/corpus/templates/videos/.builder/SEAMLESS_SYNC.md +0 -211
- package/corpus/templates/videos/.builder/rules/deploy-app.mdc +0 -22
- package/corpus/templates/videos/.builder/rules/organize-ui.mdc +0 -9
- package/corpus/templates/videos/.builder/skills/remotion/SKILL.md +0 -29
- package/corpus/templates/videos/.builder/skills/remotion/rules/animations.md +0 -27
- package/corpus/templates/videos/.builder/skills/remotion/rules/assets.md +0 -43
- package/corpus/templates/videos/.builder/skills/remotion/rules/audio.md +0 -58
- package/corpus/templates/videos/.builder/skills/remotion/rules/compositions.md +0 -129
- package/corpus/templates/videos/.builder/skills/remotion/rules/fonts.md +0 -47
- package/corpus/templates/videos/.builder/skills/remotion/rules/images.md +0 -41
- package/corpus/templates/videos/.builder/skills/remotion/rules/parameters.md +0 -59
- package/corpus/templates/videos/.builder/skills/remotion/rules/sequencing.md +0 -54
- package/corpus/templates/videos/.builder/skills/remotion/rules/tailwind.md +0 -11
- package/corpus/templates/videos/.builder/skills/remotion/rules/text-animations.md +0 -18
- package/corpus/templates/videos/.builder/skills/remotion/rules/timing.md +0 -103
- package/corpus/templates/videos/.builder/skills/remotion/rules/transparent-videos.md +0 -35
- package/corpus/templates/videos/.builder/skills/remotion/rules/trimming.md +0 -38
- package/corpus/templates/videos/.builder/skills/remotion/rules/videos.md +0 -54
- package/corpus/templates/videos/.dockerignore +0 -62
- package/corpus/templates/videos/.env.example +0 -4
- package/corpus/templates/videos/.oxfmtrc.json +0 -8
- package/corpus/templates/videos/AGENTS.md +0 -46
- package/corpus/templates/videos/CHANGELOG.md +0 -10
- package/corpus/templates/videos/DEVELOPING.md +0 -143
- package/corpus/templates/videos/README.md +0 -33
- package/corpus/templates/videos/actions/analyze-brand-assets.ts +0 -151
- package/corpus/templates/videos/actions/apply-design-system.ts +0 -35
- package/corpus/templates/videos/actions/create-design-system.ts +0 -84
- package/corpus/templates/videos/actions/create-folder.ts +0 -48
- package/corpus/templates/videos/actions/db-connect.ts +0 -45
- package/corpus/templates/videos/actions/db-health.ts +0 -24
- package/corpus/templates/videos/actions/db-status.ts +0 -28
- package/corpus/templates/videos/actions/delete-composition.ts +0 -272
- package/corpus/templates/videos/actions/delete-folder.ts +0 -27
- package/corpus/templates/videos/actions/generate-animated-component.ts +0 -470
- package/corpus/templates/videos/actions/get-composition.ts +0 -36
- package/corpus/templates/videos/actions/get-design-system.ts +0 -35
- package/corpus/templates/videos/actions/import-code.ts +0 -67
- package/corpus/templates/videos/actions/import-design-project.ts +0 -42
- package/corpus/templates/videos/actions/import-document.ts +0 -125
- package/corpus/templates/videos/actions/import-from-url.ts +0 -18
- package/corpus/templates/videos/actions/import-github.ts +0 -182
- package/corpus/templates/videos/actions/list-compositions.ts +0 -32
- package/corpus/templates/videos/actions/list-design-systems.ts +0 -66
- package/corpus/templates/videos/actions/list-folders.ts +0 -61
- package/corpus/templates/videos/actions/move-composition-to-folder.ts +0 -59
- package/corpus/templates/videos/actions/navigate.ts +0 -40
- package/corpus/templates/videos/actions/rename-folder.ts +0 -41
- package/corpus/templates/videos/actions/run.ts +0 -2
- package/corpus/templates/videos/actions/save-composition.ts +0 -114
- package/corpus/templates/videos/actions/set-default-design-system.ts +0 -40
- package/corpus/templates/videos/actions/update-composition.ts +0 -81
- package/corpus/templates/videos/actions/update-design-system.ts +0 -68
- package/corpus/templates/videos/actions/validate-compositions.ts +0 -502
- package/corpus/templates/videos/actions/view-screen.ts +0 -48
- package/corpus/templates/videos/app/components/CameraControls.tsx +0 -442
- package/corpus/templates/videos/app/components/CameraToolbar.tsx +0 -437
- package/corpus/templates/videos/app/components/CloudUpgrade.tsx +0 -287
- package/corpus/templates/videos/app/components/CollabPresenceBar.tsx +0 -81
- package/corpus/templates/videos/app/components/CompSettingsEditor.tsx +0 -107
- package/corpus/templates/videos/app/components/ComponentLibrarySidebar.tsx +0 -457
- package/corpus/templates/videos/app/components/ComponentPropsPanel.tsx +0 -227
- package/corpus/templates/videos/app/components/ComponentsSidebar.tsx +0 -70
- package/corpus/templates/videos/app/components/CompositionCard.tsx +0 -147
- package/corpus/templates/videos/app/components/CurrentElementPanel.tsx +0 -835
- package/corpus/templates/videos/app/components/CursorControls.tsx +0 -664
- package/corpus/templates/videos/app/components/CursorPositioningOverlay.tsx +0 -238
- package/corpus/templates/videos/app/components/LibraryFolderRow.tsx +0 -235
- package/corpus/templates/videos/app/components/MotionCurveSelect.tsx +0 -61
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +0 -192
- package/corpus/templates/videos/app/components/PropsEditor.tsx +0 -210
- package/corpus/templates/videos/app/components/QuestionFlow.tsx +0 -40
- package/corpus/templates/videos/app/components/Sidebar.tsx +0 -609
- package/corpus/templates/videos/app/components/StudioHeader.tsx +0 -109
- package/corpus/templates/videos/app/components/Timeline.tsx +0 -2067
- package/corpus/templates/videos/app/components/TrackPropertiesPanel.tsx +0 -922
- package/corpus/templates/videos/app/components/TweaksPanel.tsx +0 -277
- package/corpus/templates/videos/app/components/VideoPlayer.tsx +0 -487
- package/corpus/templates/videos/app/components/design-system/DesignSystemCard.tsx +0 -134
- package/corpus/templates/videos/app/components/design-system/DesignSystemPreview.tsx +0 -176
- package/corpus/templates/videos/app/components/design-system/DesignSystemSetup.tsx +0 -707
- package/corpus/templates/videos/app/components/keyframes/KeyframeActionButtons.tsx +0 -78
- package/corpus/templates/videos/app/components/keyframes/KeyframeNavigation.tsx +0 -59
- package/corpus/templates/videos/app/components/keyframes/PropertyNumberInput.tsx +0 -56
- package/corpus/templates/videos/app/components/layout/Header.tsx +0 -64
- package/corpus/templates/videos/app/components/layout/HeaderActions.tsx +0 -84
- package/corpus/templates/videos/app/components/layout/Layout.tsx +0 -132
- package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -180
- package/corpus/templates/videos/app/components/ui/accordion.tsx +0 -56
- package/corpus/templates/videos/app/components/ui/alert-dialog.tsx +0 -139
- package/corpus/templates/videos/app/components/ui/alert.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/aspect-ratio.tsx +0 -5
- package/corpus/templates/videos/app/components/ui/avatar.tsx +0 -48
- package/corpus/templates/videos/app/components/ui/badge.tsx +0 -37
- package/corpus/templates/videos/app/components/ui/breadcrumb.tsx +0 -115
- package/corpus/templates/videos/app/components/ui/button.tsx +0 -57
- package/corpus/templates/videos/app/components/ui/calendar.tsx +0 -68
- package/corpus/templates/videos/app/components/ui/card.tsx +0 -86
- package/corpus/templates/videos/app/components/ui/carousel.tsx +0 -260
- package/corpus/templates/videos/app/components/ui/chart.tsx +0 -375
- package/corpus/templates/videos/app/components/ui/checkbox.tsx +0 -28
- package/corpus/templates/videos/app/components/ui/collapsible.tsx +0 -9
- package/corpus/templates/videos/app/components/ui/command.tsx +0 -154
- package/corpus/templates/videos/app/components/ui/context-menu.tsx +0 -202
- package/corpus/templates/videos/app/components/ui/dialog.tsx +0 -130
- package/corpus/templates/videos/app/components/ui/drawer.tsx +0 -116
- package/corpus/templates/videos/app/components/ui/dropdown-menu.tsx +0 -212
- package/corpus/templates/videos/app/components/ui/form.tsx +0 -177
- package/corpus/templates/videos/app/components/ui/hover-card.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/input-otp.tsx +0 -69
- package/corpus/templates/videos/app/components/ui/input.tsx +0 -22
- package/corpus/templates/videos/app/components/ui/label.tsx +0 -24
- package/corpus/templates/videos/app/components/ui/menubar.tsx +0 -234
- package/corpus/templates/videos/app/components/ui/navigation-menu.tsx +0 -128
- package/corpus/templates/videos/app/components/ui/pagination.tsx +0 -121
- package/corpus/templates/videos/app/components/ui/popover.tsx +0 -44
- package/corpus/templates/videos/app/components/ui/progress.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/radio-group.tsx +0 -42
- package/corpus/templates/videos/app/components/ui/resizable.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/scroll-area.tsx +0 -46
- package/corpus/templates/videos/app/components/ui/select.tsx +0 -158
- package/corpus/templates/videos/app/components/ui/separator.tsx +0 -29
- package/corpus/templates/videos/app/components/ui/sheet.tsx +0 -160
- package/corpus/templates/videos/app/components/ui/sidebar.tsx +0 -782
- package/corpus/templates/videos/app/components/ui/skeleton.tsx +0 -15
- package/corpus/templates/videos/app/components/ui/slider.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/sonner.tsx +0 -58
- package/corpus/templates/videos/app/components/ui/spinner.tsx +0 -17
- package/corpus/templates/videos/app/components/ui/switch.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/table.tsx +0 -117
- package/corpus/templates/videos/app/components/ui/tabs.tsx +0 -53
- package/corpus/templates/videos/app/components/ui/textarea.tsx +0 -23
- package/corpus/templates/videos/app/components/ui/toast.tsx +0 -127
- package/corpus/templates/videos/app/components/ui/toaster.tsx +0 -33
- package/corpus/templates/videos/app/components/ui/toggle-group.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/toggle.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/tooltip.tsx +0 -30
- package/corpus/templates/videos/app/components/ui/use-toast.ts +0 -3
- package/corpus/templates/videos/app/config/constants.ts +0 -204
- package/corpus/templates/videos/app/contexts/CompositionContext.tsx +0 -437
- package/corpus/templates/videos/app/contexts/CurrentElementContext.tsx +0 -247
- package/corpus/templates/videos/app/contexts/PlaybackContext.tsx +0 -65
- package/corpus/templates/videos/app/contexts/TimelineContext.tsx +0 -433
- package/corpus/templates/videos/app/entry.client.tsx +0 -19
- package/corpus/templates/videos/app/entry.server.tsx +0 -10
- package/corpus/templates/videos/app/global.css +0 -171
- package/corpus/templates/videos/app/hooks/use-composition-collab.ts +0 -269
- package/corpus/templates/videos/app/hooks/use-composition-design-system.ts +0 -47
- package/corpus/templates/videos/app/hooks/use-database-compositions.ts +0 -144
- package/corpus/templates/videos/app/hooks/use-db-status.ts +0 -30
- package/corpus/templates/videos/app/hooks/use-design-systems.ts +0 -21
- package/corpus/templates/videos/app/hooks/use-folders.ts +0 -199
- package/corpus/templates/videos/app/hooks/use-mobile.tsx +0 -21
- package/corpus/templates/videos/app/hooks/use-navigation-state.ts +0 -52
- package/corpus/templates/videos/app/hooks/use-question-flow.ts +0 -14
- package/corpus/templates/videos/app/hooks/use-toast.ts +0 -188
- package/corpus/templates/videos/app/hooks/useUnsavedChanges.ts +0 -48
- package/corpus/templates/videos/app/i18n/ar-SA.ts +0 -446
- package/corpus/templates/videos/app/i18n/de-DE.ts +0 -470
- package/corpus/templates/videos/app/i18n/en-US.ts +0 -452
- package/corpus/templates/videos/app/i18n/es-ES.ts +0 -468
- package/corpus/templates/videos/app/i18n/fr-FR.ts +0 -469
- package/corpus/templates/videos/app/i18n/hi-IN.ts +0 -446
- package/corpus/templates/videos/app/i18n/index.ts +0 -34
- package/corpus/templates/videos/app/i18n/ja-JP.ts +0 -460
- package/corpus/templates/videos/app/i18n/ko-KR.ts +0 -453
- package/corpus/templates/videos/app/i18n/pt-BR.ts +0 -461
- package/corpus/templates/videos/app/i18n/zh-CN.ts +0 -437
- package/corpus/templates/videos/app/i18n/zh-TW.ts +0 -437
- package/corpus/templates/videos/app/lib/database-compositions.ts +0 -67
- package/corpus/templates/videos/app/lib/design-systems.ts +0 -234
- package/corpus/templates/videos/app/lib/tab-id.ts +0 -1
- package/corpus/templates/videos/app/lib/utils.ts +0 -1
- package/corpus/templates/videos/app/pages/ComponentLibrary.tsx +0 -134
- package/corpus/templates/videos/app/pages/ComponentLibraryView.tsx +0 -362
- package/corpus/templates/videos/app/pages/CompositionView.tsx +0 -715
- package/corpus/templates/videos/app/pages/DesignSystems.tsx +0 -180
- package/corpus/templates/videos/app/pages/Index.tsx +0 -258
- package/corpus/templates/videos/app/pages/NewComposition.tsx +0 -95
- package/corpus/templates/videos/app/pages/NotFound.tsx +0 -36
- package/corpus/templates/videos/app/remotion/CameraHost.tsx +0 -223
- package/corpus/templates/videos/app/remotion/animations/useElementAnimations.ts +0 -231
- package/corpus/templates/videos/app/remotion/componentRegistry.ts +0 -473
- package/corpus/templates/videos/app/remotion/components/AnimatedElement.tsx +0 -436
- package/corpus/templates/videos/app/remotion/components/InteractiveElement.tsx +0 -159
- package/corpus/templates/videos/app/remotion/components/InteractiveZoneEditor.tsx +0 -273
- package/corpus/templates/videos/app/remotion/compositions/BlankComposition.tsx +0 -204
- package/corpus/templates/videos/app/remotion/compositions/index.ts +0 -2
- package/corpus/templates/videos/app/remotion/createComponentCursorTrack.ts +0 -132
- package/corpus/templates/videos/app/remotion/docs/CURSOR_TRACKS.md +0 -285
- package/corpus/templates/videos/app/remotion/easingFunctions.ts +0 -255
- package/corpus/templates/videos/app/remotion/hooks/createInteractiveComposition.tsx +0 -283
- package/corpus/templates/videos/app/remotion/hooks/useCursorHistory.ts +0 -72
- package/corpus/templates/videos/app/remotion/hooks/useCursorTypeFromHover.ts +0 -35
- package/corpus/templates/videos/app/remotion/hooks/useEditableZones.tsx +0 -267
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimation.ts +0 -90
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimationSmooth.ts +0 -146
- package/corpus/templates/videos/app/remotion/hooks/useInteractiveComponent.ts +0 -711
- package/corpus/templates/videos/app/remotion/hooks/useRegisterInteractiveElement.ts +0 -56
- package/corpus/templates/videos/app/remotion/library-components/Button.tsx +0 -252
- package/corpus/templates/videos/app/remotion/library-components/Card.tsx +0 -241
- package/corpus/templates/videos/app/remotion/library-components/CodePanel.tsx +0 -1005
- package/corpus/templates/videos/app/remotion/library-components/FileItem.tsx +0 -196
- package/corpus/templates/videos/app/remotion/library-components/FolderItem.tsx +0 -199
- package/corpus/templates/videos/app/remotion/library-components/PrimaryButton.tsx +0 -177
- package/corpus/templates/videos/app/remotion/library-components/SecondaryButton.tsx +0 -167
- package/corpus/templates/videos/app/remotion/library-components/SectionHeader.tsx +0 -108
- package/corpus/templates/videos/app/remotion/library-components/TEMPLATE.tsx +0 -211
- package/corpus/templates/videos/app/remotion/library-components/index.ts +0 -10
- package/corpus/templates/videos/app/remotion/registry.ts +0 -91
- package/corpus/templates/videos/app/remotion/testing/animationTestUtils.ts +0 -366
- package/corpus/templates/videos/app/remotion/trackAnimation.ts +0 -179
- package/corpus/templates/videos/app/remotion/trackHelpers.ts +0 -110
- package/corpus/templates/videos/app/remotion/ui-components/Cursor.tsx +0 -182
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveButton.tsx +0 -116
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveCard.tsx +0 -126
- package/corpus/templates/videos/app/remotion/ui-components/index.ts +0 -16
- package/corpus/templates/videos/app/remotion/utils/animationHelpers.ts +0 -444
- package/corpus/templates/videos/app/remotion/utils/interactiveElements.ts +0 -235
- package/corpus/templates/videos/app/remotion/utils/springAnimation.ts +0 -76
- package/corpus/templates/videos/app/root.tsx +0 -165
- package/corpus/templates/videos/app/routes/$.tsx +0 -10
- package/corpus/templates/videos/app/routes/_index.tsx +0 -25
- package/corpus/templates/videos/app/routes/c.$compositionId.tsx +0 -10
- package/corpus/templates/videos/app/routes/components.tsx +0 -10
- package/corpus/templates/videos/app/routes/design-systems.tsx +0 -10
- package/corpus/templates/videos/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/templates/videos/app/routes/extensions.$id.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions._index.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions.tsx +0 -5
- package/corpus/templates/videos/app/routes/settings.tsx +0 -88
- package/corpus/templates/videos/app/routes/team.tsx +0 -11
- package/corpus/templates/videos/app/routes.ts +0 -4
- package/corpus/templates/videos/app/state.ts +0 -77
- package/corpus/templates/videos/app/types/elementAnimations.ts +0 -121
- package/corpus/templates/videos/app/types.ts +0 -200
- package/corpus/templates/videos/app/utils/compositionHelpers.ts +0 -445
- package/corpus/templates/videos/app/utils/debug.ts +0 -63
- package/corpus/templates/videos/app/utils/keyframeUtils.ts +0 -331
- package/corpus/templates/videos/app/utils/timelineCoordinates.ts +0 -79
- package/corpus/templates/videos/app/vite-env.d.ts +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/templates/videos/components.json +0 -20
- package/corpus/templates/videos/data/sync-config.json +0 -3
- package/corpus/templates/videos/docs/examples/create-composition.example.ts +0 -128
- package/corpus/templates/videos/drizzle.config.ts +0 -3
- package/corpus/templates/videos/learnings.defaults.md +0 -5
- package/corpus/templates/videos/package.json +0 -114
- package/corpus/templates/videos/public/agent-native-icon-dark.svg +0 -10
- package/corpus/templates/videos/public/agent-native-icon-light.svg +0 -10
- package/corpus/templates/videos/public/agent-native-logo-dark.svg +0 -21
- package/corpus/templates/videos/public/agent-native-logo-light.svg +0 -21
- package/corpus/templates/videos/public/favicon.svg +0 -1
- package/corpus/templates/videos/public/icon-180.svg +0 -1
- package/corpus/templates/videos/public/icon-192.svg +0 -1
- package/corpus/templates/videos/public/icon-512.svg +0 -1
- package/corpus/templates/videos/public/manifest.json +0 -21
- package/corpus/templates/videos/public/placeholder.svg +0 -1
- package/corpus/templates/videos/public/robots.txt +0 -14
- package/corpus/templates/videos/react-router.config.ts +0 -7
- package/corpus/templates/videos/server/db/index.ts +0 -37
- package/corpus/templates/videos/server/db/schema.ts +0 -55
- package/corpus/templates/videos/server/middleware/auth.ts +0 -15
- package/corpus/templates/videos/server/plugins/agent-chat.ts +0 -29
- package/corpus/templates/videos/server/plugins/auth.ts +0 -14
- package/corpus/templates/videos/server/plugins/collab.ts +0 -11
- package/corpus/templates/videos/server/plugins/core-routes.ts +0 -22
- package/corpus/templates/videos/server/plugins/db.ts +0 -160
- package/corpus/templates/videos/server/routes/[...page].get.ts +0 -5
- package/corpus/templates/videos/server/routes/[...page].head.ts +0 -1
- package/corpus/templates/videos/server/routes/api/save-composition-defaults.post.ts +0 -274
- package/corpus/templates/videos/shared/api.ts +0 -75
- package/corpus/templates/videos/ssr-entry.ts +0 -15
- package/corpus/templates/videos/tsconfig.json +0 -21
- package/corpus/templates/videos/vite.config.ts +0 -19
- package/corpus/templates/videos/vitest.config.ts +0 -16
- package/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/docs/content/template-videos.mdx +0 -332
|
@@ -19,6 +19,10 @@ export interface FrameGeometry {
|
|
|
19
19
|
y: number;
|
|
20
20
|
width: number;
|
|
21
21
|
height: number;
|
|
22
|
+
/** Rotation in degrees, matching a CSS `rotate(deg)` applied around the
|
|
23
|
+
* frame's own center. Optional — most geometry helpers here ignore it
|
|
24
|
+
* unless documented otherwise (see the rotation-aware helpers below). */
|
|
25
|
+
rotation?: number;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
export interface FrameEntry {
|
|
@@ -61,6 +65,15 @@ export interface CanvasSnapOptions {
|
|
|
61
65
|
bypass?: boolean;
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
export interface ResizeSnapOptions extends CanvasSnapOptions {
|
|
69
|
+
/** When set, only the single closest-matching axis snap is applied and the
|
|
70
|
+
* other axis is rescaled to match, so a shift-held aspect-ratio resize
|
|
71
|
+
* never gets distorted by independently snapping both axes to different
|
|
72
|
+
* sibling edges. Pass the frame's aspect ratio (width / height) *before*
|
|
73
|
+
* this resize's own aspect-preserving delta was applied. */
|
|
74
|
+
preserveAspectRatio?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
64
77
|
export interface ResizeFrameOptions {
|
|
65
78
|
preserveAspectRatio?: boolean;
|
|
66
79
|
resizeFromCenter?: boolean;
|
|
@@ -78,6 +91,13 @@ export interface DraftGeometryOptions {
|
|
|
78
91
|
minHeight?: number;
|
|
79
92
|
defaultWidth?: number;
|
|
80
93
|
defaultHeight?: number;
|
|
94
|
+
/** Constrain to equal width/height (square/circle) while drawing — the
|
|
95
|
+
* larger of the two dragged dimensions wins, matching Figma's shift-drag
|
|
96
|
+
* behavior for rect/ellipse tools. */
|
|
97
|
+
square?: boolean;
|
|
98
|
+
/** Draw outward from `start` in both directions (start is the shape's
|
|
99
|
+
* center) instead of from one corner to the opposite corner. */
|
|
100
|
+
fromCenter?: boolean;
|
|
81
101
|
}
|
|
82
102
|
|
|
83
103
|
export interface AlignmentGuide {
|
|
@@ -87,6 +107,35 @@ export interface AlignmentGuide {
|
|
|
87
107
|
end: number;
|
|
88
108
|
}
|
|
89
109
|
|
|
110
|
+
/** One equal-spacing "gap band" — the empty space between the moving frame
|
|
111
|
+
* and one neighboring stationary frame, on a given axis. `crossStart`/
|
|
112
|
+
* `crossEnd` are the band's extent on the OTHER axis (e.g. for a
|
|
113
|
+
* horizontal gap, that's the vertical span the tick marks/label should
|
|
114
|
+
* draw across), matching how `AlignmentGuide.start`/`end` describe a
|
|
115
|
+
* guide line's own extent. */
|
|
116
|
+
export interface DistanceGuideBand {
|
|
117
|
+
gapStart: number;
|
|
118
|
+
gapEnd: number;
|
|
119
|
+
crossStart: number;
|
|
120
|
+
crossEnd: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** A pair of equal-sized gaps around the moving frame — Figma's "smart
|
|
124
|
+
* spacing" indicator: dragging a frame so it's evenly spaced between two
|
|
125
|
+
* neighbors (or continues an existing rhythm of equally spaced siblings)
|
|
126
|
+
* highlights both gaps with the shared distance. */
|
|
127
|
+
export interface EqualGapGuide {
|
|
128
|
+
orientation: "vertical" | "horizontal";
|
|
129
|
+
/** The shared gap size, in canvas units, both bands agree on. */
|
|
130
|
+
gap: number;
|
|
131
|
+
bands: [DistanceGuideBand, DistanceGuideBand];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface EqualGapOptions {
|
|
135
|
+
/** How close two gaps must be (in canvas units) to count as "equal". */
|
|
136
|
+
toleranceCanvasPx?: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
90
139
|
export interface RotateFrameMetadata {
|
|
91
140
|
id: string;
|
|
92
141
|
geometry: FrameGeometry;
|
|
@@ -177,6 +226,22 @@ export const DEFAULT_ASSIGNED_REGION_HEIGHT = 1024;
|
|
|
177
226
|
export const DEFAULT_ASSIGNED_REGION_GAP = 320;
|
|
178
227
|
export const DEFAULT_ASSIGNED_REGION_MAX_COLUMNS = 3;
|
|
179
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Zoom range for the MultiScreenCanvas overview surface (wheel/pinch zoom,
|
|
231
|
+
* toolbar/keyboard zoom, pixel-grid threshold). Exported so every zoom-clamp
|
|
232
|
+
* in MultiScreenCanvas.tsx reads from one place instead of a locally
|
|
233
|
+
* redeclared magic number.
|
|
234
|
+
*
|
|
235
|
+
* NOTE: DesignCanvas's own single-screen pinch-zoom currently clamps to a
|
|
236
|
+
* different range (10–500) — that's a separate, pre-existing surface with
|
|
237
|
+
* its own zoom semantics (it also supports device-frame previews at fixed
|
|
238
|
+
* scales) and reconciling the two ranges is intentionally left as a
|
|
239
|
+
* follow-up rather than done here, since DesignCanvas.tsx is out of scope
|
|
240
|
+
* for this fix.
|
|
241
|
+
*/
|
|
242
|
+
export const DEFAULT_CANVAS_MIN_ZOOM = 2;
|
|
243
|
+
export const DEFAULT_CANVAS_MAX_ZOOM = 800;
|
|
244
|
+
|
|
180
245
|
export function screenToCanvasPoint(
|
|
181
246
|
point: CanvasPoint,
|
|
182
247
|
camera: CanvasCamera,
|
|
@@ -285,6 +350,41 @@ export function getRotatedFrameAngle(
|
|
|
285
350
|
};
|
|
286
351
|
}
|
|
287
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Rotates a group of frames together around a single shared pivot (the
|
|
355
|
+
* group's own center), for multi-selection rotate: each frame's own
|
|
356
|
+
* rotation increases by `deltaDegrees` (so it keeps spinning around its own
|
|
357
|
+
* center visually), AND its center orbits `groupCenter` by the same delta,
|
|
358
|
+
* so the whole selection rotates rigidly as one unit rather than each frame
|
|
359
|
+
* spinning in place where it already sits.
|
|
360
|
+
*
|
|
361
|
+
* `frames` must carry each frame's ORIGINAL (drag-start) geometry — this is
|
|
362
|
+
* a pure function of the origin snapshot and the total delta so far, not an
|
|
363
|
+
* incremental transform, matching the convention `resizeFrameGroupFromDelta`
|
|
364
|
+
* already uses for group resize.
|
|
365
|
+
*/
|
|
366
|
+
export function rotateFrameGroupAroundCenter(
|
|
367
|
+
frames: FrameEntry[],
|
|
368
|
+
groupCenter: CanvasPoint,
|
|
369
|
+
deltaDegrees: number,
|
|
370
|
+
): FrameEntry[] {
|
|
371
|
+
return frames.map((frame) => {
|
|
372
|
+
const bounds = getFrameBounds(frame.geometry);
|
|
373
|
+
const originCenter = { x: bounds.centerX, y: bounds.centerY };
|
|
374
|
+
const nextCenter = rotatePoint(originCenter, groupCenter, deltaDegrees);
|
|
375
|
+
const nextRotation = (frame.geometry.rotation ?? 0) + deltaDegrees;
|
|
376
|
+
return {
|
|
377
|
+
id: frame.id,
|
|
378
|
+
geometry: {
|
|
379
|
+
...frame.geometry,
|
|
380
|
+
x: nextCenter.x - frame.geometry.width / 2,
|
|
381
|
+
y: nextCenter.y - frame.geometry.height / 2,
|
|
382
|
+
rotation: nextRotation,
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
288
388
|
export function getFrameBounds(geometry: FrameGeometry): FrameBounds {
|
|
289
389
|
const width = geometry.width;
|
|
290
390
|
const height = geometry.height;
|
|
@@ -449,12 +549,52 @@ export function getDraftGeometryFromPoints(
|
|
|
449
549
|
minHeight = 1,
|
|
450
550
|
defaultWidth,
|
|
451
551
|
defaultHeight,
|
|
552
|
+
square = false,
|
|
553
|
+
fromCenter = false,
|
|
452
554
|
}: DraftGeometryOptions = {},
|
|
453
555
|
): FrameGeometry {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
556
|
+
// When drawing from the center, `end` marks one edge/corner of the shape
|
|
557
|
+
// rather than the opposite corner from `start` — the pointer's distance
|
|
558
|
+
// from center is a HALF-extent, so the full width/height is double the
|
|
559
|
+
// raw drag distance.
|
|
560
|
+
const centerMultiplier = fromCenter ? 2 : 1;
|
|
561
|
+
let rawWidth = Math.abs(end.x - start.x) * centerMultiplier;
|
|
562
|
+
let rawHeight = Math.abs(end.y - start.y) * centerMultiplier;
|
|
563
|
+
|
|
564
|
+
if (square) {
|
|
565
|
+
// Figma's shift-drag: the larger dragged dimension wins, both axes match
|
|
566
|
+
// it. Preserve each axis's own drag direction (handled below via
|
|
567
|
+
// drawingLeft/drawingUp) — only the magnitude is unified here.
|
|
568
|
+
const side = Math.max(rawWidth, rawHeight);
|
|
569
|
+
rawWidth = side;
|
|
570
|
+
rawHeight = side;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
let width = Math.max(rawWidth || defaultWidth || 0, minWidth);
|
|
574
|
+
let height = Math.max(rawHeight || defaultHeight || 0, minHeight);
|
|
575
|
+
|
|
576
|
+
if (square && width !== height) {
|
|
577
|
+
// Zero-drag (a plain click before any movement) falls through to
|
|
578
|
+
// defaultWidth/defaultHeight and minWidth/minHeight independently, which
|
|
579
|
+
// can disagree even though rawWidth/rawHeight were already unified
|
|
580
|
+
// above. Re-unify using the larger side so a square/circle click-to-
|
|
581
|
+
// place still starts out square instead of using mismatched defaults.
|
|
582
|
+
const side = Math.max(width, height);
|
|
583
|
+
width = side;
|
|
584
|
+
height = side;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (fromCenter) {
|
|
588
|
+
// `start` is the shape's center — grow outward symmetrically in both
|
|
589
|
+
// directions instead of anchoring one corner at `start`.
|
|
590
|
+
return {
|
|
591
|
+
x: start.x - width / 2,
|
|
592
|
+
y: start.y - height / 2,
|
|
593
|
+
width,
|
|
594
|
+
height,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
458
598
|
const drawingLeft = end.x < start.x;
|
|
459
599
|
const drawingUp = end.y < start.y;
|
|
460
600
|
|
|
@@ -493,13 +633,16 @@ export function computeMoveSnap(
|
|
|
493
633
|
let bestX: SnapCandidate | null = null;
|
|
494
634
|
let bestY: SnapCandidate | null = null;
|
|
495
635
|
const threshold = getCanvasSnapThreshold(options);
|
|
636
|
+
// Use the rotated (world-space) AABB rather than the unrotated local
|
|
637
|
+
// bounds, so a rotated frame snaps by its visual silhouette instead of an
|
|
638
|
+
// AABB that doesn't match anything on screen.
|
|
496
639
|
const stationaryBounds = stationary.map((entry) => ({
|
|
497
640
|
...entry,
|
|
498
|
-
bounds:
|
|
641
|
+
bounds: getRotatedFrameAABB(entry.geometry),
|
|
499
642
|
}));
|
|
500
643
|
|
|
501
644
|
for (const entry of moving) {
|
|
502
|
-
const movingBounds =
|
|
645
|
+
const movingBounds = getRotatedFrameAABB(entry.geometry);
|
|
503
646
|
for (const stationaryEntry of stationaryBounds) {
|
|
504
647
|
bestX = getBestCandidate(
|
|
505
648
|
bestX,
|
|
@@ -529,6 +672,168 @@ export function computeMoveSnap(
|
|
|
529
672
|
};
|
|
530
673
|
}
|
|
531
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Figma-style "smart spacing" guides (CV11): when a single moving frame sits
|
|
677
|
+
* between two stationary neighbors with matching gaps on either side — or
|
|
678
|
+
* continues that same gap on just one side — highlight both gaps with their
|
|
679
|
+
* shared distance. This is purely a *display* aid (unlike computeMoveSnap,
|
|
680
|
+
* it never adjusts the frame's position) so callers should compute it
|
|
681
|
+
* independently of, and after, any snap offset has already been applied to
|
|
682
|
+
* the moving frame's geometry.
|
|
683
|
+
*
|
|
684
|
+
* Only single-frame moves are supported (matching how Figma's own equal-gap
|
|
685
|
+
* guides only appear while dragging one object) — pass the already-resolved
|
|
686
|
+
* single moving frame, not a multi-select group.
|
|
687
|
+
*/
|
|
688
|
+
export function computeEqualGapGuides(
|
|
689
|
+
moving: FrameGeometry,
|
|
690
|
+
stationary: FrameEntry[],
|
|
691
|
+
{ toleranceCanvasPx = 1 }: EqualGapOptions = {},
|
|
692
|
+
): EqualGapGuide[] {
|
|
693
|
+
const movingBounds = getRotatedFrameAABB(moving);
|
|
694
|
+
const guides: EqualGapGuide[] = [];
|
|
695
|
+
|
|
696
|
+
const horizontal = collectAxisGapCandidates("x", movingBounds, stationary);
|
|
697
|
+
guides.push(...pairUpEqualGaps("vertical", horizontal, toleranceCanvasPx));
|
|
698
|
+
|
|
699
|
+
const vertical = collectAxisGapCandidates("y", movingBounds, stationary);
|
|
700
|
+
guides.push(...pairUpEqualGaps("horizontal", vertical, toleranceCanvasPx));
|
|
701
|
+
|
|
702
|
+
return guides;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
interface GapCandidate {
|
|
706
|
+
/** "before" = stationary frame is to the left/above the moving frame;
|
|
707
|
+
* "after" = to the right/below. */
|
|
708
|
+
side: "before" | "after";
|
|
709
|
+
gap: number;
|
|
710
|
+
gapStart: number;
|
|
711
|
+
gapEnd: number;
|
|
712
|
+
crossStart: number;
|
|
713
|
+
crossEnd: number;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function collectAxisGapCandidates(
|
|
717
|
+
axis: "x" | "y",
|
|
718
|
+
movingBounds: FrameBounds,
|
|
719
|
+
stationary: FrameEntry[],
|
|
720
|
+
): GapCandidate[] {
|
|
721
|
+
const candidates: GapCandidate[] = [];
|
|
722
|
+
for (const entry of stationary) {
|
|
723
|
+
const bounds = getRotatedFrameAABB(entry.geometry);
|
|
724
|
+
// Only frames that overlap the moving frame's extent on the OTHER axis
|
|
725
|
+
// produce a meaningful "gap between them" — otherwise the empty space
|
|
726
|
+
// isn't really a corridor connecting the two shapes.
|
|
727
|
+
const crossOverlaps =
|
|
728
|
+
axis === "x"
|
|
729
|
+
? bounds.top < movingBounds.bottom && bounds.bottom > movingBounds.top
|
|
730
|
+
: bounds.left < movingBounds.right && bounds.right > movingBounds.left;
|
|
731
|
+
if (!crossOverlaps) continue;
|
|
732
|
+
|
|
733
|
+
const crossStart =
|
|
734
|
+
axis === "x"
|
|
735
|
+
? Math.max(bounds.top, movingBounds.top)
|
|
736
|
+
: Math.max(bounds.left, movingBounds.left);
|
|
737
|
+
const crossEnd =
|
|
738
|
+
axis === "x"
|
|
739
|
+
? Math.min(bounds.bottom, movingBounds.bottom)
|
|
740
|
+
: Math.min(bounds.right, movingBounds.right);
|
|
741
|
+
|
|
742
|
+
if (axis === "x") {
|
|
743
|
+
if (bounds.right <= movingBounds.left) {
|
|
744
|
+
candidates.push({
|
|
745
|
+
side: "before",
|
|
746
|
+
gap: movingBounds.left - bounds.right,
|
|
747
|
+
gapStart: bounds.right,
|
|
748
|
+
gapEnd: movingBounds.left,
|
|
749
|
+
crossStart,
|
|
750
|
+
crossEnd,
|
|
751
|
+
});
|
|
752
|
+
} else if (bounds.left >= movingBounds.right) {
|
|
753
|
+
candidates.push({
|
|
754
|
+
side: "after",
|
|
755
|
+
gap: bounds.left - movingBounds.right,
|
|
756
|
+
gapStart: movingBounds.right,
|
|
757
|
+
gapEnd: bounds.left,
|
|
758
|
+
crossStart,
|
|
759
|
+
crossEnd,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
if (bounds.bottom <= movingBounds.top) {
|
|
764
|
+
candidates.push({
|
|
765
|
+
side: "before",
|
|
766
|
+
gap: movingBounds.top - bounds.bottom,
|
|
767
|
+
gapStart: bounds.bottom,
|
|
768
|
+
gapEnd: movingBounds.top,
|
|
769
|
+
crossStart,
|
|
770
|
+
crossEnd,
|
|
771
|
+
});
|
|
772
|
+
} else if (bounds.top >= movingBounds.bottom) {
|
|
773
|
+
candidates.push({
|
|
774
|
+
side: "after",
|
|
775
|
+
gap: bounds.top - movingBounds.bottom,
|
|
776
|
+
gapStart: movingBounds.bottom,
|
|
777
|
+
gapEnd: bounds.top,
|
|
778
|
+
crossStart,
|
|
779
|
+
crossEnd,
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return candidates;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function pairUpEqualGaps(
|
|
788
|
+
orientation: "vertical" | "horizontal",
|
|
789
|
+
candidates: GapCandidate[],
|
|
790
|
+
toleranceCanvasPx: number,
|
|
791
|
+
): EqualGapGuide[] {
|
|
792
|
+
const before = candidates.filter((c) => c.side === "before");
|
|
793
|
+
const after = candidates.filter((c) => c.side === "after");
|
|
794
|
+
const guides: EqualGapGuide[] = [];
|
|
795
|
+
|
|
796
|
+
// Closest gap on each side is the one a user is most likely dragging
|
|
797
|
+
// toward, so only pair the single closest "before" candidate against the
|
|
798
|
+
// single closest "after" candidate — otherwise a busy canvas would surface
|
|
799
|
+
// every combinatorial pair of same-ish gaps at once.
|
|
800
|
+
const closestBefore = before.reduce<GapCandidate | null>(
|
|
801
|
+
(best, c) => (!best || c.gap < best.gap ? c : best),
|
|
802
|
+
null,
|
|
803
|
+
);
|
|
804
|
+
const closestAfter = after.reduce<GapCandidate | null>(
|
|
805
|
+
(best, c) => (!best || c.gap < best.gap ? c : best),
|
|
806
|
+
null,
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
if (
|
|
810
|
+
closestBefore &&
|
|
811
|
+
closestAfter &&
|
|
812
|
+
Math.abs(closestBefore.gap - closestAfter.gap) <= toleranceCanvasPx
|
|
813
|
+
) {
|
|
814
|
+
guides.push({
|
|
815
|
+
orientation,
|
|
816
|
+
gap: (closestBefore.gap + closestAfter.gap) / 2,
|
|
817
|
+
bands: [
|
|
818
|
+
{
|
|
819
|
+
gapStart: closestBefore.gapStart,
|
|
820
|
+
gapEnd: closestBefore.gapEnd,
|
|
821
|
+
crossStart: closestBefore.crossStart,
|
|
822
|
+
crossEnd: closestBefore.crossEnd,
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
gapStart: closestAfter.gapStart,
|
|
826
|
+
gapEnd: closestAfter.gapEnd,
|
|
827
|
+
crossStart: closestAfter.crossStart,
|
|
828
|
+
crossEnd: closestAfter.crossEnd,
|
|
829
|
+
},
|
|
830
|
+
],
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return guides;
|
|
835
|
+
}
|
|
836
|
+
|
|
532
837
|
export function resizeFrameFromDelta(
|
|
533
838
|
origin: FrameGeometry,
|
|
534
839
|
handle: ResizeHandle,
|
|
@@ -652,19 +957,368 @@ export function resizeFrameGroupToBounds(
|
|
|
652
957
|
}));
|
|
653
958
|
}
|
|
654
959
|
|
|
960
|
+
/**
|
|
961
|
+
* Rotates `point` around `center` by `degrees` in the *forward* direction —
|
|
962
|
+
* i.e. the same direction as a CSS `transform: rotate(degrees deg)` applied
|
|
963
|
+
* to an element whose `transform-origin` is `center`. Use this to map a
|
|
964
|
+
* frame-local (unrotated) point into world space.
|
|
965
|
+
*
|
|
966
|
+
* Pass `-degrees` to do the inverse mapping (world space into a frame's local
|
|
967
|
+
* unrotated space).
|
|
968
|
+
*/
|
|
969
|
+
export function rotatePoint(
|
|
970
|
+
point: CanvasPoint,
|
|
971
|
+
center: CanvasPoint,
|
|
972
|
+
degrees: number,
|
|
973
|
+
): CanvasPoint {
|
|
974
|
+
if (!degrees) return point;
|
|
975
|
+
const rad = (degrees * Math.PI) / 180;
|
|
976
|
+
const dx = point.x - center.x;
|
|
977
|
+
const dy = point.y - center.y;
|
|
978
|
+
const cos = Math.cos(rad);
|
|
979
|
+
const sin = Math.sin(rad);
|
|
980
|
+
return {
|
|
981
|
+
x: center.x + dx * cos - dy * sin,
|
|
982
|
+
y: center.y + dx * sin + dy * cos,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/** Rotates a free vector (no translation component) by `degrees`. Use this to
|
|
987
|
+
* map a world-space pointer delta into a rotated frame's local axes (pass
|
|
988
|
+
* `-degrees`), or a local delta back into world space (pass `+degrees`). */
|
|
989
|
+
export function rotateVector(
|
|
990
|
+
vector: CanvasPoint,
|
|
991
|
+
degrees: number,
|
|
992
|
+
): CanvasPoint {
|
|
993
|
+
if (!degrees) return vector;
|
|
994
|
+
const rad = (degrees * Math.PI) / 180;
|
|
995
|
+
const cos = Math.cos(rad);
|
|
996
|
+
const sin = Math.sin(rad);
|
|
997
|
+
return {
|
|
998
|
+
x: vector.x * cos - vector.y * sin,
|
|
999
|
+
y: vector.x * sin + vector.y * cos,
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/** Returns the four corners of `geometry`'s rotated bounding box, in world
|
|
1004
|
+
* space, in top-left/top-right/bottom-right/bottom-left order. */
|
|
1005
|
+
export function getRotatedFrameCorners(
|
|
1006
|
+
geometry: FrameGeometry,
|
|
1007
|
+
): [CanvasPoint, CanvasPoint, CanvasPoint, CanvasPoint] {
|
|
1008
|
+
const bounds = getFrameBounds(geometry);
|
|
1009
|
+
const center = { x: bounds.centerX, y: bounds.centerY };
|
|
1010
|
+
const degrees = geometry.rotation ?? 0;
|
|
1011
|
+
const corners: CanvasPoint[] = [
|
|
1012
|
+
{ x: bounds.left, y: bounds.top },
|
|
1013
|
+
{ x: bounds.right, y: bounds.top },
|
|
1014
|
+
{ x: bounds.right, y: bounds.bottom },
|
|
1015
|
+
{ x: bounds.left, y: bounds.bottom },
|
|
1016
|
+
];
|
|
1017
|
+
return corners.map((corner) => rotatePoint(corner, center, degrees)) as [
|
|
1018
|
+
CanvasPoint,
|
|
1019
|
+
CanvasPoint,
|
|
1020
|
+
CanvasPoint,
|
|
1021
|
+
CanvasPoint,
|
|
1022
|
+
];
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/** Returns the axis-aligned bounding box that encloses `geometry` after its
|
|
1026
|
+
* rotation is applied — i.e. the world-space AABB of the rotated rect,
|
|
1027
|
+
* rather than the unrotated local rect. Frames with no rotation return their
|
|
1028
|
+
* own bounds unchanged. Use this for snap-candidate generation and marquee
|
|
1029
|
+
* hit-testing against rotated frames instead of the unrotated `FrameBounds`. */
|
|
1030
|
+
export function getRotatedFrameAABB(geometry: FrameGeometry): FrameBounds {
|
|
1031
|
+
const degrees = geometry.rotation ?? 0;
|
|
1032
|
+
if (!degrees) return getFrameBounds(geometry);
|
|
1033
|
+
const corners = getRotatedFrameCorners(geometry);
|
|
1034
|
+
const xs = corners.map((corner) => corner.x);
|
|
1035
|
+
const ys = corners.map((corner) => corner.y);
|
|
1036
|
+
const left = Math.min(...xs);
|
|
1037
|
+
const top = Math.min(...ys);
|
|
1038
|
+
const right = Math.max(...xs);
|
|
1039
|
+
const bottom = Math.max(...ys);
|
|
1040
|
+
return getFrameBounds({
|
|
1041
|
+
x: left,
|
|
1042
|
+
y: top,
|
|
1043
|
+
width: right - left,
|
|
1044
|
+
height: bottom - top,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/** An axis-aligned rectangle in `{x, y, width, height}` form, as used by a
|
|
1049
|
+
* marquee-selection drag rect. */
|
|
1050
|
+
export interface AxisRect {
|
|
1051
|
+
x: number;
|
|
1052
|
+
y: number;
|
|
1053
|
+
width: number;
|
|
1054
|
+
height: number;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/** An axis-aligned bounds rect in `{left, top, right, bottom}` form. */
|
|
1058
|
+
export interface AxisBounds {
|
|
1059
|
+
left: number;
|
|
1060
|
+
top: number;
|
|
1061
|
+
right: number;
|
|
1062
|
+
bottom: number;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Tests whether an axis-aligned rect (e.g. a marquee-selection drag rect)
|
|
1067
|
+
* intersects `bounds` (an unrotated rect) after `bounds` is rotated by
|
|
1068
|
+
* `degrees` around `center`.
|
|
1069
|
+
*
|
|
1070
|
+
* `center` defaults to the center of `bounds` itself — the common case of a
|
|
1071
|
+
* single rotated frame. Pass an explicit `center` when `bounds` describes a
|
|
1072
|
+
* child element that rotates rigidly with an ancestor frame around the
|
|
1073
|
+
* frame's own center rather than its own (e.g. layer-marquee hit-testing
|
|
1074
|
+
* against an element inside a rotated screen frame).
|
|
1075
|
+
*
|
|
1076
|
+
* A corner-containment check alone (only asking "is a corner of A inside B,
|
|
1077
|
+
* or a corner of B inside A") misses cases where the two rects cross like a
|
|
1078
|
+
* plus/hash sign — each one's edges pierce through the other without either
|
|
1079
|
+
* shape's corners landing inside the other, e.g. a thin marquee crossing the
|
|
1080
|
+
* middle of a thin rotated frame. This uses the Separating Axis Theorem
|
|
1081
|
+
* (SAT): two convex polygons do NOT intersect if and only if there exists an
|
|
1082
|
+
* axis (from either polygon's edge normals) onto which their projections
|
|
1083
|
+
* don't overlap. For an axis-aligned rect vs. a rotated rect there are
|
|
1084
|
+
* exactly 4 candidate axes to test — the rect's own x/y axes, and the
|
|
1085
|
+
* rotated rect's two (perpendicular) edge directions.
|
|
1086
|
+
*/
|
|
1087
|
+
export function rotatedRectIntersects(
|
|
1088
|
+
rect: AxisRect,
|
|
1089
|
+
bounds: AxisBounds,
|
|
1090
|
+
center: CanvasPoint = {
|
|
1091
|
+
x: (bounds.left + bounds.right) / 2,
|
|
1092
|
+
y: (bounds.top + bounds.bottom) / 2,
|
|
1093
|
+
},
|
|
1094
|
+
degrees = 0,
|
|
1095
|
+
): boolean {
|
|
1096
|
+
const rectCorners: CanvasPoint[] = [
|
|
1097
|
+
{ x: rect.x, y: rect.y },
|
|
1098
|
+
{ x: rect.x + rect.width, y: rect.y },
|
|
1099
|
+
{ x: rect.x + rect.width, y: rect.y + rect.height },
|
|
1100
|
+
{ x: rect.x, y: rect.y + rect.height },
|
|
1101
|
+
];
|
|
1102
|
+
|
|
1103
|
+
if (!degrees) {
|
|
1104
|
+
return (
|
|
1105
|
+
rect.x <= bounds.right &&
|
|
1106
|
+
rect.x + rect.width >= bounds.left &&
|
|
1107
|
+
rect.y <= bounds.bottom &&
|
|
1108
|
+
rect.y + rect.height >= bounds.top
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const boundsCorners: CanvasPoint[] = [
|
|
1113
|
+
{ x: bounds.left, y: bounds.top },
|
|
1114
|
+
{ x: bounds.right, y: bounds.top },
|
|
1115
|
+
{ x: bounds.right, y: bounds.bottom },
|
|
1116
|
+
{ x: bounds.left, y: bounds.bottom },
|
|
1117
|
+
].map((corner) => rotatePoint(corner, center, degrees));
|
|
1118
|
+
const rad = (degrees * Math.PI) / 180;
|
|
1119
|
+
// The rotated rect's two perpendicular edge directions, plus the axis
|
|
1120
|
+
// rect's own x/y axes, are the full set of SAT candidate axes for two
|
|
1121
|
+
// rectangles (each rectangle only contributes 2 unique edge normals).
|
|
1122
|
+
const axes: CanvasPoint[] = [
|
|
1123
|
+
{ x: 1, y: 0 },
|
|
1124
|
+
{ x: 0, y: 1 },
|
|
1125
|
+
{ x: Math.cos(rad), y: Math.sin(rad) },
|
|
1126
|
+
{ x: -Math.sin(rad), y: Math.cos(rad) },
|
|
1127
|
+
];
|
|
1128
|
+
|
|
1129
|
+
return axes.every((axis) =>
|
|
1130
|
+
projectionsOverlap(rectCorners, boundsCorners, axis),
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
function projectionsOverlap(
|
|
1135
|
+
a: readonly CanvasPoint[],
|
|
1136
|
+
b: readonly CanvasPoint[],
|
|
1137
|
+
axis: CanvasPoint,
|
|
1138
|
+
): boolean {
|
|
1139
|
+
const projectionA = a.map((point) => point.x * axis.x + point.y * axis.y);
|
|
1140
|
+
const projectionB = b.map((point) => point.x * axis.x + point.y * axis.y);
|
|
1141
|
+
const minA = Math.min(...projectionA);
|
|
1142
|
+
const maxA = Math.max(...projectionA);
|
|
1143
|
+
const minB = Math.min(...projectionB);
|
|
1144
|
+
const maxB = Math.max(...projectionB);
|
|
1145
|
+
return minA <= maxB && minB <= maxA;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Resize-aware transform for a single rotated frame, so dragging a resize
|
|
1150
|
+
* handle behaves the way it looks: the handle direction follows the frame's
|
|
1151
|
+
* own rotated axes, and the opposite anchor edge/corner stays visually fixed
|
|
1152
|
+
* in world space (not just in unrotated local space).
|
|
1153
|
+
*
|
|
1154
|
+
* `worldDx`/`worldDy` are the raw pointer delta in world (canvas) space, the
|
|
1155
|
+
* same values `resizeFrameFromDelta` normally takes directly. This wrapper:
|
|
1156
|
+
* 1. Rotates the world delta into the frame's local (unrotated) axes.
|
|
1157
|
+
* 2. Runs the existing unrotated `resizeFrameFromDelta` in that local space.
|
|
1158
|
+
* 3. Re-anchors the result so the corner/edge the handle keeps fixed in
|
|
1159
|
+
* local space also stays fixed in world space, by translating the new
|
|
1160
|
+
* geometry so its own rotation (around its own new center) reproduces the
|
|
1161
|
+
* original world-space anchor point.
|
|
1162
|
+
*
|
|
1163
|
+
* For `origin.rotation` falsy this is identical to calling
|
|
1164
|
+
* `resizeFrameFromDelta` directly.
|
|
1165
|
+
*/
|
|
1166
|
+
export function resizeRotatedFrameFromDelta(
|
|
1167
|
+
origin: FrameGeometry,
|
|
1168
|
+
handle: ResizeHandle,
|
|
1169
|
+
worldDx: number,
|
|
1170
|
+
worldDy: number,
|
|
1171
|
+
options: ResizeFrameOptions = {},
|
|
1172
|
+
): FrameGeometry {
|
|
1173
|
+
const degrees = origin.rotation ?? 0;
|
|
1174
|
+
if (!degrees) {
|
|
1175
|
+
return resizeFrameFromDelta(origin, handle, worldDx, worldDy, options);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const originCenter = {
|
|
1179
|
+
x: origin.x + origin.width / 2,
|
|
1180
|
+
y: origin.y + origin.height / 2,
|
|
1181
|
+
};
|
|
1182
|
+
// Alt/option resize (`resizeFromCenter`) already grows the frame
|
|
1183
|
+
// symmetrically about its own center in LOCAL space (resizeFrameFromDelta
|
|
1184
|
+
// below keeps the center fixed on both axes for that mode). To keep that
|
|
1185
|
+
// center fixed in WORLD space too — matching Figma, where alt-resizing a
|
|
1186
|
+
// rotated frame grows around its visual center rather than pivoting off an
|
|
1187
|
+
// opposite corner — the re-anchor step below must use the center as its
|
|
1188
|
+
// fixed point instead of the handle's opposite corner/edge. Using the
|
|
1189
|
+
// center as the anchor is a no-op for the rotation (a point rotates around
|
|
1190
|
+
// itself unchanged), so it stays put in world space by construction.
|
|
1191
|
+
// Non-center (default) resizes keep anchoring on the opposite corner/edge
|
|
1192
|
+
// so that world-fixed-anchor behavior is unchanged.
|
|
1193
|
+
const anchorLocalBefore = options.resizeFromCenter
|
|
1194
|
+
? originCenter
|
|
1195
|
+
: getResizeAnchorPoint(origin, handle);
|
|
1196
|
+
const anchorWorld = rotatePoint(anchorLocalBefore, originCenter, degrees);
|
|
1197
|
+
|
|
1198
|
+
// Map the world-space pointer delta into the frame's own unrotated axes so
|
|
1199
|
+
// dragging "outward along the handle" behaves the same regardless of how
|
|
1200
|
+
// the frame is rotated.
|
|
1201
|
+
const localDelta = rotateVector({ x: worldDx, y: worldDy }, -degrees);
|
|
1202
|
+
|
|
1203
|
+
const resizedLocal = resizeFrameFromDelta(
|
|
1204
|
+
{ ...origin, rotation: undefined },
|
|
1205
|
+
handle,
|
|
1206
|
+
localDelta.x,
|
|
1207
|
+
localDelta.y,
|
|
1208
|
+
options,
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1211
|
+
const centerAfterLocal = {
|
|
1212
|
+
x: resizedLocal.x + resizedLocal.width / 2,
|
|
1213
|
+
y: resizedLocal.y + resizedLocal.height / 2,
|
|
1214
|
+
};
|
|
1215
|
+
const anchorLocalAfter = options.resizeFromCenter
|
|
1216
|
+
? centerAfterLocal
|
|
1217
|
+
: getResizeAnchorPoint(resizedLocal, handle);
|
|
1218
|
+
const anchorWorldIfUntranslated = rotatePoint(
|
|
1219
|
+
anchorLocalAfter,
|
|
1220
|
+
centerAfterLocal,
|
|
1221
|
+
degrees,
|
|
1222
|
+
);
|
|
1223
|
+
const translation = {
|
|
1224
|
+
x: anchorWorld.x - anchorWorldIfUntranslated.x,
|
|
1225
|
+
y: anchorWorld.y - anchorWorldIfUntranslated.y,
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
return {
|
|
1229
|
+
...resizedLocal,
|
|
1230
|
+
x: resizedLocal.x + translation.x,
|
|
1231
|
+
y: resizedLocal.y + translation.y,
|
|
1232
|
+
rotation: degrees,
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/** The local (unrotated) point that a given resize handle keeps fixed: the
|
|
1237
|
+
* edge/corner opposite the handle, or the center of an axis the handle
|
|
1238
|
+
* doesn't affect at all (e.g. "n" leaves the horizontal axis untouched). */
|
|
1239
|
+
function getResizeAnchorPoint(
|
|
1240
|
+
geometry: FrameGeometry,
|
|
1241
|
+
handle: ResizeHandle,
|
|
1242
|
+
): CanvasPoint {
|
|
1243
|
+
const bounds = getFrameBounds(geometry);
|
|
1244
|
+
const x = handleAffectsWest(handle)
|
|
1245
|
+
? bounds.right
|
|
1246
|
+
: handleAffectsEast(handle)
|
|
1247
|
+
? bounds.left
|
|
1248
|
+
: bounds.centerX;
|
|
1249
|
+
const y = handleAffectsNorth(handle)
|
|
1250
|
+
? bounds.bottom
|
|
1251
|
+
: handleAffectsSouth(handle)
|
|
1252
|
+
? bounds.top
|
|
1253
|
+
: bounds.centerY;
|
|
1254
|
+
return { x, y };
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
/** Unrotated visual angle of each resize handle, in degrees, matching CSS
|
|
1258
|
+
* cursor convention (0 = east/right, increasing clockwise since canvas y
|
|
1259
|
+
* grows downward) — "e" points right, "se" points down-right, etc. */
|
|
1260
|
+
const RESIZE_HANDLE_ANGLES: Record<ResizeHandle, number> = {
|
|
1261
|
+
e: 0,
|
|
1262
|
+
se: 45,
|
|
1263
|
+
s: 90,
|
|
1264
|
+
sw: 135,
|
|
1265
|
+
w: 180,
|
|
1266
|
+
nw: 225,
|
|
1267
|
+
n: 270,
|
|
1268
|
+
ne: 315,
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
const RESIZE_CURSOR_BY_QUADRANT = [
|
|
1272
|
+
"ew-resize",
|
|
1273
|
+
"nwse-resize",
|
|
1274
|
+
"ns-resize",
|
|
1275
|
+
"nesw-resize",
|
|
1276
|
+
] as const;
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* Returns the resize cursor for `handle` on a frame rotated by `rotationDeg`
|
|
1280
|
+
* degrees, so the cursor always matches how the handle actually looks and
|
|
1281
|
+
* moves on screen instead of a static per-handle cursor that's only correct
|
|
1282
|
+
* when the frame isn't rotated.
|
|
1283
|
+
*
|
|
1284
|
+
* Cursor CSS only offers 4 distinct resize cursors, each valid across a pair
|
|
1285
|
+
* of opposite directions (`ew-resize` covers both due east and due west).
|
|
1286
|
+
* This adds the handle's own unrotated angle to the frame's rotation and
|
|
1287
|
+
* quantizes to the nearest 45 degrees to pick which of the 4 to use.
|
|
1288
|
+
*/
|
|
1289
|
+
export function getResizeCursorForHandle(
|
|
1290
|
+
handle: ResizeHandle,
|
|
1291
|
+
rotationDeg = 0,
|
|
1292
|
+
): string {
|
|
1293
|
+
const angle = RESIZE_HANDLE_ANGLES[handle] + rotationDeg;
|
|
1294
|
+
const normalized = ((angle % 360) + 360) % 360;
|
|
1295
|
+
const quantized = Math.round(normalized / 45) % 8;
|
|
1296
|
+
return RESIZE_CURSOR_BY_QUADRANT[quantized % 4];
|
|
1297
|
+
}
|
|
1298
|
+
|
|
655
1299
|
export function computeResizeSnap(
|
|
656
1300
|
frame: FrameGeometry,
|
|
657
1301
|
stationary: FrameEntry[],
|
|
658
1302
|
handle: ResizeHandle,
|
|
659
|
-
options:
|
|
1303
|
+
options: ResizeSnapOptions,
|
|
660
1304
|
) {
|
|
661
1305
|
if (options.bypass) {
|
|
662
1306
|
return { frame, guides: [] as AlignmentGuide[] };
|
|
663
1307
|
}
|
|
664
1308
|
|
|
1309
|
+
const threshold = getCanvasSnapThreshold(options);
|
|
1310
|
+
|
|
1311
|
+
if (options.preserveAspectRatio) {
|
|
1312
|
+
return computeAspectPreservingResizeSnap(
|
|
1313
|
+
frame,
|
|
1314
|
+
stationary,
|
|
1315
|
+
handle,
|
|
1316
|
+
threshold,
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
665
1320
|
let nextFrame = frame;
|
|
666
1321
|
const guides: AlignmentGuide[] = [];
|
|
667
|
-
const threshold = getCanvasSnapThreshold(options);
|
|
668
1322
|
|
|
669
1323
|
if (handleAffectsWest(handle) || handleAffectsEast(handle)) {
|
|
670
1324
|
const candidate = getResizeSnapCandidate(
|
|
@@ -707,6 +1361,95 @@ export function computeResizeSnap(
|
|
|
707
1361
|
return { frame: nextFrame, guides };
|
|
708
1362
|
}
|
|
709
1363
|
|
|
1364
|
+
/**
|
|
1365
|
+
* Aspect-ratio-safe variant of the independent-axis snap above. Snapping x
|
|
1366
|
+
* and y independently can each pull toward a different sibling edge, which
|
|
1367
|
+
* distorts a shift-held (aspect-locked) resize away from its ratio. Instead:
|
|
1368
|
+
* evaluate both axes' snap candidates, apply only the single closest one,
|
|
1369
|
+
* then rescale the other axis from `frame`'s own aspect ratio so the shape
|
|
1370
|
+
* stays locked to it.
|
|
1371
|
+
*/
|
|
1372
|
+
function computeAspectPreservingResizeSnap(
|
|
1373
|
+
frame: FrameGeometry,
|
|
1374
|
+
stationary: FrameEntry[],
|
|
1375
|
+
handle: ResizeHandle,
|
|
1376
|
+
threshold: number,
|
|
1377
|
+
) {
|
|
1378
|
+
const ratio = frame.width / Math.max(1, frame.height);
|
|
1379
|
+
const xCandidate =
|
|
1380
|
+
handleAffectsWest(handle) || handleAffectsEast(handle)
|
|
1381
|
+
? getResizeSnapCandidate("x", frame, stationary, handle, threshold)
|
|
1382
|
+
: null;
|
|
1383
|
+
const yCandidate =
|
|
1384
|
+
handleAffectsNorth(handle) || handleAffectsSouth(handle)
|
|
1385
|
+
? getResizeSnapCandidate("y", frame, stationary, handle, threshold)
|
|
1386
|
+
: null;
|
|
1387
|
+
|
|
1388
|
+
if (!xCandidate && !yCandidate) {
|
|
1389
|
+
return { frame, guides: [] as AlignmentGuide[] };
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
const useX =
|
|
1393
|
+
!yCandidate || (xCandidate && xCandidate.distance <= yCandidate.distance);
|
|
1394
|
+
|
|
1395
|
+
const affectsVertical =
|
|
1396
|
+
handleAffectsNorth(handle) || handleAffectsSouth(handle);
|
|
1397
|
+
const affectsHorizontal =
|
|
1398
|
+
handleAffectsWest(handle) || handleAffectsEast(handle);
|
|
1399
|
+
|
|
1400
|
+
if (useX && xCandidate) {
|
|
1401
|
+
const snappedX = applyResizeSnapOffset(
|
|
1402
|
+
frame,
|
|
1403
|
+
handle,
|
|
1404
|
+
"x",
|
|
1405
|
+
xCandidate.offset,
|
|
1406
|
+
);
|
|
1407
|
+
const nextHeight = snappedX.width / ratio;
|
|
1408
|
+
// Matches resizeFrameFromDelta's own convention: when a handle that
|
|
1409
|
+
// doesn't touch the vertical axis (e.g. "e") grows height only because
|
|
1410
|
+
// aspect-ratio derives it, that growth is centered vertically rather
|
|
1411
|
+
// than anchored to the original y.
|
|
1412
|
+
const rescaled = {
|
|
1413
|
+
...snappedX,
|
|
1414
|
+
height: nextHeight,
|
|
1415
|
+
y: getResizedAxisStart(
|
|
1416
|
+
frame.y,
|
|
1417
|
+
frame.height,
|
|
1418
|
+
nextHeight,
|
|
1419
|
+
handleAffectsNorth(handle),
|
|
1420
|
+
handleAffectsSouth(handle),
|
|
1421
|
+
!affectsVertical && nextHeight !== frame.height,
|
|
1422
|
+
),
|
|
1423
|
+
};
|
|
1424
|
+
return { frame: rescaled, guides: [xCandidate.guide] };
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
if (yCandidate) {
|
|
1428
|
+
const snappedY = applyResizeSnapOffset(
|
|
1429
|
+
frame,
|
|
1430
|
+
handle,
|
|
1431
|
+
"y",
|
|
1432
|
+
yCandidate.offset,
|
|
1433
|
+
);
|
|
1434
|
+
const nextWidth = snappedY.height * ratio;
|
|
1435
|
+
const rescaled = {
|
|
1436
|
+
...snappedY,
|
|
1437
|
+
width: nextWidth,
|
|
1438
|
+
x: getResizedAxisStart(
|
|
1439
|
+
frame.x,
|
|
1440
|
+
frame.width,
|
|
1441
|
+
nextWidth,
|
|
1442
|
+
handleAffectsWest(handle),
|
|
1443
|
+
handleAffectsEast(handle),
|
|
1444
|
+
!affectsHorizontal && nextWidth !== frame.width,
|
|
1445
|
+
),
|
|
1446
|
+
};
|
|
1447
|
+
return { frame: rescaled, guides: [yCandidate.guide] };
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
return { frame, guides: [] as AlignmentGuide[] };
|
|
1451
|
+
}
|
|
1452
|
+
|
|
710
1453
|
function getResizedAxisStart(
|
|
711
1454
|
originStart: number,
|
|
712
1455
|
originSize: number,
|
|
@@ -841,7 +1584,9 @@ function getResizeSnapCandidate(
|
|
|
841
1584
|
: frameBounds.bottom;
|
|
842
1585
|
|
|
843
1586
|
return stationary.reduce<SnapCandidate | null>((best, entry) => {
|
|
844
|
-
|
|
1587
|
+
// Rotated (world-space) AABB, not the unrotated local bounds, so
|
|
1588
|
+
// resizing snaps against a rotated sibling's visual silhouette.
|
|
1589
|
+
const stationaryBounds = getRotatedFrameAABB(entry.geometry);
|
|
845
1590
|
const targetValues =
|
|
846
1591
|
axis === "x"
|
|
847
1592
|
? [
|