@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,177 @@
|
|
|
1
|
+
// One-click plate looks: the named treatments every tool in this class ships,
|
|
2
|
+
// written into the fields this lane already has.
|
|
3
|
+
//
|
|
4
|
+
// ── WHY PRESETS AT ALL, WHEN EVERY FIELD IS ALREADY THERE ───────────────────
|
|
5
|
+
//
|
|
6
|
+
// `paint.radius`, `paint.stroke` and `paint.shadows` have all been honoured on a
|
|
7
|
+
// media plate since unify Phase 1: the corner is a uv1 alphaMap stencil, the
|
|
8
|
+
// stroke is a separate plate raster hung in front with the silhouette punched
|
|
9
|
+
// out, and the shadows are drawn outside the box with the pad baked into the
|
|
10
|
+
// mesh (raster.ts). What was missing is that assembling the LOOK meant setting
|
|
11
|
+
// nine numbers across three sections, in an order nobody is told, and being
|
|
12
|
+
// wrong about any one of them reads as "this tool cannot do the thing every
|
|
13
|
+
// other tool does in one click".
|
|
14
|
+
//
|
|
15
|
+
// shots.so ships Default / Glass Light / Glass Dark / Liquid Glass / Inset Light
|
|
16
|
+
// / Inset Dark / Outline / Border, with shadow modes None / Spread / Hug /
|
|
17
|
+
// Adaptive. Screen Studio and Tella ship the same idea under their own names.
|
|
18
|
+
// This is that shelf, in this lane's vocabulary.
|
|
19
|
+
//
|
|
20
|
+
// ── WHAT IT DELIBERATELY IS NOT ────────────────────────────────────────────
|
|
21
|
+
//
|
|
22
|
+
// NOT A DOCUMENT FIELD. Nothing records which preset was used, and there is no
|
|
23
|
+
// "preset" key on a layer. A preset is a WRITE of ordinary fields, so the
|
|
24
|
+
// author owns the result immediately and every knob stays theirs to nudge: the
|
|
25
|
+
// row is a starting point, not a mode they are now in. That also means no
|
|
26
|
+
// schema bump, nothing an older studio could misread, and no resurrection of
|
|
27
|
+
// the deleted template lane (AGENTS.md) — there is no shipped content here,
|
|
28
|
+
// only numbers this chrome could already type.
|
|
29
|
+
//
|
|
30
|
+
// NOT GLASS, HONESTLY. There is no backdrop blur: a true frosted plate needs
|
|
31
|
+
// the composited scene behind it, which the plate raster (hung in FRONT at
|
|
32
|
+
// plateOrder) structurally cannot sample, and the correct implementation is a
|
|
33
|
+
// two-group split render that doubles the pass count. So the glass rows here
|
|
34
|
+
// are a translucent stroke plus a soft shadow, which is what reads as glass
|
|
35
|
+
// over a busy background.
|
|
36
|
+
import { InspectorRow, InspectorSection, useLocked } from "@dailies-studio/ui";
|
|
37
|
+
import type { CornerRadius, Layer3D, Shadow, Stroke } from "@dailies-studio/shot/doc";
|
|
38
|
+
import { useSelectedLayers, useSelectionWrite } from "../useDocWrite.js";
|
|
39
|
+
|
|
40
|
+
/** What a preset writes. Every field is optional and an ABSENT one is DELETED
|
|
41
|
+
* rather than left alone: a look is a complete statement, so applying "Plain"
|
|
42
|
+
* after "Outline" has to remove the stroke, not leave it behind. */
|
|
43
|
+
interface PlateStyle {
|
|
44
|
+
key: string;
|
|
45
|
+
label: string;
|
|
46
|
+
title: string;
|
|
47
|
+
radius?: CornerRadius;
|
|
48
|
+
stroke?: Stroke;
|
|
49
|
+
shadows?: Shadow[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const r = (n: number): CornerRadius => ({ tl: n, tr: n, br: n, bl: n });
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The shelf.
|
|
56
|
+
*
|
|
57
|
+
* The numbers are the ones this class of tool converged on, in design px
|
|
58
|
+
* against a 1920-wide frame: a plate corner around 12-24px, a hairline at 1px,
|
|
59
|
+
* and a shadow whose blur is several times its own y offset (a tight, dark
|
|
60
|
+
* shadow reads as a sticker; a wide soft one reads as depth).
|
|
61
|
+
*/
|
|
62
|
+
const STYLES: readonly PlateStyle[] = [
|
|
63
|
+
{
|
|
64
|
+
key: "plain",
|
|
65
|
+
label: "Plain",
|
|
66
|
+
title: "Square corners, no border, no shadow",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: "soft",
|
|
70
|
+
label: "Soft",
|
|
71
|
+
title: "Rounded corners and a wide, soft drop shadow",
|
|
72
|
+
radius: r(16),
|
|
73
|
+
shadows: [{ xPx: 0, yPx: 18, blurPx: 48, spreadPx: -8, color: "#00000059" }],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: "lifted",
|
|
77
|
+
label: "Lifted",
|
|
78
|
+
title: "A deeper shadow, for a plate that sits well off its background",
|
|
79
|
+
radius: r(20),
|
|
80
|
+
shadows: [
|
|
81
|
+
// TWO entries, near and far. One shadow at this size goes muddy: the
|
|
82
|
+
// near one keeps the plate's edge defined and the far one carries the
|
|
83
|
+
// height. This is what "Deep" is in the tools that ship it.
|
|
84
|
+
{ xPx: 0, yPx: 4, blurPx: 10, spreadPx: -2, color: "#00000040" },
|
|
85
|
+
{ xPx: 0, yPx: 40, blurPx: 90, spreadPx: -16, color: "#00000073" },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: "outline",
|
|
90
|
+
label: "Outline",
|
|
91
|
+
title: "A hairline border, no shadow",
|
|
92
|
+
radius: r(12),
|
|
93
|
+
// INSIDE align: an outside stroke grows the plate's silhouette, so a
|
|
94
|
+
// recording placed to fill an exact box would no longer fill it.
|
|
95
|
+
stroke: { color: "#ffffff26", widthPx: 1, align: "inside" },
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: "glass",
|
|
99
|
+
label: "Glass",
|
|
100
|
+
title: "A bright hairline and a soft glow, the look that reads as glass over a busy background",
|
|
101
|
+
radius: r(20),
|
|
102
|
+
stroke: { color: "#ffffff40", widthPx: 1, align: "inside" },
|
|
103
|
+
shadows: [
|
|
104
|
+
// A zero-offset bright shadow IS a glow in this schema (types.ts), which
|
|
105
|
+
// is why there is one field and not two.
|
|
106
|
+
{ xPx: 0, yPx: 0, blurPx: 32, spreadPx: 0, color: "#ffffff1f" },
|
|
107
|
+
{ xPx: 0, yPx: 24, blurPx: 64, spreadPx: -12, color: "#00000066" },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
key: "frame",
|
|
112
|
+
label: "Frame",
|
|
113
|
+
title: "A thick light border, the way a screenshot sits inside a mount",
|
|
114
|
+
radius: r(8),
|
|
115
|
+
stroke: { color: "#ffffff", widthPx: 10, align: "inside" },
|
|
116
|
+
shadows: [{ xPx: 0, yPx: 12, blurPx: 32, spreadPx: -6, color: "#0000004d" }],
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
export function PlateStyleSection() {
|
|
121
|
+
const write = useSelectionWrite();
|
|
122
|
+
const layers = useSelectedLayers();
|
|
123
|
+
// Each chip writes paint, so a viewer's panel disables the shelf.
|
|
124
|
+
const locked = useLocked();
|
|
125
|
+
|
|
126
|
+
// MEDIA ONLY, and that is a scoping choice rather than a technical one: every
|
|
127
|
+
// field below is honoured on a rect and a path too. But "plate" names the
|
|
128
|
+
// thing a screenshot or a recording sits on, and offering the shelf on every
|
|
129
|
+
// layer would put a Glass row on a line and an arrow.
|
|
130
|
+
if (layers.length === 0 || !layers.every(isMedia)) return null;
|
|
131
|
+
|
|
132
|
+
const apply = (style: PlateStyle): void =>
|
|
133
|
+
write((layer) => ({
|
|
134
|
+
...layer,
|
|
135
|
+
paint: {
|
|
136
|
+
// Everything the preset does NOT name is dropped, including keys it has
|
|
137
|
+
// no opinion on, so a look is repeatable: applying the same row twice
|
|
138
|
+
// must give the same picture whatever was there first. `fill` is
|
|
139
|
+
// carried, because it is inert on media and the author may have set it
|
|
140
|
+
// for a non-media sibling.
|
|
141
|
+
...(layer.paint.fill === undefined ? {} : { fill: layer.paint.fill }),
|
|
142
|
+
...(style.radius === undefined ? {} : { radius: style.radius }),
|
|
143
|
+
...(style.stroke === undefined ? {} : { stroke: style.stroke }),
|
|
144
|
+
...(style.shadows === undefined ? {} : { shadows: style.shadows.map((s) => ({ ...s })) }),
|
|
145
|
+
},
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<InspectorSection className="insp-object" title="Plate style" persistKey="shot:plate-style">
|
|
150
|
+
<InspectorRow>
|
|
151
|
+
<div className="plate-style-grid">
|
|
152
|
+
{STYLES.map((style) => (
|
|
153
|
+
<button
|
|
154
|
+
key={style.key}
|
|
155
|
+
type="button"
|
|
156
|
+
className="plate-style-chip"
|
|
157
|
+
title={style.title}
|
|
158
|
+
disabled={locked}
|
|
159
|
+
onClick={() => apply(style)}
|
|
160
|
+
>
|
|
161
|
+
{style.label}
|
|
162
|
+
</button>
|
|
163
|
+
))}
|
|
164
|
+
</div>
|
|
165
|
+
</InspectorRow>
|
|
166
|
+
</InspectorSection>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function isMedia(layer: Layer3D): boolean {
|
|
171
|
+
return layer.kind === "image" || layer.kind === "video";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Exported for the test, which asserts the shelf's own invariants rather than
|
|
175
|
+
* its numbers: pinning nine colours would make a design tweak a test failure
|
|
176
|
+
* and teach nobody anything. */
|
|
177
|
+
export { STYLES as PLATE_STYLES };
|
|
@@ -2,72 +2,245 @@
|
|
|
2
2
|
// that can disagree. A glow IS a shadow at zero offset with a bright colour,
|
|
3
3
|
// which is exactly how the rasterizer draws it (raster.ts), so modelling them
|
|
4
4
|
// separately would be two schema fields for one Canvas2D call.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
//
|
|
6
|
+
// ── WHICH ONLY WORKS IF THE PANEL SAYS BOTH WORDS ──────────────────────
|
|
7
|
+
//
|
|
8
|
+
// This section printed "Shadow" over everything, so an author who could see a
|
|
9
|
+
// glow on the stage had no row to look at: the word appeared in ZERO pixels of
|
|
10
|
+
// the chrome, and the question it produced was "where does a glow get its
|
|
11
|
+
// colour". Each entry is now named from its OWN value, GLOW at zero offset and
|
|
12
|
+
// SHADOW otherwise. Derived rather than stored, so dragging Y off zero renames
|
|
13
|
+
// the row it is in and the label can never disagree with the paint.
|
|
14
|
+
//
|
|
15
|
+
// ── AND EVERY ENTRY, NOT JUST THE FIRST ────────────────────────────────
|
|
16
|
+
//
|
|
17
|
+
// `paint.shadows` is a LIST and the pair this lane exists for is a glow plus a
|
|
18
|
+
// drop shadow. Editing `shadows[0]` alone left the second one invisible AND
|
|
19
|
+
// uneditable on exactly the document the schema was shaped for. Entries are
|
|
20
|
+
// listed in ARRAY order, which is PAINT order (raster.ts walks the list and
|
|
21
|
+
// each entry is its own pass), so Add appends and the new entry paints last.
|
|
22
|
+
//
|
|
23
|
+
// NO INSET TOGGLE. `Shadow.inset` exists in the shared type but this lane's
|
|
24
|
+
// raster skips an inset entry outright (it needs a clip pass v1 does not do),
|
|
25
|
+
// so the control would write a field and paint nothing.
|
|
26
|
+
import {
|
|
27
|
+
ColorField,
|
|
28
|
+
IconMinus,
|
|
29
|
+
IconPlus,
|
|
30
|
+
InspectorRow,
|
|
31
|
+
InspectorSection,
|
|
32
|
+
NumberField,
|
|
33
|
+
PropertyGrid,
|
|
34
|
+
useLocked,
|
|
35
|
+
} from "@dailies-studio/ui";
|
|
36
|
+
import type { ScrubHandlers } from "@dailies-studio/ui";
|
|
37
|
+
import { removeArrayElementTracks } from "@dailies-studio/shot/doc";
|
|
38
|
+
import { KeyframeDot } from "../KeyframeDot.js";
|
|
39
|
+
import type { Layer3D, Shadow } from "@dailies-studio/shot/doc";
|
|
40
|
+
import { useSelectedLayers, useSelectionScrub, useSelectionValue, useSelectionWrite } from "../useDocWrite.js";
|
|
8
41
|
|
|
42
|
+
/** What Add creates: the neutral soft drop. A zero-everything entry paints
|
|
43
|
+
* nothing, and an author who clicks Add and sees no change cannot tell whether
|
|
44
|
+
* it worked. */
|
|
9
45
|
const DEFAULT_SHADOW: Shadow = { xPx: 0, yPx: 12, blurPx: 32, spreadPx: 0, color: "#00000080" };
|
|
10
46
|
|
|
47
|
+
/** The four numbers, in the order they read as a sentence: offset, then
|
|
48
|
+
* softness, then growth. */
|
|
49
|
+
const SHADOW_NUMBERS = [
|
|
50
|
+
{ field: "xPx", label: "X", title: "Horizontal offset. Zero on both axes is a glow." },
|
|
51
|
+
{ field: "yPx", label: "Y", title: "Vertical offset. Zero on both axes is a glow." },
|
|
52
|
+
{ field: "blurPx", label: "Blur", title: "Blur radius" },
|
|
53
|
+
{ field: "spreadPx", label: "Spread", title: "Spread (signed: negative shrinks)" },
|
|
54
|
+
] as const;
|
|
55
|
+
type ShadowNumber = (typeof SHADOW_NUMBERS)[number]["field"];
|
|
56
|
+
|
|
11
57
|
export function ShadowSection() {
|
|
12
58
|
const write = useSelectionWrite();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const shadows = [...(layer.paint.shadows ?? [DEFAULT_SHADOW])];
|
|
22
|
-
shadows[0] = { ...DEFAULT_SHADOW, ...shadows[0], ...next };
|
|
23
|
-
return { ...layer, paint: { ...layer.paint, shadows } };
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const shadow = first.value ?? DEFAULT_SHADOW;
|
|
59
|
+
// Add and each entry's remove are plain buttons, so they read a viewer's
|
|
60
|
+
// lock here; every field is a widget that reads it itself.
|
|
61
|
+
const locked = useLocked();
|
|
62
|
+
// The LARGEST count in the selection, not the first layer's: with two
|
|
63
|
+
// layers holding two and one entries, every entry must have a row. A layer
|
|
64
|
+
// without an index reads undefined there, so that row shows Mixed, and
|
|
65
|
+
// `withShadow`/`withoutShadow` skip it.
|
|
66
|
+
const entries = Math.max(0, ...useSelectedLayers().map((layer) => layer.paint.shadows?.length ?? 0));
|
|
27
67
|
|
|
28
68
|
return (
|
|
29
69
|
<InspectorSection
|
|
70
|
+
className="insp-object"
|
|
30
71
|
title="Shadow"
|
|
31
72
|
persistKey="shot:shadow"
|
|
32
73
|
action={
|
|
33
74
|
<button
|
|
34
75
|
type="button"
|
|
35
|
-
className="section-action"
|
|
36
|
-
title=
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
: patch({})
|
|
41
|
-
}
|
|
76
|
+
className="btn is-icon insp-section-action"
|
|
77
|
+
title="Add shadow or glow"
|
|
78
|
+
aria-label="Add shadow or glow"
|
|
79
|
+
disabled={locked}
|
|
80
|
+
onClick={() => write(appendShadow)}
|
|
42
81
|
>
|
|
43
|
-
|
|
82
|
+
<IconPlus />
|
|
44
83
|
</button>
|
|
45
84
|
}
|
|
46
85
|
>
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
{entries === 0 ? <p className="insp-empty">No shadow or glow</p> : null}
|
|
87
|
+
{Array.from({ length: entries }, (_, index) => (
|
|
88
|
+
<ShadowEntry key={index} index={index} locked={locked} />
|
|
89
|
+
))}
|
|
90
|
+
</InspectorSection>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* ONE entry. A component of its own because the hooks are per index and the
|
|
96
|
+
* list length changes under the author's fingers, which is the same reason the
|
|
97
|
+
* 2D lane's shadow rows are components.
|
|
98
|
+
*/
|
|
99
|
+
function ShadowEntry(props: { index: number; locked: boolean }) {
|
|
100
|
+
const { index } = props;
|
|
101
|
+
const write = useSelectionWrite();
|
|
102
|
+
const color = useSelectionValue((layer) => layer.paint.shadows?.[index]?.color);
|
|
103
|
+
const colorScrub = useSelectionScrub((layer, raw) => withShadow(layer, index, { color: String(raw) }));
|
|
104
|
+
const x = useShadowNumber(index, "xPx");
|
|
105
|
+
const y = useShadowNumber(index, "yPx");
|
|
106
|
+
const blur = useShadowNumber(index, "blurPx");
|
|
107
|
+
const spread = useShadowNumber(index, "spreadPx");
|
|
108
|
+
const fields: Record<ShadowNumber, ShadowNumberField> = {
|
|
109
|
+
xPx: x,
|
|
110
|
+
yPx: y,
|
|
111
|
+
blurPx: blur,
|
|
112
|
+
spreadPx: spread,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// THE NAME THE AUTHOR IS LOOKING FOR, derived from the live offsets so it
|
|
116
|
+
// follows a drag rather than describing what the entry was when it was added.
|
|
117
|
+
// The number is the paint slot, which is the only thing that distinguishes
|
|
118
|
+
// two entries of the same kind.
|
|
119
|
+
const name = `${x.value === 0 && y.value === 0 ? "Glow" : "Shadow"} ${index + 1}`;
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<InspectorRow
|
|
124
|
+
label={name}
|
|
125
|
+
trailing={
|
|
126
|
+
<>
|
|
127
|
+
{/* A GLOW IS A ZERO-OFFSET SHADOW, so this diamond is what a glow
|
|
128
|
+
pulse is authored with. */}
|
|
129
|
+
<KeyframeDot path={`paint.shadows.${index}.color`} label={`${name} colour`} />
|
|
130
|
+
{/* The diamond's own button, in the same lane inside the box: two
|
|
131
|
+
verbs read as one kind of control only if they rest at one size
|
|
132
|
+
and strength, and the remove says it destroys on hover. */}
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
className="insp-key is-danger"
|
|
136
|
+
title={`Remove ${name}`}
|
|
137
|
+
aria-label={`Remove ${name}`}
|
|
138
|
+
disabled={props.locked}
|
|
139
|
+
onClick={() => write((layer) => withoutShadow(layer, index))}
|
|
140
|
+
>
|
|
141
|
+
<IconMinus />
|
|
142
|
+
</button>
|
|
143
|
+
</>
|
|
144
|
+
}
|
|
145
|
+
>
|
|
146
|
+
<ColorField
|
|
147
|
+
value={color.value ?? DEFAULT_SHADOW.color}
|
|
148
|
+
mixed={color.mixed}
|
|
149
|
+
ariaLabel={`${name} colour`}
|
|
150
|
+
scrub={colorScrub}
|
|
151
|
+
commit={(hex) => write((layer) => withShadow(layer, index, { color: hex }))}
|
|
152
|
+
/>
|
|
153
|
+
</InspectorRow>
|
|
154
|
+
<PropertyGrid>
|
|
155
|
+
{SHADOW_NUMBERS.map((f) => (
|
|
156
|
+
<InspectorRow key={f.field}>
|
|
157
|
+
<NumberField
|
|
158
|
+
value={fields[f.field].value ?? 0}
|
|
159
|
+
mixed={fields[f.field].mixed}
|
|
160
|
+
label={f.label}
|
|
161
|
+
ariaLabel={`${f.label}, ${name}`}
|
|
162
|
+
unit="px"
|
|
163
|
+
title={f.title}
|
|
164
|
+
step={1}
|
|
165
|
+
// Blur alone has a floor (a negative blur is not a blur). X, Y
|
|
166
|
+
// and Spread are SIGNED and unbounded.
|
|
167
|
+
{...(f.field === "blurPx" ? { min: 0 } : {})}
|
|
168
|
+
trailing={<KeyframeDot path={`paint.shadows.${index}.${f.field}`} label={`${f.label}, ${name}`} />}
|
|
169
|
+
onCommit={fields[f.field].commit}
|
|
170
|
+
onScrubStart={fields[f.field].scrub.start}
|
|
171
|
+
onScrub={fields[f.field].scrub.move}
|
|
172
|
+
onScrubEnd={fields[f.field].scrub.end}
|
|
55
173
|
/>
|
|
56
174
|
</InspectorRow>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<InspectorRow>
|
|
61
|
-
<NumberField value={shadow.yPx} label="Y" ariaLabel="Shadow Y" unit="px" step={1} onCommit={(v) => patch({ yPx: v })} />
|
|
62
|
-
</InspectorRow>
|
|
63
|
-
<InspectorRow>
|
|
64
|
-
<NumberField value={shadow.blurPx} label="Blur" ariaLabel="Shadow blur" unit="px" min={0} step={1} onCommit={(v) => patch({ blurPx: v })} />
|
|
65
|
-
</InspectorRow>
|
|
66
|
-
<InspectorRow>
|
|
67
|
-
<NumberField value={shadow.spreadPx} label="Spread" ariaLabel="Shadow spread" unit="px" step={1} onCommit={(v) => patch({ spreadPx: v })} />
|
|
68
|
-
</InspectorRow>
|
|
69
|
-
</>
|
|
70
|
-
) : null}
|
|
71
|
-
</InspectorSection>
|
|
175
|
+
))}
|
|
176
|
+
</PropertyGrid>
|
|
177
|
+
</>
|
|
72
178
|
);
|
|
73
179
|
}
|
|
180
|
+
|
|
181
|
+
interface ShadowNumberField {
|
|
182
|
+
value: number | undefined;
|
|
183
|
+
mixed: boolean;
|
|
184
|
+
commit: (value: number) => void;
|
|
185
|
+
scrub: ScrubHandlers;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** One number of one entry: what it READS across the selection, what a typed
|
|
189
|
+
* value COMMITS, and what a label drag SCRUBS. Four identical calls rather
|
|
190
|
+
* than four sets of three, and the read is the SCALAR the row displays. */
|
|
191
|
+
function useShadowNumber(index: number, field: ShadowNumber): ShadowNumberField {
|
|
192
|
+
const write = useSelectionWrite();
|
|
193
|
+
const { value, mixed } = useSelectionValue((layer) => layer.paint.shadows?.[index]?.[field]);
|
|
194
|
+
const scrub = useSelectionScrub((layer, raw) => withShadow(layer, index, { [field]: Number(raw) }));
|
|
195
|
+
return {
|
|
196
|
+
value,
|
|
197
|
+
mixed,
|
|
198
|
+
commit: (next) => write((layer) => withShadow(layer, index, { [field]: next })),
|
|
199
|
+
scrub,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Patch ONE EXISTING entry.
|
|
205
|
+
*
|
|
206
|
+
* A layer whose list is shorter than `index` is LEFT ALONE rather than grown to
|
|
207
|
+
* fit: the index is an array slot, so growing would materialise a shadow on a
|
|
208
|
+
* layer the author has no row for, and a sparse list would reach the
|
|
209
|
+
* rasterizer. Returning the layer by reference is also what lets
|
|
210
|
+
* `writeSelection` leave the document identical when nothing changed.
|
|
211
|
+
*/
|
|
212
|
+
function withShadow(layer: Layer3D, index: number, next: Partial<Shadow>): Layer3D {
|
|
213
|
+
const shadows = layer.paint.shadows ?? [];
|
|
214
|
+
const current = shadows[index];
|
|
215
|
+
if (current === undefined) return layer;
|
|
216
|
+
const out = [...shadows];
|
|
217
|
+
out[index] = { ...current, ...next };
|
|
218
|
+
return { ...layer, paint: { ...layer.paint, shadows: out } };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function appendShadow(layer: Layer3D): Layer3D {
|
|
222
|
+
return {
|
|
223
|
+
...layer,
|
|
224
|
+
paint: { ...layer.paint, shadows: [...(layer.paint.shadows ?? []), DEFAULT_SHADOW] },
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Remove one entry — AND RENUMBER ITS TRACKS.
|
|
230
|
+
*
|
|
231
|
+
* A shadow's tracks are addressed by array INDEX (`paint.shadows.1.color`), so
|
|
232
|
+
* removing entry 0 from a three-shadow layer leaves the track that animated
|
|
233
|
+
* shadow 1 pointing at what is now shadow 1 — a different shadow. Nothing
|
|
234
|
+
* errors: the path still resolves and validate is satisfied, so the wrong glow
|
|
235
|
+
* pulses and there is no signal at all.
|
|
236
|
+
*
|
|
237
|
+
* `routeLayerEdit`'s orphan sweep cannot catch this, because both paths still
|
|
238
|
+
* exist. This op is the only place that knows an element was removed, so it is
|
|
239
|
+
* the only place the renumber can live.
|
|
240
|
+
*/
|
|
241
|
+
function withoutShadow(layer: Layer3D, index: number): Layer3D {
|
|
242
|
+
const shadows = layer.paint.shadows ?? [];
|
|
243
|
+
if (shadows[index] === undefined) return layer;
|
|
244
|
+
const next = { ...layer, paint: { ...layer.paint, shadows: shadows.filter((_, i) => i !== index) } };
|
|
245
|
+
return removeArrayElementTracks(next, "paint.shadows", index);
|
|
246
|
+
}
|