@dailies-studio/shot-editor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.vite/manifest.json +382 -0
- package/dist/assets/AgentPanel-CQejLbiX.js +2 -0
- package/dist/assets/AgentPanel-DJEphah0.css +1 -0
- package/dist/assets/AgentQuestionDialog-BqkD0kXF.js +1 -0
- package/dist/assets/CodeStudio-Dv4ihHpz.js +23 -0
- package/dist/assets/CommentsPanel-B4yhhT1T.js +1 -0
- package/dist/assets/ComponentLibraryRail-Ch_dsAru.js +1 -0
- package/dist/assets/ComponentStage-BRhRotyH.js +1 -0
- package/dist/assets/CurvePane-BjFVabKX.css +1 -0
- package/dist/assets/CurvePane-R22WzllJ.js +1 -0
- package/dist/assets/ExportDialog-CWLQWTmG.js +2 -0
- package/dist/assets/FontPicker-DWKaYL7F.js +1 -0
- package/dist/assets/FontPicker-v0IOIArM.css +1 -0
- package/dist/assets/GenerateDrawer-Bh3SqDKt.js +2 -0
- package/dist/assets/InsertDrawer-Ce1fod1L.js +1 -0
- package/dist/assets/LibraryBrowser-D9sEGz5w.js +2 -0
- package/dist/assets/MakeItYoursSection-CMO4319_.js +2 -0
- package/dist/assets/MaterialGraphCanvas-BFzl4wWR.js +23 -0
- package/dist/assets/MaterialGraphCanvas-BIUD59ik.css +1 -0
- package/dist/assets/MaterialWorkspace-CqTWqaRA.js +14 -0
- package/dist/assets/PreferencesDialog-CBf9_OoD.js +1 -0
- package/dist/assets/PresetsSection-CUEaoCVU.js +1 -0
- package/dist/assets/SoundHistory-BeS8EW1h.js +1 -0
- package/dist/assets/SoundMode-BmcZru3i.js +3 -0
- package/dist/assets/StockSounds-DdAUGRYK.js +1 -0
- package/dist/assets/TemplateFieldSection-CaeXpLFo.js +1 -0
- package/dist/assets/VersionHistoryPanel-CxG6XhNP.js +1 -0
- package/dist/assets/board-B88EPuLO.css +1 -0
- package/dist/assets/board-CL-he7SL.js +3 -0
- package/dist/assets/components-0oOSPN0l.js +1 -0
- package/dist/assets/googleFontRanges-gp32wJMo.js +1 -0
- package/dist/assets/googleFonts-BNon6M7X.js +1 -0
- package/dist/assets/iconsAndAliases-DL7gXP5j.js +1863 -0
- package/dist/assets/index-4F5NQmI8.css +1 -0
- package/dist/assets/index-BGHQGV5z.js +117 -0
- package/dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/assets/libraryModel-CpIwfFha.js +1 -0
- package/dist/assets/lucide-6iK64tTB.js +9319 -0
- package/dist/assets/motionStamp-CH-Hew4E.js +1 -0
- package/dist/assets/takeMeasure-Tdg0TxEi.js +1 -0
- package/dist/assets/webmcp-BsB9gxWC.js +2 -0
- package/dist/index.html +34 -3
- package/package.json +12 -9
- package/src/addFamilies.ts +66 -0
- package/src/api.ts +1631 -55
- package/src/app/App.tsx +977 -198
- package/src/app/lazyPanel.tsx +137 -0
- package/src/app/lazySurfaces.tsx +203 -0
- package/src/audio/index.tsx +41 -10
- package/src/audio/meter.ts +485 -0
- package/src/audio/meterMath.ts +273 -0
- package/src/audio/meterStore.ts +155 -0
- package/src/audio/offlineMix.ts +289 -0
- package/src/audio/preview.ts +928 -118
- package/src/bridge.ts +15 -5
- package/src/bridgeTypes.ts +1611 -36
- package/src/channels.ts +17 -32
- package/src/fonts/googleFonts.ts +4 -0
- package/src/hostApi.ts +174 -0
- package/src/icons.tsx +770 -0
- package/src/layerWords.ts +61 -0
- package/src/main.tsx +56 -4
- package/src/panels/ResizeHandle.tsx +33 -43
- package/src/panels/agent/AgentDots.tsx +36 -0
- package/src/panels/agent/AgentPanel.tsx +119 -43
- package/src/panels/agent/AgentQuestionDialog.tsx +202 -0
- package/src/panels/agent/agent.css +113 -97
- package/src/panels/agent/agentGate.ts +35 -0
- package/src/panels/code/CodeDefaultsPanel.tsx +345 -0
- package/src/panels/code/CodeStudio.tsx +373 -0
- package/src/panels/code/FileTree.tsx +265 -0
- package/src/panels/code/codeBufferGuard.ts +52 -0
- package/src/panels/code/codeParts.tsx +321 -0
- package/src/panels/comments/CommentComposer.tsx +239 -0
- package/src/panels/comments/CommentThread.tsx +346 -0
- package/src/panels/comments/CommentsPanel.tsx +336 -0
- package/src/panels/comments/InboxButton.tsx +131 -0
- package/src/panels/comments/MentionMenu.tsx +98 -0
- package/src/panels/comments/parts.tsx +171 -0
- package/src/panels/export/ExportDialog.tsx +919 -96
- package/src/panels/export/ExportScrim.tsx +57 -0
- package/src/panels/files/AssetsTab.tsx +656 -0
- package/src/panels/files/FilePanel.tsx +1466 -216
- package/src/panels/files/LayerMarks.tsx +40 -0
- package/src/panels/files/LeftColumn.tsx +37 -0
- package/src/panels/files/McpSection.tsx +690 -47
- package/src/panels/files/MissingAssetsNotice.tsx +60 -0
- package/src/panels/files/assetDrag.ts +79 -0
- package/src/panels/files/resourceParts.tsx +255 -0
- package/src/panels/fonts/FontPicker.tsx +762 -0
- package/src/panels/fonts/faceCache.ts +207 -0
- package/src/panels/fonts/fontPicker.css +271 -0
- package/src/panels/fonts/pickerModel.ts +265 -0
- package/src/panels/fonts/pickerRequest.ts +46 -0
- package/src/panels/header/AccountAvatar.tsx +76 -0
- package/src/panels/header/AgentChip.tsx +77 -0
- package/src/panels/header/AppMenu.tsx +213 -0
- package/src/panels/header/Header.tsx +564 -84
- package/src/panels/header/HistoryControls.tsx +31 -5
- package/src/panels/header/PresenceStack.tsx +329 -0
- package/src/panels/header/ProjectTitle.tsx +232 -0
- package/src/panels/header/ShareButton.tsx +59 -0
- package/src/panels/header/StatusBadges.tsx +358 -27
- package/src/panels/header/SyncDeletedDialog.tsx +88 -0
- package/src/panels/header/ZoomControls.tsx +46 -15
- package/src/panels/header/agentHandoff.ts +52 -0
- package/src/panels/header/leave.ts +26 -0
- package/src/panels/help/HelpSection.tsx +189 -163
- package/src/panels/insert/InsertDrawer.tsx +723 -0
- package/src/panels/insert/iconSet.ts +109 -0
- package/src/panels/inspector/ExposeDot.tsx +117 -0
- package/src/panels/inspector/FramingRows.tsx +314 -44
- package/src/panels/inspector/InspectorFooter.tsx +91 -0
- package/src/panels/inspector/InspectorHead.tsx +425 -0
- package/src/panels/inspector/InspectorPanel.tsx +408 -124
- package/src/panels/inspector/KeyframeDot.tsx +373 -0
- package/src/panels/inspector/KeyframeSection.tsx +257 -0
- package/src/panels/inspector/MarkerSection.tsx +55 -11
- package/src/panels/inspector/ParamRow.tsx +84 -53
- package/src/panels/inspector/RightColumn.tsx +152 -0
- package/src/panels/inspector/TimeSection.tsx +866 -0
- package/src/panels/inspector/animate/EaseControl.tsx +244 -0
- package/src/panels/inspector/animate/PresetsSection.tsx +135 -0
- package/src/panels/inspector/animate/ShotSection.tsx +562 -48
- package/src/panels/inspector/design/AlignRow.tsx +95 -31
- package/src/panels/inspector/design/AppearanceSection.tsx +118 -9
- package/src/panels/inspector/design/ClonerSection.tsx +323 -62
- package/src/panels/inspector/design/ComponentSection.tsx +50 -43
- package/src/panels/inspector/design/CornerSection.tsx +45 -14
- package/src/panels/inspector/design/DefinitionProps.tsx +315 -0
- package/src/panels/inspector/design/DefinitionSection.tsx +136 -0
- package/src/panels/inspector/design/DeviceSection.tsx +210 -0
- package/src/panels/inspector/design/FillSection.tsx +83 -51
- package/src/panels/inspector/design/FontField.tsx +196 -0
- package/src/panels/inspector/design/HtmlSection.tsx +23 -12
- package/src/panels/inspector/design/InstanceSection.tsx +373 -154
- package/src/panels/inspector/design/MaskSection.tsx +84 -0
- package/src/panels/inspector/design/MaterialSection.tsx +177 -0
- package/src/panels/inspector/design/MediaSection.tsx +273 -120
- package/src/panels/inspector/design/MeshSection.tsx +910 -82
- package/src/panels/inspector/design/PaintRows.tsx +550 -0
- package/src/panels/inspector/design/PlateStyleSection.tsx +177 -0
- package/src/panels/inspector/design/ShadowSection.tsx +221 -48
- package/src/panels/inspector/design/SplineFollowSection.tsx +235 -0
- package/src/panels/inspector/design/StrokeSection.tsx +228 -43
- package/src/panels/inspector/design/TemplateFieldSection.tsx +57 -0
- package/src/panels/inspector/design/TransformSection.tsx +244 -50
- package/src/panels/inspector/design/TypographySection.tsx +679 -110
- package/src/panels/inspector/layout.ts +295 -0
- package/src/panels/inspector/propValue.ts +199 -0
- package/src/panels/inspector/scene/CameraSection.tsx +232 -22
- package/src/panels/inspector/scene/EffectsSection.tsx +722 -71
- package/src/panels/inspector/scene/MakeItYoursSection.tsx +180 -0
- package/src/panels/inspector/scene/SceneDocSection.tsx +191 -0
- package/src/panels/inspector/scene/SceneSection.tsx +219 -44
- package/src/panels/inspector/scene/TransitionSection.tsx +523 -72
- package/src/panels/inspector/storyboard/StoryboardReferenceSection.tsx +593 -0
- package/src/panels/inspector/storyboard/VideoStill.tsx +120 -0
- package/src/panels/inspector/timeModel.ts +190 -0
- package/src/panels/inspector/useDocWrite.ts +438 -146
- package/src/panels/library/LibraryBrowser.tsx +435 -0
- package/src/panels/library/LibraryGrid.tsx +190 -0
- package/src/panels/library/LibraryPreviewPanel.tsx +349 -0
- package/src/panels/library/LibraryRail.tsx +84 -0
- package/src/panels/library/LibrarySoundPanel.tsx +293 -0
- package/src/panels/library/SoundHistory.tsx +245 -0
- package/src/panels/library/StockSounds.tsx +390 -0
- package/src/panels/library/libraryModel.ts +147 -0
- package/src/panels/library/stockSearch.ts +77 -0
- package/src/panels/maskMarks.tsx +117 -0
- package/src/panels/material/MaterialCommentNode.tsx +54 -0
- package/src/panels/material/MaterialGraphCanvas.tsx +861 -0
- package/src/panels/material/MaterialGraphMenu.tsx +45 -0
- package/src/panels/material/MaterialGroupNode.tsx +56 -0
- package/src/panels/material/MaterialLibrary.tsx +253 -0
- package/src/panels/material/MaterialNode.tsx +453 -0
- package/src/panels/material/MaterialNodePalette.tsx +349 -0
- package/src/panels/material/MaterialParameterControls.tsx +525 -0
- package/src/panels/material/MaterialRerouteNode.tsx +42 -0
- package/src/panels/material/MaterialWorkspace.tsx +501 -0
- package/src/panels/material/NodePreview.tsx +70 -0
- package/src/panels/material/flowModel.ts +441 -0
- package/src/panels/material/parameterValues.ts +231 -0
- package/src/panels/material/previewScheduler.ts +235 -0
- package/src/panels/material/reactFlow.css +6 -0
- package/src/panels/material/socketGlyph.ts +85 -0
- package/src/panels/material/viewportMemory.ts +58 -0
- package/src/panels/preferences/PreferencesDialog.tsx +215 -0
- package/src/panels/share/ShareComponentDialog.tsx +247 -0
- package/src/panels/stage/StageMenu.tsx +35 -5
- package/src/panels/stage/StagePanel.tsx +338 -23
- package/src/panels/stage/cellSlots.tsx +70 -0
- package/src/panels/storyboard/BoardCanvas.tsx +739 -0
- package/src/panels/storyboard/BoardCursors.tsx +158 -0
- package/src/panels/storyboard/BoardDropDialog.tsx +161 -0
- package/src/panels/storyboard/BoardPlan.tsx +42 -0
- package/src/panels/storyboard/ComponentSheet.tsx +187 -0
- package/src/panels/storyboard/ComponentStage.tsx +235 -0
- package/src/panels/storyboard/MiniSketch.tsx +173 -0
- package/src/panels/storyboard/PartPicker.tsx +64 -0
- package/src/panels/storyboard/PlanPanel.tsx +617 -0
- package/src/panels/storyboard/ReferencePreview.tsx +217 -0
- package/src/panels/storyboard/ShotBrief.tsx +360 -0
- package/src/panels/storyboard/ShotCard.tsx +251 -0
- package/src/panels/storyboard/StagePreview.tsx +348 -0
- package/src/panels/storyboard/StillThumbs.tsx +162 -0
- package/src/panels/storyboard/StoryboardView.tsx +79 -0
- package/src/panels/storyboard/board.css +1065 -0
- package/src/panels/storyboard/board.ts +12 -0
- package/src/panels/storyboard/boardClipboard.ts +111 -0
- package/src/panels/storyboard/boardOrder.ts +68 -0
- package/src/panels/storyboard/boardRows.tsx +425 -0
- package/src/panels/storyboard/liveCap.ts +90 -0
- package/src/panels/storyboard/plan.css +295 -0
- package/src/panels/storyboard/posterCache.ts +133 -0
- package/src/panels/storyboard/shotboard/ComponentPicker.tsx +373 -0
- package/src/panels/storyboard/shotboard/ImagePicker.tsx +145 -0
- package/src/panels/storyboard/shotboard/ShotBoard.tsx +292 -0
- package/src/panels/storyboard/shotboard/SketchCanvas.tsx +443 -0
- package/src/panels/storyboard/shotboard/SketchInspector.tsx +471 -0
- package/src/panels/storyboard/shotboard/SketchItem.tsx +240 -0
- package/src/panels/storyboard/shotboard/SketchLayers.tsx +130 -0
- package/src/panels/storyboard/shotboard/SketchPlay.tsx +108 -0
- package/src/panels/storyboard/shotboard/SketchStrip.tsx +178 -0
- package/src/panels/storyboard/shotboard/SketchToolFooter.tsx +99 -0
- package/src/panels/storyboard/shotboard/sketch.css +1392 -0
- package/src/panels/storyboard/shotboard/sketchModel.ts +219 -0
- package/src/panels/storyboard/storyboardDrop.ts +164 -0
- package/src/panels/studio/ComponentLibraryRail.tsx +346 -0
- package/src/panels/studio/ComponentSidePanel.tsx +355 -0
- package/src/panels/studio/ComponentStudio.tsx +243 -0
- package/src/panels/studio/ComponentsHome.tsx +318 -0
- package/src/panels/studio/ComponentsPreview.tsx +179 -0
- package/src/panels/studio/EveryUse.tsx +244 -0
- package/src/panels/studio/ThisUsePanel.tsx +679 -0
- package/src/panels/studio/componentParts.tsx +341 -0
- package/src/panels/studio/components.ts +6 -0
- package/src/panels/studio/newCodeComponent.ts +66 -0
- package/src/panels/timeline/AudioFxButton.tsx +290 -0
- package/src/panels/timeline/AudioLane.tsx +674 -85
- package/src/panels/timeline/BlockRow.tsx +154 -85
- package/src/panels/timeline/ChannelRow.tsx +378 -129
- package/src/panels/timeline/CurvePane.tsx +508 -0
- package/src/panels/timeline/Filmstrip.tsx +361 -0
- package/src/panels/timeline/GenerateDrawer.tsx +407 -0
- package/src/panels/timeline/KeyStretch.tsx +115 -0
- package/src/panels/timeline/LifespanRow.tsx +730 -47
- package/src/panels/timeline/MarkerLane.tsx +46 -8
- package/src/panels/timeline/PlayButton.tsx +91 -0
- package/src/panels/timeline/PropertyPicker.tsx +254 -0
- package/src/panels/timeline/ShotRow.tsx +400 -0
- package/src/panels/timeline/SoundMode.tsx +1406 -0
- package/src/panels/timeline/TimelineDock.tsx +2338 -272
- package/src/panels/timeline/TransportVolume.tsx +163 -0
- package/src/panels/timeline/beatRuler.ts +74 -0
- package/src/panels/timeline/curveModel.ts +500 -0
- package/src/panels/timeline/duckUnderVoice.ts +68 -0
- package/src/panels/timeline/keyframeMenu.ts +138 -0
- package/src/panels/timeline/labelWidth.ts +49 -0
- package/src/panels/timeline/marquee.ts +155 -0
- package/src/panels/timeline/model.ts +1860 -199
- package/src/panels/timeline/snap.ts +125 -43
- package/src/panels/timeline/staggerPreview.tsx +92 -0
- package/src/panels/timeline/takeMeasure.ts +72 -0
- package/src/panels/timeline/useLive.ts +48 -0
- package/src/panels/timeline/viewport.ts +234 -0
- package/src/panels/toolbar/BackChip.tsx +116 -0
- package/src/panels/toolbar/CameraViewBar.tsx +118 -49
- package/src/panels/toolbar/CanvasBar.tsx +117 -0
- package/src/panels/toolbar/InsertButton.tsx +38 -0
- package/src/panels/toolbar/IsolationTrail.tsx +156 -0
- package/src/panels/toolbar/PanelToggles.tsx +86 -0
- package/src/panels/toolbar/ShadingBar.tsx +119 -26
- package/src/panels/toolbar/ToolDockBar.tsx +329 -80
- package/src/panels/toolbar/ToolFooter.tsx +102 -0
- package/src/panels/toolbar/ViewModeBar.tsx +247 -38
- package/src/panels/toolbar/WorkPlaneBar.tsx +94 -0
- package/src/panels/toolbar/useAddRows.tsx +326 -0
- package/src/panels/toolbar/useDismiss.ts +122 -0
- package/src/panels/versions/VersionHistoryPanel.tsx +274 -0
- package/src/panels/versions/versionModel.ts +103 -0
- package/src/panels/virtualWindow.ts +271 -0
- package/src/shotTokens.css +151 -60
- package/src/stage/FrustumGizmo.tsx +504 -84
- package/src/stage/GridPlane.tsx +225 -16
- package/src/stage/NodePreviews.tsx +628 -0
- package/src/stage/PerfHud.tsx +437 -47
- package/src/stage/SplitRenderer.tsx +816 -169
- package/src/stage/StageApp.tsx +4274 -486
- package/src/stage/StageRootBoundary.tsx +114 -0
- package/src/stage/StageTools.tsx +651 -151
- package/src/stage/TransformGizmo.tsx +696 -0
- package/src/stage/adaptivePresentation.ts +145 -0
- package/src/stage/bridgeClient.ts +2522 -41
- package/src/stage/exportWorker.ts +9 -0
- package/src/stage/feed.ts +305 -14
- package/src/stage/fontPreview.ts +176 -0
- package/src/stage/frustumGeometry.ts +319 -1
- package/src/stage/furnitureTokens.ts +33 -0
- package/src/stage/gizmoMath.ts +508 -16
- package/src/stage/gpuTimer.ts +276 -0
- package/src/stage/instanceModules.ts +194 -33
- package/src/stage/interactions/move.ts +24 -5
- package/src/stage/isolation.ts +291 -33
- package/src/stage/jsSelfProfiler.ts +325 -0
- package/src/stage/main.tsx +116 -16
- package/src/stage/modalState.ts +222 -23
- package/src/stage/moduleEpoch.ts +60 -0
- package/src/stage/motionPathStage.ts +279 -0
- package/src/stage/motionPreview.ts +74 -0
- package/src/stage/overlays/Overlays.tsx +1112 -159
- package/src/stage/overlays/Rulers.tsx +495 -0
- package/src/stage/panes.ts +159 -10
- package/src/stage/project.ts +68 -3
- package/src/stage/renderScaleController.ts +730 -0
- package/src/stage/rulers.ts +129 -0
- package/src/stage/sceneExtent.ts +75 -0
- package/src/stage/shading.ts +20 -0
- package/src/stage/splineStage.ts +632 -0
- package/src/stage/stagePerformanceTelemetry.ts +717 -0
- package/src/stage/stageTheme.ts +36 -0
- package/src/stage/stageWarmup.ts +11 -0
- package/src/stage/textAutoSize.ts +124 -0
- package/src/stage/tier1Export.ts +641 -0
- package/src/stage/tokenColor.ts +14 -9
- package/src/stage/view.ts +56 -9
- package/src/stage/workingView.ts +277 -33
- package/src/state/accountPrefs.ts +261 -0
- package/src/state/agentActions.ts +173 -15
- package/src/state/agentActivity.ts +198 -0
- package/src/state/agentQuestion.ts +239 -0
- package/src/state/bootOpen.ts +42 -0
- package/src/state/cameraVerbs.ts +139 -0
- package/src/state/clientId.ts +6 -1
- package/src/state/comments.ts +1099 -0
- package/src/state/context.tsx +19 -1
- package/src/state/editorPrefs.ts +220 -0
- package/src/state/errorReports.ts +121 -0
- package/src/state/fieldWrite.ts +161 -0
- package/src/state/fontRecents.ts +70 -0
- package/src/state/fonts.ts +656 -0
- package/src/state/graphClipboard.ts +414 -0
- package/src/state/imageThumbs.ts +216 -0
- package/src/state/insert.ts +444 -67
- package/src/state/isolationTrail.ts +92 -0
- package/src/state/keyMoves.ts +134 -0
- package/src/state/keyframeClipboard.ts +177 -0
- package/src/state/keymap.ts +1153 -117
- package/src/state/layoutPrefs.ts +272 -0
- package/src/state/layouts.ts +205 -0
- package/src/state/measureMedia.ts +167 -0
- package/src/state/menu.ts +2341 -28
- package/src/state/motionStamp.ts +7 -0
- package/src/state/panelSize.ts +375 -5
- package/src/state/pendingChanges.ts +119 -0
- package/src/state/playHold.ts +78 -0
- package/src/state/playbackPreparation.ts +562 -0
- package/src/state/posterCapture.ts +242 -0
- package/src/state/presence.ts +254 -0
- package/src/state/projectComponents.ts +160 -0
- package/src/state/renderEvents.ts +298 -18
- package/src/state/runtimeErrors.ts +46 -0
- package/src/state/selection.ts +12 -0
- package/src/state/shortcuts.ts +1606 -0
- package/src/state/sketchGuide.ts +51 -0
- package/src/state/splineRefs.ts +87 -0
- package/src/state/stageHealth.ts +259 -0
- package/src/state/stageWatchdog.ts +47 -0
- package/src/state/stillStage.ts +330 -0
- package/src/state/stillThumbs.ts +474 -0
- package/src/state/store.ts +23591 -2982
- package/src/state/storyboardModel.ts +528 -0
- package/src/state/sync.ts +1257 -0
- package/src/state/syncCache.ts +159 -0
- package/src/state/triangles.ts +13 -0
- package/src/state/types.ts +1698 -55
- package/src/state/unsavedGuard.ts +49 -0
- package/src/state/viewMode.ts +200 -0
- package/src/state/webmcp.ts +1128 -0
- package/src/state/workspace.ts +1147 -0
- package/src/styles/assets-tab.css +304 -0
- package/src/styles/canvas.css +545 -0
- package/src/styles/comments.css +1435 -0
- package/src/styles/controls.css +162 -0
- package/src/styles/dialogs.css +390 -0
- package/src/styles/insert-drawer.css +586 -0
- package/src/styles/inspector-board.css +207 -0
- package/src/styles/inspector-object.css +486 -0
- package/src/styles/inspector-shot.css +252 -0
- package/src/styles/inspector.css +360 -0
- package/src/styles/left-column.css +1628 -0
- package/src/styles/library-preview.css +575 -0
- package/src/styles/library.css +512 -0
- package/src/styles/modes/code.css +569 -0
- package/src/styles/modes/component.css +1561 -0
- package/src/styles/modes/material.css +1201 -0
- package/src/styles/modes/storyboard.css +518 -0
- package/src/styles/share-component.css +49 -0
- package/src/styles/shell.css +653 -0
- package/src/styles/shot-brief.css +360 -0
- package/src/styles/states.css +76 -0
- package/src/styles/sync.css +380 -0
- package/src/styles/timeline-graph.css +384 -0
- package/src/styles/timeline-meters.css +89 -0
- package/src/styles/timeline-rows.css +1959 -0
- package/src/styles/timeline-sound.css +1003 -0
- package/src/styles/timeline.css +754 -0
- package/src/styles/tool-footer.css +525 -0
- package/src/styles/topbar.css +886 -0
- package/src/styles/versions.css +262 -0
- package/src/styles.css +72 -2921
- package/src/tools.ts +108 -23
- package/dist/assets/index-B7notge7.css +0 -1
- package/dist/assets/index-BBE6Ta9L.js +0 -52
- package/src/panels/files/icons.tsx +0 -118
- package/src/panels/header/DocSwitcher.tsx +0 -85
- package/src/panels/header/TransportBar.tsx +0 -86
- package/src/panels/inspector/animate/BlockTiming.tsx +0 -341
- package/src/panels/inspector/animate/DuringBlocks.tsx +0 -85
- package/src/panels/inspector/animate/InOutPresets.tsx +0 -57
- package/src/panels/inspector/animate/ResolvedChannels.tsx +0 -150
- package/src/panels/inspector/animate/useBlocks.ts +0 -43
- package/src/panels/material/MaterialPicker.tsx +0 -172
- package/src/panels/timeline/SceneStrip.tsx +0 -145
- package/src/panels/toolbar/AddMenu.tsx +0 -230
- package/src/stage/MoveGizmo.tsx +0 -411
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
// The node thumbnails, and the four rules that keep them from costing more than
|
|
2
|
+
// the graph they describe.
|
|
3
|
+
//
|
|
4
|
+
// A preview is a real GPU readback: the stage renders each asked-for node's
|
|
5
|
+
// output to an atlas cell and reads it back, and a readback is a pipeline
|
|
6
|
+
// stall. So the chrome, which is the half that knows what the author can
|
|
7
|
+
// actually see, does the deciding:
|
|
8
|
+
//
|
|
9
|
+
// VIEWPORT-VISIBLE ONLY. `visiblePreviewNodes` is the filter, and it is a
|
|
10
|
+
// pure function of (nodes, viewport, canvas box) so it can be checked
|
|
11
|
+
// without mounting anything. A 200-node graph zoomed to one corner asks for
|
|
12
|
+
// the four cards on screen.
|
|
13
|
+
//
|
|
14
|
+
// ONE REQUEST IN FLIGHT. A pan is thirty viewport events; thirty overlapping
|
|
15
|
+
// readbacks would queue thirty stalls behind each other and the last answer
|
|
16
|
+
// would arrive seconds after the pan stopped. The newest ask waits, and the
|
|
17
|
+
// ones it overtook are simply dropped — nobody wants the intermediate
|
|
18
|
+
// frames of a pan.
|
|
19
|
+
//
|
|
20
|
+
// DEBOUNCED, so a keystroke in a Float field is one batch after the typing
|
|
21
|
+
// stops rather than one per character.
|
|
22
|
+
//
|
|
23
|
+
// KEYED BY THE PIXEL SIGNATURE, and a batch whose `semanticSignature` is no
|
|
24
|
+
// longer current is THROWN AWAY rather than painted. The stage answers
|
|
25
|
+
// asynchronously; by the time a batch lands the author may have rewired the
|
|
26
|
+
// node it describes, and a thumbnail that is quietly one edit stale is
|
|
27
|
+
// worse than no thumbnail at all — it is a wrong answer with a picture.
|
|
28
|
+
//
|
|
29
|
+
// And the bitmaps are OWNED here: an `ImageBitmap` holds GPU-side memory until
|
|
30
|
+
// `close()` is called, so every replacement closes what it replaced and
|
|
31
|
+
// `dispose()` closes the lot. Leaking them is invisible until a long session
|
|
32
|
+
// runs the tab out of memory.
|
|
33
|
+
import { MAX_NODE_PREVIEWS } from "../../bridgeTypes.js";
|
|
34
|
+
import type { NodePreviewBatch, NodePreviewRequest } from "../../bridgeTypes.js";
|
|
35
|
+
|
|
36
|
+
/** A card's own box in GRAPH units. Only used to decide "is any of this on
|
|
37
|
+
* screen", so it is deliberately generous rather than measured: a card that is
|
|
38
|
+
* half a width off the edge is about to be scrolled into view. */
|
|
39
|
+
const CARD = { width: 220, height: 150 } as const;
|
|
40
|
+
|
|
41
|
+
/** How far outside the canvas still counts as visible, in screen px. One card's
|
|
42
|
+
* worth, so a small pan does not re-ask for what it just uncovered. */
|
|
43
|
+
const VIEWPORT_PAD = 240;
|
|
44
|
+
|
|
45
|
+
/** How long the edits have to stop before a batch goes out. Long enough to
|
|
46
|
+
* swallow a typed number, short enough that a committed edit feels answered. */
|
|
47
|
+
export const PREVIEW_DEBOUNCE_MS = 120;
|
|
48
|
+
|
|
49
|
+
/** What one node contributes to the visibility test. A structural subset of
|
|
50
|
+
* `MaterialGraphNode`, so the caller passes graph nodes straight in. */
|
|
51
|
+
export interface PreviewCandidate {
|
|
52
|
+
id: string;
|
|
53
|
+
position: readonly [number, number];
|
|
54
|
+
preview?: true | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The preview-enabled nodes that are actually on screen, newest-first order
|
|
59
|
+
* preserved from the input.
|
|
60
|
+
*
|
|
61
|
+
* Clamped to `MAX_NODE_PREVIEWS` here rather than left to the stage, because
|
|
62
|
+
* the CHROME is the half that can choose WHICH ones to drop — and dropping the
|
|
63
|
+
* tail of a screen-order list is a scroll position, which is what the bridge's
|
|
64
|
+
* own clamp comment says it means.
|
|
65
|
+
*/
|
|
66
|
+
export function visiblePreviewNodes(
|
|
67
|
+
nodes: readonly PreviewCandidate[],
|
|
68
|
+
viewport: { x: number; y: number; zoom: number },
|
|
69
|
+
box: { width: number; height: number },
|
|
70
|
+
): string[] {
|
|
71
|
+
const zoom = Number.isFinite(viewport.zoom) && viewport.zoom > 0 ? viewport.zoom : 1;
|
|
72
|
+
const x = Number.isFinite(viewport.x) ? viewport.x : 0;
|
|
73
|
+
const y = Number.isFinite(viewport.y) ? viewport.y : 0;
|
|
74
|
+
const out: string[] = [];
|
|
75
|
+
for (const node of nodes) {
|
|
76
|
+
if (node.preview !== true) continue;
|
|
77
|
+
const left = node.position[0] * zoom + x;
|
|
78
|
+
const top = node.position[1] * zoom + y;
|
|
79
|
+
const right = left + CARD.width * zoom;
|
|
80
|
+
const bottom = top + CARD.height * zoom;
|
|
81
|
+
if (right < -VIEWPORT_PAD || left > box.width + VIEWPORT_PAD) continue;
|
|
82
|
+
if (bottom < -VIEWPORT_PAD || top > box.height + VIEWPORT_PAD) continue;
|
|
83
|
+
out.push(node.id);
|
|
84
|
+
if (out.length >= MAX_NODE_PREVIEWS) break;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** What the canvas knows and the scheduler needs. `pixelSignature` decides
|
|
90
|
+
* whether an ask is NEW; `semanticSignature` decides whether an ANSWER is
|
|
91
|
+
* still current. Two different questions, so two different signatures. */
|
|
92
|
+
export interface PreviewAsk {
|
|
93
|
+
materialId: string;
|
|
94
|
+
layerId: string;
|
|
95
|
+
slot: number | null;
|
|
96
|
+
nodeIds: readonly string[];
|
|
97
|
+
size: number;
|
|
98
|
+
pixelSignature: string;
|
|
99
|
+
semanticSignature: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A thumbnail, or the stage's sentence about why there is not one. */
|
|
103
|
+
export type PreviewEntry = ImageBitmap | string;
|
|
104
|
+
|
|
105
|
+
export interface PreviewScheduler {
|
|
106
|
+
/** The newest truth. Null means "nothing wants previews" — inside a subgraph,
|
|
107
|
+
* with no graph open, or while the stage has no preview target — and it
|
|
108
|
+
* releases everything held. */
|
|
109
|
+
ask(next: PreviewAsk | null): void;
|
|
110
|
+
dispose(): void;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface PreviewSchedulerDeps {
|
|
114
|
+
request(request: NodePreviewRequest): Promise<NodePreviewBatch | null>;
|
|
115
|
+
/** Called with a fresh map whenever the held set changes. */
|
|
116
|
+
onChange(entries: ReadonlyMap<string, PreviewEntry>): void;
|
|
117
|
+
debounceMs?: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function createPreviewScheduler(deps: PreviewSchedulerDeps): PreviewScheduler {
|
|
121
|
+
const held = new Map<string, PreviewEntry>();
|
|
122
|
+
const debounce = deps.debounceMs ?? PREVIEW_DEBOUNCE_MS;
|
|
123
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
124
|
+
let inFlight = false;
|
|
125
|
+
let pending: PreviewAsk | null = null;
|
|
126
|
+
/** The ask the held bitmaps answer. A repeat of it is a no-op. */
|
|
127
|
+
let satisfied: string | null = null;
|
|
128
|
+
let disposed = false;
|
|
129
|
+
|
|
130
|
+
const keyOf = (ask: PreviewAsk): string =>
|
|
131
|
+
`${ask.materialId}|${ask.slot ?? "-"}|${ask.size}|${ask.pixelSignature}|${[...ask.nodeIds].sort().join(",")}`;
|
|
132
|
+
|
|
133
|
+
const release = (entry: PreviewEntry | undefined): void => {
|
|
134
|
+
// A string is a message and owns nothing. Only a bitmap has to be closed,
|
|
135
|
+
// and `close` is guarded because jsdom's ImageBitmap stand-ins have none.
|
|
136
|
+
if (entry === undefined || typeof entry === "string") return;
|
|
137
|
+
if (typeof entry.close === "function") entry.close();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const clearHeld = (): void => {
|
|
141
|
+
if (held.size === 0) return;
|
|
142
|
+
for (const entry of held.values()) release(entry);
|
|
143
|
+
held.clear();
|
|
144
|
+
deps.onChange(new Map(held));
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const land = (ask: PreviewAsk, batch: NodePreviewBatch): void => {
|
|
148
|
+
// STALE ANSWERS ARE DROPPED WHOLE. A batch is one render of one graph; half
|
|
149
|
+
// of it cannot be current.
|
|
150
|
+
if (batch.materialId !== ask.materialId) return;
|
|
151
|
+
if (batch.semanticSignature !== ask.semanticSignature) return;
|
|
152
|
+
const wanted = new Set(ask.nodeIds);
|
|
153
|
+
for (const [id, entry] of held) {
|
|
154
|
+
if (wanted.has(id)) continue;
|
|
155
|
+
release(entry);
|
|
156
|
+
held.delete(id);
|
|
157
|
+
}
|
|
158
|
+
for (const result of batch.results) {
|
|
159
|
+
if (!wanted.has(result.nodeId)) continue;
|
|
160
|
+
release(held.get(result.nodeId));
|
|
161
|
+
held.set(result.nodeId, result.bitmap ?? result.message);
|
|
162
|
+
}
|
|
163
|
+
satisfied = keyOf(ask);
|
|
164
|
+
deps.onChange(new Map(held));
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const run = (ask: PreviewAsk): void => {
|
|
168
|
+
inFlight = true;
|
|
169
|
+
const request: NodePreviewRequest = {
|
|
170
|
+
materialId: ask.materialId,
|
|
171
|
+
layerId: ask.layerId,
|
|
172
|
+
slot: ask.slot,
|
|
173
|
+
nodeIds: ask.nodeIds,
|
|
174
|
+
size: ask.size,
|
|
175
|
+
};
|
|
176
|
+
void deps
|
|
177
|
+
.request(request)
|
|
178
|
+
.then((batch) => {
|
|
179
|
+
if (disposed || batch === null) return;
|
|
180
|
+
land(ask, batch);
|
|
181
|
+
})
|
|
182
|
+
.catch(() => {
|
|
183
|
+
// The stage refused or went away. Silent: the cards keep whatever they
|
|
184
|
+
// had, and the next committed edit asks again.
|
|
185
|
+
})
|
|
186
|
+
.finally(() => {
|
|
187
|
+
inFlight = false;
|
|
188
|
+
if (disposed) return;
|
|
189
|
+
// THE OVERTAKEN ASKS ARE GONE, not queued. `pending` only ever holds
|
|
190
|
+
// the newest, so a pan that produced thirty of them costs two requests.
|
|
191
|
+
const next = pending;
|
|
192
|
+
pending = null;
|
|
193
|
+
if (next !== null && keyOf(next) !== satisfied) run(next);
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
ask(next) {
|
|
199
|
+
if (disposed) return;
|
|
200
|
+
if (timer !== null) {
|
|
201
|
+
clearTimeout(timer);
|
|
202
|
+
timer = null;
|
|
203
|
+
}
|
|
204
|
+
if (next === null || next.nodeIds.length === 0) {
|
|
205
|
+
pending = null;
|
|
206
|
+
satisfied = null;
|
|
207
|
+
clearHeld();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (keyOf(next) === satisfied) {
|
|
211
|
+
pending = null;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
pending = next;
|
|
215
|
+
timer = setTimeout(() => {
|
|
216
|
+
timer = null;
|
|
217
|
+
const ask = pending;
|
|
218
|
+
if (ask === null) return;
|
|
219
|
+
// Held while one is out. The settle path above picks `pending` back up,
|
|
220
|
+
// which is what makes "one in flight" true without a queue.
|
|
221
|
+
if (inFlight) return;
|
|
222
|
+
pending = null;
|
|
223
|
+
run(ask);
|
|
224
|
+
}, debounce);
|
|
225
|
+
},
|
|
226
|
+
dispose() {
|
|
227
|
+
disposed = true;
|
|
228
|
+
if (timer !== null) clearTimeout(timer);
|
|
229
|
+
timer = null;
|
|
230
|
+
pending = null;
|
|
231
|
+
for (const entry of held.values()) release(entry);
|
|
232
|
+
held.clear();
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/* React Flow's own stylesheet, in the `vendor` cascade layer under every
|
|
2
|
+
house rule, as the /scene index had it. Imported by MaterialGraphCanvas
|
|
3
|
+
alone, so it ships in the material canvas's chunk and only the material
|
|
4
|
+
nodes pay for it. The index's first statement fixes the layer order before
|
|
5
|
+
this can arrive, so the layer keeps its rank. */
|
|
6
|
+
@import "@xyflow/react/dist/style.css" layer(vendor);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// THE SOCKET VOCABULARY: shape carries the type, and there is exactly one ink.
|
|
2
|
+
//
|
|
3
|
+
// ── WHY NOT A COLOUR PER TYPE ────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// Every shipped node editor colours its sockets, and this one may not. The
|
|
6
|
+
// house design system is monochrome plus ONE blue, and the blue is signal:
|
|
7
|
+
// selection, focus, the armed thing. Nine socket types would be nine hues that
|
|
8
|
+
// are none of them a studio colour: an unbounded second palette.
|
|
9
|
+
//
|
|
10
|
+
// So the TYPE is a shape and the STATE is the ink:
|
|
11
|
+
//
|
|
12
|
+
// --text-dim at rest
|
|
13
|
+
// --text when a wire lands on it
|
|
14
|
+
// --accent ringed, while a live drag could land here
|
|
15
|
+
// opacity .45 while a live drag could NOT
|
|
16
|
+
//
|
|
17
|
+
// A reader learns nine shapes once; they then read identically in both themes,
|
|
18
|
+
// at every zoom, and for an author who cannot tell red from green.
|
|
19
|
+
//
|
|
20
|
+
// ── AND WHY THE TABLE IS A TYPED `Record` ────────────────────────────────
|
|
21
|
+
//
|
|
22
|
+
// `Record<MaterialGraphSocketType, …>` and not a partial map with a fallback: a
|
|
23
|
+
// tenth socket type added to the registry must be a compile error here rather
|
|
24
|
+
// than a handle that silently draws as a circle and lies about what it carries.
|
|
25
|
+
import type { MaterialGraphSocketType } from "@dailies-studio/shot/doc";
|
|
26
|
+
|
|
27
|
+
export interface MaterialSocketGlyph {
|
|
28
|
+
/** The class that draws the shape. Every one of these resolves in
|
|
29
|
+
* `styles.css` and paints from `--text*` / `--border*` / `--accent*` only —
|
|
30
|
+
* `materialSocketGlyph.test.ts` holds both halves of that. */
|
|
31
|
+
shape: string;
|
|
32
|
+
/** What the shape means, said in words for the handle's tooltip. */
|
|
33
|
+
label: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The nine shapes, chosen so that width reads as width: a float is the smallest
|
|
38
|
+
* closed shape, a vec2 is a diamond, a vec3 a square, a vec4 a rounded square.
|
|
39
|
+
* The two hollow rings are the two things that are not plain numbers (a colour
|
|
40
|
+
* and a texture handle), and the two broken outlines are the two that are not a
|
|
41
|
+
* concrete value (an integer's discrete steps, a generic's "whatever arrives").
|
|
42
|
+
*/
|
|
43
|
+
export const SOCKET_GLYPHS: Record<MaterialGraphSocketType, MaterialSocketGlyph> = {
|
|
44
|
+
float: { shape: "material-socket-circle", label: "Float" },
|
|
45
|
+
int: { shape: "material-socket-circle-dotted", label: "Integer" },
|
|
46
|
+
bool: { shape: "material-socket-triangle", label: "Boolean" },
|
|
47
|
+
vec2: { shape: "material-socket-diamond", label: "Vector 2" },
|
|
48
|
+
vec3: { shape: "material-socket-square", label: "Vector 3" },
|
|
49
|
+
vec4: { shape: "material-socket-square-round", label: "Vector 4" },
|
|
50
|
+
color: { shape: "material-socket-ring", label: "Colour" },
|
|
51
|
+
texture: { shape: "material-socket-ring-double", label: "Texture" },
|
|
52
|
+
numeric: { shape: "material-socket-circle-dashed", label: "Any number" },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* What a LIVE drag says about this handle.
|
|
57
|
+
*
|
|
58
|
+
* `"idle"` is the resting state and the only one there is when no wire is in
|
|
59
|
+
* hand. The other two are the answer `canConnect` already gives — shown rather
|
|
60
|
+
* than discovered by dropping and being refused.
|
|
61
|
+
*/
|
|
62
|
+
export type MaterialSocketDrop = "idle" | "ok" | "blocked";
|
|
63
|
+
|
|
64
|
+
/** The whole class list for one handle, in one place, so the card renderers
|
|
65
|
+
* cannot each spell the state modifiers slightly differently. */
|
|
66
|
+
export function socketGlyphClass(
|
|
67
|
+
type: MaterialGraphSocketType,
|
|
68
|
+
state: { connected: boolean; drop: MaterialSocketDrop },
|
|
69
|
+
): string {
|
|
70
|
+
const glyph = SOCKET_GLYPHS[type];
|
|
71
|
+
return [
|
|
72
|
+
"material-socket",
|
|
73
|
+
glyph.shape,
|
|
74
|
+
state.connected ? "is-connected" : "",
|
|
75
|
+
state.drop === "ok" ? "is-droppable" : "",
|
|
76
|
+
state.drop === "blocked" ? "is-blocked" : "",
|
|
77
|
+
]
|
|
78
|
+
.filter((part) => part !== "")
|
|
79
|
+
.join(" ");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The handle's tooltip: what it is called, and what it carries. */
|
|
83
|
+
export function socketTitle(label: string, type: MaterialGraphSocketType): string {
|
|
84
|
+
return `${label} · ${SOCKET_GLYPHS[type].label}`;
|
|
85
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Where the author last left each graph, per scope.
|
|
2
|
+
//
|
|
3
|
+
// ── WHY A MODULE MAP AND NOT THE DOCUMENT ───────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// A pan and a zoom are the same class of thing as `materialSnapToGrid`: they
|
|
6
|
+
// describe where a person is looking, not what the material is. Writing them to
|
|
7
|
+
// `Doc3D` would make scrolling the canvas a document edit — an undo entry, an
|
|
8
|
+
// autosave, and a diff in every agent's next read of the file — for a gesture
|
|
9
|
+
// that changes no pixel of the render.
|
|
10
|
+
//
|
|
11
|
+
// ── AND WHY NOT COMPONENT STATE ─────────────────────────────────────────
|
|
12
|
+
//
|
|
13
|
+
// The canvas UNMOUNTS whenever the author flips to the TSL view, enters a
|
|
14
|
+
// subgraph, or changes slot. Component state dies with it, so every one of
|
|
15
|
+
// those cost a `fitView` back to the origin — the author lost their place for
|
|
16
|
+
// pressing a button and coming back. A module Map outlives the component and
|
|
17
|
+
// dies with the tab, which is exactly the lifetime a "where was I" belongs to.
|
|
18
|
+
//
|
|
19
|
+
// Keyed by material AND scope trail, because a function body is its own canvas
|
|
20
|
+
// with its own layout; sharing one viewport across the two would land the
|
|
21
|
+
// author somewhere arbitrary on every entry.
|
|
22
|
+
|
|
23
|
+
export interface GraphViewport {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
zoom: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** `materialId + "/" + path.join("/")`. The main graph's trail is empty, so its
|
|
30
|
+
* key ends in a trailing slash — deliberate, since it keeps the main scope and
|
|
31
|
+
* a function called "" (which cannot exist) from ever colliding. */
|
|
32
|
+
export function materialViewportKey(materialId: string, path: readonly string[]): string {
|
|
33
|
+
return `${materialId}/${path.join("/")}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ponytail: unbounded, one entry per (material, scope) an author visits. A
|
|
37
|
+
// session reaches dozens; a cap would be eviction policy for nothing.
|
|
38
|
+
const REMEMBERED = new Map<string, GraphViewport>();
|
|
39
|
+
|
|
40
|
+
export function rememberMaterialViewport(key: string, viewport: GraphViewport): void {
|
|
41
|
+
// Garbage in a viewport is not hypothetical: React Flow reports NaN for a
|
|
42
|
+
// moment when its container is measured at zero, which is every mount under
|
|
43
|
+
// jsdom and a real one behind a `display: none` panel. Storing it would make
|
|
44
|
+
// the NEXT entry restore to nowhere with no way back but the frame key.
|
|
45
|
+
if (!Number.isFinite(viewport.x) || !Number.isFinite(viewport.y)) return;
|
|
46
|
+
if (!Number.isFinite(viewport.zoom) || viewport.zoom <= 0) return;
|
|
47
|
+
REMEMBERED.set(key, { x: viewport.x, y: viewport.y, zoom: viewport.zoom });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function recallMaterialViewport(key: string): GraphViewport | null {
|
|
51
|
+
return REMEMBERED.get(key) ?? null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** For the suites, which must not inherit one another's pan. Never called by
|
|
55
|
+
* the app: a session's memory has no reason to be thrown away. */
|
|
56
|
+
export function clearMaterialViewports(): void {
|
|
57
|
+
REMEMBERED.clear();
|
|
58
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// The Preferences dialog (gap 5, Paper "PreferencesDialog / dark").
|
|
2
|
+
//
|
|
3
|
+
// Opened by the app menu row, ⌘, and the `prefs.open` WebMCP verb, all of
|
|
4
|
+
// which set `prefsOpen`; mounted once, in AppMenu. Every control applies at
|
|
5
|
+
// once through the setter the rest of the chrome already uses (the View menu
|
|
6
|
+
// rows, ⇧R), so there is no Save: Done only closes.
|
|
7
|
+
//
|
|
8
|
+
// It is chrome state, never `edit`: a viewer can open it and change any row.
|
|
9
|
+
import type { ReactNode } from "react";
|
|
10
|
+
import { Dialog, SegmentedControl, Toggle } from "@dailies-studio/ui";
|
|
11
|
+
import { useStudioTheme } from "@dailies-studio/ui/theme";
|
|
12
|
+
import type { StudioThemePreference } from "@dailies-studio/ui/theme";
|
|
13
|
+
import { isPlaybackResolution } from "../../bridgeTypes.js";
|
|
14
|
+
import type { PlaybackResolution } from "../../bridgeTypes.js";
|
|
15
|
+
import { useShotEditor, useStore } from "../../state/context.js";
|
|
16
|
+
import { isCloudWorkspace } from "../../state/posterCapture.js";
|
|
17
|
+
import { shortcutFor } from "../../state/shortcuts.js";
|
|
18
|
+
|
|
19
|
+
const THEMES: { value: StudioThemePreference; label: string }[] = [
|
|
20
|
+
{ value: "system", label: "System" },
|
|
21
|
+
{ value: "light", label: "Light" },
|
|
22
|
+
{ value: "dark", label: "Dark" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const PLAYBACK_RESOLUTION_OPTIONS: { value: PlaybackResolution; label: string }[] = [
|
|
26
|
+
{ value: "auto", label: "Auto" },
|
|
27
|
+
{ value: "full", label: "Full" },
|
|
28
|
+
{ value: "fast", label: "Fast" },
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
function Section(props: { label: string; children: ReactNode }) {
|
|
32
|
+
return (
|
|
33
|
+
<section className="prefs-section" aria-label={props.label}>
|
|
34
|
+
<div className="prefs-section-label">{props.label}</div>
|
|
35
|
+
{props.children}
|
|
36
|
+
</section>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One row: the label (and a hint under it) on the left, the control right.
|
|
41
|
+
* The control takes the label as its accessible name. */
|
|
42
|
+
function Row(props: { label: string; hint?: string; children: ReactNode }) {
|
|
43
|
+
return (
|
|
44
|
+
<div className="prefs-row">
|
|
45
|
+
<div className="prefs-row-text">
|
|
46
|
+
<span className="prefs-row-label">{props.label}</span>
|
|
47
|
+
{props.hint !== undefined && <span className="prefs-row-hint">{props.hint}</span>}
|
|
48
|
+
</div>
|
|
49
|
+
<div className="prefs-row-control">{props.children}</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function PreferencesDialog() {
|
|
55
|
+
const store = useStore();
|
|
56
|
+
const open = useShotEditor((s) => s.prefsOpen);
|
|
57
|
+
const { preference, setPreference } = useStudioTheme();
|
|
58
|
+
const rulers = useShotEditor((s) => s.rulers);
|
|
59
|
+
const showGrid = useShotEditor((s) => s.showGrid);
|
|
60
|
+
const smartGuides = useShotEditor((s) => s.smartGuides);
|
|
61
|
+
const motionPaths = useShotEditor((s) => s.motionPaths);
|
|
62
|
+
const toolbarPosition = useShotEditor((s) => s.toolbarPosition);
|
|
63
|
+
const playbackResolution = useShotEditor((s) => s.playbackResolution);
|
|
64
|
+
const blockLabels = useShotEditor((s) => s.blockLabels);
|
|
65
|
+
const selectMovesPlayhead = useShotEditor((s) => s.selectMovesPlayhead);
|
|
66
|
+
const fieldLabels = useShotEditor((s) => s.fieldLabels);
|
|
67
|
+
const showFpsBadge = useShotEditor((s) => s.showFpsBadge);
|
|
68
|
+
const showBackendBadge = useShotEditor((s) => s.showBackendBadge);
|
|
69
|
+
const close = (): void => store.setPrefsOpen(false);
|
|
70
|
+
const rulersKey = shortcutFor("view.rulers");
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Dialog
|
|
74
|
+
open={open}
|
|
75
|
+
size="wide"
|
|
76
|
+
className="prefs-dialog"
|
|
77
|
+
onClose={close}
|
|
78
|
+
title={
|
|
79
|
+
<span className="prefs-title">
|
|
80
|
+
Preferences
|
|
81
|
+
<kbd className="prefs-kbd">{shortcutFor("prefs.open")}</kbd>
|
|
82
|
+
</span>
|
|
83
|
+
}
|
|
84
|
+
actions={
|
|
85
|
+
<>
|
|
86
|
+
<span className="prefs-footnote" data-testid="prefs-footnote">
|
|
87
|
+
{isCloudWorkspace() ? "Saved to your account. This browser keeps a copy." : "Saved in this browser."}
|
|
88
|
+
</span>
|
|
89
|
+
<button type="button" className="btn is-primary" onClick={close}>
|
|
90
|
+
Done
|
|
91
|
+
</button>
|
|
92
|
+
</>
|
|
93
|
+
}
|
|
94
|
+
>
|
|
95
|
+
<div className="prefs-body" data-testid="prefs-dialog">
|
|
96
|
+
<Section label="Appearance">
|
|
97
|
+
<Row label="Theme">
|
|
98
|
+
<SegmentedControl
|
|
99
|
+
ariaLabel="Theme"
|
|
100
|
+
options={THEMES}
|
|
101
|
+
value={preference}
|
|
102
|
+
onChange={(v) => setPreference(v as StudioThemePreference)}
|
|
103
|
+
/>
|
|
104
|
+
</Row>
|
|
105
|
+
</Section>
|
|
106
|
+
<Section label="Canvas">
|
|
107
|
+
<Row label="Rulers" hint={`On the camera view and inside a component.${rulersKey === undefined ? "" : ` ${rulersKey}`}`}>
|
|
108
|
+
<Toggle ariaLabel="Rulers" checked={rulers} onChange={(on) => store.setEditorPref("rulers", on)} />
|
|
109
|
+
</Row>
|
|
110
|
+
<Row label="Grid">
|
|
111
|
+
<Toggle
|
|
112
|
+
ariaLabel="Grid"
|
|
113
|
+
checked={showGrid}
|
|
114
|
+
onChange={(on) => {
|
|
115
|
+
if (on !== store.getState().showGrid) store.toggleGrid();
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
118
|
+
</Row>
|
|
119
|
+
<Row label="Smart guides" hint="Ctrl turns snapping off while you drag">
|
|
120
|
+
<Toggle
|
|
121
|
+
ariaLabel="Smart guides"
|
|
122
|
+
checked={smartGuides}
|
|
123
|
+
onChange={(on) => store.setEditorPref("smartGuides", on)}
|
|
124
|
+
/>
|
|
125
|
+
</Row>
|
|
126
|
+
<Row label="Motion paths" hint="Path of the selected layer's keys">
|
|
127
|
+
<Toggle
|
|
128
|
+
ariaLabel="Motion paths"
|
|
129
|
+
checked={motionPaths}
|
|
130
|
+
onChange={(on) => store.setEditorPref("motionPaths", on)}
|
|
131
|
+
/>
|
|
132
|
+
</Row>
|
|
133
|
+
<Row label="Toolbar position">
|
|
134
|
+
<SegmentedControl
|
|
135
|
+
ariaLabel="Toolbar position"
|
|
136
|
+
options={[
|
|
137
|
+
{ value: "bottom", label: "Bottom" },
|
|
138
|
+
{ value: "top", label: "Top" },
|
|
139
|
+
]}
|
|
140
|
+
value={toolbarPosition}
|
|
141
|
+
onChange={(v) => store.setEditorPref("toolbarPosition", v === "top" ? "top" : "bottom")}
|
|
142
|
+
/>
|
|
143
|
+
</Row>
|
|
144
|
+
<Row
|
|
145
|
+
label="Playback resolution"
|
|
146
|
+
hint="Auto lowers it while playing only when the GPU falls behind. Paused frames and exports stay full."
|
|
147
|
+
>
|
|
148
|
+
<SegmentedControl
|
|
149
|
+
ariaLabel="Playback resolution"
|
|
150
|
+
options={PLAYBACK_RESOLUTION_OPTIONS}
|
|
151
|
+
value={playbackResolution}
|
|
152
|
+
onChange={(v) => store.setEditorPref("playbackResolution", isPlaybackResolution(v) ? v : "auto")}
|
|
153
|
+
/>
|
|
154
|
+
</Row>
|
|
155
|
+
</Section>
|
|
156
|
+
<Section label="Timeline">
|
|
157
|
+
<Row label="Camera move labels">
|
|
158
|
+
<SegmentedControl
|
|
159
|
+
ariaLabel="Camera move labels"
|
|
160
|
+
options={[
|
|
161
|
+
{ value: "fit", label: "When they fit" },
|
|
162
|
+
{ value: "off", label: "Off" },
|
|
163
|
+
]}
|
|
164
|
+
value={blockLabels}
|
|
165
|
+
onChange={(v) => store.setEditorPref("blockLabels", v === "off" ? "off" : "fit")}
|
|
166
|
+
/>
|
|
167
|
+
</Row>
|
|
168
|
+
<Row label="Move playhead to selection">
|
|
169
|
+
<Toggle
|
|
170
|
+
ariaLabel="Move playhead to selection"
|
|
171
|
+
checked={selectMovesPlayhead}
|
|
172
|
+
onChange={(on) => store.setSelectMovesPlayhead(on)}
|
|
173
|
+
/>
|
|
174
|
+
</Row>
|
|
175
|
+
</Section>
|
|
176
|
+
<Section label="Inspector">
|
|
177
|
+
<Row label="Field labels" hint="Compact shows a glyph. Named shows the word.">
|
|
178
|
+
<SegmentedControl
|
|
179
|
+
ariaLabel="Field labels"
|
|
180
|
+
options={[
|
|
181
|
+
{ value: "compact", label: "Compact" },
|
|
182
|
+
{ value: "named", label: "Named" },
|
|
183
|
+
]}
|
|
184
|
+
value={fieldLabels}
|
|
185
|
+
onChange={(v) => store.setEditorPref("fieldLabels", v === "named" ? "named" : "compact")}
|
|
186
|
+
/>
|
|
187
|
+
</Row>
|
|
188
|
+
</Section>
|
|
189
|
+
<Section label="Status">
|
|
190
|
+
<Row label="FPS badge">
|
|
191
|
+
<Toggle ariaLabel="FPS badge" checked={showFpsBadge} onChange={(on) => store.setFpsBadge(on)} />
|
|
192
|
+
</Row>
|
|
193
|
+
<Row label="Renderer badge">
|
|
194
|
+
<Toggle
|
|
195
|
+
ariaLabel="Renderer badge"
|
|
196
|
+
checked={showBackendBadge}
|
|
197
|
+
onChange={(on) => store.setBackendBadge(on)}
|
|
198
|
+
/>
|
|
199
|
+
</Row>
|
|
200
|
+
</Section>
|
|
201
|
+
<Section label="Layout">
|
|
202
|
+
<Row label="Panel sizes and docks">
|
|
203
|
+
<button
|
|
204
|
+
type="button"
|
|
205
|
+
className="btn"
|
|
206
|
+
onClick={() => store.resetLayout(window.innerWidth, window.innerHeight)}
|
|
207
|
+
>
|
|
208
|
+
Reset panel layout
|
|
209
|
+
</button>
|
|
210
|
+
</Row>
|
|
211
|
+
</Section>
|
|
212
|
+
</div>
|
|
213
|
+
</Dialog>
|
|
214
|
+
);
|
|
215
|
+
}
|