@adminide-stack/yantra-mobile 12.0.69-alpha.9 → 12.0.69
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/lib/components/GatewayConnector/GatewayConnector.js +2 -2
- package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -1
- package/lib/components/KeyboardComposerDock.js +8 -1
- package/lib/components/KeyboardComposerDock.js.map +1 -1
- package/lib/components/NavigationHeader/NavigationHeader.js +2 -2
- package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -1
- package/lib/config/env-config.js +4 -0
- package/lib/config/env-config.js.map +1 -1
- package/lib/contexts/ChatLiveStreamContext.js +4 -1
- package/lib/contexts/ChatLiveStreamContext.js.map +1 -1
- package/lib/features/agent-chat/NativeAgentChat.js +2 -0
- package/lib/features/agent-chat/NativeAgentChat.js.map +1 -1
- package/lib/features/apps/AppsCatalog.js +2 -2
- package/lib/features/apps/AppsCatalog.js.map +1 -1
- package/lib/features/audio-input/MicErrorBoundary.js +2 -2
- package/lib/features/audio-input/MicErrorBoundary.js.map +1 -1
- package/lib/features/canvas/AudioEditorExperience.js +308 -0
- package/lib/features/canvas/AudioEditorExperience.js.map +1 -0
- package/lib/features/canvas/CanvasAgentChatPane.js +310 -0
- package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -0
- package/lib/features/canvas/CanvasBoardsGrid.js +414 -0
- package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -0
- package/lib/features/canvas/CanvasChatResultCard.js +113 -0
- package/lib/features/canvas/CanvasChatResultCard.js.map +1 -0
- package/lib/features/canvas/CanvasEditToolsPanel.js +179 -0
- package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -0
- package/lib/features/canvas/CanvasExperience.js +859 -0
- package/lib/features/canvas/CanvasExperience.js.map +1 -0
- package/lib/features/canvas/CanvasGeneratePanel.js +514 -0
- package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -0
- package/lib/features/canvas/CanvasLibrarySheet.js +355 -0
- package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -0
- package/lib/features/canvas/CanvasLooksPanel.js +184 -0
- package/lib/features/canvas/CanvasLooksPanel.js.map +1 -0
- package/lib/features/canvas/CanvasTasksPanel.js +138 -0
- package/lib/features/canvas/CanvasTasksPanel.js.map +1 -0
- package/lib/features/canvas/CanvasTemplatesPanel.js +226 -0
- package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -0
- package/lib/features/canvas/CanvasToolDock.js +423 -0
- package/lib/features/canvas/CanvasToolDock.js.map +1 -0
- package/lib/features/canvas/FrameExtractorExperience.js +242 -0
- package/lib/features/canvas/FrameExtractorExperience.js.map +1 -0
- package/lib/features/canvas/ImageEditorExperience.js +491 -0
- package/lib/features/canvas/ImageEditorExperience.js.map +1 -0
- package/lib/features/canvas/InfluencerStudioExperience.js +288 -0
- package/lib/features/canvas/InfluencerStudioExperience.js.map +1 -0
- package/lib/features/canvas/MoodboardExperience.js +205 -0
- package/lib/features/canvas/MoodboardExperience.js.map +1 -0
- package/lib/features/canvas/NativeCanvasViewer.js +929 -0
- package/lib/features/canvas/NativeCanvasViewer.js.map +1 -0
- package/lib/features/canvas/PromoContextFields.js +150 -0
- package/lib/features/canvas/PromoContextFields.js.map +1 -0
- package/lib/features/canvas/SetStudioExperience.js +323 -0
- package/lib/features/canvas/SetStudioExperience.js.map +1 -0
- package/lib/features/canvas/VideoClipsExperience.js +175 -0
- package/lib/features/canvas/VideoClipsExperience.js.map +1 -0
- package/lib/features/canvas/VideoEditExperience.js +824 -0
- package/lib/features/canvas/VideoEditExperience.js.map +1 -0
- package/lib/features/canvas/VideoEditorExperience.js +3050 -0
- package/lib/features/canvas/VideoEditorExperience.js.map +1 -0
- package/lib/features/canvas/VideoGeneratorExperience.js +415 -0
- package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -0
- package/lib/features/canvas/aiEdit.js +53 -0
- package/lib/features/canvas/aiEdit.js.map +1 -0
- package/lib/features/canvas/canvasAgentChat.js +76 -0
- package/lib/features/canvas/canvasAgentChat.js.map +1 -0
- package/lib/features/canvas/canvasBoardsCatalog.js +59 -0
- package/lib/features/canvas/canvasBoardsCatalog.js.map +1 -0
- package/lib/features/canvas/canvasBoardsSnapshot.js +14 -1
- package/lib/features/canvas/canvasBoardsSnapshot.js.map +1 -1
- package/lib/features/canvas/canvasChatDisplay.js +38 -0
- package/lib/features/canvas/canvasChatDisplay.js.map +1 -0
- package/lib/features/canvas/canvasChatTemplates.js +219 -0
- package/lib/features/canvas/canvasChatTemplates.js.map +1 -0
- package/lib/features/canvas/canvasCore.js +138 -1
- package/lib/features/canvas/canvasCore.js.map +1 -1
- package/lib/features/canvas/canvasEditOps.js +224 -0
- package/lib/features/canvas/canvasEditOps.js.map +1 -0
- package/lib/features/canvas/canvasTasks.js +187 -0
- package/lib/features/canvas/canvasTasks.js.map +1 -0
- package/lib/features/canvas/designPromptTemplates.js +3084 -0
- package/lib/features/canvas/designPromptTemplates.js.map +1 -0
- package/lib/features/canvas/editTools.js +54 -0
- package/lib/features/canvas/editTools.js.map +1 -0
- package/lib/features/canvas/extendVideo.js +5 -0
- package/lib/features/canvas/extendVideo.js.map +1 -0
- package/lib/features/canvas/frameExtract.js +33 -0
- package/lib/features/canvas/frameExtract.js.map +1 -0
- package/lib/features/canvas/generationModels.js +201 -0
- package/lib/features/canvas/generationModels.js.map +1 -0
- package/lib/features/canvas/influencer/influencerPipeline.js +170 -0
- package/lib/features/canvas/influencer/influencerPipeline.js.map +1 -0
- package/lib/features/canvas/influencer/productReel.js +72 -0
- package/lib/features/canvas/influencer/productReel.js.map +1 -0
- package/lib/features/canvas/influencer/reelPlan.js +159 -0
- package/lib/features/canvas/influencer/reelPlan.js.map +1 -0
- package/lib/features/canvas/moodboardCore.js +13 -0
- package/lib/features/canvas/moodboardCore.js.map +1 -0
- package/lib/features/canvas/promoProjectImport.js +99 -0
- package/lib/features/canvas/promoProjectImport.js.map +1 -0
- package/lib/features/canvas/promoVideo.js +312 -0
- package/lib/features/canvas/promoVideo.js.map +1 -0
- package/lib/features/canvas/recorder/CameraRecorderExperience.js +109 -0
- package/lib/features/canvas/recorder/CameraRecorderExperience.js.map +1 -0
- package/lib/features/canvas/sessionIdentity.js +28 -1
- package/lib/features/canvas/sessionIdentity.js.map +1 -1
- package/lib/features/canvas/set/SetViewportWebView.js +133 -0
- package/lib/features/canvas/set/SetViewportWebView.js.map +1 -0
- package/lib/features/canvas/set/cameraPath.js +194 -0
- package/lib/features/canvas/set/cameraPath.js.map +1 -0
- package/lib/features/canvas/set/setProject.js +24 -0
- package/lib/features/canvas/set/setProject.js.map +1 -0
- package/lib/features/canvas/storageLibrary.js +184 -0
- package/lib/features/canvas/storageLibrary.js.map +1 -0
- package/lib/features/canvas/studioCatalog.js +129 -0
- package/lib/features/canvas/studioCatalog.js.map +1 -0
- package/lib/features/canvas/studioLooks.js +189 -0
- package/lib/features/canvas/studioLooks.js.map +1 -0
- package/lib/features/canvas/surfaceIndex.js +63 -1
- package/lib/features/canvas/surfaceIndex.js.map +1 -1
- package/lib/features/canvas/templateImport/invideoNative.js +221 -0
- package/lib/features/canvas/templateImport/invideoNative.js.map +1 -0
- package/lib/features/canvas/templateImport/loadTemplate.js +43 -0
- package/lib/features/canvas/templateImport/loadTemplate.js.map +1 -0
- package/lib/features/canvas/templateImport/renderConfig.js +93 -0
- package/lib/features/canvas/templateImport/renderConfig.js.map +1 -0
- package/lib/features/canvas/useStudioCatalogTemplates.js +134 -0
- package/lib/features/canvas/useStudioCatalogTemplates.js.map +1 -0
- package/lib/features/canvas/video3d.js +109 -0
- package/lib/features/canvas/video3d.js.map +1 -0
- package/lib/features/canvas/videoClips.js +42 -0
- package/lib/features/canvas/videoClips.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +120 -0
- package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/agentLoop.js +69 -0
- package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/brainClient.js +45 -0
- package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -0
- package/lib/features/canvas/videoEditor/agent/cutTools.js +129 -0
- package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -0
- package/lib/features/canvas/videoEditor/editorModel.js +346 -0
- package/lib/features/canvas/videoEditor/editorModel.js.map +1 -0
- package/lib/features/canvas/videoEditor/exportRenderer.js +214 -0
- package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -0
- package/lib/features/canvas/videoEditor/filters.js +41 -0
- package/lib/features/canvas/videoEditor/filters.js.map +1 -0
- package/lib/features/canvas/videoEditor/mediaActions.js +57 -0
- package/lib/features/canvas/videoEditor/mediaActions.js.map +1 -0
- package/lib/features/canvas/videoEditor/remoteMediaClient.js +129 -0
- package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -0
- package/lib/features/canvas/videoEditor/solidColorPng.js +115 -0
- package/lib/features/canvas/videoEditor/solidColorPng.js.map +1 -0
- package/lib/features/canvas/videoEditor/videoEditOps.js +191 -0
- package/lib/features/canvas/videoEditor/videoEditOps.js.map +1 -0
- package/lib/features/canvas/videoEditor/videoProjectsStore.js +82 -0
- package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -0
- package/lib/features/canvas/videoRenderer.js +8 -0
- package/lib/features/canvas/videoRenderer.js.map +1 -0
- package/lib/features/canvas/withRemoteSafeArea.js +2 -2
- package/lib/features/canvas/withRemoteSafeArea.js.map +1 -1
- package/lib/features/characters/characterStudioProps.js +14 -0
- package/lib/features/characters/characterStudioProps.js.map +1 -0
- package/lib/features/chat/ChatCodeBlock.js +7 -3
- package/lib/features/chat/ChatCodeBlock.js.map +1 -1
- package/lib/features/chat/ChatTranscript.js +7 -3
- package/lib/features/chat/ChatTranscript.js.map +1 -1
- package/lib/features/chat/ChatWidgetCard.js +13 -0
- package/lib/features/chat/ChatWidgetCard.js.map +1 -0
- package/lib/features/chat/ConnectorConnectCard.js +164 -0
- package/lib/features/chat/ConnectorConnectCard.js.map +1 -0
- package/lib/features/chat/ConnectorConnectPrompt.js +254 -0
- package/lib/features/chat/ConnectorConnectPrompt.js.map +1 -0
- package/lib/features/chat/MessageActionBar.js.map +1 -1
- package/lib/features/chat/QueuedFollowUps.js +71 -0
- package/lib/features/chat/QueuedFollowUps.js.map +1 -0
- package/lib/features/chat/chatWidgets.js +37 -0
- package/lib/features/chat/chatWidgets.js.map +1 -0
- package/lib/features/chat/connectorConnect.js +179 -0
- package/lib/features/chat/connectorConnect.js.map +1 -0
- package/lib/features/chat/connectorConnectHandbacks.js +55 -0
- package/lib/features/chat/connectorConnectHandbacks.js.map +1 -0
- package/lib/features/design/DesignEditorExperience.js +643 -0
- package/lib/features/design/DesignEditorExperience.js.map +1 -0
- package/lib/features/design/DesignExperience.js +444 -0
- package/lib/features/design/DesignExperience.js.map +1 -0
- package/lib/features/design/designCore.js +298 -0
- package/lib/features/design/designCore.js.map +1 -0
- package/lib/features/design/designIndex.js +150 -0
- package/lib/features/design/designIndex.js.map +1 -0
- package/lib/features/design/exportDesign.js +133 -0
- package/lib/features/design/exportDesign.js.map +1 -0
- package/lib/features/job-search/ApplicationsPanel.js +907 -0
- package/lib/features/job-search/ApplicationsPanel.js.map +1 -0
- package/lib/features/job-search/ContactsPanel.js +627 -0
- package/lib/features/job-search/ContactsPanel.js.map +1 -0
- package/lib/features/job-search/InsightsPanel.js +299 -0
- package/lib/features/job-search/InsightsPanel.js.map +1 -0
- package/lib/features/job-search/InterviewPanel.js +637 -0
- package/lib/features/job-search/InterviewPanel.js.map +1 -0
- package/lib/features/job-search/JdPastePrompt.js +130 -0
- package/lib/features/job-search/JdPastePrompt.js.map +1 -0
- package/lib/features/job-search/JobCard.js +199 -0
- package/lib/features/job-search/JobCard.js.map +1 -0
- package/lib/features/job-search/JobDetailSheet.js +255 -0
- package/lib/features/job-search/JobDetailSheet.js.map +1 -0
- package/lib/features/job-search/JobSearchAgentChatPane.js +377 -0
- package/lib/features/job-search/JobSearchAgentChatPane.js.map +1 -0
- package/lib/features/job-search/JobSearchExperience.js +1324 -0
- package/lib/features/job-search/JobSearchExperience.js.map +1 -0
- package/lib/features/job-search/JobSearchLocationField.js +231 -0
- package/lib/features/job-search/JobSearchLocationField.js.map +1 -0
- package/lib/features/job-search/ProfilePanel.js +679 -0
- package/lib/features/job-search/ProfilePanel.js.map +1 -0
- package/lib/features/job-search/RepliesPanel.js +344 -0
- package/lib/features/job-search/RepliesPanel.js.map +1 -0
- package/lib/features/job-search/SavedPanel.js +297 -0
- package/lib/features/job-search/SavedPanel.js.map +1 -0
- package/lib/features/job-search/chat/widgetContent.js +29 -0
- package/lib/features/job-search/chat/widgetContent.js.map +1 -0
- package/lib/features/job-search/cvText.js +91 -0
- package/lib/features/job-search/cvText.js.map +1 -0
- package/lib/features/job-search/jobAgentSwipe.js +7 -0
- package/lib/features/job-search/jobAgentSwipe.js.map +1 -0
- package/lib/features/job-search/jobSearchClient.js +184 -0
- package/lib/features/job-search/jobSearchClient.js.map +1 -0
- package/lib/features/job-search/jobSearchExec.js +14 -0
- package/lib/features/job-search/jobSearchExec.js.map +1 -0
- package/lib/features/job-search/jobSearchRuntime.js +50 -0
- package/lib/features/job-search/jobSearchRuntime.js.map +1 -0
- package/lib/features/job-search/jobSearchTheme.js +44 -0
- package/lib/features/job-search/jobSearchTheme.js.map +1 -0
- package/lib/features/job-search/savedJobs.js +85 -0
- package/lib/features/job-search/savedJobs.js.map +1 -0
- package/lib/features/job-search/searchHistory.js +117 -0
- package/lib/features/job-search/searchHistory.js.map +1 -0
- package/lib/features/job-search/types.js +36 -0
- package/lib/features/job-search/types.js.map +1 -0
- package/lib/features/job-search/useJobSearchSession.js +558 -0
- package/lib/features/job-search/useJobSearchSession.js.map +1 -0
- package/lib/features/messaging/ChatComponents.js +529 -0
- package/lib/features/messaging/ChatComponents.js.map +1 -0
- package/lib/features/messaging/ChatInviteDeepLink.js +116 -0
- package/lib/features/messaging/ChatInviteDeepLink.js.map +1 -0
- package/lib/features/messaging/ContactsScreen.js +288 -0
- package/lib/features/messaging/ContactsScreen.js.map +1 -0
- package/lib/features/messaging/ConversationListScreen.js +147 -0
- package/lib/features/messaging/ConversationListScreen.js.map +1 -0
- package/lib/features/messaging/MessageActions.js +290 -0
- package/lib/features/messaging/MessageActions.js.map +1 -0
- package/lib/features/messaging/NativeChatExperience.js +189 -0
- package/lib/features/messaging/NativeChatExperience.js.map +1 -0
- package/lib/features/messaging/RegistrationScreen.js +11 -14
- package/lib/features/messaging/RegistrationScreen.js.map +1 -1
- package/lib/features/messaging/ThreadScreen.js +215 -0
- package/lib/features/messaging/ThreadScreen.js.map +1 -0
- package/lib/features/messaging/chatInviteLink.js +52 -0
- package/lib/features/messaging/chatInviteLink.js.map +1 -0
- package/lib/features/messaging/chatModel.js +278 -0
- package/lib/features/messaging/chatModel.js.map +1 -0
- package/lib/features/messaging/chatOperations.js +106 -1
- package/lib/features/messaging/chatOperations.js.map +1 -1
- package/lib/features/messaging/emojiCatalog.js +60 -0
- package/lib/features/messaging/emojiCatalog.js.map +1 -0
- package/lib/features/messaging/emojiKeywords.js +1592 -0
- package/lib/features/messaging/emojiKeywords.js.map +1 -0
- package/lib/features/messaging/nativeChatChannelQuery.js +27 -0
- package/lib/features/messaging/nativeChatChannelQuery.js.map +1 -0
- package/lib/features/messaging/phoneNumbers.js +52 -1
- package/lib/features/messaging/phoneNumbers.js.map +1 -1
- package/lib/features/messaging/sha256.js +68 -0
- package/lib/features/messaging/sha256.js.map +1 -0
- package/lib/features/messaging/useChatData.js +421 -0
- package/lib/features/messaging/useChatData.js.map +1 -0
- package/lib/features/messaging/useContactMatches.js +191 -0
- package/lib/features/messaging/useContactMatches.js.map +1 -0
- package/lib/features/messaging/usePhoneVerification.js +12 -12
- package/lib/features/messaging/usePhoneVerification.js.map +1 -1
- package/lib/features/messaging/yantraChatOrg.js +8 -3
- package/lib/features/messaging/yantraChatOrg.js.map +1 -1
- package/lib/features/resume/AnnotateModal.js +100 -0
- package/lib/features/resume/AnnotateModal.js.map +1 -0
- package/lib/features/resume/AnnotationBar.js +69 -0
- package/lib/features/resume/AnnotationBar.js.map +1 -0
- package/lib/features/resume/ExportSheet.js +105 -0
- package/lib/features/resume/ExportSheet.js.map +1 -0
- package/lib/features/resume/ResumeAgentChatPane.js +95 -0
- package/lib/features/resume/ResumeAgentChatPane.js.map +1 -0
- package/lib/features/resume/ResumeEditor.js +676 -0
- package/lib/features/resume/ResumeEditor.js.map +1 -0
- package/lib/features/resume/ResumeExperience.js +235 -0
- package/lib/features/resume/ResumeExperience.js.map +1 -0
- package/lib/features/resume/ResumeListPanel.js +262 -0
- package/lib/features/resume/ResumeListPanel.js.map +1 -0
- package/lib/features/resume/ResumeToolbar.js +236 -0
- package/lib/features/resume/ResumeToolbar.js.map +1 -0
- package/lib/features/resume/annotations.js +17 -0
- package/lib/features/resume/annotations.js.map +1 -0
- package/lib/features/resume/documentCss.js +52 -0
- package/lib/features/resume/documentCss.js.map +1 -0
- package/lib/features/resume/draft.js +89 -0
- package/lib/features/resume/draft.js.map +1 -0
- package/lib/features/resume/exportResume.js +43 -0
- package/lib/features/resume/exportResume.js.map +1 -0
- package/lib/features/resume/pickResumePhoto.js +22 -0
- package/lib/features/resume/pickResumePhoto.js.map +1 -0
- package/lib/features/resume/renderResume.js +121 -0
- package/lib/features/resume/renderResume.js.map +1 -0
- package/lib/features/resume/resumeClient.js +69 -0
- package/lib/features/resume/resumeClient.js.map +1 -0
- package/lib/features/resume/resumeExec.js +14 -0
- package/lib/features/resume/resumeExec.js.map +1 -0
- package/lib/features/resume/resumeIndex.js +244 -0
- package/lib/features/resume/resumeIndex.js.map +1 -0
- package/lib/features/resume/resumeRuntime.js +50 -0
- package/lib/features/resume/resumeRuntime.js.map +1 -0
- package/lib/features/resume/resumeTheme.js +34 -0
- package/lib/features/resume/resumeTheme.js.map +1 -0
- package/lib/features/resume/resumeToolbox.js +49 -0
- package/lib/features/resume/resumeToolbox.js.map +1 -0
- package/lib/features/resume/templates.js +90 -0
- package/lib/features/resume/templates.js.map +1 -0
- package/lib/features/resume/types.js +10 -0
- package/lib/features/resume/types.js.map +1 -0
- package/lib/features/resume/useResumeSession.js +183 -0
- package/lib/features/resume/useResumeSession.js.map +1 -0
- package/lib/features/shopping/DealsPanel.js +254 -0
- package/lib/features/shopping/DealsPanel.js.map +1 -0
- package/lib/features/shopping/HistoryPanel.js +147 -0
- package/lib/features/shopping/HistoryPanel.js.map +1 -0
- package/lib/features/shopping/OrdersPanel.js +157 -0
- package/lib/features/shopping/OrdersPanel.js.map +1 -0
- package/lib/features/shopping/ProductCard.js +326 -0
- package/lib/features/shopping/ProductCard.js.map +1 -0
- package/lib/features/shopping/ProductDetailSheet.js +313 -0
- package/lib/features/shopping/ProductDetailSheet.js.map +1 -0
- package/lib/features/shopping/ProductFilterBar.js +153 -0
- package/lib/features/shopping/ProductFilterBar.js.map +1 -0
- package/lib/features/shopping/ProductPhoto.js +27 -0
- package/lib/features/shopping/ProductPhoto.js.map +1 -0
- package/lib/features/shopping/SavedPanel.js +139 -0
- package/lib/features/shopping/SavedPanel.js.map +1 -0
- package/lib/features/shopping/ShoppingAgentChatPane.js +436 -0
- package/lib/features/shopping/ShoppingAgentChatPane.js.map +1 -0
- package/lib/features/shopping/ShoppingExperience.js +888 -0
- package/lib/features/shopping/ShoppingExperience.js.map +1 -0
- package/lib/features/shopping/TrendingSections.js +199 -0
- package/lib/features/shopping/TrendingSections.js.map +1 -0
- package/lib/features/shopping/WatchlistPanel.js +148 -0
- package/lib/features/shopping/WatchlistPanel.js.map +1 -0
- package/lib/features/shopping/catalog.js +238 -0
- package/lib/features/shopping/catalog.js.map +1 -0
- package/lib/features/shopping/chat/ShoppingChatResultCard.js +175 -0
- package/lib/features/shopping/chat/ShoppingChatResultCard.js.map +1 -0
- package/lib/features/shopping/chat/streamAssistantReply.js +34 -0
- package/lib/features/shopping/chat/streamAssistantReply.js.map +1 -0
- package/lib/features/shopping/chat/widgetContent.js +233 -0
- package/lib/features/shopping/chat/widgetContent.js.map +1 -0
- package/lib/features/shopping/hooks/useTrendingProducts.js +162 -0
- package/lib/features/shopping/hooks/useTrendingProducts.js.map +1 -0
- package/lib/features/shopping/productImage.js +42 -0
- package/lib/features/shopping/productImage.js.map +1 -0
- package/lib/features/shopping/savedProducts.js +84 -0
- package/lib/features/shopping/savedProducts.js.map +1 -0
- package/lib/features/shopping/services/catalogActions.js +166 -0
- package/lib/features/shopping/services/catalogActions.js.map +1 -0
- package/lib/features/shopping/services/parsePriceCheckIntent.js +58 -0
- package/lib/features/shopping/services/parsePriceCheckIntent.js.map +1 -0
- package/lib/features/shopping/services/parseShoppingIntent.js +67 -0
- package/lib/features/shopping/services/parseShoppingIntent.js.map +1 -0
- package/lib/features/shopping/services/productAvailability.js +25 -0
- package/lib/features/shopping/services/productAvailability.js.map +1 -0
- package/lib/features/shopping/services/productFilters.js +72 -0
- package/lib/features/shopping/services/productFilters.js.map +1 -0
- package/lib/features/shopping/services/retailerUrl.js +75 -0
- package/lib/features/shopping/services/retailerUrl.js.map +1 -0
- package/lib/features/shopping/services/shoppingChatReply.js +46 -0
- package/lib/features/shopping/services/shoppingChatReply.js.map +1 -0
- package/lib/features/shopping/services/shoppingProductSearch.js +336 -0
- package/lib/features/shopping/services/shoppingProductSearch.js.map +1 -0
- package/lib/features/shopping/services/shoppingSearchConnectorClient.js +41 -0
- package/lib/features/shopping/services/shoppingSearchConnectorClient.js.map +1 -0
- package/lib/features/shopping/shopAgentSwipe.js +7 -0
- package/lib/features/shopping/shopAgentSwipe.js.map +1 -0
- package/lib/features/shopping/shoppingCart.js +116 -0
- package/lib/features/shopping/shoppingCart.js.map +1 -0
- package/lib/features/shopping/shoppingExec.js +14 -0
- package/lib/features/shopping/shoppingExec.js.map +1 -0
- package/lib/features/shopping/shoppingHistoryStore.js +176 -0
- package/lib/features/shopping/shoppingHistoryStore.js.map +1 -0
- package/lib/features/shopping/shoppingRuntime.js +63 -0
- package/lib/features/shopping/shoppingRuntime.js.map +1 -0
- package/lib/features/shopping/timeAgo.js +14 -0
- package/lib/features/shopping/timeAgo.js.map +1 -0
- package/lib/features/shopping/useShoppingSearch.js +262 -0
- package/lib/features/shopping/useShoppingSearch.js.map +1 -0
- package/lib/features/travel/BookHeaderGlow.js +48 -0
- package/lib/features/travel/BookHeaderGlow.js.map +1 -0
- package/lib/features/travel/BookingsPanel.js +29 -0
- package/lib/features/travel/BookingsPanel.js.map +1 -0
- package/lib/features/travel/DiscoverPanel.js +155 -0
- package/lib/features/travel/DiscoverPanel.js.map +1 -0
- package/lib/features/travel/FlightCompareBar.js +86 -0
- package/lib/features/travel/FlightCompareBar.js.map +1 -0
- package/lib/features/travel/FlightDealsBoard.js +100 -0
- package/lib/features/travel/FlightDealsBoard.js.map +1 -0
- package/lib/features/travel/HistoryPanel.js +82 -0
- package/lib/features/travel/HistoryPanel.js.map +1 -0
- package/lib/features/travel/PopularDestinations.js +144 -0
- package/lib/features/travel/PopularDestinations.js.map +1 -0
- package/lib/features/travel/SavedPanel.js +27 -0
- package/lib/features/travel/SavedPanel.js.map +1 -0
- package/lib/features/travel/TravelAgentChatPane.js +303 -0
- package/lib/features/travel/TravelAgentChatPane.js.map +1 -0
- package/lib/features/travel/TravelBookHero.js +425 -0
- package/lib/features/travel/TravelBookHero.js.map +1 -0
- package/lib/features/travel/TravelDatesField.js +234 -0
- package/lib/features/travel/TravelDatesField.js.map +1 -0
- package/lib/features/travel/TravelDetailSheet.js +106 -0
- package/lib/features/travel/TravelDetailSheet.js.map +1 -0
- package/lib/features/travel/TravelExperience.js +624 -0
- package/lib/features/travel/TravelExperience.js.map +1 -0
- package/lib/features/travel/TravelGuestsField.js +85 -0
- package/lib/features/travel/TravelGuestsField.js.map +1 -0
- package/lib/features/travel/TravelLanding.js +318 -0
- package/lib/features/travel/TravelLanding.js.map +1 -0
- package/lib/features/travel/TravelLocationField.js +179 -0
- package/lib/features/travel/TravelLocationField.js.map +1 -0
- package/lib/features/travel/TravelPropertyCard.js +266 -0
- package/lib/features/travel/TravelPropertyCard.js.map +1 -0
- package/lib/features/travel/TravelPropertyPhoto.js +22 -0
- package/lib/features/travel/TravelPropertyPhoto.js.map +1 -0
- package/lib/features/travel/TravelRailFlyout.js +79 -0
- package/lib/features/travel/TravelRailFlyout.js.map +1 -0
- package/lib/features/travel/TravelResultsMap.js +126 -0
- package/lib/features/travel/TravelResultsMap.js.map +1 -0
- package/lib/features/travel/WorkspacePanel.js +148 -0
- package/lib/features/travel/WorkspacePanel.js.map +1 -0
- package/lib/features/travel/appNav.js +244 -0
- package/lib/features/travel/appNav.js.map +1 -0
- package/lib/features/travel/calendarDays.js +50 -0
- package/lib/features/travel/calendarDays.js.map +1 -0
- package/lib/features/travel/catalog.js +72 -0
- package/lib/features/travel/catalog.js.map +1 -0
- package/lib/features/travel/chat/TravelChatResultCard.js +107 -0
- package/lib/features/travel/chat/TravelChatResultCard.js.map +1 -0
- package/lib/features/travel/chat/widgetContent.js +107 -0
- package/lib/features/travel/chat/widgetContent.js.map +1 -0
- package/lib/features/travel/flightDeals.js +65 -0
- package/lib/features/travel/flightDeals.js.map +1 -0
- package/lib/features/travel/mapCoordinates.js +36 -0
- package/lib/features/travel/mapCoordinates.js.map +1 -0
- package/lib/features/travel/parseTravelIntent.js +303 -0
- package/lib/features/travel/parseTravelIntent.js.map +1 -0
- package/lib/features/travel/savedStays.js +66 -0
- package/lib/features/travel/savedStays.js.map +1 -0
- package/lib/features/travel/services/flightDealsBoard.js +111 -0
- package/lib/features/travel/services/flightDealsBoard.js.map +1 -0
- package/lib/features/travel/services/flightSearchConnectorClient.js +42 -0
- package/lib/features/travel/services/flightSearchConnectorClient.js.map +1 -0
- package/lib/features/travel/services/geocodeLocation.js +79 -0
- package/lib/features/travel/services/geocodeLocation.js.map +1 -0
- package/lib/features/travel/services/placePredictions.js +113 -0
- package/lib/features/travel/services/placePredictions.js.map +1 -0
- package/lib/features/travel/services/resolveOriginCity.js +27 -0
- package/lib/features/travel/services/resolveOriginCity.js.map +1 -0
- package/lib/features/travel/services/resortifiConnectorClient.js +76 -0
- package/lib/features/travel/services/resortifiConnectorClient.js.map +1 -0
- package/lib/features/travel/services/travelFlightSearch.js +289 -0
- package/lib/features/travel/services/travelFlightSearch.js.map +1 -0
- package/lib/features/travel/services/travelPropertySearch.js +377 -0
- package/lib/features/travel/services/travelPropertySearch.js.map +1 -0
- package/lib/features/travel/travelAgentSwipe.js +7 -0
- package/lib/features/travel/travelAgentSwipe.js.map +1 -0
- package/lib/features/travel/travelExec.js +14 -0
- package/lib/features/travel/travelExec.js.map +1 -0
- package/lib/features/travel/travelHistoryStore.js +108 -0
- package/lib/features/travel/travelHistoryStore.js.map +1 -0
- package/lib/features/travel/travelRuntime.js +62 -0
- package/lib/features/travel/travelRuntime.js.map +1 -0
- package/lib/features/travel/types.js +9 -0
- package/lib/features/travel/types.js.map +1 -0
- package/lib/features/travel/useTravelSearch.js +330 -0
- package/lib/features/travel/useTravelSearch.js.map +1 -0
- package/lib/features/travel/workspaceContent.js +548 -0
- package/lib/features/travel/workspaceContent.js.map +1 -0
- package/lib/hooks/useCdecliChannel.js +128 -6
- package/lib/hooks/useCdecliChannel.js.map +1 -1
- package/lib/hooks/useChatApi.js +4 -2
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +77 -63
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/hooks/useHostConnectorCard.js +24 -0
- package/lib/hooks/useHostConnectorCard.js.map +1 -0
- package/lib/hooks/useObtainSystemToken.js +23 -5
- package/lib/hooks/useObtainSystemToken.js.map +1 -1
- package/lib/hooks/webViewRetentionPolicy.js +1 -0
- package/lib/hooks/webViewRetentionPolicy.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/screens/Chat/index.js +51 -22
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/ChatNative/index.js +13 -2
- package/lib/screens/ChatNative/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js +3 -3
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/ChatHistoryLanding.js +32 -32
- package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js +12 -6
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js.map +1 -1
- package/lib/screens/ResumeNative/useResumeHostChat.js +12 -6
- package/lib/screens/ResumeNative/useResumeHostChat.js.map +1 -1
- package/lib/screens/ShoppingNative/useShoppingHostChat.js +12 -6
- package/lib/screens/ShoppingNative/useShoppingHostChat.js.map +1 -1
- package/lib/screens/TravelNative/useTravelHostChat.js +12 -6
- package/lib/screens/TravelNative/useTravelHostChat.js.map +1 -1
- package/lib/screens/WebBuilder/WebViewWithNavigation.js +2 -2
- package/lib/screens/WebBuilder/WebViewWithNavigation.js.map +1 -1
- package/lib/services/brainQuickReply.js +38 -1
- package/lib/services/brainQuickReply.js.map +1 -1
- package/lib/state/chatThreadMerge.js +6 -1
- package/lib/state/chatThreadMerge.js.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promoVideo.js","sources":["../../../src/features/canvas/promoVideo.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/promoVideoRpc` — catalog + submit/poll\n * envelope. Transport stays `RunMediaAction` (host or remote exec).\n */\n\nexport const PROMO_CONNECTOR = 'yantra-video-generation';\nexport const PRODUCE_SUBMIT_ACTION = 'YANTRA_VIDEO_GENERATION_PRODUCE_SUBMIT';\nexport const PRODUCE_STATUS_ACTION = 'YANTRA_VIDEO_GENERATION_PRODUCE_STATUS';\n/** Design lane: brief → editable studio project (no render). */\nexport const DESIGN_PROJECT_ACTION = 'YANTRA_VIDEO_GENERATION_DESIGN_PROJECT';\nexport const DESIGN_TIMEOUT_MS = 4 * 60_000;\n\nexport interface PromoPreset {\n id: string;\n name: string;\n description: string;\n defaultDurationSeconds: number;\n needsSourceVideo: boolean;\n}\n\nexport const PROMO_PRESETS: readonly PromoPreset[] = [\n {\n id: 'product-teaser',\n name: 'Product teaser',\n description: 'Cinematic launch teaser: hero shots, a reveal, one closing line.',\n defaultDurationSeconds: 30,\n needsSourceVideo: false,\n },\n {\n id: 'brand-film',\n name: 'Brand film',\n description: 'Mood-led brand piece: story, atmosphere, music-first.',\n defaultDurationSeconds: 60,\n needsSourceVideo: false,\n },\n {\n id: 'motion-promo',\n name: 'Motion promo',\n description: 'Kinetic type and motion graphics for a feature, offer or launch.',\n defaultDurationSeconds: 30,\n needsSourceVideo: false,\n },\n {\n id: 'explainer',\n name: 'Explainer',\n description: 'Narrated explainer with captions: what, why, how.',\n defaultDurationSeconds: 60,\n needsSourceVideo: false,\n },\n {\n id: 'social-hook',\n name: 'Social hook',\n description: 'Vertical scroll-stopper: instant hook, big captions, one message.',\n defaultDurationSeconds: 15,\n needsSourceVideo: false,\n },\n {\n id: 'footage-remix',\n name: 'Remix footage',\n description: 'Cut a video already on the canvas into a promo with graphics and music.',\n defaultDurationSeconds: 30,\n needsSourceVideo: true,\n },\n];\n\nexport const PROMO_PLAYBOOKS: readonly { id: string; name: string }[] = [\n { id: '', name: 'Preset default' },\n { id: 'premium-minimalist', name: 'Premium minimalist' },\n { id: 'clean-professional', name: 'Clean professional' },\n { id: 'flat-motion-graphics', name: 'Flat motion graphics' },\n { id: 'minimalist-diagram', name: 'Minimalist diagram' },\n { id: 'anime-ghibli', name: 'Anime / Ghibli' },\n];\n\nexport function defaultNarration(presetId: string): boolean {\n return presetId !== 'brand-film' && presetId !== 'social-hook';\n}\n\nexport const DEFAULT_PROMO_PRESET = 'product-teaser';\nexport const PROMO_DURATIONS = [15, 30, 45, 60, 90] as const;\nexport const PROMO_ASPECT_RATIOS = ['16:9', '9:16', '1:1'] as const;\nexport const PROMO_POLL_EVERY_MS = 20_000;\nexport const PROMO_POLL_MAX_MS = 75 * 60_000;\n\nexport function lookupPromoPreset(id: string): PromoPreset {\n return PROMO_PRESETS.find((p) => p.id === id) ?? PROMO_PRESETS[0];\n}\n\nexport interface PromoContext {\n onScreenText: string;\n keyPoints: string;\n audience: string;\n tone: string;\n avoid: string;\n brandColors: string;\n}\n\nexport const EMPTY_PROMO_CONTEXT: PromoContext = {\n onScreenText: '',\n keyPoints: '',\n audience: '',\n tone: '',\n avoid: '',\n brandColors: '',\n};\n\nexport function hasPromoContext(value: PromoContext, logoUrl?: string | null): boolean {\n return Boolean(logoUrl) || Object.values(value).some((v) => v.trim().length > 0);\n}\n\n/** Hexes in a colours field — mirrors the connector parser. */\nexport function readBrandColors(raw: string): string[] {\n const out: string[] = [];\n for (const token of raw.split(/[\\s,]+/)) {\n const m = token.trim().match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (!m) continue;\n const h =\n m[1].length === 3\n ? m[1]\n .split('')\n .map((c) => c + c)\n .join('')\n : m[1];\n const hex = `#${h.toLowerCase()}`;\n if (!out.includes(hex)) out.push(hex);\n }\n return out.slice(0, 6);\n}\n\nexport interface PromoRunOptions {\n prompt: string;\n preset: string;\n durationSeconds: number;\n aspectRatio: string;\n referenceImageUrls?: string[];\n sourceVideoUrl?: string;\n brandName?: string;\n callToAction?: string;\n logoUrl?: string;\n onScreenText?: string;\n keyPoints?: string;\n audience?: string;\n tone?: string;\n avoid?: string;\n brandColors?: string;\n captions?: boolean;\n narration?: boolean;\n stylePlaybook?: string;\n}\n\nexport interface PromoRunResult {\n url: string;\n title: string;\n projectId: string;\n preset: string;\n pipeline: string;\n durationSeconds?: number;\n summary?: string;\n}\n\nexport function buildPromoRunParams(opts: PromoRunOptions): Record<string, unknown> {\n const referenceImageUrls = (opts.referenceImageUrls ?? []).filter((u) => /^https?:\\/\\//i.test(u));\n return {\n prompt: opts.prompt,\n preset: opts.preset,\n durationSeconds: opts.durationSeconds,\n aspectRatio: opts.aspectRatio,\n ...(referenceImageUrls.length ? { referenceImageUrls } : {}),\n ...(opts.sourceVideoUrl ? { sourceVideoUrl: opts.sourceVideoUrl } : {}),\n ...(opts.brandName ? { brandName: opts.brandName } : {}),\n ...(opts.callToAction ? { callToAction: opts.callToAction } : {}),\n ...(opts.logoUrl ? { logoUrl: opts.logoUrl } : {}),\n ...(opts.onScreenText?.trim() ? { onScreenText: opts.onScreenText } : {}),\n ...(opts.keyPoints?.trim() ? { keyPoints: opts.keyPoints } : {}),\n ...(opts.audience?.trim() ? { audience: opts.audience.trim() } : {}),\n ...(opts.tone?.trim() ? { tone: opts.tone.trim() } : {}),\n ...(opts.avoid?.trim() ? { avoid: opts.avoid.trim() } : {}),\n ...(opts.brandColors?.trim() ? { brandColors: opts.brandColors } : {}),\n ...(typeof opts.captions === 'boolean' ? { captions: opts.captions } : {}),\n ...(typeof opts.narration === 'boolean' ? { narration: opts.narration } : {}),\n ...(opts.stylePlaybook ? { stylePlaybook: opts.stylePlaybook } : {}),\n timeoutMs: 55 * 60_000,\n };\n}\n\nexport function parsePromoRunResult(result: Record<string, unknown>): PromoRunResult | null {\n const data = (result.data ?? result) as Record<string, unknown>;\n const samples = data.samples as Array<{ uri?: string }> | undefined;\n const url = (typeof data.videoUri === 'string' && data.videoUri) || samples?.find((s) => s?.uri)?.uri || '';\n if (!url) return null;\n const prod = (data.production ?? {}) as Record<string, unknown>;\n const s = (k: string) => (typeof prod[k] === 'string' ? (prod[k] as string) : undefined);\n const n = (k: string) => (typeof prod[k] === 'number' ? (prod[k] as number) : undefined);\n return {\n url,\n title: s('title') ?? 'Marketing video',\n projectId: s('projectId') ?? (typeof data.operationName === 'string' ? data.operationName : ''),\n preset: s('preset') ?? '',\n pipeline: s('pipeline') ?? '',\n durationSeconds: n('durationSeconds'),\n summary: s('summary'),\n };\n}\n\nexport interface PromoSubmitHandle {\n projectId: string;\n sandboxId: string;\n}\n\nexport function parseSubmitResult(result: Record<string, unknown>): PromoSubmitHandle | null {\n const d = (result.data ?? result) as Record<string, unknown>;\n const projectId = typeof d.projectId === 'string' ? d.projectId : '';\n const sandboxId = typeof d.sandboxId === 'string' ? d.sandboxId : '';\n return projectId && sandboxId ? { projectId, sandboxId } : null;\n}\n\nexport type PromoPollState = 'running' | 'succeeded' | 'failed';\n\nexport interface PromoPoll {\n state: PromoPollState;\n progress: string[];\n error?: string;\n result?: PromoRunResult;\n}\n\nexport function parsePollResult(result: Record<string, unknown>): PromoPoll {\n const d = (result.data ?? result) as Record<string, unknown>;\n const state: PromoPollState = d.state === 'succeeded' || d.state === 'failed' ? d.state : 'running';\n const progress = Array.isArray(d.progress) ? (d.progress.filter((x) => typeof x === 'string') as string[]) : [];\n if (state === 'succeeded') {\n const run = parsePromoRunResult(d);\n return run\n ? { state, progress, result: run }\n : { state: 'failed', progress, error: 'Production finished but returned no video' };\n }\n if (state === 'failed') {\n return { state, progress, error: typeof d.error === 'string' ? d.error : 'Marketing video production failed' };\n }\n return { state, progress };\n}\n\nexport async function producePromoVideo(\n run: (action: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>,\n opts: PromoRunOptions,\n onProgress?: (msg: string) => void,\n sleep: (ms: number) => Promise<void> = (ms) => new Promise((r) => setTimeout(r, ms)),\n isCancelled?: () => boolean,\n): Promise<PromoRunResult> {\n onProgress?.('Starting the production…');\n const submit = await run(PRODUCE_SUBMIT_ACTION, buildPromoRunParams(opts));\n const handle = parseSubmitResult(submit);\n if (!handle) throw new Error('Could not start the production (no handle returned)');\n\n const deadline = Date.now() + PROMO_POLL_MAX_MS;\n let lastProgress = '';\n let pollErrors = 0;\n while (Date.now() < deadline) {\n if (isCancelled?.()) throw new Error('cancelled');\n await sleep(PROMO_POLL_EVERY_MS);\n if (isCancelled?.()) throw new Error('cancelled');\n let poll: PromoPoll;\n try {\n const raw = await run(PRODUCE_STATUS_ACTION, {\n projectId: handle.projectId,\n sandboxId: handle.sandboxId,\n });\n poll = parsePollResult(raw);\n pollErrors = 0;\n } catch (err) {\n if (++pollErrors >= 4) throw err instanceof Error ? err : new Error(String(err));\n continue;\n }\n const line = poll.progress.at(-1);\n if (line && line !== lastProgress) {\n lastProgress = line;\n onProgress?.(line);\n }\n if (poll.state === 'succeeded' && poll.result) return poll.result;\n if (poll.state === 'failed') throw new Error(poll.error || 'Marketing video production failed');\n }\n throw new Error('The production is taking longer than expected — check back shortly.');\n}\n\n// ── Design lane (web 0.43) ──────────────────────────────────────────────────\n\nexport interface DesignPromoOptions extends PromoRunOptions {\n sourceVideoSeconds?: number;\n musicUrl?: string;\n}\n\nexport interface DesignedPromo {\n project: Record<string, unknown>;\n title: string;\n card: { category: string; industry?: string; reason?: string };\n summary: {\n scenes: number;\n textLayers: number;\n mediaLayers: number;\n seconds: number;\n sceneNames: string[];\n aspect: string;\n };\n notes: string[];\n}\n\nexport function buildDesignParams(opts: DesignPromoOptions): Record<string, unknown> {\n const { captions: _c, narration: _n, stylePlaybook: _p, ...rest } = opts;\n const base = buildPromoRunParams(rest);\n delete base.timeoutMs;\n return {\n ...base,\n ...(opts.sourceVideoSeconds && opts.sourceVideoSeconds > 0\n ? { sourceVideoSeconds: opts.sourceVideoSeconds }\n : {}),\n ...(opts.musicUrl && /^https?:\\/\\//i.test(opts.musicUrl) ? { musicUrl: opts.musicUrl } : {}),\n };\n}\n\nexport function parseDesignResult(result: Record<string, unknown>): DesignedPromo | null {\n const body = (result?.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n const project = body?.project;\n if (!project || typeof project !== 'object' || !Array.isArray((project as Record<string, unknown>).tracks)) {\n return null;\n }\n const summary = (body.summary ?? {}) as Partial<DesignedPromo['summary']>;\n const card = (body.card ?? {}) as Partial<DesignedPromo['card']>;\n return {\n project: project as Record<string, unknown>,\n title: typeof body.title === 'string' && body.title.trim() ? body.title.trim() : 'Video project',\n card: {\n category: typeof card.category === 'string' ? card.category : 'Promos',\n ...(card.industry ? { industry: card.industry } : {}),\n ...(card.reason ? { reason: card.reason } : {}),\n },\n summary: {\n scenes: Number(summary.scenes) || 0,\n textLayers: Number(summary.textLayers) || 0,\n mediaLayers: Number(summary.mediaLayers) || 0,\n seconds: Number(summary.seconds) || 0,\n sceneNames: Array.isArray(summary.sceneNames) ? summary.sceneNames.map(String) : [],\n aspect: typeof summary.aspect === 'string' ? summary.aspect : 'auto',\n },\n notes: Array.isArray(body.notes) ? body.notes.map(String) : [],\n };\n}\n\nexport async function designPromoProject(\n run: (action: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>,\n opts: DesignPromoOptions,\n): Promise<DesignedPromo> {\n const raw = await run(DESIGN_PROJECT_ACTION, buildDesignParams(opts));\n if (raw.successful === false) throw new Error((raw.error as string) || 'Could not design the video');\n const designed = parseDesignResult(raw);\n if (!designed) throw new Error('Could not design the video (no project returned)');\n return designed;\n}\n"],"names":["s"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,MAAM,eAAkB,GAAA;AACxB,MAAM,qBAAwB,GAAA;AAC9B,MAAM,qBAAwB,GAAA;AAE9B,MAAM,qBAAwB,GAAA;AAS9B,MAAM,gBAAwC,CAAC;AAAA,EACpD,EAAI,EAAA,gBAAA;AAAA,EACJ,IAAM,EAAA,gBAAA;AAAA,EACN,WAAa,EAAA,kEAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,YAAA;AAAA,EACJ,IAAM,EAAA,YAAA;AAAA,EACN,WAAa,EAAA,uDAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,cAAA;AAAA,EACJ,IAAM,EAAA,cAAA;AAAA,EACN,WAAa,EAAA,kEAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,WAAA;AAAA,EACJ,IAAM,EAAA,WAAA;AAAA,EACN,WAAa,EAAA,mDAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,aAAA;AAAA,EACJ,IAAM,EAAA,aAAA;AAAA,EACN,WAAa,EAAA,mEAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,eAAA;AAAA,EACJ,IAAM,EAAA,eAAA;AAAA,EACN,WAAa,EAAA,yEAAA;AAAA,EACb,sBAAwB,EAAA,EAAA;AAAA,EACxB,gBAAkB,EAAA;AACpB,CAAC;AACM,MAAM,kBAGP,CAAC;AAAA,EACL,EAAI,EAAA,EAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,oBAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,oBAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,sBAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,oBAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAG,EAAA;AAAA,EACD,EAAI,EAAA,cAAA;AAAA,EACJ,IAAM,EAAA;AACR,CAAC;AACM,SAAS,iBAAiB,QAA2B,EAAA;AAC1D,EAAO,OAAA,QAAA,KAAa,gBAAgB,QAAa,KAAA,aAAA;AACnD;AACO,MAAM,oBAAuB,GAAA;AAC7B,MAAM,kBAAkB,CAAC,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,IAAI,EAAE;AAC3C,MAAM,mBAAsB,GAAA,CAAC,MAAQ,EAAA,MAAA,EAAQ,KAAK;AAClD,MAAM,mBAAsB,GAAA;AAC5B,MAAM,oBAAoB,EAAK,GAAA;AAC/B,SAAS,kBAAkB,EAAyB,EAAA;AArF3D,EAAA,IAAA,EAAA;AAsFE,EAAO,OAAA,CAAA,EAAA,GAAA,aAAA,CAAc,KAAK,CAAK,CAAA,KAAA,CAAA,CAAE,OAAO,EAAE,CAAA,KAAnC,IAAwC,GAAA,EAAA,GAAA,aAAA,CAAc,CAAC,CAAA;AAChE;AASO,MAAM,mBAAoC,GAAA;AAAA,EAC/C,YAAc,EAAA,EAAA;AAAA,EACd,SAAW,EAAA,EAAA;AAAA,EACX,QAAU,EAAA,EAAA;AAAA,EACV,IAAM,EAAA,EAAA;AAAA,EACN,KAAO,EAAA,EAAA;AAAA,EACP,WAAa,EAAA;AACf;AACgB,SAAA,eAAA,CAAgB,OAAqB,OAAkC,EAAA;AACrF,EAAA,OAAO,OAAQ,CAAA,OAAO,CAAK,IAAA,MAAA,CAAO,MAAO,CAAA,KAAK,CAAE,CAAA,IAAA,CAAK,CAAK,CAAA,KAAA,CAAA,CAAE,IAAK,EAAA,CAAE,SAAS,CAAC,CAAA;AAC/E;AAGO,SAAS,gBAAgB,GAAuB,EAAA;AACrD,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,KAAS,IAAA,GAAA,CAAI,KAAM,CAAA,QAAQ,CAAG,EAAA;AACvC,IAAA,MAAM,CAAI,GAAA,KAAA,CAAM,IAAK,EAAA,CAAE,MAAM,gCAAgC,CAAA;AAC7D,IAAA,IAAI,CAAC,CAAG,EAAA;AACR,IAAM,MAAA,CAAA,GAAI,EAAE,CAAC,CAAA,CAAE,WAAW,CAAI,GAAA,CAAA,CAAE,CAAC,CAAE,CAAA,KAAA,CAAM,EAAE,CAAE,CAAA,GAAA,CAAI,OAAK,CAAI,GAAA,CAAC,EAAE,IAAK,CAAA,EAAE,CAAI,GAAA,CAAA,CAAE,CAAC,CAAA;AAC3E,IAAA,MAAM,GAAM,GAAA,CAAA,CAAA,EAAI,CAAE,CAAA,WAAA,EAAa,CAAA,CAAA;AAC/B,IAAA,IAAI,CAAC,GAAI,CAAA,QAAA,CAAS,GAAG,CAAG,EAAA,GAAA,CAAI,KAAK,GAAG,CAAA;AAAA;AAEtC,EAAO,OAAA,GAAA,CAAI,KAAM,CAAA,CAAA,EAAG,CAAC,CAAA;AACvB;AA8BO,SAAS,oBAAoB,IAAgD,EAAA;AArJpF,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAsJE,EAAM,MAAA,kBAAA,GAAA,CAAA,CAAsB,EAAK,GAAA,IAAA,CAAA,kBAAA,KAAL,IAA2B,GAAA,EAAA,GAAA,EAAI,EAAA,MAAA,CAAO,CAAK,CAAA,KAAA,eAAA,CAAgB,IAAK,CAAA,CAAC,CAAC,CAAA;AAC9F,EAAO,OAAA,aAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA;AAAA,IACL,QAAQ,IAAK,CAAA,MAAA;AAAA,IACb,QAAQ,IAAK,CAAA,MAAA;AAAA,IACb,iBAAiB,IAAK,CAAA,eAAA;AAAA,IACtB,aAAa,IAAK,CAAA;AAAA,GAAA,EACd,mBAAmB,MAAS,GAAA;AAAA,IAC9B;AAAA,GACE,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,cAAiB,GAAA;AAAA,IACxB,gBAAgB,IAAK,CAAA;AAAA,GACnB,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,SAAY,GAAA;AAAA,IACnB,WAAW,IAAK,CAAA;AAAA,GACd,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,YAAe,GAAA;AAAA,IACtB,cAAc,IAAK,CAAA;AAAA,GACjB,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,OAAU,GAAA;AAAA,IACjB,SAAS,IAAK,CAAA;AAAA,MACZ,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,YAAA,KAAL,mBAAmB,IAAS,EAAA,IAAA;AAAA,IAC9B,cAAc,IAAK,CAAA;AAAA,MACjB,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,SAAA,KAAL,mBAAgB,IAAS,EAAA,IAAA;AAAA,IAC3B,WAAW,IAAK,CAAA;AAAA,MACd,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,QAAA,KAAL,mBAAe,IAAS,EAAA,IAAA;AAAA,IAC1B,QAAA,EAAU,IAAK,CAAA,QAAA,CAAS,IAAK;AAAA,MAC3B,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,IAAA,KAAL,mBAAW,IAAS,EAAA,IAAA;AAAA,IACtB,IAAA,EAAM,IAAK,CAAA,IAAA,CAAK,IAAK;AAAA,MACnB,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,KAAA,KAAL,mBAAY,IAAS,EAAA,IAAA;AAAA,IACvB,KAAA,EAAO,IAAK,CAAA,KAAA,CAAM,IAAK;AAAA,MACrB,EAAC,CAAA,EAAA,CAAA,CACD,EAAK,GAAA,IAAA,CAAA,WAAA,KAAL,mBAAkB,IAAS,EAAA,IAAA;AAAA,IAC7B,aAAa,IAAK,CAAA;AAAA,MAChB,EAAC,CAAA,EACD,OAAO,IAAA,CAAK,aAAa,SAAY,GAAA;AAAA,IACvC,UAAU,IAAK,CAAA;AAAA,MACb,EAAC,CAAA,EACD,OAAO,IAAA,CAAK,cAAc,SAAY,GAAA;AAAA,IACxC,WAAW,IAAK,CAAA;AAAA,GACd,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,aAAgB,GAAA;AAAA,IACvB,eAAe,IAAK,CAAA;AAAA,GACtB,GAAI,EA9CC,CAAA,EAAA;AAAA,IA+CL,WAAW,EAAK,GAAA;AAAA,GAClB,CAAA;AACF;AACO,SAAS,oBAAoB,MAAwD,EAAA;AAzM5F,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA0ME,EAAM,MAAA,IAAA,GAAA,CAAQ,EAAO,GAAA,MAAA,CAAA,IAAA,KAAP,IAAe,GAAA,EAAA,GAAA,MAAA;AAC7B,EAAA,MAAM,UAAU,IAAK,CAAA,OAAA;AAGrB,EAAA,MAAM,MAAM,OAAO,IAAA,CAAK,QAAa,KAAA,QAAA,IAAY,KAAK,QAAY,KAAA,CAAA,EAAA,GAAA,OAAA,IAAA,IAAA,GAAA,MAAA,GAAA,OAAA,CAAS,IAAK,CAAA,CAAAA,OAAKA,EAAA,IAAA,IAAA,GAAA,MAAA,GAAAA,EAAG,CAAA,GAAA,CAAA,KAAtB,mBAA4B,GAAO,CAAA,IAAA,EAAA;AACrG,EAAI,IAAA,CAAC,KAAY,OAAA,IAAA;AACjB,EAAA,MAAM,IAAQ,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,UAAL,KAAA,IAAA,GAAA,EAAA,GAAmB,EAAC;AAClC,EAAM,MAAA,CAAA,GAAI,CAAC,CAAA,KAAc,OAAO,IAAA,CAAK,CAAC,CAAM,KAAA,QAAA,GAAW,IAAK,CAAA,CAAC,CAAc,GAAA,MAAA;AAC3E,EAAM,MAAA,CAAA,GAAI,CAAC,CAAA,KAAc,OAAO,IAAA,CAAK,CAAC,CAAM,KAAA,QAAA,GAAW,IAAK,CAAA,CAAC,CAAc,GAAA,MAAA;AAC3E,EAAO,OAAA;AAAA,IACL,GAAA;AAAA,IACA,KAAO,EAAA,CAAA,EAAA,GAAA,CAAA,CAAE,OAAO,CAAA,KAAT,IAAc,GAAA,EAAA,GAAA,iBAAA;AAAA,IACrB,SAAA,EAAA,CAAW,EAAE,GAAA,CAAA,CAAA,WAAW,CAAb,KAAA,IAAA,GAAA,EAAA,GAAmB,OAAO,IAAK,CAAA,aAAA,KAAkB,QAAW,GAAA,IAAA,CAAK,aAAgB,GAAA,EAAA;AAAA,IAC5F,MAAQ,EAAA,CAAA,EAAA,GAAA,CAAA,CAAE,QAAQ,CAAA,KAAV,IAAe,GAAA,EAAA,GAAA,EAAA;AAAA,IACvB,QAAU,EAAA,CAAA,EAAA,GAAA,CAAA,CAAE,UAAU,CAAA,KAAZ,IAAiB,GAAA,EAAA,GAAA,EAAA;AAAA,IAC3B,eAAA,EAAiB,EAAE,iBAAiB,CAAA;AAAA,IACpC,OAAA,EAAS,EAAE,SAAS;AAAA,GACtB;AACF;AAKO,SAAS,kBAAkB,MAA2D,EAAA;AAjO7F,EAAA,IAAA,EAAA;AAkOE,EAAM,MAAA,CAAA,GAAA,CAAK,EAAO,GAAA,MAAA,CAAA,IAAA,KAAP,IAAe,GAAA,EAAA,GAAA,MAAA;AAC1B,EAAA,MAAM,YAAY,OAAO,CAAA,CAAE,SAAc,KAAA,QAAA,GAAW,EAAE,SAAY,GAAA,EAAA;AAClE,EAAA,MAAM,YAAY,OAAO,CAAA,CAAE,SAAc,KAAA,QAAA,GAAW,EAAE,SAAY,GAAA,EAAA;AAClE,EAAA,OAAO,aAAa,SAAY,GAAA;AAAA,IAC9B,SAAA;AAAA,IACA;AAAA,GACE,GAAA,IAAA;AACN;AAQO,SAAS,gBAAgB,MAA4C,EAAA;AAjP5E,EAAA,IAAA,EAAA;AAkPE,EAAM,MAAA,CAAA,GAAA,CAAK,EAAO,GAAA,MAAA,CAAA,IAAA,KAAP,IAAe,GAAA,EAAA,GAAA,MAAA;AAC1B,EAAM,MAAA,KAAA,GAAwB,EAAE,KAAU,KAAA,WAAA,IAAe,EAAE,KAAU,KAAA,QAAA,GAAW,EAAE,KAAQ,GAAA,SAAA;AAC1F,EAAA,MAAM,QAAW,GAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,CAAE,QAAQ,CAAI,GAAA,CAAA,CAAE,QAAS,CAAA,MAAA,CAAO,CAAK,CAAA,KAAA,OAAO,CAAM,KAAA,QAAQ,IAAgB,EAAC;AAC1G,EAAA,IAAI,UAAU,WAAa,EAAA;AACzB,IAAM,MAAA,GAAA,GAAM,oBAAoB,CAAC,CAAA;AACjC,IAAA,OAAO,GAAM,GAAA;AAAA,MACX,KAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAQ,EAAA;AAAA,KACN,GAAA;AAAA,MACF,KAAO,EAAA,QAAA;AAAA,MACP,QAAA;AAAA,MACA,KAAO,EAAA;AAAA,KACT;AAAA;AAEF,EAAA,IAAI,UAAU,QAAU,EAAA;AACtB,IAAO,OAAA;AAAA,MACL,KAAA;AAAA,MACA,QAAA;AAAA,MACA,OAAO,OAAO,CAAA,CAAE,KAAU,KAAA,QAAA,GAAW,EAAE,KAAQ,GAAA;AAAA,KACjD;AAAA;AAEF,EAAO,OAAA;AAAA,IACL,KAAA;AAAA,IACA;AAAA,GACF;AACF;AACA,eAAsB,iBAAkB,CAAA,GAAA,EAA4F,IAAuB,EAAA,UAAA,EAAoC,QAAuC,CAAM,EAAA,KAAA,IAAI,OAAQ,CAAA,CAAA,CAAA,KAAK,UAAW,CAAA,CAAA,EAAG,EAAE,CAAC,GAAG,WAAsD,EAAA;AACrU,EAAa,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAA,+BAAA,CAAA;AACb,EAAA,MAAM,SAAS,MAAM,GAAA,CAAI,qBAAuB,EAAA,mBAAA,CAAoB,IAAI,CAAC,CAAA;AACzE,EAAM,MAAA,MAAA,GAAS,kBAAkB,MAAM,CAAA;AACvC,EAAA,IAAI,CAAC,MAAA,EAAc,MAAA,IAAI,MAAM,qDAAqD,CAAA;AAClF,EAAM,MAAA,QAAA,GAAW,IAAK,CAAA,GAAA,EAAQ,GAAA,iBAAA;AAC9B,EAAA,IAAI,YAAe,GAAA,EAAA;AACnB,EAAA,IAAI,UAAa,GAAA,CAAA;AACjB,EAAO,OAAA,IAAA,CAAK,GAAI,EAAA,GAAI,QAAU,EAAA;AAC5B,IAAA,IAAI,WAAiB,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,EAAA,EAAA,MAAM,IAAI,KAAA,CAAM,WAAW,CAAA;AAChD,IAAA,MAAM,MAAM,mBAAmB,CAAA;AAC/B,IAAA,IAAI,WAAiB,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,EAAA,EAAA,MAAM,IAAI,KAAA,CAAM,WAAW,CAAA;AAChD,IAAI,IAAA,IAAA;AACJ,IAAI,IAAA;AACF,MAAM,MAAA,GAAA,GAAM,MAAM,GAAA,CAAI,qBAAuB,EAAA;AAAA,QAC3C,WAAW,MAAO,CAAA,SAAA;AAAA,QAClB,WAAW,MAAO,CAAA;AAAA,OACnB,CAAA;AACD,MAAA,IAAA,GAAO,gBAAgB,GAAG,CAAA;AAC1B,MAAa,UAAA,GAAA,CAAA;AAAA,aACN,GAAK,EAAA;AACZ,MAAI,IAAA,EAAE,UAAc,IAAA,CAAA,EAAS,MAAA,GAAA,YAAe,KAAQ,GAAA,GAAA,GAAM,IAAI,KAAA,CAAM,MAAO,CAAA,GAAG,CAAC,CAAA;AAC/E,MAAA;AAAA;AAEF,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,QAAS,CAAA,EAAA,CAAG,EAAE,CAAA;AAChC,IAAI,IAAA,IAAA,IAAQ,SAAS,YAAc,EAAA;AACjC,MAAe,YAAA,GAAA,IAAA;AACf,MAAa,UAAA,IAAA,IAAA,GAAA,MAAA,GAAA,UAAA,CAAA,IAAA,CAAA;AAAA;AAEf,IAAA,IAAI,KAAK,KAAU,KAAA,WAAA,IAAe,IAAK,CAAA,MAAA,SAAe,IAAK,CAAA,MAAA;AAC3D,IAAI,IAAA,IAAA,CAAK,UAAU,QAAU,EAAA,MAAM,IAAI,KAAM,CAAA,IAAA,CAAK,SAAS,mCAAmC,CAAA;AAAA;AAEhG,EAAM,MAAA,IAAI,MAAM,0EAAqE,CAAA;AACvF;AA0BO,SAAS,kBAAkB,IAAmD,EAAA;AACnF,EAAA,MAKI,EAJF,GAAA,IAAA,EAAA;AAAA,IAAU,QAAA,EAAA,EAAA;AAAA,IACV,SAAW,EAAA,EAAA;AAAA,IACX,aAAe,EAAA;AAAA,GA5UnB,GA8UM,EADC,EAAA,IAAA,GAAA,SAAA,CACD,EADC,EAAA;AAAA,IAHH,UAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GAAA,CAAA;AAGF,EAAM,MAAA,IAAA,GAAO,oBAAoB,IAAI,CAAA;AACrC,EAAA,OAAO,IAAK,CAAA,SAAA;AACZ,EAAA,OAAO,iDACF,IACC,CAAA,EAAA,IAAA,CAAK,kBAAsB,IAAA,IAAA,CAAK,qBAAqB,CAAI,GAAA;AAAA,IAC3D,oBAAoB,IAAK,CAAA;AAAA,GAC3B,GAAI,EACA,CAAA,EAAA,IAAA,CAAK,YAAY,eAAgB,CAAA,IAAA,CAAK,IAAK,CAAA,QAAQ,CAAI,GAAA;AAAA,IACzD,UAAU,IAAK,CAAA;AAAA,MACb,EAAC,CAAA;AAET;AACO,SAAS,kBAAkB,MAAuD,EAAA;AA3VzF,EAAA,IAAA,EAAA,EAAA,EAAA;AA4VE,EAAM,MAAA,IAAA,GAAA,CAAQ,iCAAQ,IAAQ,KAAA,OAAO,OAAO,IAAS,KAAA,QAAA,GAAW,OAAO,IAAO,GAAA,MAAA;AAC9E,EAAA,MAAM,UAAU,IAAM,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA,OAAA;AACtB,EAAI,IAAA,CAAC,OAAW,IAAA,OAAO,OAAY,KAAA,QAAA,IAAY,CAAC,KAAM,CAAA,OAAA,CAAS,OAAoC,CAAA,MAAM,CAAG,EAAA;AAC1G,IAAO,OAAA,IAAA;AAAA;AAET,EAAA,MAAM,OAAW,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,OAAL,KAAA,IAAA,GAAA,EAAA,GAAgB,EAAC;AAClC,EAAA,MAAM,IAAQ,GAAA,CAAA,EAAA,GAAA,IAAA,CAAK,IAAL,KAAA,IAAA,GAAA,EAAA,GAAa,EAAC;AAC5B,EAAO,OAAA;AAAA,IACL,OAAA;AAAA,IACA,KAAO,EAAA,OAAO,IAAK,CAAA,KAAA,KAAU,QAAY,IAAA,IAAA,CAAK,KAAM,CAAA,IAAA,EAAS,GAAA,IAAA,CAAK,KAAM,CAAA,IAAA,EAAS,GAAA,eAAA;AAAA,IACjF,IAAM,EAAA,cAAA,CAAA,cAAA,CAAA;AAAA,MACJ,UAAU,OAAO,IAAA,CAAK,QAAa,KAAA,QAAA,GAAW,KAAK,QAAW,GAAA;AAAA,KAAA,EAC1D,KAAK,QAAW,GAAA;AAAA,MAClB,UAAU,IAAK,CAAA;AAAA,KACb,GAAA,EACA,CAAA,EAAA,IAAA,CAAK,MAAS,GAAA;AAAA,MAChB,QAAQ,IAAK,CAAA;AAAA,QACX,EAAC,CAAA;AAAA,IAEP,OAAS,EAAA;AAAA,MACP,MAAQ,EAAA,MAAA,CAAO,OAAQ,CAAA,MAAM,CAAK,IAAA,CAAA;AAAA,MAClC,UAAY,EAAA,MAAA,CAAO,OAAQ,CAAA,UAAU,CAAK,IAAA,CAAA;AAAA,MAC1C,WAAa,EAAA,MAAA,CAAO,OAAQ,CAAA,WAAW,CAAK,IAAA,CAAA;AAAA,MAC5C,OAAS,EAAA,MAAA,CAAO,OAAQ,CAAA,OAAO,CAAK,IAAA,CAAA;AAAA,MACpC,UAAA,EAAY,KAAM,CAAA,OAAA,CAAQ,OAAQ,CAAA,UAAU,CAAI,GAAA,OAAA,CAAQ,UAAW,CAAA,GAAA,CAAI,MAAM,CAAA,GAAI,EAAC;AAAA,MAClF,QAAQ,OAAO,OAAA,CAAQ,MAAW,KAAA,QAAA,GAAW,QAAQ,MAAS,GAAA;AAAA,KAChE;AAAA,IACA,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,IAAK,CAAA,KAAK,CAAI,GAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,MAAM,CAAA,GAAI;AAAC,GAC/D;AACF;AACsB,eAAA,kBAAA,CAAmB,KAA4F,IAAkD,EAAA;AACrL,EAAA,MAAM,MAAM,MAAM,GAAA,CAAI,qBAAuB,EAAA,iBAAA,CAAkB,IAAI,CAAC,CAAA;AACpE,EAAI,IAAA,GAAA,CAAI,eAAe,KAAO,EAAA,MAAM,IAAI,KAAM,CAAA,GAAA,CAAI,SAAmB,4BAA4B,CAAA;AACjG,EAAM,MAAA,QAAA,GAAW,kBAAkB,GAAG,CAAA;AACtC,EAAA,IAAI,CAAC,QAAA,EAAgB,MAAA,IAAI,MAAM,kDAAkD,CAAA;AACjF,EAAO,OAAA,QAAA;AACT"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {jsxs,jsx,Fragment}from'react/jsx-runtime';import {useState}from'react';import {StyleSheet,View,Pressable,Text,ActivityIndicator}from'react-native';import {MaterialCommunityIcons}from'@expo/vector-icons';import {useSafeAreaInsets}from'react-native-safe-area-context';import {friendlyMediaError}from'../videoEditor/mediaActions.js';function CameraRecorderExperience({
|
|
2
|
+
onClose,
|
|
3
|
+
onPick,
|
|
4
|
+
onPlaced
|
|
5
|
+
}) {
|
|
6
|
+
const insets = useSafeAreaInsets();
|
|
7
|
+
const [busy, setBusy] = useState(false);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
const capture = async (source) => {
|
|
10
|
+
setBusy(true);
|
|
11
|
+
setError(null);
|
|
12
|
+
try {
|
|
13
|
+
const items = await onPick(source);
|
|
14
|
+
if (!items.length) {
|
|
15
|
+
setError("No recording captured.");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
onPlaced(items);
|
|
19
|
+
onClose();
|
|
20
|
+
} catch (err) {
|
|
21
|
+
setError(friendlyMediaError(err, "record"));
|
|
22
|
+
} finally {
|
|
23
|
+
setBusy(false);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles.root, {
|
|
27
|
+
paddingTop: insets.top + 8,
|
|
28
|
+
paddingBottom: insets.bottom + 16
|
|
29
|
+
}], children: [
|
|
30
|
+
/* @__PURE__ */ jsxs(View, { style: styles.head, children: [
|
|
31
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: onClose, hitSlop: 10, children: /* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "close", size: 22, color: "#e2e8f0" }) }),
|
|
32
|
+
/* @__PURE__ */ jsx(Text, { style: styles.title, children: "Record" }),
|
|
33
|
+
/* @__PURE__ */ jsx(View, { style: {
|
|
34
|
+
width: 22
|
|
35
|
+
} })
|
|
36
|
+
] }),
|
|
37
|
+
/* @__PURE__ */ jsx(Text, { style: styles.fine, children: "Capture camera video or a still for the board. Full desktop screen share stays on web." }),
|
|
38
|
+
/* @__PURE__ */ jsx(Pressable, { onPress: () => void capture("camera-video"), disabled: busy, style: [styles.cta, busy && styles.ctaOff], children: busy ? /* @__PURE__ */ jsx(ActivityIndicator, { color: "#0f172a" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "video-outline", size: 20, color: "#0f172a" }),
|
|
40
|
+
/* @__PURE__ */ jsx(Text, { style: styles.ctaLabel, children: "Record video" })
|
|
41
|
+
] }) }),
|
|
42
|
+
/* @__PURE__ */ jsxs(Pressable, { onPress: () => void capture("camera-photo"), disabled: busy, style: [styles.secondary, busy && styles.ctaOff], children: [
|
|
43
|
+
/* @__PURE__ */ jsx(MaterialCommunityIcons, { name: "camera-outline", size: 20, color: "#F7F7FA" }),
|
|
44
|
+
/* @__PURE__ */ jsx(Text, { style: styles.secondaryLabel, children: "Take photo" })
|
|
45
|
+
] }),
|
|
46
|
+
error ? /* @__PURE__ */ jsx(Text, { style: styles.error, children: error }) : null
|
|
47
|
+
] });
|
|
48
|
+
}
|
|
49
|
+
const styles = StyleSheet.create({
|
|
50
|
+
root: {
|
|
51
|
+
flex: 1,
|
|
52
|
+
backgroundColor: "#0B0B0E",
|
|
53
|
+
paddingHorizontal: 16
|
|
54
|
+
},
|
|
55
|
+
head: {
|
|
56
|
+
flexDirection: "row",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
justifyContent: "space-between",
|
|
59
|
+
marginBottom: 10
|
|
60
|
+
},
|
|
61
|
+
title: {
|
|
62
|
+
fontSize: 17,
|
|
63
|
+
fontWeight: "700",
|
|
64
|
+
color: "#F7F7FA"
|
|
65
|
+
},
|
|
66
|
+
fine: {
|
|
67
|
+
color: "#7A7A88",
|
|
68
|
+
fontSize: 12,
|
|
69
|
+
lineHeight: 16,
|
|
70
|
+
marginBottom: 20
|
|
71
|
+
},
|
|
72
|
+
cta: {
|
|
73
|
+
flexDirection: "row",
|
|
74
|
+
alignItems: "center",
|
|
75
|
+
justifyContent: "center",
|
|
76
|
+
gap: 8,
|
|
77
|
+
paddingVertical: 14,
|
|
78
|
+
borderRadius: 12,
|
|
79
|
+
backgroundColor: "#F7F7FA",
|
|
80
|
+
marginBottom: 10
|
|
81
|
+
},
|
|
82
|
+
secondary: {
|
|
83
|
+
flexDirection: "row",
|
|
84
|
+
alignItems: "center",
|
|
85
|
+
justifyContent: "center",
|
|
86
|
+
gap: 8,
|
|
87
|
+
paddingVertical: 14,
|
|
88
|
+
borderRadius: 12,
|
|
89
|
+
backgroundColor: "#1F1F24"
|
|
90
|
+
},
|
|
91
|
+
ctaOff: {
|
|
92
|
+
opacity: 0.45
|
|
93
|
+
},
|
|
94
|
+
ctaLabel: {
|
|
95
|
+
fontWeight: "700",
|
|
96
|
+
color: "#0f172a",
|
|
97
|
+
fontSize: 15
|
|
98
|
+
},
|
|
99
|
+
secondaryLabel: {
|
|
100
|
+
fontWeight: "600",
|
|
101
|
+
color: "#F7F7FA",
|
|
102
|
+
fontSize: 15
|
|
103
|
+
},
|
|
104
|
+
error: {
|
|
105
|
+
color: "#FECACA",
|
|
106
|
+
fontSize: 12,
|
|
107
|
+
marginTop: 14
|
|
108
|
+
}
|
|
109
|
+
});export{CameraRecorderExperience};//# sourceMappingURL=CameraRecorderExperience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CameraRecorderExperience.js","sources":["../../../../src/features/canvas/recorder/CameraRecorderExperience.tsx"],"sourcesContent":["/**\n * Phone twin of web ScreenRecorder — camera (+ optional mic) capture onto the board.\n * True display capture (getDisplayMedia / ReplayKit broadcast) stays system-level;\n * this ships the in-app recording studio path.\n */\nimport React, { useState } from 'react';\nimport { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';\nimport { MaterialCommunityIcons } from '@expo/vector-icons';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport type { CanvasItem } from '../canvasCore';\nimport type { MediaPickSource } from '../CanvasToolDock';\nimport { friendlyMediaError } from '../videoEditor/mediaActions';\n\nexport function CameraRecorderExperience({\n onClose,\n onPick,\n onPlaced,\n}: {\n onClose: () => void;\n onPick: (source: MediaPickSource) => Promise<CanvasItem[]>;\n onPlaced: (items: CanvasItem[]) => void;\n}) {\n const insets = useSafeAreaInsets();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const capture = async (source: MediaPickSource) => {\n setBusy(true);\n setError(null);\n try {\n const items = await onPick(source);\n if (!items.length) {\n setError('No recording captured.');\n return;\n }\n onPlaced(items);\n onClose();\n } catch (err: unknown) {\n setError(friendlyMediaError(err, 'record'));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <View style={[styles.root, { paddingTop: insets.top + 8, paddingBottom: insets.bottom + 16 }]}>\n <View style={styles.head}>\n <Pressable onPress={onClose} hitSlop={10}>\n <MaterialCommunityIcons name=\"close\" size={22} color=\"#e2e8f0\" />\n </Pressable>\n <Text style={styles.title}>Record</Text>\n <View style={{ width: 22 }} />\n </View>\n <Text style={styles.fine}>\n Capture camera video or a still for the board. Full desktop screen share stays on web.\n </Text>\n <Pressable\n onPress={() => void capture('camera-video')}\n disabled={busy}\n style={[styles.cta, busy && styles.ctaOff]}\n >\n {busy ? (\n <ActivityIndicator color=\"#0f172a\" />\n ) : (\n <>\n <MaterialCommunityIcons name=\"video-outline\" size={20} color=\"#0f172a\" />\n <Text style={styles.ctaLabel}>Record video</Text>\n </>\n )}\n </Pressable>\n <Pressable\n onPress={() => void capture('camera-photo')}\n disabled={busy}\n style={[styles.secondary, busy && styles.ctaOff]}\n >\n <MaterialCommunityIcons name=\"camera-outline\" size={20} color=\"#F7F7FA\" />\n <Text style={styles.secondaryLabel}>Take photo</Text>\n </Pressable>\n {error ? <Text style={styles.error}>{error}</Text> : null}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n root: { flex: 1, backgroundColor: '#0B0B0E', paddingHorizontal: 16 },\n head: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginBottom: 10,\n },\n title: { fontSize: 17, fontWeight: '700', color: '#F7F7FA' },\n fine: { color: '#7A7A88', fontSize: 12, lineHeight: 16, marginBottom: 20 },\n cta: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingVertical: 14,\n borderRadius: 12,\n backgroundColor: '#F7F7FA',\n marginBottom: 10,\n },\n secondary: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n paddingVertical: 14,\n borderRadius: 12,\n backgroundColor: '#1F1F24',\n },\n ctaOff: { opacity: 0.45 },\n ctaLabel: { fontWeight: '700', color: '#0f172a', fontSize: 15 },\n secondaryLabel: { fontWeight: '600', color: '#F7F7FA', fontSize: 15 },\n error: { color: '#FECACA', fontSize: 12, marginTop: 14 },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -18,4 +18,31 @@ function tokenExpiryMs(token) {
|
|
|
18
18
|
const claims = b64urlJson(parts[1]);
|
|
19
19
|
const exp = claims == null ? void 0 : claims.exp;
|
|
20
20
|
return typeof exp === "number" && Number.isFinite(exp) ? exp * 1e3 : null;
|
|
21
|
-
}
|
|
21
|
+
}
|
|
22
|
+
function sessionIdentityFromToken(token) {
|
|
23
|
+
if (!token) return {};
|
|
24
|
+
const parts = token.split(".");
|
|
25
|
+
if (parts.length < 2) return {};
|
|
26
|
+
const claims = b64urlJson(parts[1]);
|
|
27
|
+
if (!claims) return {};
|
|
28
|
+
const pick = (...keys) => {
|
|
29
|
+
for (const key of keys) {
|
|
30
|
+
const value = claims[key];
|
|
31
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
32
|
+
}
|
|
33
|
+
return void 0;
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
org: pick("orgName", "tenantId", "org", "organization"),
|
|
37
|
+
user: pick("email", "username", "name", "sub", "userId")
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function describeSession(token, indexUrl) {
|
|
41
|
+
const id = sessionIdentityFromToken(token);
|
|
42
|
+
const host = indexUrl.replace(/^https?:\/\//, "").split("/")[0];
|
|
43
|
+
const parts = [];
|
|
44
|
+
if (id.org) parts.push(`org ${id.org}`);
|
|
45
|
+
if (id.user) parts.push(id.user);
|
|
46
|
+
if (host) parts.push(host);
|
|
47
|
+
return parts.join(" \xB7 ");
|
|
48
|
+
}export{describeSession,sessionIdentityFromToken,tokenExpiryMs};//# sourceMappingURL=sessionIdentity.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionIdentity.js","sources":["../../../src/features/canvas/sessionIdentity.ts"],"sourcesContent":["/**\n * Best-effort identity readout from the surface session token - purely for\n * DISPLAY. The canvas index scopes rows by the token's tenant, so \"No\n * canvases yet\" is ambiguous without saying WHO the index was asked as: the\n * same account sees different boards per org, and a phone whose org\n * bootstrap picked a different default org reports empty while the web shows\n * boards. No verification here (display only) - the payload is decoded, not\n * trusted.\n */\nexport interface SessionIdentity {\n org?: string;\n user?: string;\n}\n\nfunction b64urlJson(segment: string): Record<string, unknown> | null {\n try {\n const b64 = segment.replace(/-/g, '+').replace(/_/g, '/');\n const pad = b64 + '='.repeat((4 - (b64.length % 4)) % 4);\n // atob exists in RN (Hermes) and the web; Buffer covers node/jest.\n const text =\n typeof atob === 'function'\n ? atob(pad)\n : // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n (\n require('buffer') as { Buffer: { from(s: string, e: string): { toString(e: string): string } } }\n ).Buffer.from(pad, 'base64').toString('utf8');\n return JSON.parse(text) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * The token's `exp` claim in epoch milliseconds, or null if it cannot be read.\n * Used to schedule a re-mint before the surface session expires. Display-only\n * decode (no verification), same as the identity readout.\n */\nexport function tokenExpiryMs(token: string | null | undefined): number | null {\n if (!token) return null;\n const parts = token.split('.');\n if (parts.length < 2) return null;\n const claims = b64urlJson(parts[1]);\n const exp = claims?.exp;\n return typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null;\n}\n\nexport function sessionIdentityFromToken(token: string | null | undefined): SessionIdentity {\n if (!token) return {};\n const parts = token.split('.');\n if (parts.length < 2) return {};\n const claims = b64urlJson(parts[1]);\n if (!claims) return {};\n const pick = (...keys: string[]): string | undefined => {\n for (const key of keys) {\n const value = claims[key];\n if (typeof value === 'string' && value.trim()) return value.trim();\n }\n return undefined;\n };\n return {\n org: pick('orgName', 'tenantId', 'org', 'organization'),\n user: pick('email', 'username', 'name', 'sub', 'userId'),\n };\n}\n\n/** \"org acme · user jo@x.com · index surface-index-backend.foo\" fine print. */\nexport function describeSession(token: string | null | undefined, indexUrl: string): string {\n const id = sessionIdentityFromToken(token);\n const host = indexUrl.replace(/^https?:\\/\\//, '').split('/')[0];\n const parts: string[] = [];\n if (id.org) parts.push(`org ${id.org}`);\n if (id.user) parts.push(id.user);\n if (host) parts.push(host);\n return parts.join(' · ');\n}\n"],"names":[],"mappings":"AAaA,SAAS,WAAW,OAAiD,EAAA;AACnE,EAAI,IAAA;AACF,IAAM,MAAA,GAAA,GAAM,QAAQ,OAAQ,CAAA,IAAA,EAAM,GAAG,CAAE,CAAA,OAAA,CAAQ,MAAM,GAAG,CAAA;AACxD,IAAM,MAAA,GAAA,GAAM,MAAM,GAAI,CAAA,MAAA,CAAA,CAAQ,IAAI,GAAI,CAAA,MAAA,GAAS,KAAK,CAAC,CAAA;AAErD,IAAA,MAAM,IAAO,GAAA,OAAO,IAAS,KAAA,UAAA,GAAa,KAAK,GAAG,CAAA;AAAA;AAAA,MAEjD,OAAA,CAAQ,QAAQ,CAMd,CAAA,MAAA,CAAO,KAAK,GAAK,EAAA,QAAQ,CAAE,CAAA,QAAA,CAAS,MAAM;AAAA,KAAA;AAC7C,IAAO,OAAA,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,GAChB,CAAA,OAAA,CAAA,EAAA;AACN,IAAO,OAAA,IAAA;AAAA;AAEX;AAOO,SAAS,cAAc,KAAiD,EAAA;AAC7E,EAAI,IAAA,CAAC,OAAc,OAAA,IAAA;AACnB,EAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAI,IAAA,KAAA,CAAM,MAAS,GAAA,CAAA,EAAU,OAAA,IAAA;AAC7B,EAAA,MAAM,MAAS,GAAA,UAAA,CAAW,KAAM,CAAA,CAAC,CAAC,CAAA;AAClC,EAAA,MAAM,MAAM,MAAQ,IAAA,IAAA,GAAA,MAAA,GAAA,MAAA,CAAA,GAAA;AACpB,EAAO,OAAA,OAAO,QAAQ,QAAY,IAAA,MAAA,CAAO,SAAS,GAAG,CAAA,GAAI,MAAM,GAAO,GAAA,IAAA;AACxE"}
|
|
1
|
+
{"version":3,"file":"sessionIdentity.js","sources":["../../../src/features/canvas/sessionIdentity.ts"],"sourcesContent":["/**\n * Best-effort identity readout from the surface session token - purely for\n * DISPLAY. The canvas index scopes rows by the token's tenant, so \"No\n * canvases yet\" is ambiguous without saying WHO the index was asked as: the\n * same account sees different boards per org, and a phone whose org\n * bootstrap picked a different default org reports empty while the web shows\n * boards. No verification here (display only) - the payload is decoded, not\n * trusted.\n */\nexport interface SessionIdentity {\n org?: string;\n user?: string;\n}\n\nfunction b64urlJson(segment: string): Record<string, unknown> | null {\n try {\n const b64 = segment.replace(/-/g, '+').replace(/_/g, '/');\n const pad = b64 + '='.repeat((4 - (b64.length % 4)) % 4);\n // atob exists in RN (Hermes) and the web; Buffer covers node/jest.\n const text =\n typeof atob === 'function'\n ? atob(pad)\n : // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require\n (\n require('buffer') as { Buffer: { from(s: string, e: string): { toString(e: string): string } } }\n ).Buffer.from(pad, 'base64').toString('utf8');\n return JSON.parse(text) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * The token's `exp` claim in epoch milliseconds, or null if it cannot be read.\n * Used to schedule a re-mint before the surface session expires. Display-only\n * decode (no verification), same as the identity readout.\n */\nexport function tokenExpiryMs(token: string | null | undefined): number | null {\n if (!token) return null;\n const parts = token.split('.');\n if (parts.length < 2) return null;\n const claims = b64urlJson(parts[1]);\n const exp = claims?.exp;\n return typeof exp === 'number' && Number.isFinite(exp) ? exp * 1000 : null;\n}\n\nexport function sessionIdentityFromToken(token: string | null | undefined): SessionIdentity {\n if (!token) return {};\n const parts = token.split('.');\n if (parts.length < 2) return {};\n const claims = b64urlJson(parts[1]);\n if (!claims) return {};\n const pick = (...keys: string[]): string | undefined => {\n for (const key of keys) {\n const value = claims[key];\n if (typeof value === 'string' && value.trim()) return value.trim();\n }\n return undefined;\n };\n return {\n org: pick('orgName', 'tenantId', 'org', 'organization'),\n user: pick('email', 'username', 'name', 'sub', 'userId'),\n };\n}\n\n/** \"org acme · user jo@x.com · index surface-index-backend.foo\" fine print. */\nexport function describeSession(token: string | null | undefined, indexUrl: string): string {\n const id = sessionIdentityFromToken(token);\n const host = indexUrl.replace(/^https?:\\/\\//, '').split('/')[0];\n const parts: string[] = [];\n if (id.org) parts.push(`org ${id.org}`);\n if (id.user) parts.push(id.user);\n if (host) parts.push(host);\n return parts.join(' · ');\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {jsx}from'react/jsx-runtime';import {useRef,useMemo}from'react';import {StyleSheet,View}from'react-native';import {useWebViewRetention}from'../../../hooks/useWebViewRetention.js';function loadWebView() {
|
|
2
|
+
try {
|
|
3
|
+
return require("react-native-webview").WebView;
|
|
4
|
+
} catch (e) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function esc(value) {
|
|
9
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
10
|
+
}
|
|
11
|
+
function setViewportHtml(opts) {
|
|
12
|
+
const world = opts.worldUrl ? esc(opts.worldUrl) : "";
|
|
13
|
+
const prop = opts.meshOrImageUrl ? esc(opts.meshOrImageUrl) : "";
|
|
14
|
+
const cam = opts.camera;
|
|
15
|
+
return `<!DOCTYPE html><html><head>
|
|
16
|
+
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
|
17
|
+
<style>html,body{margin:0;height:100%;background:#0b0b0e;overflow:hidden}canvas{display:block;width:100%;height:100%}</style>
|
|
18
|
+
</head><body>
|
|
19
|
+
<script type="importmap">{"imports":{"three":"https://unpkg.com/three@0.160.0/build/three.module.js","three/addons/":"https://unpkg.com/three@0.160.0/examples/jsm/"}}<\/script>
|
|
20
|
+
<script type="module">
|
|
21
|
+
import * as THREE from 'three';
|
|
22
|
+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
23
|
+
const worldUrl=${JSON.stringify(world)};
|
|
24
|
+
const propUrl=${JSON.stringify(prop)};
|
|
25
|
+
const scene=new THREE.Scene();
|
|
26
|
+
scene.background=new THREE.Color(0x1a1a1e);
|
|
27
|
+
const camera=new THREE.PerspectiveCamera(${cam.fov},1,0.1,200);
|
|
28
|
+
camera.position.set(${cam.position.x},${cam.position.y},${cam.position.z});
|
|
29
|
+
/* preserveDrawingBuffer stays FALSE: it doubles the framebuffer and stops the
|
|
30
|
+
driver discarding it after compositing. capture() re-renders synchronously
|
|
31
|
+
immediately before toDataURL(), which reads valid pixels without it. */
|
|
32
|
+
const renderer=new THREE.WebGLRenderer({antialias:true,preserveDrawingBuffer:false});
|
|
33
|
+
renderer.setPixelRatio(Math.min(devicePixelRatio,2));
|
|
34
|
+
document.body.appendChild(renderer.domElement);
|
|
35
|
+
const controls=new OrbitControls(camera,renderer.domElement);
|
|
36
|
+
controls.target.set(${cam.target.x},${cam.target.y},${cam.target.z});
|
|
37
|
+
controls.enableDamping=true;
|
|
38
|
+
const light=new THREE.DirectionalLight(0xffffff,1.1);
|
|
39
|
+
light.position.set(2,4,3);scene.add(light);scene.add(new THREE.AmbientLight(0xffffff,0.45));
|
|
40
|
+
const ground=new THREE.Mesh(new THREE.CircleGeometry(4,48),new THREE.MeshStandardMaterial({color:0x2a2a30,roughness:0.9}));
|
|
41
|
+
ground.rotation.x=-Math.PI/2;scene.add(ground);
|
|
42
|
+
function fit(){const w=innerWidth,h=innerHeight;camera.aspect=w/Math.max(1,h);camera.updateProjectionMatrix();renderer.setSize(w,h,false);}
|
|
43
|
+
addEventListener('resize',fit);fit();
|
|
44
|
+
function post(type,payload){window.ReactNativeWebView&&window.ReactNativeWebView.postMessage(JSON.stringify({type,...payload}));}
|
|
45
|
+
if(worldUrl){new THREE.TextureLoader().load(worldUrl,tex=>{tex.mapping=THREE.EquirectangularReflectionMapping;scene.background=tex;scene.environment=tex;});}
|
|
46
|
+
if(propUrl){
|
|
47
|
+
if(/\\.glb($|\\?)/i.test(propUrl)){
|
|
48
|
+
import('three/addons/loaders/GLTFLoader.js').then(({GLTFLoader})=>{
|
|
49
|
+
new GLTFLoader().load(propUrl,g=>{const root=g.scene;root.position.set(0,0,0);scene.add(root);});
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
new THREE.TextureLoader().load(propUrl,tex=>{
|
|
53
|
+
const aspect=tex.image.width/Math.max(1,tex.image.height);
|
|
54
|
+
const w=1.2,h=w/aspect;
|
|
55
|
+
const mesh=new THREE.Mesh(new THREE.PlaneGeometry(w,h),new THREE.MeshBasicMaterial({map:tex,transparent:true}));
|
|
56
|
+
mesh.position.set(0,h/2,0);scene.add(mesh);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function tick(){controls.update();renderer.render(scene,camera);requestAnimationFrame(tick);}tick();
|
|
61
|
+
function capture(){renderer.render(scene,camera);return renderer.domElement.toDataURL('image/jpeg',0.92);}
|
|
62
|
+
addEventListener('message',(ev)=>{
|
|
63
|
+
let msg={};try{msg=JSON.parse(ev.data);}catch(e){return;}
|
|
64
|
+
if(msg.type==='capture'){post('frame',{dataUrl:capture()});}
|
|
65
|
+
if(msg.type==='setCamera'&&msg.camera){
|
|
66
|
+
const c=msg.camera;camera.position.set(c.position.x,c.position.y,c.position.z);
|
|
67
|
+
controls.target.set(c.target.x,c.target.y,c.target.z);controls.update();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
document.addEventListener('message',(ev)=>{
|
|
71
|
+
let msg={};try{msg=JSON.parse(ev.data);}catch(e){return;}
|
|
72
|
+
if(msg.type==='capture'){post('frame',{dataUrl:capture()});}
|
|
73
|
+
});
|
|
74
|
+
post('ready',{});
|
|
75
|
+
<\/script></body></html>`;
|
|
76
|
+
}
|
|
77
|
+
function SetViewportWebView({
|
|
78
|
+
worldUrl,
|
|
79
|
+
propUrl,
|
|
80
|
+
camera,
|
|
81
|
+
onFrame,
|
|
82
|
+
webRef
|
|
83
|
+
}) {
|
|
84
|
+
const WebView = loadWebView();
|
|
85
|
+
const ref = useRef(null);
|
|
86
|
+
const html = useMemo(() => setViewportHtml({
|
|
87
|
+
worldUrl,
|
|
88
|
+
meshOrImageUrl: propUrl,
|
|
89
|
+
camera
|
|
90
|
+
}), [worldUrl, propUrl, camera]);
|
|
91
|
+
const shouldRender = useWebViewRetention({
|
|
92
|
+
releaseOnBlur: true
|
|
93
|
+
});
|
|
94
|
+
if (webRef) {
|
|
95
|
+
webRef.current = {
|
|
96
|
+
capture: () => {
|
|
97
|
+
var _a, _b;
|
|
98
|
+
(_b = (_a = ref.current) == null ? void 0 : _a.injectJavaScript) == null ? void 0 : _b.call(_a, `window.dispatchEvent(new MessageEvent('message',{data:JSON.stringify({type:'capture'})}));true;`);
|
|
99
|
+
},
|
|
100
|
+
setCamera: (c) => {
|
|
101
|
+
var _a, _b;
|
|
102
|
+
(_b = (_a = ref.current) == null ? void 0 : _a.injectJavaScript) == null ? void 0 : _b.call(_a, `window.dispatchEvent(new MessageEvent('message',{data:${JSON.stringify(JSON.stringify({
|
|
103
|
+
type: "setCamera",
|
|
104
|
+
camera: c
|
|
105
|
+
}))}}));true;`);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (!WebView || !shouldRender) return /* @__PURE__ */ jsx(View, { style: styles.fallback });
|
|
110
|
+
return /* @__PURE__ */ jsx(WebView, { ref: (node) => {
|
|
111
|
+
ref.current = node;
|
|
112
|
+
}, originWhitelist: ["*"], source: {
|
|
113
|
+
html
|
|
114
|
+
}, style: styles.view, onMessage: (event) => {
|
|
115
|
+
try {
|
|
116
|
+
const msg = JSON.parse(event.nativeEvent.data);
|
|
117
|
+
if (msg.type === "frame" && msg.dataUrl) onFrame == null ? void 0 : onFrame(msg.dataUrl);
|
|
118
|
+
} catch (e) {
|
|
119
|
+
}
|
|
120
|
+
}, allowFileAccess: true, mixedContentMode: "always" });
|
|
121
|
+
}
|
|
122
|
+
const styles = StyleSheet.create({
|
|
123
|
+
view: {
|
|
124
|
+
flex: 1,
|
|
125
|
+
backgroundColor: "#0B0B0E",
|
|
126
|
+
minHeight: 220
|
|
127
|
+
},
|
|
128
|
+
fallback: {
|
|
129
|
+
flex: 1,
|
|
130
|
+
minHeight: 220,
|
|
131
|
+
backgroundColor: "#1F1F24"
|
|
132
|
+
}
|
|
133
|
+
});export{SetViewportWebView};//# sourceMappingURL=SetViewportWebView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SetViewportWebView.js","sources":["../../../../src/features/canvas/set/SetViewportWebView.tsx"],"sourcesContent":["/**\n * Three.js set viewport in a WebView — orbit + still capture for native Set studio.\n * Full desktop SetEditor gizmos stay on web; this ships the interactive viewport.\n */\nimport React, { useMemo, useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport type { SetCamera } from '../set/setProject';\nimport { useWebViewRetention } from '../../../hooks/useWebViewRetention';\n\nfunction loadWebView(): React.ComponentType<Record<string, unknown>> | null {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports, global-require\n return require('react-native-webview').WebView as React.ComponentType<Record<string, unknown>>;\n } catch {\n return null;\n }\n}\n\nfunction esc(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\nfunction setViewportHtml(opts: { worldUrl?: string; meshOrImageUrl?: string; camera: SetCamera }): string {\n const world = opts.worldUrl ? esc(opts.worldUrl) : '';\n const prop = opts.meshOrImageUrl ? esc(opts.meshOrImageUrl) : '';\n const cam = opts.camera;\n return `<!DOCTYPE html><html><head>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no\">\n<style>html,body{margin:0;height:100%;background:#0b0b0e;overflow:hidden}canvas{display:block;width:100%;height:100%}</style>\n</head><body>\n<script type=\"importmap\">{\"imports\":{\"three\":\"https://unpkg.com/three@0.160.0/build/three.module.js\",\"three/addons/\":\"https://unpkg.com/three@0.160.0/examples/jsm/\"}}</script>\n<script type=\"module\">\nimport * as THREE from 'three';\nimport { OrbitControls } from 'three/addons/controls/OrbitControls.js';\nconst worldUrl=${JSON.stringify(world)};\nconst propUrl=${JSON.stringify(prop)};\nconst scene=new THREE.Scene();\nscene.background=new THREE.Color(0x1a1a1e);\nconst camera=new THREE.PerspectiveCamera(${cam.fov},1,0.1,200);\ncamera.position.set(${cam.position.x},${cam.position.y},${cam.position.z});\n/* preserveDrawingBuffer stays FALSE: it doubles the framebuffer and stops the\n driver discarding it after compositing. capture() re-renders synchronously\n immediately before toDataURL(), which reads valid pixels without it. */\nconst renderer=new THREE.WebGLRenderer({antialias:true,preserveDrawingBuffer:false});\nrenderer.setPixelRatio(Math.min(devicePixelRatio,2));\ndocument.body.appendChild(renderer.domElement);\nconst controls=new OrbitControls(camera,renderer.domElement);\ncontrols.target.set(${cam.target.x},${cam.target.y},${cam.target.z});\ncontrols.enableDamping=true;\nconst light=new THREE.DirectionalLight(0xffffff,1.1);\nlight.position.set(2,4,3);scene.add(light);scene.add(new THREE.AmbientLight(0xffffff,0.45));\nconst ground=new THREE.Mesh(new THREE.CircleGeometry(4,48),new THREE.MeshStandardMaterial({color:0x2a2a30,roughness:0.9}));\nground.rotation.x=-Math.PI/2;scene.add(ground);\nfunction fit(){const w=innerWidth,h=innerHeight;camera.aspect=w/Math.max(1,h);camera.updateProjectionMatrix();renderer.setSize(w,h,false);}\naddEventListener('resize',fit);fit();\nfunction post(type,payload){window.ReactNativeWebView&&window.ReactNativeWebView.postMessage(JSON.stringify({type,...payload}));}\nif(worldUrl){new THREE.TextureLoader().load(worldUrl,tex=>{tex.mapping=THREE.EquirectangularReflectionMapping;scene.background=tex;scene.environment=tex;});}\nif(propUrl){\n if(/\\\\.glb($|\\\\?)/i.test(propUrl)){\n import('three/addons/loaders/GLTFLoader.js').then(({GLTFLoader})=>{\n new GLTFLoader().load(propUrl,g=>{const root=g.scene;root.position.set(0,0,0);scene.add(root);});\n });\n } else {\n new THREE.TextureLoader().load(propUrl,tex=>{\n const aspect=tex.image.width/Math.max(1,tex.image.height);\n const w=1.2,h=w/aspect;\n const mesh=new THREE.Mesh(new THREE.PlaneGeometry(w,h),new THREE.MeshBasicMaterial({map:tex,transparent:true}));\n mesh.position.set(0,h/2,0);scene.add(mesh);\n });\n }\n}\nfunction tick(){controls.update();renderer.render(scene,camera);requestAnimationFrame(tick);}tick();\nfunction capture(){renderer.render(scene,camera);return renderer.domElement.toDataURL('image/jpeg',0.92);}\naddEventListener('message',(ev)=>{\n let msg={};try{msg=JSON.parse(ev.data);}catch(e){return;}\n if(msg.type==='capture'){post('frame',{dataUrl:capture()});}\n if(msg.type==='setCamera'&&msg.camera){\n const c=msg.camera;camera.position.set(c.position.x,c.position.y,c.position.z);\n controls.target.set(c.target.x,c.target.y,c.target.z);controls.update();\n }\n});\ndocument.addEventListener('message',(ev)=>{\n let msg={};try{msg=JSON.parse(ev.data);}catch(e){return;}\n if(msg.type==='capture'){post('frame',{dataUrl:capture()});}\n});\npost('ready',{});\n</script></body></html>`;\n}\n\nexport function SetViewportWebView({\n worldUrl,\n propUrl,\n camera,\n onFrame,\n webRef,\n}: {\n worldUrl?: string;\n propUrl?: string;\n camera: SetCamera;\n onFrame?: (dataUrl: string) => void;\n webRef?: React.MutableRefObject<{ capture: () => void; setCamera: (c: SetCamera) => void } | null>;\n}) {\n const WebView = loadWebView();\n const ref = useRef<{ injectJavaScript?: (js: string) => void } | null>(null);\n const html = useMemo(\n () => setViewportHtml({ worldUrl, meshOrImageUrl: propUrl, camera }),\n [worldUrl, propUrl, camera],\n );\n /**\n * A live WebGL context with its own three.js runtime is the single most\n * expensive thing this app can hold. It rebuilds from `html` on return, so\n * release it once the viewport is off-screen or the app is backgrounded.\n */\n const shouldRender = useWebViewRetention({ releaseOnBlur: true });\n\n if (webRef) {\n webRef.current = {\n capture: () => {\n ref.current?.injectJavaScript?.(\n `window.dispatchEvent(new MessageEvent('message',{data:JSON.stringify({type:'capture'})}));true;`,\n );\n },\n setCamera: (c) => {\n ref.current?.injectJavaScript?.(\n `window.dispatchEvent(new MessageEvent('message',{data:${JSON.stringify(\n JSON.stringify({ type: 'setCamera', camera: c }),\n )}}));true;`,\n );\n },\n };\n }\n\n if (!WebView || !shouldRender) return <View style={styles.fallback} />;\n\n return (\n <WebView\n ref={(node: { injectJavaScript?: (js: string) => void } | null) => {\n ref.current = node;\n }}\n originWhitelist={['*']}\n source={{ html }}\n style={styles.view}\n onMessage={(event: { nativeEvent: { data: string } }) => {\n try {\n const msg = JSON.parse(event.nativeEvent.data) as { type?: string; dataUrl?: string };\n if (msg.type === 'frame' && msg.dataUrl) onFrame?.(msg.dataUrl);\n } catch {\n /* ignore */\n }\n }}\n allowFileAccess\n mixedContentMode=\"always\"\n />\n );\n}\n\nconst styles = StyleSheet.create({\n view: { flex: 1, backgroundColor: '#0B0B0E', minHeight: 220 },\n fallback: { flex: 1, minHeight: 220, backgroundColor: '#1F1F24' },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
const MOVES = [{
|
|
21
|
+
kind: "orbit-left",
|
|
22
|
+
label: "Orbit left",
|
|
23
|
+
hint: "Arc around the subject, anticlockwise",
|
|
24
|
+
amount: 45,
|
|
25
|
+
unit: "deg"
|
|
26
|
+
}, {
|
|
27
|
+
kind: "orbit-right",
|
|
28
|
+
label: "Orbit right",
|
|
29
|
+
hint: "Arc around the subject, clockwise",
|
|
30
|
+
amount: 45,
|
|
31
|
+
unit: "deg"
|
|
32
|
+
}, {
|
|
33
|
+
kind: "turntable",
|
|
34
|
+
label: "Turntable",
|
|
35
|
+
hint: "A full circle around the subject - the product shot",
|
|
36
|
+
amount: 360,
|
|
37
|
+
unit: "deg"
|
|
38
|
+
}, {
|
|
39
|
+
kind: "dolly-in",
|
|
40
|
+
label: "Push in",
|
|
41
|
+
hint: "Travel towards the subject on the lens axis",
|
|
42
|
+
amount: 1.2,
|
|
43
|
+
unit: "m"
|
|
44
|
+
}, {
|
|
45
|
+
kind: "dolly-out",
|
|
46
|
+
label: "Pull back",
|
|
47
|
+
hint: "Travel away, opening the frame up",
|
|
48
|
+
amount: 1.2,
|
|
49
|
+
unit: "m"
|
|
50
|
+
}, {
|
|
51
|
+
kind: "truck-left",
|
|
52
|
+
label: "Truck left",
|
|
53
|
+
hint: "Slide sideways, keeping the subject framed",
|
|
54
|
+
amount: 1,
|
|
55
|
+
unit: "m"
|
|
56
|
+
}, {
|
|
57
|
+
kind: "truck-right",
|
|
58
|
+
label: "Truck right",
|
|
59
|
+
hint: "Slide the other way",
|
|
60
|
+
amount: 1,
|
|
61
|
+
unit: "m"
|
|
62
|
+
}, {
|
|
63
|
+
kind: "crane-up",
|
|
64
|
+
label: "Crane up",
|
|
65
|
+
hint: "Rise, looking down as you go",
|
|
66
|
+
amount: 1,
|
|
67
|
+
unit: "m"
|
|
68
|
+
}, {
|
|
69
|
+
kind: "crane-down",
|
|
70
|
+
label: "Crane down",
|
|
71
|
+
hint: "Drop towards the floor",
|
|
72
|
+
amount: 1,
|
|
73
|
+
unit: "m"
|
|
74
|
+
}];
|
|
75
|
+
const findMove = (kind) => {
|
|
76
|
+
var _a;
|
|
77
|
+
return (_a = MOVES.find((move) => move.kind === kind)) != null ? _a : MOVES[0];
|
|
78
|
+
};
|
|
79
|
+
const easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
80
|
+
const add = (a, b) => ({
|
|
81
|
+
x: a.x + b.x,
|
|
82
|
+
y: a.y + b.y,
|
|
83
|
+
z: a.z + b.z
|
|
84
|
+
});
|
|
85
|
+
const sub = (a, b) => ({
|
|
86
|
+
x: a.x - b.x,
|
|
87
|
+
y: a.y - b.y,
|
|
88
|
+
z: a.z - b.z
|
|
89
|
+
});
|
|
90
|
+
const scale = (a, k) => ({
|
|
91
|
+
x: a.x * k,
|
|
92
|
+
y: a.y * k,
|
|
93
|
+
z: a.z * k
|
|
94
|
+
});
|
|
95
|
+
const length = (a) => Math.hypot(a.x, a.y, a.z);
|
|
96
|
+
const normalise = (a) => {
|
|
97
|
+
const len = length(a);
|
|
98
|
+
return len > 1e-6 ? scale(a, 1 / len) : {
|
|
99
|
+
x: 0,
|
|
100
|
+
y: 0,
|
|
101
|
+
z: 1
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
function rotateY(v, radians) {
|
|
105
|
+
const cos = Math.cos(radians);
|
|
106
|
+
const sin = Math.sin(radians);
|
|
107
|
+
return {
|
|
108
|
+
x: v.x * cos + v.z * sin,
|
|
109
|
+
y: v.y,
|
|
110
|
+
z: -v.x * sin + v.z * cos
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const round = (v) => ({
|
|
114
|
+
x: Math.round(v.x * 1e4) / 1e4,
|
|
115
|
+
y: Math.round(v.y * 1e4) / 1e4,
|
|
116
|
+
z: Math.round(v.z * 1e4) / 1e4
|
|
117
|
+
});
|
|
118
|
+
function cameraPath(start, options) {
|
|
119
|
+
var _a;
|
|
120
|
+
const {
|
|
121
|
+
move,
|
|
122
|
+
frames
|
|
123
|
+
} = options;
|
|
124
|
+
const count = Math.max(1, Math.floor(frames));
|
|
125
|
+
const def = findMove(move);
|
|
126
|
+
const amount = (_a = options.amount) != null ? _a : def.amount;
|
|
127
|
+
if (count === 1) return [__spreadValues({}, start)];
|
|
128
|
+
const loops = move === "turntable";
|
|
129
|
+
const offset = sub(start.position, start.target);
|
|
130
|
+
const forward = normalise(sub(start.target, start.position));
|
|
131
|
+
const right = normalise({
|
|
132
|
+
x: forward.z,
|
|
133
|
+
y: 0,
|
|
134
|
+
z: -forward.x
|
|
135
|
+
});
|
|
136
|
+
return Array.from({
|
|
137
|
+
length: count
|
|
138
|
+
}, (_, index) => {
|
|
139
|
+
const raw = loops ? index / count : index / (count - 1);
|
|
140
|
+
const t = loops ? raw : easeInOut(raw);
|
|
141
|
+
const camera = {
|
|
142
|
+
position: __spreadValues({}, start.position),
|
|
143
|
+
target: __spreadValues({}, start.target),
|
|
144
|
+
fov: start.fov
|
|
145
|
+
};
|
|
146
|
+
switch (move) {
|
|
147
|
+
case "orbit-left":
|
|
148
|
+
case "orbit-right":
|
|
149
|
+
case "turntable": {
|
|
150
|
+
const direction = move === "orbit-right" ? -1 : 1;
|
|
151
|
+
const radians = amount * Math.PI / 180 * t * direction;
|
|
152
|
+
camera.position = add(start.target, rotateY(offset, radians));
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
case "dolly-in":
|
|
156
|
+
case "dolly-out": {
|
|
157
|
+
const direction = move === "dolly-in" ? 1 : -1;
|
|
158
|
+
const travel = scale(forward, amount * t * direction);
|
|
159
|
+
camera.position = add(start.position, travel);
|
|
160
|
+
const remaining = length(sub(start.target, camera.position));
|
|
161
|
+
if (direction === 1 && remaining < 0.35) {
|
|
162
|
+
camera.position = add(start.target, scale(forward, -0.35));
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case "truck-left":
|
|
167
|
+
case "truck-right": {
|
|
168
|
+
const direction = move === "truck-right" ? 1 : -1;
|
|
169
|
+
const travel = scale(right, amount * t * direction);
|
|
170
|
+
camera.position = add(start.position, travel);
|
|
171
|
+
camera.target = add(start.target, travel);
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case "crane-up":
|
|
175
|
+
case "crane-down": {
|
|
176
|
+
const direction = move === "crane-up" ? 1 : -1;
|
|
177
|
+
const rise = amount * t * direction;
|
|
178
|
+
camera.position = __spreadProps(__spreadValues({}, start.position), {
|
|
179
|
+
y: start.position.y + rise
|
|
180
|
+
});
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
position: round(camera.position),
|
|
186
|
+
target: round(camera.target),
|
|
187
|
+
fov: camera.fov
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const MAX_MOVE_FRAMES = 180;
|
|
192
|
+
function frameCount(durationSec, fps) {
|
|
193
|
+
return Math.max(2, Math.min(MAX_MOVE_FRAMES, Math.round(durationSec * fps)));
|
|
194
|
+
}export{MAX_MOVE_FRAMES,MOVES,cameraPath,easeInOut,findMove,frameCount};//# sourceMappingURL=cameraPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cameraPath.js","sources":["../../../../src/features/canvas/set/cameraPath.ts"],"sourcesContent":["/**\n * Camera moves: the difference between a 3D still and a 3D SHOT.\n *\n * A move is a list of camera positions, one per frame, which the stage renders\n * and the connector composes into a clip. Everything here is pure - no three,\n * no DOM - because the interesting part is the geometry, and geometry is\n * exactly the thing that is easy to get subtly wrong and hard to see in a\n * moving picture.\n *\n * Moves are named the way a crew names them. \"Orbit\" turns around the subject,\n * \"dolly\" travels on the lens axis, \"truck\" slides sideways, \"crane\" changes\n * height. A push-in is a dolly, not a zoom: zooming flattens the perspective\n * and travelling does not, and that difference is the whole reason to block a\n * shot in 3D rather than crop a still.\n */\nimport type { SetCamera, Vec3 } from './setProject';\n\nexport type MoveKind =\n | 'orbit-left'\n | 'orbit-right'\n | 'turntable'\n | 'dolly-in'\n | 'dolly-out'\n | 'truck-left'\n | 'truck-right'\n | 'crane-up'\n | 'crane-down';\n\nexport interface MoveDef {\n kind: MoveKind;\n label: string;\n /** One line saying what the camera DOES, in a crew's words. */\n hint: string;\n /** Default amount: degrees for orbits, metres for the rest. */\n amount: number;\n unit: 'deg' | 'm';\n}\n\nexport const MOVES: readonly MoveDef[] = [\n { kind: 'orbit-left', label: 'Orbit left', hint: 'Arc around the subject, anticlockwise', amount: 45, unit: 'deg' },\n { kind: 'orbit-right', label: 'Orbit right', hint: 'Arc around the subject, clockwise', amount: 45, unit: 'deg' },\n {\n kind: 'turntable',\n label: 'Turntable',\n hint: 'A full circle around the subject - the product shot',\n amount: 360,\n unit: 'deg',\n },\n { kind: 'dolly-in', label: 'Push in', hint: 'Travel towards the subject on the lens axis', amount: 1.2, unit: 'm' },\n { kind: 'dolly-out', label: 'Pull back', hint: 'Travel away, opening the frame up', amount: 1.2, unit: 'm' },\n {\n kind: 'truck-left',\n label: 'Truck left',\n hint: 'Slide sideways, keeping the subject framed',\n amount: 1,\n unit: 'm',\n },\n { kind: 'truck-right', label: 'Truck right', hint: 'Slide the other way', amount: 1, unit: 'm' },\n { kind: 'crane-up', label: 'Crane up', hint: 'Rise, looking down as you go', amount: 1, unit: 'm' },\n { kind: 'crane-down', label: 'Crane down', hint: 'Drop towards the floor', amount: 1, unit: 'm' },\n];\n\nexport const findMove = (kind: MoveKind): MoveDef => MOVES.find((move) => move.kind === kind) ?? MOVES[0];\n\n/**\n * Ease in and out.\n *\n * A linear camera move starts and stops dead, which reads as a glitch rather\n * than as a camera. The exception is the turntable: it loops, and easing a\n * loop puts a visible hitch at the seam.\n */\nexport const easeInOut = (t: number): number => (t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2);\n\nconst add = (a: Vec3, b: Vec3): Vec3 => ({ x: a.x + b.x, y: a.y + b.y, z: a.z + b.z });\nconst sub = (a: Vec3, b: Vec3): Vec3 => ({ x: a.x - b.x, y: a.y - b.y, z: a.z - b.z });\nconst scale = (a: Vec3, k: number): Vec3 => ({ x: a.x * k, y: a.y * k, z: a.z * k });\nconst length = (a: Vec3): number => Math.hypot(a.x, a.y, a.z);\n\nconst normalise = (a: Vec3): Vec3 => {\n const len = length(a);\n return len > 1e-6 ? scale(a, 1 / len) : { x: 0, y: 0, z: 1 };\n};\n\n/** Rotate a vector around the Y axis. Orbits are horizontal; a camera that rolls is a mistake, not a move. */\nfunction rotateY(v: Vec3, radians: number): Vec3 {\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return { x: v.x * cos + v.z * sin, y: v.y, z: -v.x * sin + v.z * cos };\n}\n\nconst round = (v: Vec3): Vec3 => ({\n x: Math.round(v.x * 10000) / 10000,\n y: Math.round(v.y * 10000) / 10000,\n z: Math.round(v.z * 10000) / 10000,\n});\n\nexport interface MovePathOptions {\n move: MoveKind;\n /** Degrees for an orbit, metres for a travelling move. */\n amount?: number;\n frames: number;\n}\n\n/**\n * The camera at each frame of a move.\n *\n * Always returns `frames` cameras, the first being exactly where the camera is\n * now - so the clip starts on the frame the user composed, not near it.\n */\nexport function cameraPath(start: SetCamera, options: MovePathOptions): SetCamera[] {\n const { move, frames } = options;\n const count = Math.max(1, Math.floor(frames));\n const def = findMove(move);\n const amount = options.amount ?? def.amount;\n if (count === 1) return [{ ...start }];\n\n // A turntable comes back to where it started, so it must NOT repeat the\n // first frame at the end - that is a duplicate frame on a loop - and it\n // must not ease, or the loop hitches at the seam.\n const loops = move === 'turntable';\n const offset = sub(start.position, start.target);\n const forward = normalise(sub(start.target, start.position));\n const right = normalise({ x: forward.z, y: 0, z: -forward.x });\n\n return Array.from({ length: count }, (_, index) => {\n const raw = loops ? index / count : index / (count - 1);\n const t = loops ? raw : easeInOut(raw);\n const camera: SetCamera = { position: { ...start.position }, target: { ...start.target }, fov: start.fov };\n\n switch (move) {\n case 'orbit-left':\n case 'orbit-right':\n case 'turntable': {\n const direction = move === 'orbit-right' ? -1 : 1;\n const radians = ((amount * Math.PI) / 180) * t * direction;\n camera.position = add(start.target, rotateY(offset, radians));\n break;\n }\n case 'dolly-in':\n case 'dolly-out': {\n const direction = move === 'dolly-in' ? 1 : -1;\n const travel = scale(forward, amount * t * direction);\n camera.position = add(start.position, travel);\n // Stop short of the target on a push-in: travelling THROUGH the\n // thing you are looking at inverts the shot for the last frames.\n const remaining = length(sub(start.target, camera.position));\n if (direction === 1 && remaining < 0.35) {\n camera.position = add(start.target, scale(forward, -0.35));\n }\n break;\n }\n case 'truck-left':\n case 'truck-right': {\n const direction = move === 'truck-right' ? 1 : -1;\n const travel = scale(right, amount * t * direction);\n // The target travels too: trucking is a slide, not a pan, and a\n // fixed target would swing the lens round as the camera passes.\n camera.position = add(start.position, travel);\n camera.target = add(start.target, travel);\n break;\n }\n case 'crane-up':\n case 'crane-down': {\n const direction = move === 'crane-up' ? 1 : -1;\n const rise = amount * t * direction;\n camera.position = { ...start.position, y: start.position.y + rise };\n // The target stays put, so the lens tilts to hold the subject -\n // which is what a crane actually looks like.\n break;\n }\n default:\n break;\n }\n\n return { position: round(camera.position), target: round(camera.target), fov: camera.fov };\n });\n}\n\n/** Frame count for a duration, clamped to what is sane to render and upload. */\nexport const MAX_MOVE_FRAMES = 180;\n\nexport function frameCount(durationSec: number, fps: number): number {\n return Math.max(2, Math.min(MAX_MOVE_FRAMES, Math.round(durationSec * fps)));\n}\n"],"names":[],"mappings":"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"}
|