@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
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// kind-specific section here follows.
|
|
3
3
|
//
|
|
4
4
|
// ROWS COME FROM THE CONTRACT, NEVER FROM THE STORED VALUES. The widget for a
|
|
5
|
-
// prop is decided by its ControlSpec through the shared `
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// `instance.props` instead would
|
|
10
|
-
// with no kinds, no ranges and
|
|
5
|
+
// prop is decided by its ControlSpec through the shared `PropRow`, the one row
|
|
6
|
+
// every ControlSpec surface renders (a definition's published props, a code
|
|
7
|
+
// component's defaults, one use of a component on the board or in Components),
|
|
8
|
+
// so a colour prop gets the colour field and an enum its words here for exactly
|
|
9
|
+
// the reason it does there. Deriving rows from `instance.props` instead would
|
|
10
|
+
// show only props somebody had already changed, with no kinds, no ranges and
|
|
11
|
+
// no labels.
|
|
11
12
|
//
|
|
12
13
|
// WHICH contract: the LIVE one from the registry when the project still has the
|
|
13
14
|
// component, falling back to the `{source:"snapshot"}` contract the document
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
// ── QUARANTINE, WHICH IS THE POINT OF THE WHOLE SECTION ─────────────────
|
|
19
20
|
//
|
|
20
21
|
// A stored prop whose contract key has gone is NOT dropped and NOT hidden. The
|
|
21
|
-
//
|
|
22
|
+
// Accept plan (`planInstanceAccept`, whose rename/orphan planner is
|
|
22
23
|
// `resolveTracksAgainstContract` underneath) classifies it, and it gets its own
|
|
23
24
|
// row above the contract rows: the value it is holding, what it was keyed on,
|
|
24
25
|
// and the two things an author can do about it. Both documented real-world
|
|
@@ -31,59 +32,28 @@
|
|
|
31
32
|
// default and stores nothing; `buildProps` supplies it at render time. Baking
|
|
32
33
|
// defaults in at insert time would freeze them against later edits to the
|
|
33
34
|
// component itself.
|
|
34
|
-
import { useEffect, useState } from "react";
|
|
35
|
+
import { useEffect, useMemo, useState } from "react";
|
|
35
36
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
INSTANCE_PROP_PREFIX,
|
|
38
|
+
acceptStepWords,
|
|
39
|
+
findLayer,
|
|
40
|
+
frozenDefaultWords,
|
|
41
|
+
frozenDefaultsOf,
|
|
42
|
+
planInstanceAccept,
|
|
39
43
|
} from "@dailies-studio/shot/doc";
|
|
44
|
+
import type { FrozenDefault, InstanceAcceptPlan } from "@dailies-studio/shot/doc";
|
|
45
|
+
import { controlLabel, orderSpecs } from "@dailies-studio/contract";
|
|
40
46
|
import type { Contract, ControlSpec } from "@dailies-studio/contract";
|
|
41
47
|
import type { Value } from "@dailies-studio/engine";
|
|
42
|
-
import { InspectorRow, InspectorSection, NumberField,
|
|
48
|
+
import { InspectorRow, InspectorSection, NumberField, PropRow, useContextMenu, useLocked } from "@dailies-studio/ui";
|
|
49
|
+
import type { PropControlAsset, PropRowReset } from "@dailies-studio/ui";
|
|
43
50
|
import { useShotEditor, useStore } from "../../../state/context.js";
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"number",
|
|
51
|
-
"string",
|
|
52
|
-
"color",
|
|
53
|
-
"boolean",
|
|
54
|
-
"enum",
|
|
55
|
-
"asset",
|
|
56
|
-
"vec2",
|
|
57
|
-
"vec3",
|
|
58
|
-
"quaternion",
|
|
59
|
-
"curve",
|
|
60
|
-
"gradient",
|
|
61
|
-
]);
|
|
62
|
-
|
|
63
|
-
/** Contract order, then key — the motion inspector's `orderedSpecs` rule. */
|
|
64
|
-
function orderedSpecs(contract: Contract): ControlSpec[] {
|
|
65
|
-
return Object.values(contract.keys).sort((a, b) => {
|
|
66
|
-
const ao = a.order ?? Number.MAX_SAFE_INTEGER;
|
|
67
|
-
const bo = b.order ?? Number.MAX_SAFE_INTEGER;
|
|
68
|
-
return ao !== bo ? ao - bo : a.key.localeCompare(b.key);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** PropControl hands back whatever its widget produced; only engine Values may
|
|
73
|
-
* be stored. Anything else is refused rather than written, because the next
|
|
74
|
-
* save would refuse the document. */
|
|
75
|
-
function asValue(raw: unknown): Value | null {
|
|
76
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
77
|
-
if (typeof raw === "string" || typeof raw === "boolean") return raw;
|
|
78
|
-
if (
|
|
79
|
-
Array.isArray(raw) &&
|
|
80
|
-
(raw.length === 2 || raw.length === 3 || raw.length === 4) &&
|
|
81
|
-
raw.every((n) => typeof n === "number" && Number.isFinite(n))
|
|
82
|
-
) {
|
|
83
|
-
return raw as Value;
|
|
84
|
-
}
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
51
|
+
import { instanceDriftOf, instanceRegistryContract, withInstanceClockOffset } from "../../../state/store.js";
|
|
52
|
+
import { sameUseValue } from "../../../state/workspace.js";
|
|
53
|
+
import { useExposeOffered } from "../ExposeDot.js";
|
|
54
|
+
import { KeyframeDot } from "../KeyframeDot.js";
|
|
55
|
+
import { coercePropValue, isVectorSpec, outsideRangeOf, projectAssetsOf, propEditOf, shownPropValue } from "../propValue.js";
|
|
56
|
+
import { useSelectedLayers, useSelectionScrub } from "../useDocWrite.js";
|
|
87
57
|
|
|
88
58
|
export function InstanceSection() {
|
|
89
59
|
const store = useStore();
|
|
@@ -93,14 +63,35 @@ export function InstanceSection() {
|
|
|
93
63
|
const libraryLoaded = useShotEditor((s) => s.libraryLoaded);
|
|
94
64
|
const libraryError = useShotEditor((s) => s.libraryError);
|
|
95
65
|
const layers = useSelectedLayers();
|
|
66
|
+
const failures = useShotEditor((s) => s.stagePieceFailures);
|
|
96
67
|
const [rebinding, setRebinding] = useState(false);
|
|
68
|
+
// Also the refusal of a Replace, which binds a contract the same way.
|
|
97
69
|
const [rebindError, setRebindError] = useState<string | null>(null);
|
|
70
|
+
const replaceMenu = useContextMenu();
|
|
71
|
+
// A viewer's panel: the verbs below write, so they are disabled with it, as
|
|
72
|
+
// every widget under the lock is. Open code only opens, and stays live.
|
|
73
|
+
const locked = useLocked();
|
|
74
|
+
// The Project's assets, which an asset prop picks from. Memoised on the
|
|
75
|
+
// asset table: the section repaints on every document identity change, and
|
|
76
|
+
// the table itself changes only on an upload.
|
|
77
|
+
const assetTable = doc?.assets;
|
|
78
|
+
const assets = useMemo(() => projectAssetsOf(assetTable), [assetTable]);
|
|
98
79
|
|
|
99
80
|
// ONE layer at a time, deliberately. An instance's props belong to one
|
|
100
81
|
// component's contract, so a fan-out across a mixed selection would write
|
|
101
82
|
// keys the other layers' components never had.
|
|
102
83
|
const layer = layers.length === 1 && layers[0]?.kind === "instance" ? layers[0] : null;
|
|
103
84
|
const componentId = layer?.instance.component ?? null;
|
|
85
|
+
const layerId = layer?.id ?? null;
|
|
86
|
+
|
|
87
|
+
// The Clock field's DRAG half: a drag moves the module's clock while the
|
|
88
|
+
// pointer is down, one undo entry, rather than waiting for the release.
|
|
89
|
+
// Guarded on the id, because the seam fans out over the live selection.
|
|
90
|
+
const clockScrub = useSelectionScrub((l, raw) =>
|
|
91
|
+
l.kind === "instance" && l.id === layerId && typeof raw === "number" && Number.isFinite(raw)
|
|
92
|
+
? { ...l, instance: withInstanceClockOffset(l.instance, raw) }
|
|
93
|
+
: l,
|
|
94
|
+
);
|
|
104
95
|
|
|
105
96
|
// Hooks stay unconditional (the section mounts for every selection and
|
|
106
97
|
// self-gates on kind).
|
|
@@ -113,57 +104,156 @@ export function InstanceSection() {
|
|
|
113
104
|
if (doc === null || layer === null || componentId === null) return null;
|
|
114
105
|
|
|
115
106
|
const row = library.find((r) => r.id === componentId);
|
|
107
|
+
const loadError = failures.find((f) => f.kind === "instance" && f.layerId === layer.id);
|
|
116
108
|
const ref = layer.instance.contract;
|
|
117
109
|
const snapshot: Contract | null = ref?.source === "snapshot" ? ref.contract : null;
|
|
118
110
|
const live = contracts[componentId];
|
|
119
111
|
const contract = live ?? snapshot;
|
|
120
|
-
|
|
121
|
-
// successful fetch, not merely "loading finished". A FAILED fetch also ends
|
|
122
|
-
// with an empty list, and reporting every instance as an unknown component
|
|
123
|
-
// over a transient network failure would tell the author to delete work.
|
|
124
|
-
const drift = libraryLoaded
|
|
125
|
-
? instanceContractDrift(doc, (id) => {
|
|
126
|
-
const r = library.find((c) => c.id === id);
|
|
127
|
-
const c = contracts[id];
|
|
128
|
-
return r === undefined || c === undefined
|
|
129
|
-
? null
|
|
130
|
-
: { availability: r.contractAvailability ?? "inferred", contract: c };
|
|
131
|
-
}).filter((d) => d.layerId === layer.id)
|
|
132
|
-
: [];
|
|
112
|
+
const drift = instanceDriftOf({ doc, library, libraryLoaded, contracts }, layer.id);
|
|
133
113
|
const missing = libraryLoaded && row === undefined;
|
|
134
114
|
|
|
135
|
-
const specs = contract === null || contract === undefined ? [] :
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
115
|
+
const specs = contract === null || contract === undefined ? [] : orderSpecs(contract);
|
|
116
|
+
// THE ACCEPT PLAN, ONE for the drift notice and the quarantine list, so the
|
|
117
|
+
// notice says what the press does and the list is exactly what it sets
|
|
118
|
+
// aside. Planned on the STORED layer: `layer` is painted at the playhead,
|
|
119
|
+
// so an animated prop's value there is a sample, and a plan from it would
|
|
120
|
+
// describe a write the store does not make. Against the LIVE contract only:
|
|
121
|
+
// a key is orphaned relative to what the component accepts today. The
|
|
122
|
+
// registry row only says how Accept would bind, which no step depends on,
|
|
123
|
+
// so a list that has not loaded (or failed) still shows the quarantine,
|
|
124
|
+
// with its Discard. A malformed contract throws, and then there is no plan.
|
|
125
|
+
const registry =
|
|
126
|
+
instanceRegistryContract({ library, contracts }, componentId) ??
|
|
127
|
+
(live === undefined ? null : { availability: "inferred" as const, contract: live });
|
|
128
|
+
const stored = findLayer(doc, layer.id)?.layer;
|
|
129
|
+
let plan: InstanceAcceptPlan | null = null;
|
|
130
|
+
if (registry !== null && stored?.kind === "instance" && stored.id === layer.id) {
|
|
131
|
+
try {
|
|
132
|
+
plan = planInstanceAccept(stored, registry, null);
|
|
133
|
+
} catch {
|
|
134
|
+
plan = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// WHAT THE STAGE RENDERS for each unset prop of a snapshot-bound layer: the
|
|
138
|
+
// FROZEN default, not the live one the rows would otherwise show. Shown on
|
|
139
|
+
// the row and named in the drift notice, so a picture that differs from
|
|
140
|
+
// the component's current look says why.
|
|
141
|
+
const frozen: FrozenDefault[] =
|
|
142
|
+
registry !== null && stored?.kind === "instance" && stored.id === layer.id ? frozenDefaultsOf(stored, registry) : [];
|
|
143
|
+
const orphans = (plan?.steps ?? []).flatMap((step) =>
|
|
144
|
+
step.op === "keep-aside" && step.value ? [{ key: step.key, reason: step.reason }] : [],
|
|
145
|
+
);
|
|
140
146
|
|
|
141
147
|
return (
|
|
142
|
-
<InspectorSection title="Component" persistKey="shot:instance">
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
148
|
+
<InspectorSection className="insp-object" title="Component" persistKey="shot:instance">
|
|
149
|
+
{/* THE MODULE, and for a PROJECT component it is a door. A builtin ships
|
|
150
|
+
inside a package and has no file to open, and a component the registry
|
|
151
|
+
has lost has nothing to open either, so both stay plain text — the
|
|
152
|
+
panel's rule for a verb this subject cannot do at all.
|
|
153
|
+
|
|
154
|
+
The plain-text arm is a READ-ONLY VALUE, so the row is the house
|
|
155
|
+
readout (`insp-readout`), its value the `.insp-dim` span, with
|
|
156
|
+
`.is-text` when it has a NAME to show: a display name set in the
|
|
157
|
+
numeral font reads as a measurement. It said `insp-fixed` for a long
|
|
158
|
+
time, a class with no rule anywhere in the repo, so the row had no
|
|
159
|
+
face at all. */}
|
|
160
|
+
<InspectorRow label="Module" {...(row === undefined || row.builtin === true ? { className: "insp-readout" } : {})}>
|
|
161
|
+
{row === undefined || row.builtin === true ? (
|
|
162
|
+
<span className={row?.name === undefined ? "insp-dim" : "insp-dim is-text"} title={componentId}>
|
|
163
|
+
{row?.name ?? componentId}
|
|
164
|
+
</span>
|
|
165
|
+
) : (
|
|
166
|
+
<button
|
|
167
|
+
type="button"
|
|
168
|
+
className="link-button"
|
|
169
|
+
data-testid="instance-open-code"
|
|
170
|
+
title={`Open ${row.rel}`}
|
|
171
|
+
onClick={() => void store.openCodeComponent(componentId)}
|
|
172
|
+
>
|
|
173
|
+
{row.name}
|
|
174
|
+
</button>
|
|
175
|
+
)}
|
|
147
176
|
</InspectorRow>
|
|
148
177
|
|
|
178
|
+
{/* THE LOAD OR DRAW ERROR (F50). The stage draws a dashed placeholder where this
|
|
179
|
+
layer would be and reports it as a piece failure; this row names the
|
|
180
|
+
error and offers the three ways out. Replace picks another component
|
|
181
|
+
and swaps it in place, one undo step (`replaceInstanceComponent`), so
|
|
182
|
+
the layer keeps its place, timing and props. Remove deletes THIS layer
|
|
183
|
+
by id, never whatever block or key has focus. */}
|
|
184
|
+
{loadError !== undefined && (
|
|
185
|
+
<div className="insp-inline-error" data-testid="instance-load-error">
|
|
186
|
+
<span>{`This component failed to draw: ${loadError.message}`}</span>
|
|
187
|
+
<div className="insp-buttons">
|
|
188
|
+
{row === undefined || row.builtin === true ? null : (
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
className="btn"
|
|
192
|
+
data-testid="instance-error-open-code"
|
|
193
|
+
onClick={() => void store.openCodeComponent(componentId)}
|
|
194
|
+
>
|
|
195
|
+
Open code
|
|
196
|
+
</button>
|
|
197
|
+
)}
|
|
198
|
+
<button
|
|
199
|
+
type="button"
|
|
200
|
+
className="btn"
|
|
201
|
+
data-testid="instance-replace"
|
|
202
|
+
title="Swap this layer's component for another"
|
|
203
|
+
disabled={locked}
|
|
204
|
+
onClick={(e) => {
|
|
205
|
+
const at = e.currentTarget.getBoundingClientRect();
|
|
206
|
+
const others = library.filter((r) => r.host === "three" && r.id !== componentId);
|
|
207
|
+
replaceMenu.open(
|
|
208
|
+
{ x: at.left, y: at.bottom },
|
|
209
|
+
others.length === 0
|
|
210
|
+
? [{ kind: "action", id: "none", label: "No other components to use", disabled: true, onSelect() {} }]
|
|
211
|
+
: others.map((r) => ({
|
|
212
|
+
kind: "action",
|
|
213
|
+
id: r.id,
|
|
214
|
+
label: r.name,
|
|
215
|
+
detail: r.rel,
|
|
216
|
+
onSelect() {
|
|
217
|
+
void store.replaceInstanceComponent(layer.id, r.id).then(setRebindError);
|
|
218
|
+
},
|
|
219
|
+
})),
|
|
220
|
+
{ search: "Find a component" },
|
|
221
|
+
);
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
Replace
|
|
225
|
+
</button>
|
|
226
|
+
<button type="button" className="btn" title="Delete this layer" disabled={locked} onClick={() => store.removeLayer(layer.id)}>
|
|
227
|
+
Remove
|
|
228
|
+
</button>
|
|
229
|
+
</div>
|
|
230
|
+
{replaceMenu.menu}
|
|
231
|
+
</div>
|
|
232
|
+
)}
|
|
233
|
+
|
|
149
234
|
{/* mo1's "Play" on an instance, and the reason it is a NUMBER rather than
|
|
150
235
|
a button: retriggering a module is an offset, not state, so it stays a
|
|
151
236
|
pure function of the frame and an out-of-order export samples the same
|
|
152
237
|
pose a scrub does. Negative holds the module at its own frame 0 until
|
|
153
|
-
the scene catches up.
|
|
154
|
-
|
|
238
|
+
the scene catches up. Its name starts with the word in its box, so
|
|
239
|
+
the Named label over the box and the Compact prefix in it agree. */}
|
|
240
|
+
<InspectorRow>
|
|
155
241
|
<NumberField
|
|
156
242
|
value={layer.instance.clockOffsetFrames ?? 0}
|
|
157
|
-
|
|
243
|
+
label="Clock"
|
|
244
|
+
ariaLabel="Clock offset"
|
|
158
245
|
unit="f"
|
|
159
246
|
step={1}
|
|
160
247
|
onCommit={(next) => store.setInstanceClockOffset(layer.id, next)}
|
|
248
|
+
onScrubStart={clockScrub.start}
|
|
249
|
+
onScrub={clockScrub.move}
|
|
250
|
+
onScrubEnd={clockScrub.end}
|
|
161
251
|
/>
|
|
162
252
|
</InspectorRow>
|
|
163
253
|
|
|
164
254
|
{libraryError !== null && (
|
|
165
255
|
<div className="insp-inline-error">
|
|
166
|
-
{`The component registry could not be read (${libraryError})
|
|
256
|
+
{`The component registry could not be read (${libraryError}), so this instance cannot be checked.`}
|
|
167
257
|
</div>
|
|
168
258
|
)}
|
|
169
259
|
|
|
@@ -177,49 +267,78 @@ export function InstanceSection() {
|
|
|
177
267
|
{drift.length > 0 && (
|
|
178
268
|
<div className="insp-notice is-warn">
|
|
179
269
|
{drift.map((d) => (
|
|
180
|
-
<span key={d.code}>
|
|
270
|
+
<span key={d.code} className="insp-notice-line">
|
|
271
|
+
{d.message}
|
|
272
|
+
</span>
|
|
181
273
|
))}
|
|
274
|
+
{/* What the press will do, BEFORE it: the same plan the store
|
|
275
|
+
writes and `dailies validate` prints, in the same words. */}
|
|
276
|
+
{frozen.length > 0 && (
|
|
277
|
+
<span className="insp-notice-line" data-instance-frozen={layer.id}>
|
|
278
|
+
{`On screen now this layer ${frozen.map(frozenDefaultWords).join("; ")}.`}
|
|
279
|
+
</span>
|
|
280
|
+
)}
|
|
281
|
+
{plan !== null && (
|
|
282
|
+
<span className="insp-notice-line" data-instance-accept-steps={layer.id}>
|
|
283
|
+
{plan.steps.length > 0
|
|
284
|
+
? `Accepting will: ${plan.steps.map(acceptStepWords).join("; ")}.`
|
|
285
|
+
: frozen.length > 0
|
|
286
|
+
? "Accepting renders the live defaults."
|
|
287
|
+
: "Accepting only records the current contract."}
|
|
288
|
+
</span>
|
|
289
|
+
)}
|
|
182
290
|
{/* The ONE action drift offers, and it is never automatic. Re-binding
|
|
183
291
|
is a statement that the component's CURRENT contract is the one
|
|
184
292
|
this instance means; the planner moves every renamed key's value
|
|
185
|
-
and
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
setRebinding(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
293
|
+
and keyframes, every value outside a range comes back inside it,
|
|
294
|
+
and every orphan's value stays exactly where it is. */}
|
|
295
|
+
<div className="insp-buttons">
|
|
296
|
+
<button
|
|
297
|
+
className="btn"
|
|
298
|
+
disabled={rebinding || locked}
|
|
299
|
+
data-instance-rebind={layer.id}
|
|
300
|
+
title="Re-record this instance's contract hash and source from the project's current component, following any renames and bringing values back inside its ranges"
|
|
301
|
+
onClick={() => {
|
|
302
|
+
setRebinding(true);
|
|
303
|
+
void store.rebindInstance(layer.id).then((err) => {
|
|
304
|
+
setRebinding(false);
|
|
305
|
+
setRebindError(err);
|
|
306
|
+
});
|
|
307
|
+
}}
|
|
308
|
+
>
|
|
309
|
+
Accept current contract
|
|
310
|
+
</button>
|
|
311
|
+
</div>
|
|
201
312
|
</div>
|
|
202
313
|
)}
|
|
203
314
|
{rebindError !== null && <div className="insp-inline-error">{rebindError}</div>}
|
|
204
315
|
|
|
205
|
-
{orphans.map((key) => (
|
|
316
|
+
{orphans.map(({ key, reason }) => (
|
|
206
317
|
<div key={`orphan:${key}`} className="insp-notice is-warn" data-instance-orphan={key}>
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
>
|
|
215
|
-
|
|
216
|
-
|
|
318
|
+
{/* Never "nothing was deleted": Accept deletes such a key's
|
|
319
|
+
keyframes. The value is what this row keeps. */}
|
|
320
|
+
{reason === "gone"
|
|
321
|
+
? `"${key}" is not a prop of this component any more. Its value is kept here and is not ` +
|
|
322
|
+
`passed to the component.`
|
|
323
|
+
: `"${key}" now takes a different kind of value. The value stored here is of the old kind, ` +
|
|
324
|
+
`and the component is still handed it. Discard it to use the default.`}
|
|
325
|
+
<div className="insp-buttons">
|
|
326
|
+
<button
|
|
327
|
+
className="btn"
|
|
328
|
+
data-instance-drop={key}
|
|
329
|
+
disabled={locked}
|
|
330
|
+
title={`Delete the stored value for "${key}". This is the only thing that ever removes it.`}
|
|
331
|
+
onClick={() => store.clearInstanceProp(layer.id, key)}
|
|
332
|
+
>
|
|
333
|
+
Discard
|
|
334
|
+
</button>
|
|
335
|
+
</div>
|
|
217
336
|
</div>
|
|
218
337
|
))}
|
|
219
338
|
|
|
220
339
|
{contract === null || contract === undefined ? (
|
|
221
340
|
<div className="insp-notice">
|
|
222
|
-
No contract available for this component
|
|
341
|
+
No contract available for this component, so its props cannot be edited here.
|
|
223
342
|
</div>
|
|
224
343
|
) : (
|
|
225
344
|
<>
|
|
@@ -236,6 +355,9 @@ export function InstanceSection() {
|
|
|
236
355
|
layerId={layer.id}
|
|
237
356
|
spec={spec}
|
|
238
357
|
value={layer.instance.props[spec.key]}
|
|
358
|
+
frozen={frozen.find((f) => f.key === spec.key)}
|
|
359
|
+
animated={layer.tracks?.[`${INSTANCE_PROP_PREFIX}${spec.key}`] !== undefined}
|
|
360
|
+
assets={assets}
|
|
239
361
|
/>
|
|
240
362
|
))}
|
|
241
363
|
</>
|
|
@@ -244,59 +366,156 @@ export function InstanceSection() {
|
|
|
244
366
|
);
|
|
245
367
|
}
|
|
246
368
|
|
|
247
|
-
|
|
248
|
-
|
|
369
|
+
/**
|
|
370
|
+
* One prop of one placed instance: the row, its diamond, its Reset.
|
|
371
|
+
*
|
|
372
|
+
* `value` is the layer AS PAINTED at the playhead (`useSelectedLayers`), so an
|
|
373
|
+
* animated prop shows its sampled value, and a typed one keys at the playhead
|
|
374
|
+
* (`patchInstance` routes the edit).
|
|
375
|
+
*/
|
|
376
|
+
function InstancePropRow(props: {
|
|
377
|
+
layerId: string;
|
|
378
|
+
spec: ControlSpec;
|
|
379
|
+
value: Value | undefined;
|
|
380
|
+
/** The frozen default the stage renders for this unset prop, when it is
|
|
381
|
+
* not the live one (`frozenDefaultsOf`). */
|
|
382
|
+
frozen?: FrozenDefault | undefined;
|
|
383
|
+
/** The prop carries keyframes (`instance.props.<key>` has a track). */
|
|
384
|
+
animated: boolean;
|
|
385
|
+
assets: readonly PropControlAsset[];
|
|
386
|
+
}) {
|
|
387
|
+
const { layerId, spec, animated } = props;
|
|
249
388
|
const store = useStore();
|
|
389
|
+
const locked = useLocked();
|
|
250
390
|
const [error, setError] = useState<string | null>(null);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
391
|
+
const label = controlLabel(spec);
|
|
392
|
+
const path = `${INSTANCE_PROP_PREFIX}${spec.key}`;
|
|
393
|
+
const vector = isVectorSpec(spec);
|
|
394
|
+
const pinOffered = useExposeOffered(path);
|
|
395
|
+
// An unset prop shows (and edits from) the default the runtime's
|
|
396
|
+
// `buildProps` will supply, without ever storing it: the FROZEN one while
|
|
397
|
+
// the layer still renders its snapshot, else the spec's. `slot` and `event`
|
|
398
|
+
// carry no default at all, hence the presence check.
|
|
399
|
+
const fallback = props.frozen !== undefined ? props.frozen.frozen : "default" in spec ? spec.default : undefined;
|
|
400
|
+
const stored = props.value !== undefined;
|
|
401
|
+
// THE BLUE DOT (C4): a value this use stores that differs from the master,
|
|
402
|
+
// compared as the engine value the default is stored as (a curve's default
|
|
403
|
+
// is its decoded object, its stored value the canonical JSON).
|
|
404
|
+
const master = fallback === undefined ? null : coercePropValue(spec, fallback);
|
|
405
|
+
const changed = props.value !== undefined && !(master !== null && sameUseValue(props.value, master, spec.kind));
|
|
406
|
+
|
|
407
|
+
// A STORED value the range no longer holds (the component narrowed it, or
|
|
408
|
+
// a hand edit put it there), said under the row with the verb that brings
|
|
409
|
+
// it inside. Not for an animated prop: its keyframes are its value, and a
|
|
410
|
+
// typed edit of it is a key at the playhead.
|
|
411
|
+
const outside = animated ? null : outsideRangeOf(spec, props.value);
|
|
257
412
|
|
|
258
413
|
const commit = (raw: unknown): void => {
|
|
259
|
-
const
|
|
260
|
-
if (
|
|
261
|
-
setError(
|
|
414
|
+
const edit = propEditOf(spec, raw, fallback);
|
|
415
|
+
if (edit.kind === "refused") {
|
|
416
|
+
setError(edit.reason);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
// An asset's None CLEARS the prop, which under a track is the reset's data
|
|
420
|
+
// loss again (`routeTrackedEdit` takes the animation with a removed
|
|
421
|
+
// value), and a keyframe cannot hold "no asset" either. Refused, as the
|
|
422
|
+
// reset is, rather than dropping every key from a picker.
|
|
423
|
+
if (edit.kind === "clear" && animated) {
|
|
424
|
+
setError(`${label} is animated. Choosing None would delete its keyframes: remove them on the timeline first.`);
|
|
262
425
|
return;
|
|
263
426
|
}
|
|
264
427
|
setError(null);
|
|
265
|
-
store.
|
|
428
|
+
if (edit.kind === "clear") store.clearInstanceProp(layerId, spec.key);
|
|
429
|
+
else store.setInstanceProp(layerId, spec.key, edit.value);
|
|
266
430
|
};
|
|
267
431
|
|
|
432
|
+
// THE DRAG HALF. A colour picker's three bars, a range field's slider and a
|
|
433
|
+
// gradient stop's colour route a drag entirely through `scrub.move` and
|
|
434
|
+
// never call `commit` while the pointer is down, so a row holding only the
|
|
435
|
+
// commit half is a control whose thumb moves and whose document does not.
|
|
436
|
+
//
|
|
437
|
+
// A value the contract refuses is REFUSED by writing nothing rather than by
|
|
438
|
+
// setting `error`: a capture runs per pointermove and inside the store's
|
|
439
|
+
// own transaction, and a React state write from there would re-render the
|
|
440
|
+
// panel mid-gesture sixty times a second to say what the typed path says
|
|
441
|
+
// once. Guarded on the ID as well as the kind: the seam fans out over the
|
|
442
|
+
// LIVE selection, and a prop key belongs to one component's contract.
|
|
443
|
+
const scrub = useSelectionScrub((layer, raw) => {
|
|
444
|
+
if (layer.kind !== "instance" || layer.id !== layerId) return layer;
|
|
445
|
+
const next = coercePropValue(spec, raw);
|
|
446
|
+
return next === null
|
|
447
|
+
? layer
|
|
448
|
+
: { ...layer, instance: { ...layer.instance, props: { ...layer.instance.props, [spec.key]: next } } };
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// THE RESET, shown while a value is stored. REFUSED while the prop is
|
|
452
|
+
// animated: clearing a tracked prop reads to the router as "take its
|
|
453
|
+
// animation with it" (`routeTrackedEdit`), so one press deleted every key
|
|
454
|
+
// the author had set while the tooltip promised only the default back.
|
|
455
|
+
const reset: PropRowReset | undefined = stored
|
|
456
|
+
? {
|
|
457
|
+
onReset: () => store.clearInstanceProp(layerId, spec.key),
|
|
458
|
+
title: "Clear the stored value and use the component's default",
|
|
459
|
+
props: { "data-instance-reset": spec.key },
|
|
460
|
+
...(animated
|
|
461
|
+
? { refused: `${label} is animated. A reset would delete its keyframes: remove them on the timeline first.` }
|
|
462
|
+
: {}),
|
|
463
|
+
}
|
|
464
|
+
: undefined;
|
|
465
|
+
|
|
268
466
|
return (
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
467
|
+
<PropRow
|
|
468
|
+
spec={spec}
|
|
469
|
+
value={shownPropValue(spec, props.value ?? fallback)}
|
|
470
|
+
commit={commit}
|
|
471
|
+
scrub={scrub}
|
|
472
|
+
// The path is the contract key's, and `layerTrackablePath` types it from
|
|
473
|
+
// this same spec. The diamond is ABSENT rather than dead for a `slot` or
|
|
474
|
+
// `event` prop and for a stale key, since `layerTrackRefusal` refuses
|
|
475
|
+
// both, the rule it follows in every other section.
|
|
476
|
+
//
|
|
477
|
+
// PER BOX: every box of a vector carries the vector's diamond, which
|
|
478
|
+
// names the axes its boxes show as keying together. A one-box control
|
|
479
|
+
// keeps its diamond and its expose pin together in its box.
|
|
480
|
+
trailing={({ axes }) => <KeyframeDot path={path} label={label} pin={!vector} parts={axes} />}
|
|
481
|
+
// A VECTOR'S ONE PIN, in the label column once per row (KeyframeDot's
|
|
482
|
+
// header: one pin per track). In its first box's lane beside the
|
|
483
|
+
// diamond it overflowed that third of the row and was clipped at the
|
|
484
|
+
// panel's floor. Only while it is offered: the column draws a slot for
|
|
485
|
+
// whatever it is handed, even a pin that renders nothing.
|
|
486
|
+
{...(vector && pinOffered ? { actions: <KeyframeDot path={path} label={label} diamond={false} /> } : {})}
|
|
487
|
+
changed={changed}
|
|
488
|
+
inherited={!stored}
|
|
489
|
+
{...(reset !== undefined ? { reset } : {})}
|
|
490
|
+
error={error}
|
|
491
|
+
notice={
|
|
492
|
+
outside === null ? (
|
|
493
|
+
props.frozen === undefined || stored ? undefined : (
|
|
494
|
+
<span data-instance-frozen-key={spec.key}>
|
|
495
|
+
Frozen default. The component now defaults to {String(shownPropValue(spec, props.frozen.live))}; Accept current contract
|
|
496
|
+
to render it.
|
|
285
497
|
</span>
|
|
286
|
-
)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
498
|
+
)
|
|
499
|
+
) : (
|
|
500
|
+
<>
|
|
501
|
+
<span>{outside.words}</span>
|
|
502
|
+
<div className="insp-buttons">
|
|
503
|
+
<button
|
|
504
|
+
type="button"
|
|
505
|
+
className="btn"
|
|
506
|
+
disabled={locked}
|
|
507
|
+
data-instance-inside={spec.key}
|
|
508
|
+
title={outside.title}
|
|
509
|
+
onClick={() => commit(outside.inside)}
|
|
510
|
+
>
|
|
511
|
+
Bring inside
|
|
512
|
+
</button>
|
|
513
|
+
</div>
|
|
514
|
+
</>
|
|
515
|
+
)
|
|
516
|
+
}
|
|
517
|
+
assets={props.assets}
|
|
518
|
+
dotProps={{ "data-use-changed": spec.key }}
|
|
519
|
+
/>
|
|
301
520
|
);
|
|
302
521
|
}
|