@editframe/elements 0.37.3-beta → 0.38.1
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/EF_FRAMEGEN.js +17 -14
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/EF_RENDERING.js.map +1 -1
- package/dist/canvas/EFCanvas.d.ts +9 -2
- package/dist/canvas/EFCanvas.js +14 -4
- package/dist/canvas/EFCanvas.js.map +1 -1
- package/dist/canvas/EFCanvasItem.d.ts +2 -2
- package/dist/canvas/overlays/SelectionOverlay.d.ts +10 -2
- package/dist/canvas/overlays/SelectionOverlay.js +5 -12
- package/dist/canvas/overlays/SelectionOverlay.js.map +1 -1
- package/dist/canvas/overlays/overlayState.js.map +1 -1
- package/dist/canvas/selection/SelectionController.js.map +1 -1
- package/dist/elements/EFAudio.d.ts +1 -11
- package/dist/elements/EFAudio.js +2 -10
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +5 -9
- package/dist/elements/EFCaptions.js +34 -11
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +10 -8
- package/dist/elements/EFImage.js +117 -32
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +2 -2
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +15 -92
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +10 -11
- package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
- package/dist/elements/EFMedia/{AssetIdMediaEngine.js → FileMediaEngine.js} +44 -24
- package/dist/elements/EFMedia/FileMediaEngine.js.map +1 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +14 -13
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +12 -7
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
- package/dist/elements/EFMedia/shared/timeoutUtils.js +44 -0
- package/dist/elements/EFMedia/shared/timeoutUtils.js.map +1 -0
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +1 -1
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +4 -4
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +14 -8
- package/dist/elements/EFMedia.js +52 -19
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +2 -2
- package/dist/elements/EFPanZoom.js +1 -1
- package/dist/elements/EFPanZoom.js.map +1 -1
- package/dist/elements/EFSourceMixin.js +16 -8
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +5 -8
- package/dist/elements/EFSurface.js +4 -43
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +33 -8
- package/dist/elements/EFTemporal.js +92 -40
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +3 -0
- package/dist/elements/EFText.js +54 -21
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.js +8 -4
- package/dist/elements/EFTextSegment.js.map +1 -1
- package/dist/elements/EFTimegroup.d.ts +26 -43
- package/dist/elements/EFTimegroup.js +295 -314
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +44 -42
- package/dist/elements/EFVideo.js +259 -172
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +3 -8
- package/dist/elements/EFWaveform.js +18 -13
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/ElementPositionInfo.js.map +1 -1
- package/dist/elements/FetchMixin.js.map +1 -1
- package/dist/elements/TargetController.d.ts +0 -3
- package/dist/elements/TargetController.js +12 -35
- package/dist/elements/TargetController.js.map +1 -1
- package/dist/elements/TimegroupController.js.map +1 -1
- package/dist/elements/cloneFactoryRegistry.d.ts +14 -0
- package/dist/elements/cloneFactoryRegistry.js +15 -0
- package/dist/elements/cloneFactoryRegistry.js.map +1 -0
- package/dist/elements/renderTemporalAudio.js +8 -6
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/elements/setupTemporalHierarchy.js +62 -0
- package/dist/elements/setupTemporalHierarchy.js.map +1 -0
- package/dist/elements/updateAnimations.js +62 -87
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/getRenderInfo.d.ts +3 -2
- package/dist/getRenderInfo.js +20 -4
- package/dist/getRenderInfo.js.map +1 -1
- package/dist/gui/ContextMixin.js +68 -12
- package/dist/gui/ContextMixin.js.map +1 -1
- package/dist/gui/Controllable.js +1 -1
- package/dist/gui/Controllable.js.map +1 -1
- package/dist/gui/EFActiveRootTemporal.d.ts +2 -2
- package/dist/gui/EFActiveRootTemporal.js.map +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +2 -2
- package/dist/gui/EFControls.js.map +1 -1
- package/dist/gui/EFDial.d.ts +2 -2
- package/dist/gui/EFDial.js +12 -9
- package/dist/gui/EFDial.js.map +1 -1
- package/dist/gui/EFFilmstrip.d.ts +2 -0
- package/dist/gui/EFFilmstrip.js +18 -10
- package/dist/gui/EFFilmstrip.js.map +1 -1
- package/dist/gui/EFFitScale.d.ts +28 -4
- package/dist/gui/EFFitScale.js +88 -26
- package/dist/gui/EFFitScale.js.map +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +2 -2
- package/dist/gui/EFFocusOverlay.js +3 -3
- package/dist/gui/EFFocusOverlay.js.map +1 -1
- package/dist/gui/EFOverlayItem.d.ts +2 -2
- package/dist/gui/EFOverlayLayer.d.ts +2 -2
- package/dist/gui/EFPause.d.ts +2 -2
- package/dist/gui/EFPause.js +1 -1
- package/dist/gui/EFPlay.d.ts +2 -2
- package/dist/gui/EFPlay.js +1 -1
- package/dist/gui/EFPreview.js +1 -1
- package/dist/gui/EFResizableBox.d.ts +2 -2
- package/dist/gui/EFResizableBox.js +5 -5
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +2 -2
- package/dist/gui/EFScrubber.js +8 -13
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +6 -2
- package/dist/gui/EFTimeDisplay.js +25 -7
- package/dist/gui/EFTimeDisplay.js.map +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +2 -2
- package/dist/gui/EFTimelineRuler.js +3 -3
- package/dist/gui/EFTimelineRuler.js.map +1 -1
- package/dist/gui/EFToggleLoop.d.ts +2 -2
- package/dist/gui/EFToggleLoop.js +1 -1
- package/dist/gui/EFTogglePlay.d.ts +2 -2
- package/dist/gui/EFTogglePlay.js +1 -1
- package/dist/gui/EFTransformHandles.d.ts +2 -2
- package/dist/gui/EFTransformHandles.js +6 -6
- package/dist/gui/EFTransformHandles.js.map +1 -1
- package/dist/gui/EFWorkbench.d.ts +40 -36
- package/dist/gui/EFWorkbench.js +436 -822
- package/dist/gui/EFWorkbench.js.map +1 -1
- package/dist/gui/FitScaleHelpers.js.map +1 -1
- package/dist/gui/PlaybackController.d.ts +3 -8
- package/dist/gui/PlaybackController.js +59 -56
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/TargetOrContextMixin.js +43 -6
- package/dist/gui/TargetOrContextMixin.js.map +1 -1
- package/dist/gui/ef-theme.css +136 -0
- package/dist/gui/hierarchy/EFHierarchy.d.ts +2 -2
- package/dist/gui/hierarchy/EFHierarchy.js +14 -24
- package/dist/gui/hierarchy/EFHierarchy.js.map +1 -1
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
- package/dist/gui/hierarchy/EFHierarchyItem.js +22 -10
- package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -1
- package/dist/gui/icons.js.map +1 -1
- package/dist/gui/previewSettingsContext.d.ts +18 -0
- package/dist/gui/previewSettingsContext.js.map +1 -1
- package/dist/gui/theme.js +34 -0
- package/dist/gui/theme.js.map +1 -0
- package/dist/gui/timeline/EFTimeline.d.ts +2 -2
- package/dist/gui/timeline/EFTimeline.js +70 -52
- package/dist/gui/timeline/EFTimeline.js.map +1 -1
- package/dist/gui/timeline/EFTimelineRow.d.ts +5 -3
- package/dist/gui/timeline/EFTimelineRow.js +55 -32
- package/dist/gui/timeline/EFTimelineRow.js.map +1 -1
- package/dist/gui/timeline/TrimHandles.d.ts +23 -9
- package/dist/gui/timeline/TrimHandles.js +224 -51
- package/dist/gui/timeline/TrimHandles.js.map +1 -1
- package/dist/gui/timeline/flattenHierarchy.js.map +1 -1
- package/dist/gui/timeline/timelineEditingContext.d.ts +34 -0
- package/dist/gui/timeline/timelineEditingContext.js +24 -0
- package/dist/gui/timeline/timelineEditingContext.js.map +1 -0
- package/dist/gui/timeline/timelineStateContext.js.map +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +2 -3
- package/dist/gui/timeline/tracks/CaptionsTrack.js +17 -75
- package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/EFThumbnailStrip.d.ts +52 -0
- package/dist/gui/timeline/tracks/EFThumbnailStrip.js +596 -0
- package/dist/gui/timeline/tracks/EFThumbnailStrip.js.map +1 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TextTrack.d.ts +3 -2
- package/dist/gui/timeline/tracks/TextTrack.js +17 -43
- package/dist/gui/timeline/tracks/TextTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +3 -4
- package/dist/gui/timeline/tracks/TimegroupTrack.js +33 -23
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TrackItem.d.ts +7 -9
- package/dist/gui/timeline/tracks/TrackItem.js +18 -17
- package/dist/gui/timeline/tracks/TrackItem.js.map +1 -1
- package/dist/gui/timeline/tracks/VideoTrack.d.ts +3 -3
- package/dist/gui/timeline/tracks/VideoTrack.js +11 -14
- package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -1
- package/dist/gui/timeline/tracks/waveformUtils.js +1 -1
- package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -1
- package/dist/gui/tree/EFTree.d.ts +2 -2
- package/dist/gui/tree/EFTree.js +8 -14
- package/dist/gui/tree/EFTree.js.map +1 -1
- package/dist/gui/tree/EFTreeItem.d.ts +2 -2
- package/dist/gui/tree/EFTreeItem.js +3 -3
- package/dist/gui/tree/EFTreeItem.js.map +1 -1
- package/dist/gui/tree/treeContext.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/preview/AdaptiveResolutionTracker.js +3 -3
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
- package/dist/preview/FrameController.d.ts +2 -17
- package/dist/preview/FrameController.js +40 -63
- package/dist/preview/FrameController.js.map +1 -1
- package/dist/preview/QualityUpgradeScheduler.d.ts +76 -0
- package/dist/preview/QualityUpgradeScheduler.js +158 -0
- package/dist/preview/QualityUpgradeScheduler.js.map +1 -0
- package/dist/preview/RenderContext.d.ts +119 -1
- package/dist/preview/RenderContext.js +21 -3
- package/dist/preview/RenderContext.js.map +1 -1
- package/dist/preview/RenderProfiler.js.map +1 -1
- package/dist/preview/RenderStats.js +85 -0
- package/dist/preview/RenderStats.js.map +1 -0
- package/dist/preview/encoding/canvasEncoder.js +2 -52
- package/dist/preview/encoding/canvasEncoder.js.map +1 -1
- package/dist/preview/encoding/mainThreadEncoder.js.map +1 -1
- package/dist/preview/encoding/workerEncoder.js.map +1 -1
- package/dist/preview/logger.js.map +1 -1
- package/dist/preview/previewSettings.d.ts +34 -0
- package/dist/preview/previewSettings.js +29 -17
- package/dist/preview/previewSettings.js.map +1 -1
- package/dist/preview/previewTypes.js +4 -4
- package/dist/preview/previewTypes.js.map +1 -1
- package/dist/preview/renderElementToCanvas.d.ts +44 -0
- package/dist/preview/renderElementToCanvas.js +72 -0
- package/dist/preview/renderElementToCanvas.js.map +1 -0
- package/dist/preview/renderTimegroupToCanvas.d.ts +134 -32
- package/dist/preview/renderTimegroupToCanvas.js +321 -146
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
- package/dist/preview/renderTimegroupToCanvas.types.d.ts +51 -0
- package/dist/preview/renderTimegroupToVideo.d.ts +20 -35
- package/dist/preview/renderTimegroupToVideo.js +94 -106
- package/dist/preview/renderTimegroupToVideo.js.map +1 -1
- package/dist/preview/renderTimegroupToVideo.types.d.ts +42 -0
- package/dist/preview/renderVideoToVideo.js +286 -0
- package/dist/preview/renderVideoToVideo.js.map +1 -0
- package/dist/preview/renderers.d.ts +56 -0
- package/dist/preview/renderers.js +13 -1
- package/dist/preview/renderers.js.map +1 -1
- package/dist/preview/rendering/ScaleConfig.js +74 -0
- package/dist/preview/rendering/ScaleConfig.js.map +1 -0
- package/dist/preview/rendering/inlineImages.d.ts +13 -0
- package/dist/preview/rendering/inlineImages.js +7 -44
- package/dist/preview/rendering/inlineImages.js.map +1 -1
- package/dist/preview/rendering/loadImage.d.ts +8 -0
- package/dist/preview/rendering/loadImage.js +22 -0
- package/dist/preview/rendering/loadImage.js.map +1 -0
- package/dist/preview/rendering/renderToImageNative.js +3 -3
- package/dist/preview/rendering/renderToImageNative.js.map +1 -1
- package/dist/preview/rendering/serializeTimelineDirect.js +224 -68
- package/dist/preview/rendering/serializeTimelineDirect.js.map +1 -1
- package/dist/preview/statsTrackingStrategy.js +1 -101
- package/dist/preview/statsTrackingStrategy.js.map +1 -1
- package/dist/preview/workers/WorkerPool.js +0 -1
- package/dist/preview/workers/WorkerPool.js.map +1 -1
- package/dist/preview/workers/encoderWorkerInline.js +21 -54
- package/dist/preview/workers/encoderWorkerInline.js.map +1 -1
- package/dist/render/EFRenderAPI.d.ts +2 -1
- package/dist/render/EFRenderAPI.js +12 -36
- package/dist/render/EFRenderAPI.js.map +1 -1
- package/dist/render/getRenderData.js +4 -4
- package/dist/render/getRenderData.js.map +1 -1
- package/dist/style.css +114 -163
- package/dist/transcoding/cache/RequestDeduplicator.js +1 -0
- package/dist/transcoding/cache/RequestDeduplicator.js.map +1 -1
- package/dist/transcoding/types/index.d.ts +1 -1
- package/dist/transcoding/utils/UrlGenerator.js +10 -3
- package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
- package/dist/utils/LRUCache.js +1 -0
- package/dist/utils/LRUCache.js.map +1 -1
- package/dist/utils/frameTime.js +23 -1
- package/dist/utils/frameTime.js.map +1 -1
- package/package.json +45 -8
- package/scripts/build-css.js +8 -1
- package/test/setup.ts +0 -1
- package/test/useAssetMSW.ts +50 -0
- package/test/visualRegressionUtils.ts +23 -9
- package/tsdown.config.ts +6 -1
- package/dist/_virtual/rolldown_runtime.js +0 -27
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +0 -1
- package/dist/elements/EFThumbnailStrip.d.ts +0 -167
- package/dist/elements/EFThumbnailStrip.js +0 -731
- package/dist/elements/EFThumbnailStrip.js.map +0 -1
- package/dist/elements/SessionThumbnailCache.js +0 -154
- package/dist/elements/SessionThumbnailCache.js.map +0 -1
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +0 -688
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +0 -1
- package/dist/node_modules/react/cjs/react.development.js +0 -1521
- package/dist/node_modules/react/cjs/react.development.js.map +0 -1
- package/dist/node_modules/react/index.js +0 -13
- package/dist/node_modules/react/index.js.map +0 -1
- package/dist/node_modules/react/jsx-runtime.js +0 -13
- package/dist/node_modules/react/jsx-runtime.js.map +0 -1
- package/dist/preview/encoding/types.d.ts +0 -1
- package/dist/preview/renderTimegroupPreview.js +0 -686
- package/dist/preview/renderTimegroupPreview.js.map +0 -1
- package/dist/preview/rendering/renderToImage.d.ts +0 -2
- package/dist/preview/rendering/renderToImage.js +0 -95
- package/dist/preview/rendering/renderToImage.js.map +0 -1
- package/dist/preview/rendering/renderToImageForeignObject.js +0 -163
- package/dist/preview/rendering/renderToImageForeignObject.js.map +0 -1
- package/dist/preview/rendering/renderToImageNative.d.ts +0 -1
- package/dist/preview/rendering/svgSerializer.js +0 -43
- package/dist/preview/rendering/svgSerializer.js.map +0 -1
- package/dist/preview/rendering/types.d.ts +0 -2
- package/dist/preview/thumbnailCacheSettings.js +0 -52
- package/dist/preview/thumbnailCacheSettings.js.map +0 -1
- package/dist/sandbox/PlaybackControls.d.ts +0 -1
- package/dist/sandbox/PlaybackControls.js +0 -10
- package/dist/sandbox/PlaybackControls.js.map +0 -1
- package/dist/sandbox/ScenarioRunner.d.ts +0 -1
- package/dist/sandbox/ScenarioRunner.js +0 -1
- package/dist/sandbox/defineSandbox.d.ts +0 -1
- package/dist/sandbox/index.d.ts +0 -3
- package/dist/sandbox/index.js +0 -2
- package/test/EFVideo.framegen.browsertest.ts +0 -80
- package/test/thumbnail-performance-test.html +0 -116
package/dist/gui/EFWorkbench.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
+
import { TWMixin } from "./TWMixin2.js";
|
|
2
|
+
import { updateAnimations } from "../elements/updateAnimations.js";
|
|
1
3
|
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.95.0/helpers/decorate.js";
|
|
2
4
|
import { ContextMixin } from "./ContextMixin.js";
|
|
3
|
-
import { TWMixin } from "./TWMixin2.js";
|
|
4
|
-
import { getPreviewPresentationMode, getPreviewResolutionScale, getRenderMode, getShowStats, isNativeCanvasApiAvailable, setPreviewPresentationMode, setPreviewResolutionScale, setRenderMode, setShowStats } from "../preview/previewSettings.js";
|
|
5
|
-
import { renderTimegroupToCanvas } from "../preview/renderTimegroupToCanvas.js";
|
|
6
|
-
import { RenderCancelledError, renderTimegroupToVideo } from "../preview/renderTimegroupToVideo.js";
|
|
7
5
|
import { findRootTemporal } from "../elements/findRootTemporal.js";
|
|
8
6
|
import { ICONS, phosphorIcon } from "./icons.js";
|
|
9
|
-
import {
|
|
10
|
-
import "../elements/EFThumbnailStrip.js";
|
|
11
|
-
import { createStatsTrackingStrategy } from "../preview/statsTrackingStrategy.js";
|
|
12
|
-
import { getThumbnailCacheMaxSize, onThumbnailCacheSettingsChanged, setThumbnailCacheMaxSize } from "../preview/thumbnailCacheSettings.js";
|
|
13
|
-
import { AdaptiveResolutionTracker } from "../preview/AdaptiveResolutionTracker.js";
|
|
7
|
+
import { getPreviewPresentationMode, getPreviewResolutionScale, getRenderMode, getShowStats, getShowThumbnailTimestamps, isNativeCanvasApiAvailable, setPreviewPresentationMode, setRenderMode, setShowStats, setShowThumbnailTimestamps } from "../preview/previewSettings.js";
|
|
14
8
|
import { previewSettingsContext } from "./previewSettingsContext.js";
|
|
9
|
+
import { AdaptiveResolutionTracker } from "../preview/AdaptiveResolutionTracker.js";
|
|
10
|
+
import { RenderStats } from "../preview/RenderStats.js";
|
|
11
|
+
import { DomStatsStrategy } from "../preview/statsTrackingStrategy.js";
|
|
15
12
|
import "./EFFitScale.js";
|
|
16
13
|
import { EFTimegroup } from "../elements/EFTimegroup.js";
|
|
17
14
|
import { provide } from "@lit/context";
|
|
@@ -39,15 +36,11 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
39
36
|
renderMode: getRenderMode(),
|
|
40
37
|
resolutionScale: getPreviewResolutionScale(),
|
|
41
38
|
showStats: getShowStats(),
|
|
42
|
-
|
|
39
|
+
showThumbnailTimestamps: getShowThumbnailTimestamps()
|
|
43
40
|
};
|
|
44
41
|
this.renderMode = this.previewSettings.renderMode;
|
|
45
42
|
this.presentationMode = this.previewSettings.presentationMode;
|
|
46
43
|
this.previewResolutionScale = this.previewSettings.resolutionScale;
|
|
47
|
-
this.debugThumbnailTimestamps = false;
|
|
48
|
-
this.thumbnailCacheMaxSize = this.previewSettings.thumbnailCacheMaxSize;
|
|
49
|
-
this.thumbnailCacheStats = null;
|
|
50
|
-
this.cacheStatsUpdateInterval = null;
|
|
51
44
|
this.exportOptions = {
|
|
52
45
|
includeAudio: true,
|
|
53
46
|
scale: 1,
|
|
@@ -61,20 +54,16 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
61
54
|
this.isAtRest = true;
|
|
62
55
|
this.currentAdaptiveScale = 1;
|
|
63
56
|
this.showStats = this.previewSettings.showStats;
|
|
64
|
-
this.
|
|
57
|
+
this.themeMode = this.getInitialTheme();
|
|
58
|
+
this.renderStats = null;
|
|
59
|
+
this.systemThemeMediaQuery = null;
|
|
60
|
+
this.systemThemeListener = null;
|
|
61
|
+
this.domStatsStrategy = null;
|
|
65
62
|
this.isScrubbingRef = { current: false };
|
|
66
63
|
this.restDebounceTimer = null;
|
|
67
64
|
this.playingCheckInterval = null;
|
|
68
65
|
this.adaptiveTracker = null;
|
|
69
66
|
this.savePanZoomDebounceTimer = null;
|
|
70
|
-
this.cloneOverlayRef = createRef();
|
|
71
|
-
this.cloneRefresh = null;
|
|
72
|
-
this.cloneAnimationFrame = null;
|
|
73
|
-
this.cloneRootElement = null;
|
|
74
|
-
this.cloneTimegroup = null;
|
|
75
|
-
this.structureObserver = null;
|
|
76
|
-
this.rebuildPending = false;
|
|
77
|
-
this.canvasRefresh = null;
|
|
78
67
|
this.canvasPreviewRef = createRef();
|
|
79
68
|
this.canvasPreviewResult = null;
|
|
80
69
|
this.canvasAnimationFrame = null;
|
|
@@ -101,29 +90,20 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
101
90
|
static {
|
|
102
91
|
this.styles = [css`
|
|
103
92
|
:host {
|
|
104
|
-
display:
|
|
105
|
-
|
|
93
|
+
display: grid;
|
|
94
|
+
grid-template-rows: auto 1fr 280px;
|
|
95
|
+
grid-template-columns: 280px 1fr;
|
|
106
96
|
width: 100%;
|
|
107
97
|
height: 100%;
|
|
108
|
-
min-width: 0;
|
|
109
|
-
min-height: 0;
|
|
110
98
|
overflow: hidden;
|
|
99
|
+
background-color: var(--ef-color-bg);
|
|
111
100
|
|
|
112
|
-
/*
|
|
113
|
-
--workbench-bg:
|
|
114
|
-
--workbench-overlay-border:
|
|
115
|
-
--workbench-overlay-bg:
|
|
116
|
-
--toolbar-bg:
|
|
117
|
-
--toolbar-border:
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
:host(.dark), :host-context(.dark) {
|
|
121
|
-
/* Dark mode colors */
|
|
122
|
-
--workbench-bg: rgb(2 6 23); /* slate-950 */
|
|
123
|
-
--workbench-overlay-border: rgb(96 165 250); /* blue-400 */
|
|
124
|
-
--workbench-overlay-bg: rgb(30 58 138); /* blue-900 */
|
|
125
|
-
--toolbar-bg: rgb(2 6 23);
|
|
126
|
-
--toolbar-border: rgba(148, 163, 184, 0.15);
|
|
101
|
+
/* Component tokens (reference globals from ef-theme.css) */
|
|
102
|
+
--workbench-bg: var(--ef-color-bg);
|
|
103
|
+
--workbench-overlay-border: var(--ef-color-primary);
|
|
104
|
+
--workbench-overlay-bg: var(--ef-color-primary-subtle);
|
|
105
|
+
--toolbar-bg: var(--ef-color-bg-elevated);
|
|
106
|
+
--toolbar-border: var(--ef-color-border-subtle);
|
|
127
107
|
}
|
|
128
108
|
|
|
129
109
|
/* Utility classes (not relying on external Tailwind) */
|
|
@@ -186,36 +166,36 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
186
166
|
justify-content: center;
|
|
187
167
|
gap: 6px;
|
|
188
168
|
padding: 6px 12px;
|
|
189
|
-
background:
|
|
190
|
-
border: 1px solid
|
|
169
|
+
background: var(--ef-color-bg-inset);
|
|
170
|
+
border: 1px solid var(--ef-color-border-subtle);
|
|
191
171
|
border-radius: 6px;
|
|
192
|
-
color:
|
|
172
|
+
color: var(--ef-color-text);
|
|
193
173
|
font-size: 12px;
|
|
194
|
-
font-weight:
|
|
174
|
+
font-weight: 600;
|
|
195
175
|
cursor: pointer;
|
|
196
176
|
transition: all 0.15s ease;
|
|
197
177
|
}
|
|
198
178
|
|
|
199
179
|
.toolbar-btn:hover {
|
|
200
|
-
background:
|
|
201
|
-
border-color:
|
|
180
|
+
background: var(--ef-color-hover);
|
|
181
|
+
border-color: var(--ef-color-border);
|
|
202
182
|
}
|
|
203
183
|
|
|
204
184
|
.toolbar-btn.active {
|
|
205
|
-
background:
|
|
206
|
-
border-color:
|
|
207
|
-
color:
|
|
185
|
+
background: var(--ef-color-primary-subtle);
|
|
186
|
+
border-color: var(--ef-color-primary);
|
|
187
|
+
color: var(--ef-color-primary-hover);
|
|
208
188
|
}
|
|
209
189
|
|
|
210
190
|
.toolbar-btn.primary {
|
|
211
|
-
background:
|
|
191
|
+
background: var(--ef-color-primary);
|
|
212
192
|
border-color: transparent;
|
|
213
193
|
color: white;
|
|
214
194
|
font-weight: 600;
|
|
215
195
|
}
|
|
216
196
|
|
|
217
197
|
.toolbar-btn.primary:hover {
|
|
218
|
-
background:
|
|
198
|
+
background: var(--ef-color-primary-hover);
|
|
219
199
|
}
|
|
220
200
|
|
|
221
201
|
.toolbar-icon-btn {
|
|
@@ -225,23 +205,23 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
225
205
|
width: 32px;
|
|
226
206
|
height: 32px;
|
|
227
207
|
padding: 0;
|
|
228
|
-
background:
|
|
229
|
-
border: 1px solid
|
|
208
|
+
background: var(--ef-color-bg-inset);
|
|
209
|
+
border: 1px solid var(--ef-color-border-subtle);
|
|
230
210
|
border-radius: 6px;
|
|
231
|
-
color:
|
|
211
|
+
color: var(--ef-color-text);
|
|
232
212
|
cursor: pointer;
|
|
233
213
|
transition: all 0.15s ease;
|
|
234
214
|
}
|
|
235
215
|
|
|
236
216
|
.toolbar-icon-btn:hover {
|
|
237
|
-
background:
|
|
238
|
-
border-color:
|
|
217
|
+
background: var(--ef-color-hover);
|
|
218
|
+
border-color: var(--ef-color-border);
|
|
239
219
|
}
|
|
240
220
|
|
|
241
221
|
.toolbar-icon-btn.active {
|
|
242
|
-
background:
|
|
243
|
-
border-color:
|
|
244
|
-
color:
|
|
222
|
+
background: var(--ef-color-primary-subtle);
|
|
223
|
+
border-color: var(--ef-color-primary);
|
|
224
|
+
color: var(--ef-color-primary-hover);
|
|
245
225
|
}
|
|
246
226
|
|
|
247
227
|
.mode-indicator {
|
|
@@ -258,15 +238,15 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
258
238
|
}
|
|
259
239
|
|
|
260
240
|
.mode-indicator.dom {
|
|
261
|
-
background:
|
|
262
|
-
color:
|
|
263
|
-
border: 1px solid
|
|
241
|
+
background: color-mix(in srgb, var(--ef-color-success) 15%, transparent);
|
|
242
|
+
color: var(--ef-color-success);
|
|
243
|
+
border: 1px solid color-mix(in srgb, var(--ef-color-success) 30%, transparent);
|
|
264
244
|
}
|
|
265
245
|
|
|
266
246
|
.mode-indicator.canvas {
|
|
267
|
-
background:
|
|
268
|
-
color:
|
|
269
|
-
border: 1px solid
|
|
247
|
+
background: color-mix(in srgb, var(--ef-color-type-image) 15%, transparent);
|
|
248
|
+
color: var(--ef-color-type-image);
|
|
249
|
+
border: 1px solid color-mix(in srgb, var(--ef-color-type-image) 30%, transparent);
|
|
270
250
|
}
|
|
271
251
|
|
|
272
252
|
.canvas-container {
|
|
@@ -277,6 +257,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
277
257
|
grid-template-columns: 100%;
|
|
278
258
|
grid-template-rows: 100%;
|
|
279
259
|
min-height: 0;
|
|
260
|
+
background: var(--ef-color-bg);
|
|
280
261
|
}
|
|
281
262
|
|
|
282
263
|
.canvas-container ::slotted(*) {
|
|
@@ -286,7 +267,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
286
267
|
grid-row: 1;
|
|
287
268
|
}
|
|
288
269
|
|
|
289
|
-
.
|
|
270
|
+
.canvas-overlay {
|
|
290
271
|
position: absolute;
|
|
291
272
|
inset: 0;
|
|
292
273
|
pointer-events: none;
|
|
@@ -303,13 +284,13 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
303
284
|
top: 8px;
|
|
304
285
|
left: 8px;
|
|
305
286
|
width: 200px;
|
|
306
|
-
background:
|
|
287
|
+
background: color-mix(in srgb, var(--ef-color-bg-elevated) 90%, transparent);
|
|
307
288
|
backdrop-filter: blur(4px);
|
|
308
289
|
border-radius: 6px;
|
|
309
290
|
padding: 8px 12px;
|
|
310
291
|
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
|
311
292
|
font-size: 11px;
|
|
312
|
-
color:
|
|
293
|
+
color: var(--ef-color-text);
|
|
313
294
|
z-index: 10;
|
|
314
295
|
pointer-events: none;
|
|
315
296
|
line-height: 1.5;
|
|
@@ -322,7 +303,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
322
303
|
}
|
|
323
304
|
|
|
324
305
|
.playback-stats .stat-label {
|
|
325
|
-
color:
|
|
306
|
+
color: var(--ef-color-text-muted);
|
|
326
307
|
flex-shrink: 0;
|
|
327
308
|
width: 85px;
|
|
328
309
|
}
|
|
@@ -335,15 +316,15 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
335
316
|
}
|
|
336
317
|
|
|
337
318
|
.playback-stats .stat-value.good {
|
|
338
|
-
color:
|
|
319
|
+
color: var(--ef-color-success);
|
|
339
320
|
}
|
|
340
321
|
|
|
341
322
|
.playback-stats .stat-value.warning {
|
|
342
|
-
color:
|
|
323
|
+
color: var(--ef-color-warning);
|
|
343
324
|
}
|
|
344
325
|
|
|
345
326
|
.playback-stats .stat-value.bad {
|
|
346
|
-
color:
|
|
327
|
+
color: var(--ef-color-danger);
|
|
347
328
|
}
|
|
348
329
|
|
|
349
330
|
.pressure-histogram {
|
|
@@ -353,7 +334,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
353
334
|
height: 24px;
|
|
354
335
|
margin-top: 8px;
|
|
355
336
|
padding-top: 8px;
|
|
356
|
-
border-top: 1px solid
|
|
337
|
+
border-top: 1px solid var(--ef-color-border-subtle);
|
|
357
338
|
}
|
|
358
339
|
|
|
359
340
|
.pressure-histogram .bar {
|
|
@@ -365,22 +346,22 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
365
346
|
}
|
|
366
347
|
|
|
367
348
|
.pressure-histogram .bar.nominal {
|
|
368
|
-
background:
|
|
349
|
+
background: var(--ef-color-success);
|
|
369
350
|
height: 25%;
|
|
370
351
|
}
|
|
371
352
|
|
|
372
353
|
.pressure-histogram .bar.fair {
|
|
373
|
-
background:
|
|
354
|
+
background: var(--ef-color-warning);
|
|
374
355
|
height: 50%;
|
|
375
356
|
}
|
|
376
357
|
|
|
377
358
|
.pressure-histogram .bar.serious {
|
|
378
|
-
background:
|
|
359
|
+
background: var(--ef-color-warning);
|
|
379
360
|
height: 75%;
|
|
380
361
|
}
|
|
381
362
|
|
|
382
363
|
.pressure-histogram .bar.critical {
|
|
383
|
-
background:
|
|
364
|
+
background: var(--ef-color-danger);
|
|
384
365
|
height: 100%;
|
|
385
366
|
}
|
|
386
367
|
|
|
@@ -389,7 +370,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
389
370
|
justify-content: space-between;
|
|
390
371
|
margin-top: 4px;
|
|
391
372
|
font-size: 9px;
|
|
392
|
-
color:
|
|
373
|
+
color: var(--ef-color-text-subtle);
|
|
393
374
|
}
|
|
394
375
|
|
|
395
376
|
.dropdown-panel {
|
|
@@ -398,11 +379,11 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
398
379
|
padding: 14px 16px;
|
|
399
380
|
min-width: 260px;
|
|
400
381
|
max-width: calc(100vw - 32px);
|
|
401
|
-
background:
|
|
402
|
-
border: 1px solid
|
|
382
|
+
background: var(--ef-color-bg-elevated);
|
|
383
|
+
border: 1px solid var(--ef-color-border);
|
|
403
384
|
border-radius: 10px;
|
|
404
385
|
backdrop-filter: blur(12px);
|
|
405
|
-
box-shadow: 0 8px 32px
|
|
386
|
+
box-shadow: 0 8px 32px color-mix(in srgb, var(--ef-color-bg) 50%, transparent);
|
|
406
387
|
}
|
|
407
388
|
|
|
408
389
|
.dropdown-panel::backdrop {
|
|
@@ -431,11 +412,11 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
431
412
|
justify-content: space-between;
|
|
432
413
|
margin-bottom: 12px;
|
|
433
414
|
padding-bottom: 10px;
|
|
434
|
-
border-bottom: 1px solid
|
|
415
|
+
border-bottom: 1px solid var(--ef-color-border-subtle);
|
|
435
416
|
}
|
|
436
417
|
|
|
437
418
|
.dropdown-title {
|
|
438
|
-
color:
|
|
419
|
+
color: var(--ef-color-text);
|
|
439
420
|
font-size: 13px;
|
|
440
421
|
font-weight: 600;
|
|
441
422
|
}
|
|
@@ -443,8 +424,100 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
443
424
|
.dropdown-close {
|
|
444
425
|
background: transparent;
|
|
445
426
|
border: none;
|
|
446
|
-
color:
|
|
427
|
+
color: var(--ef-color-text-subtle);
|
|
447
428
|
cursor: pointer;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.dropdown-section {
|
|
432
|
+
background: var(--ef-color-bg-inset);
|
|
433
|
+
border-radius: 8px;
|
|
434
|
+
padding: 12px;
|
|
435
|
+
margin-top: 10px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.dropdown-label {
|
|
439
|
+
color: var(--ef-color-text);
|
|
440
|
+
font-size: 11px;
|
|
441
|
+
font-weight: 600;
|
|
442
|
+
margin-bottom: 6px;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.dropdown-description {
|
|
446
|
+
margin-top: 8px;
|
|
447
|
+
color: var(--ef-color-text-subtle);
|
|
448
|
+
font-size: 10px;
|
|
449
|
+
line-height: 1.4;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.button-group {
|
|
453
|
+
display: flex;
|
|
454
|
+
gap: 6px;
|
|
455
|
+
margin-top: 6px;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.button-group-btn {
|
|
459
|
+
flex: 1;
|
|
460
|
+
padding: 6px 8px;
|
|
461
|
+
border: 1px solid transparent;
|
|
462
|
+
border-radius: 4px;
|
|
463
|
+
font-size: 10px;
|
|
464
|
+
font-weight: 500;
|
|
465
|
+
cursor: pointer;
|
|
466
|
+
transition: all 0.15s ease;
|
|
467
|
+
background: transparent;
|
|
468
|
+
color: var(--ef-color-text-muted);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.button-group-btn.active {
|
|
472
|
+
background: var(--ef-color-selected);
|
|
473
|
+
color: var(--ef-color-primary);
|
|
474
|
+
border-color: var(--ef-color-primary-subtle);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.checkbox-label {
|
|
478
|
+
display: flex;
|
|
479
|
+
align-items: center;
|
|
480
|
+
gap: 8px;
|
|
481
|
+
cursor: pointer;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.checkbox-label input[type="checkbox"] {
|
|
485
|
+
width: 14px;
|
|
486
|
+
height: 14px;
|
|
487
|
+
accent-color: var(--ef-color-primary);
|
|
488
|
+
cursor: pointer;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.checkbox-label span {
|
|
492
|
+
color: var(--ef-color-text);
|
|
493
|
+
font-size: 12px;
|
|
494
|
+
font-weight: 500;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.dropdown-select {
|
|
498
|
+
width: 100%;
|
|
499
|
+
padding: 6px 8px;
|
|
500
|
+
background: var(--ef-color-bg-inset);
|
|
501
|
+
border: 1px solid var(--ef-color-border);
|
|
502
|
+
border-radius: 6px;
|
|
503
|
+
color: var(--ef-color-text);
|
|
504
|
+
font-size: 11px;
|
|
505
|
+
cursor: pointer;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.dropdown-input {
|
|
509
|
+
width: 100%;
|
|
510
|
+
padding: 5px 7px;
|
|
511
|
+
background: var(--ef-color-bg-inset);
|
|
512
|
+
border: 1px solid var(--ef-color-border);
|
|
513
|
+
border-radius: 4px;
|
|
514
|
+
color: var(--ef-color-text);
|
|
515
|
+
font-size: 11px;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.dropdown-input:disabled {
|
|
519
|
+
opacity: 0.5;
|
|
520
|
+
cursor: not-allowed;
|
|
448
521
|
padding: 2px;
|
|
449
522
|
line-height: 1;
|
|
450
523
|
font-size: 14px;
|
|
@@ -452,7 +525,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
452
525
|
}
|
|
453
526
|
|
|
454
527
|
.dropdown-close:hover {
|
|
455
|
-
color:
|
|
528
|
+
color: var(--ef-color-text-muted);
|
|
456
529
|
}
|
|
457
530
|
`];
|
|
458
531
|
}
|
|
@@ -461,6 +534,8 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
461
534
|
}
|
|
462
535
|
connectedCallback() {
|
|
463
536
|
super.connectedCallback();
|
|
537
|
+
this.applyTheme();
|
|
538
|
+
if (!this.hasAttribute("rendering") && typeof window !== "undefined" && "FRAMEGEN_BRIDGE" in window) this.rendering = true;
|
|
464
539
|
this.addEventListener("transform-changed", this.boundHandleTransformChanged);
|
|
465
540
|
this.startMotionStateTracking();
|
|
466
541
|
this.adaptiveTracker = new AdaptiveResolutionTracker({ onScaleChange: (scale) => {
|
|
@@ -471,29 +546,20 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
471
546
|
this.canvasPreviewResult.setResolutionScale(scale);
|
|
472
547
|
console.log(`[EFWorkbench] Resolution changed ${(oldScale * 100).toFixed(0)}% → ${(scale * 100).toFixed(0)}% (instant)`);
|
|
473
548
|
}
|
|
474
|
-
}
|
|
549
|
+
}
|
|
475
550
|
} });
|
|
476
|
-
this.
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
this.previewSettings = {
|
|
482
|
-
...this.previewSettings,
|
|
483
|
-
thumbnailCacheMaxSize: newSize
|
|
551
|
+
this.renderStats = new RenderStats(this.adaptiveTracker);
|
|
552
|
+
if (typeof window !== "undefined") {
|
|
553
|
+
this.systemThemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
554
|
+
this.systemThemeListener = () => {
|
|
555
|
+
if (this.themeMode === "system") this.applyTheme();
|
|
484
556
|
};
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
});
|
|
557
|
+
this.systemThemeMediaQuery.addEventListener("change", this.systemThemeListener);
|
|
558
|
+
}
|
|
488
559
|
}
|
|
489
560
|
disconnectedCallback() {
|
|
490
561
|
super.disconnectedCallback();
|
|
491
|
-
if (this.
|
|
492
|
-
this.statsStrategy.stop();
|
|
493
|
-
this.statsStrategy = null;
|
|
494
|
-
}
|
|
495
|
-
if (this.presentationMode === "clone") this.stopCloneOverlay();
|
|
496
|
-
else if (this.presentationMode === "dom") this.stopDomMode();
|
|
562
|
+
if (this.presentationMode === "dom") this.stopDomMode();
|
|
497
563
|
else if (this.presentationMode === "canvas") this.stopCanvasMode();
|
|
498
564
|
const timegroup = this.getTimegroup();
|
|
499
565
|
if (timegroup) {
|
|
@@ -501,8 +567,9 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
501
567
|
timegroup.style.pointerEvents = "";
|
|
502
568
|
}
|
|
503
569
|
this.removeEventListener("transform-changed", this.boundHandleTransformChanged);
|
|
570
|
+
if (this.systemThemeMediaQuery && this.systemThemeListener) this.systemThemeMediaQuery.removeEventListener("change", this.systemThemeListener);
|
|
504
571
|
this.stopMotionStateTracking();
|
|
505
|
-
this.stopCacheStatsUpdates();
|
|
572
|
+
if (typeof this.stopCacheStatsUpdates === "function") this.stopCacheStatsUpdates();
|
|
506
573
|
if (this.adaptiveTracker) {
|
|
507
574
|
this.adaptiveTracker.dispose();
|
|
508
575
|
this.adaptiveTracker = null;
|
|
@@ -517,25 +584,29 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
517
584
|
requestAnimationFrame(() => {
|
|
518
585
|
this.restorePreviewPanZoom();
|
|
519
586
|
});
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
587
|
+
this.updateComplete.then(() => {
|
|
588
|
+
if (this.presentationMode === "dom") this.initDomMode();
|
|
589
|
+
else if (this.presentationMode === "canvas") this.initCanvasMode();
|
|
590
|
+
});
|
|
523
591
|
}
|
|
524
592
|
handleTransformChanged(e) {
|
|
525
593
|
this.panZoomTransform = e.detail;
|
|
526
594
|
this.debouncedSavePreviewPanZoom();
|
|
527
|
-
if (this.presentationMode === "
|
|
528
|
-
else if (this.presentationMode === "canvas") {
|
|
595
|
+
if (this.presentationMode === "canvas") {
|
|
529
596
|
this.updateCanvasTransform();
|
|
530
597
|
const zoomRatio = e.detail.scale / this.lastCanvasZoom;
|
|
531
598
|
if (zoomRatio < .75 || zoomRatio > 1.33) {
|
|
532
599
|
if (this.zoomReinitTimeout !== null) clearTimeout(this.zoomReinitTimeout);
|
|
533
600
|
this.zoomReinitTimeout = window.setTimeout(() => {
|
|
534
601
|
this.zoomReinitTimeout = null;
|
|
535
|
-
if (this.presentationMode === "canvas") {
|
|
602
|
+
if (this.presentationMode === "canvas" && this.canvasPreviewResult) {
|
|
536
603
|
this.lastCanvasZoom = this.panZoomTransform.scale;
|
|
537
|
-
this.
|
|
538
|
-
this.
|
|
604
|
+
const timegroup = this.getTimegroup();
|
|
605
|
+
const canvasContainer = this.canvasPreviewRef.value;
|
|
606
|
+
if (timegroup && canvasContainer) {
|
|
607
|
+
const newScale = this.previewResolutionScale === "auto" ? this.getEffectiveResolutionScale(timegroup, canvasContainer) : this.getResolutionScale(timegroup, canvasContainer);
|
|
608
|
+
this.canvasPreviewResult.setResolutionScale(newScale);
|
|
609
|
+
}
|
|
539
610
|
}
|
|
540
611
|
}, 500);
|
|
541
612
|
}
|
|
@@ -605,8 +676,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
605
676
|
panZoomElement.y = this.panZoomTransform.y;
|
|
606
677
|
panZoomElement.scale = this.panZoomTransform.scale;
|
|
607
678
|
}
|
|
608
|
-
if (this.presentationMode === "
|
|
609
|
-
else if (this.presentationMode === "canvas") this.updateCanvasTransform();
|
|
679
|
+
if (this.presentationMode === "canvas") this.updateCanvasTransform();
|
|
610
680
|
});
|
|
611
681
|
}
|
|
612
682
|
} catch (error) {
|
|
@@ -660,6 +730,18 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
660
730
|
else if (!isInMotion && wasInMotion) this.handleMotionStop();
|
|
661
731
|
}
|
|
662
732
|
/**
|
|
733
|
+
* Pause or unpause the canvas overlay components (EFCanvas, SelectionOverlay)
|
|
734
|
+
* to avoid layout-thrashing during playback.
|
|
735
|
+
*/
|
|
736
|
+
setOverlaysPaused(paused) {
|
|
737
|
+
const canvasSlot = this.querySelector("[slot='canvas']");
|
|
738
|
+
if (!canvasSlot) return;
|
|
739
|
+
const efCanvas = canvasSlot.querySelector("ef-canvas");
|
|
740
|
+
if (efCanvas && "paused" in efCanvas) efCanvas.paused = paused;
|
|
741
|
+
const overlay = canvasSlot.querySelector("ef-canvas-selection-overlay") ?? this.querySelector("ef-canvas-selection-overlay");
|
|
742
|
+
if (overlay && "paused" in overlay) overlay.paused = paused;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
663
745
|
* Called when motion starts (playing or scrubbing began).
|
|
664
746
|
*/
|
|
665
747
|
handleMotionStart() {
|
|
@@ -668,6 +750,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
668
750
|
this.restDebounceTimer = null;
|
|
669
751
|
}
|
|
670
752
|
this.isAtRest = false;
|
|
753
|
+
this.setOverlaysPaused(true);
|
|
671
754
|
if (this.previewResolutionScale === "auto" && this.adaptiveTracker) {
|
|
672
755
|
const timegroup = this.getTimegroup();
|
|
673
756
|
if (timegroup) {
|
|
@@ -678,10 +761,8 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
678
761
|
this.adaptiveTracker.initializeAtScale(displayScale);
|
|
679
762
|
this.currentAdaptiveScale = this.adaptiveTracker.getRecommendedScale();
|
|
680
763
|
if (this.canvasPreviewResult) this.canvasPreviewResult.setResolutionScale(this.currentAdaptiveScale);
|
|
681
|
-
console.log(`[EFWorkbench] Motion started, set resolution to ${(this.currentAdaptiveScale * 100).toFixed(0)}% (displayScale=${(displayScale * 100).toFixed(0)}%)`);
|
|
682
764
|
}
|
|
683
765
|
}
|
|
684
|
-
console.log(`[EFWorkbench] Motion started (playing=${this.isPlaying}, scrubbing=${this.isScrubbing})`);
|
|
685
766
|
}
|
|
686
767
|
/**
|
|
687
768
|
* Called when motion stops (not playing and not scrubbing).
|
|
@@ -699,14 +780,11 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
699
780
|
*/
|
|
700
781
|
transitionToRest() {
|
|
701
782
|
this.isAtRest = true;
|
|
702
|
-
|
|
783
|
+
this.setOverlaysPaused(false);
|
|
703
784
|
if (this.previewResolutionScale === "auto" && this.presentationMode === "canvas") {
|
|
704
785
|
this.adaptiveTracker?.reset();
|
|
705
786
|
this.currentAdaptiveScale = 1;
|
|
706
|
-
if (this.canvasPreviewResult)
|
|
707
|
-
this.canvasPreviewResult.setResolutionScale(1);
|
|
708
|
-
console.log("[EFWorkbench] Set full resolution for rest state (instant)");
|
|
709
|
-
}
|
|
787
|
+
if (this.canvasPreviewResult) this.canvasPreviewResult.setResolutionScale(1);
|
|
710
788
|
}
|
|
711
789
|
}
|
|
712
790
|
/**
|
|
@@ -742,173 +820,11 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
742
820
|
this.renderMode = this.previewSettings.renderMode;
|
|
743
821
|
this.previewResolutionScale = this.previewSettings.resolutionScale;
|
|
744
822
|
this.showStats = this.previewSettings.showStats;
|
|
745
|
-
this.thumbnailCacheMaxSize = this.previewSettings.thumbnailCacheMaxSize;
|
|
746
|
-
this.updateStatsStrategy();
|
|
747
|
-
}
|
|
748
|
-
/**
|
|
749
|
-
* Update or create stats tracking strategy based on current mode and settings.
|
|
750
|
-
*/
|
|
751
|
-
updateStatsStrategy() {
|
|
752
|
-
if (this.statsStrategy) {
|
|
753
|
-
this.statsStrategy.stop();
|
|
754
|
-
this.statsStrategy = null;
|
|
755
|
-
}
|
|
756
|
-
if (!this.showStats) return;
|
|
757
|
-
const timegroup = this.getTimegroup();
|
|
758
|
-
if (!timegroup || !this.adaptiveTracker) return;
|
|
759
|
-
const compositionWidth = timegroup.offsetWidth || 1920;
|
|
760
|
-
const compositionHeight = timegroup.offsetHeight || 1080;
|
|
761
|
-
const strategy = createStatsTrackingStrategy(this.presentationMode, {
|
|
762
|
-
timegroup,
|
|
763
|
-
adaptiveTracker: this.adaptiveTracker,
|
|
764
|
-
canvasPreviewResult: this.canvasPreviewResult ?? void 0,
|
|
765
|
-
compositionWidth,
|
|
766
|
-
compositionHeight,
|
|
767
|
-
getResolutionScale: this.canvasPreviewResult?.getResolutionScale,
|
|
768
|
-
isAtRest: () => this.isAtRest,
|
|
769
|
-
isExporting: () => this.isExporting
|
|
770
|
-
});
|
|
771
|
-
if (strategy) {
|
|
772
|
-
this.statsStrategy = strategy;
|
|
773
|
-
strategy.start();
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
initCloneOverlay() {
|
|
777
|
-
if (this.presentationMode !== "clone") return;
|
|
778
|
-
const timegroup = this.getTimegroup();
|
|
779
|
-
const cloneContainer = this.cloneOverlayRef.value;
|
|
780
|
-
if (!timegroup || !cloneContainer) {
|
|
781
|
-
setTimeout(() => this.initCloneOverlay(), 100);
|
|
782
|
-
return;
|
|
783
|
-
}
|
|
784
|
-
this.cloneTimegroup = timegroup;
|
|
785
|
-
timegroup.proxyMode = false;
|
|
786
|
-
timegroup.updateComplete.then(() => {
|
|
787
|
-
if (this.presentationMode !== "clone") return;
|
|
788
|
-
this.finishCloneSetup(timegroup, cloneContainer);
|
|
789
|
-
});
|
|
790
|
-
}
|
|
791
|
-
finishCloneSetup(timegroup, cloneContainer) {
|
|
792
|
-
timegroup.style.clipPath = "inset(100%)";
|
|
793
|
-
timegroup.style.pointerEvents = "none";
|
|
794
|
-
cloneContainer.style.display = "block";
|
|
795
|
-
this.rebuildClone(timegroup);
|
|
796
|
-
this.setupStructureObserver(timegroup);
|
|
797
|
-
}
|
|
798
|
-
rebuildClone(timegroup) {
|
|
799
|
-
if (this.presentationMode !== "clone") return;
|
|
800
|
-
const container = this.cloneOverlayRef.value;
|
|
801
|
-
if (!container) return;
|
|
802
|
-
try {
|
|
803
|
-
const { container: previewContainer, refresh } = renderTimegroupPreview(timegroup);
|
|
804
|
-
container.innerHTML = "";
|
|
805
|
-
previewContainer.classList.add("clone-content");
|
|
806
|
-
container.appendChild(previewContainer);
|
|
807
|
-
this.cloneRefresh = refresh;
|
|
808
|
-
this.cloneRootElement = previewContainer.firstElementChild ?? null;
|
|
809
|
-
if (this.cloneRootElement) {
|
|
810
|
-
this.cloneRootElement.style.opacity = "1";
|
|
811
|
-
this.cloneRootElement.style.clipPath = "none";
|
|
812
|
-
this.cloneRootElement.style.position = "relative";
|
|
813
|
-
this.cloneRootElement.style.inset = "auto";
|
|
814
|
-
this.cloneRootElement.style.top = "0";
|
|
815
|
-
this.cloneRootElement.style.right = "auto";
|
|
816
|
-
this.cloneRootElement.style.bottom = "auto";
|
|
817
|
-
this.cloneRootElement.style.left = "0";
|
|
818
|
-
}
|
|
819
|
-
this.updateCloneTransform();
|
|
820
|
-
this.observeShadowRoots(timegroup);
|
|
821
|
-
if (this.cloneAnimationFrame === null) this.startCloneLoop();
|
|
822
|
-
} catch (e) {
|
|
823
|
-
console.error("Failed to build clone:", e);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
setupStructureObserver(timegroup) {
|
|
827
|
-
if (this.structureObserver) this.structureObserver.disconnect();
|
|
828
|
-
this.structureObserver = new MutationObserver((mutations) => {
|
|
829
|
-
if (this.presentationMode !== "clone") return;
|
|
830
|
-
if (mutations.some((m) => m.type === "childList" && (m.addedNodes.length > 0 || m.removedNodes.length > 0)) && !this.rebuildPending) {
|
|
831
|
-
this.rebuildPending = true;
|
|
832
|
-
requestAnimationFrame(() => {
|
|
833
|
-
this.rebuildPending = false;
|
|
834
|
-
if (this.presentationMode === "clone") this.rebuildClone(timegroup);
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
});
|
|
838
|
-
this.structureObserver.observe(timegroup, {
|
|
839
|
-
childList: true,
|
|
840
|
-
subtree: true
|
|
841
|
-
});
|
|
842
|
-
this.observeShadowRoots(timegroup);
|
|
843
|
-
}
|
|
844
|
-
observeShadowRoots(root) {
|
|
845
|
-
if (!this.structureObserver) return;
|
|
846
|
-
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
|
|
847
|
-
let node = root;
|
|
848
|
-
while (node) {
|
|
849
|
-
if (node.shadowRoot) this.structureObserver.observe(node.shadowRoot, {
|
|
850
|
-
childList: true,
|
|
851
|
-
subtree: true
|
|
852
|
-
});
|
|
853
|
-
node = walker.nextNode();
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
updateCloneTransform() {
|
|
857
|
-
if (this.presentationMode !== "clone") return;
|
|
858
|
-
const container = this.cloneOverlayRef.value;
|
|
859
|
-
if (!container) return;
|
|
860
|
-
const cloneContent = container.querySelector(".clone-content");
|
|
861
|
-
if (!cloneContent) return;
|
|
862
|
-
const { x, y, scale } = this.panZoomTransform;
|
|
863
|
-
cloneContent.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
|
|
864
|
-
}
|
|
865
|
-
startCloneLoop() {
|
|
866
|
-
const loop = () => {
|
|
867
|
-
if (this.presentationMode !== "clone" || !this.cloneRefresh) {
|
|
868
|
-
this.cloneAnimationFrame = null;
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
if (!this.isExporting) {
|
|
872
|
-
this.cloneRefresh();
|
|
873
|
-
if (this.cloneRootElement) {
|
|
874
|
-
this.cloneRootElement.style.clipPath = "none";
|
|
875
|
-
this.cloneRootElement.style.opacity = "1";
|
|
876
|
-
this.cloneRootElement.style.position = "relative";
|
|
877
|
-
this.cloneRootElement.style.inset = "auto";
|
|
878
|
-
this.cloneRootElement.style.top = "0";
|
|
879
|
-
this.cloneRootElement.style.right = "auto";
|
|
880
|
-
this.cloneRootElement.style.bottom = "auto";
|
|
881
|
-
this.cloneRootElement.style.left = "0";
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
this.cloneAnimationFrame = requestAnimationFrame(loop);
|
|
885
|
-
};
|
|
886
|
-
this.cloneAnimationFrame = requestAnimationFrame(loop);
|
|
887
|
-
}
|
|
888
|
-
stopCloneOverlay() {
|
|
889
|
-
if (this.cloneAnimationFrame !== null) {
|
|
890
|
-
cancelAnimationFrame(this.cloneAnimationFrame);
|
|
891
|
-
this.cloneAnimationFrame = null;
|
|
892
|
-
}
|
|
893
|
-
if (this.structureObserver) {
|
|
894
|
-
this.structureObserver.disconnect();
|
|
895
|
-
this.structureObserver = null;
|
|
896
|
-
}
|
|
897
|
-
this.cloneRefresh = null;
|
|
898
|
-
this.cloneRootElement = null;
|
|
899
|
-
this.cloneTimegroup = null;
|
|
900
|
-
this.rebuildPending = false;
|
|
901
|
-
const container = this.cloneOverlayRef.value;
|
|
902
|
-
if (container) {
|
|
903
|
-
container.innerHTML = "";
|
|
904
|
-
container.style.display = "none";
|
|
905
|
-
}
|
|
906
823
|
}
|
|
907
824
|
async handlePresentationModeChange(mode) {
|
|
908
825
|
if (mode === this.presentationMode) return;
|
|
909
826
|
const previousMode = this.presentationMode;
|
|
910
|
-
if (previousMode === "
|
|
911
|
-
else if (previousMode === "dom") this.stopDomMode();
|
|
827
|
+
if (previousMode === "dom") this.stopDomMode();
|
|
912
828
|
else if (previousMode === "canvas") this.stopCanvasMode();
|
|
913
829
|
setPreviewPresentationMode(mode);
|
|
914
830
|
this.previewSettings = {
|
|
@@ -916,8 +832,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
916
832
|
presentationMode: mode
|
|
917
833
|
};
|
|
918
834
|
await this.updateComplete;
|
|
919
|
-
if (mode === "
|
|
920
|
-
else if (mode === "dom") this.initDomMode();
|
|
835
|
+
if (mode === "dom") this.initDomMode();
|
|
921
836
|
else if (mode === "canvas") this.initCanvasMode();
|
|
922
837
|
}
|
|
923
838
|
initDomMode() {
|
|
@@ -928,15 +843,26 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
928
843
|
return;
|
|
929
844
|
}
|
|
930
845
|
const fitScale = this.querySelector("[slot='canvas']");
|
|
931
|
-
if (fitScale?.removeScale && fitScale?.paused !== void 0) {
|
|
846
|
+
if (!!(fitScale?.removeScale && fitScale?.paused !== void 0)) {
|
|
932
847
|
fitScale.paused = true;
|
|
933
848
|
fitScale.removeScale();
|
|
934
849
|
}
|
|
935
850
|
timegroup.proxyMode = false;
|
|
936
851
|
timegroup.style.clipPath = "";
|
|
937
852
|
timegroup.style.pointerEvents = "";
|
|
853
|
+
if (this.showStats && this.adaptiveTracker) {
|
|
854
|
+
this.domStatsStrategy = new DomStatsStrategy({
|
|
855
|
+
timegroup,
|
|
856
|
+
adaptiveTracker: this.adaptiveTracker
|
|
857
|
+
});
|
|
858
|
+
this.domStatsStrategy.start();
|
|
859
|
+
}
|
|
938
860
|
}
|
|
939
861
|
stopDomMode() {
|
|
862
|
+
if (this.domStatsStrategy) {
|
|
863
|
+
this.domStatsStrategy.stop();
|
|
864
|
+
this.domStatsStrategy = null;
|
|
865
|
+
}
|
|
940
866
|
const timegroup = this.getTimegroup();
|
|
941
867
|
if (timegroup) {
|
|
942
868
|
timegroup.style.clipPath = "inset(100%)";
|
|
@@ -944,20 +870,16 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
944
870
|
}
|
|
945
871
|
const fitScale = this.querySelector("[slot='canvas']");
|
|
946
872
|
if (fitScale?.paused !== void 0) fitScale.paused = false;
|
|
947
|
-
if (this.statsStrategy) {
|
|
948
|
-
this.statsStrategy.stop();
|
|
949
|
-
this.statsStrategy = null;
|
|
950
|
-
}
|
|
951
873
|
}
|
|
952
874
|
/**
|
|
953
875
|
* Get the resolution scale for canvas rendering (for fixed scale modes).
|
|
954
|
-
*
|
|
876
|
+
*
|
|
955
877
|
* Logic:
|
|
956
878
|
* - Get actual displayed size from getBoundingClientRect()
|
|
957
879
|
* - For "Full": render at displayed size (1:1 pixel mapping)
|
|
958
880
|
* - For other settings: render at that % of displayed size
|
|
959
881
|
* - Never exceed composition size (100%)
|
|
960
|
-
*
|
|
882
|
+
*
|
|
961
883
|
* Note: For "auto" mode, use getEffectiveResolutionScale() instead.
|
|
962
884
|
*/
|
|
963
885
|
getResolutionScale(timegroup, _canvasContainer) {
|
|
@@ -969,18 +891,9 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
969
891
|
const displayedHeight = rect.height;
|
|
970
892
|
const displayScale = Math.min(displayedWidth / compositionWidth, displayedHeight / compositionHeight);
|
|
971
893
|
const targetScale = this.previewResolutionScale === 1 ? displayScale : Math.min(displayScale, this.previewResolutionScale);
|
|
972
|
-
|
|
973
|
-
const renderWidth = Math.floor(compositionWidth * finalScale);
|
|
974
|
-
const renderHeight = Math.floor(compositionHeight * finalScale);
|
|
975
|
-
console.log(`[EFWorkbench] Resolution scale:
|
|
976
|
-
Composition (offsetWidth×offsetHeight): ${compositionWidth}×${compositionHeight}
|
|
977
|
-
Displayed (boundingRect): ${Math.round(displayedWidth)}×${Math.round(displayedHeight)}
|
|
978
|
-
Display scale: ${(displayScale * 100).toFixed(1)}%
|
|
979
|
-
Setting: ${this.previewResolutionScale === 1 ? "Full" : `${Math.round(this.previewResolutionScale * 100)}%`}
|
|
980
|
-
Final: ${(finalScale * 100).toFixed(1)}% → ${renderWidth}×${renderHeight}`);
|
|
981
|
-
return finalScale;
|
|
894
|
+
return Math.max(.1, Math.min(1, targetScale));
|
|
982
895
|
}
|
|
983
|
-
initCanvasMode() {
|
|
896
|
+
async initCanvasMode() {
|
|
984
897
|
if (this.presentationMode !== "canvas") return;
|
|
985
898
|
const timegroup = this.getTimegroup();
|
|
986
899
|
const canvasContainer = this.canvasPreviewRef.value;
|
|
@@ -989,20 +902,23 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
989
902
|
return;
|
|
990
903
|
}
|
|
991
904
|
timegroup.proxyMode = false;
|
|
992
|
-
timegroup.
|
|
905
|
+
timegroup.canvasPreviewActive = true;
|
|
906
|
+
timegroup.style.clipPath = "";
|
|
993
907
|
timegroup.style.pointerEvents = "none";
|
|
994
908
|
canvasContainer.style.display = "block";
|
|
995
909
|
const initialResolutionScale = this.previewResolutionScale === "auto" ? this.getEffectiveResolutionScale(timegroup, canvasContainer) : this.getResolutionScale(timegroup, canvasContainer);
|
|
996
910
|
this.lastCanvasZoom = this.panZoomTransform.scale;
|
|
997
|
-
timegroup.offsetWidth;
|
|
998
|
-
timegroup.offsetHeight;
|
|
999
911
|
try {
|
|
912
|
+
await timegroup.seekTask.taskComplete;
|
|
913
|
+
if (timegroup.playbackController) await new Promise((resolve) => setTimeout(resolve, 0));
|
|
914
|
+
updateAnimations(timegroup);
|
|
915
|
+
const { renderTimegroupToCanvas } = await import("../preview/renderTimegroupToCanvas.js");
|
|
1000
916
|
const result = renderTimegroupToCanvas(timegroup, {
|
|
1001
917
|
scale: 1,
|
|
1002
918
|
resolutionScale: initialResolutionScale
|
|
1003
919
|
});
|
|
1004
920
|
this.canvasPreviewResult = result;
|
|
1005
|
-
const { container, canvas, refresh
|
|
921
|
+
const { container, canvas, refresh } = result;
|
|
1006
922
|
canvas.classList.add("clone-content");
|
|
1007
923
|
canvasContainer.innerHTML = "";
|
|
1008
924
|
canvasContainer.appendChild(container);
|
|
@@ -1010,7 +926,10 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1010
926
|
const loop = async () => {
|
|
1011
927
|
if (this.presentationMode !== "canvas") return;
|
|
1012
928
|
if (!this.isExporting) try {
|
|
929
|
+
const renderStart = performance.now();
|
|
1013
930
|
await refresh();
|
|
931
|
+
const renderTime = performance.now() - renderStart;
|
|
932
|
+
if (this.renderStats) this.renderStats.recordFrame(renderTime, performance.now(), this.isAtRest);
|
|
1014
933
|
this.updateCanvasTransform();
|
|
1015
934
|
} catch (e) {
|
|
1016
935
|
console.error("Canvas refresh failed:", e);
|
|
@@ -1031,11 +950,10 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1031
950
|
clearTimeout(this.zoomReinitTimeout);
|
|
1032
951
|
this.zoomReinitTimeout = null;
|
|
1033
952
|
}
|
|
953
|
+
this.canvasPreviewResult?.dispose();
|
|
1034
954
|
this.canvasPreviewResult = null;
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
this.statsStrategy = null;
|
|
1038
|
-
}
|
|
955
|
+
const timegroup = this.getTimegroup();
|
|
956
|
+
if (timegroup) timegroup.canvasPreviewActive = false;
|
|
1039
957
|
const container = this.canvasPreviewRef.value;
|
|
1040
958
|
if (container) {
|
|
1041
959
|
container.innerHTML = "";
|
|
@@ -1051,12 +969,12 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1051
969
|
const { x, y, scale } = this.panZoomTransform;
|
|
1052
970
|
canvas.style.transform = `translate(${x}px, ${y}px) scale(${scale})`;
|
|
1053
971
|
}
|
|
1054
|
-
initCanvasRenderer() {
|
|
972
|
+
async initCanvasRenderer() {
|
|
1055
973
|
const timegroup = this.getTimegroup();
|
|
1056
974
|
if (!timegroup) return null;
|
|
1057
975
|
try {
|
|
976
|
+
const { renderTimegroupToCanvas } = await import("../preview/renderTimegroupToCanvas.js");
|
|
1058
977
|
const { canvas, refresh } = renderTimegroupToCanvas(timegroup, 1);
|
|
1059
|
-
this.canvasRefresh = refresh;
|
|
1060
978
|
return {
|
|
1061
979
|
canvas,
|
|
1062
980
|
refresh
|
|
@@ -1082,6 +1000,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1082
1000
|
this.exportProgress = null;
|
|
1083
1001
|
this.exportStatus = "rendering";
|
|
1084
1002
|
try {
|
|
1003
|
+
const { renderTimegroupToVideo } = await import("../preview/renderTimegroupToVideo.js");
|
|
1085
1004
|
await renderTimegroupToVideo(timegroup, {
|
|
1086
1005
|
...options,
|
|
1087
1006
|
signal: this.exportAbortController.signal,
|
|
@@ -1097,6 +1016,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1097
1016
|
this.exportAbortController = null;
|
|
1098
1017
|
}, 2e3);
|
|
1099
1018
|
} catch (e) {
|
|
1019
|
+
const { RenderCancelledError } = await import("../preview/renderTimegroupToVideo.js");
|
|
1100
1020
|
if (e instanceof RenderCancelledError) {
|
|
1101
1021
|
console.log("Export cancelled by user");
|
|
1102
1022
|
this.exportStatus = "cancelled";
|
|
@@ -1188,73 +1108,61 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1188
1108
|
renderMode: mode
|
|
1189
1109
|
};
|
|
1190
1110
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
setPreviewResolutionScale(scale);
|
|
1111
|
+
handleShowStatsToggle(enabled) {
|
|
1112
|
+
setShowStats(enabled);
|
|
1194
1113
|
this.previewSettings = {
|
|
1195
1114
|
...this.previewSettings,
|
|
1196
|
-
|
|
1115
|
+
showStats: enabled
|
|
1197
1116
|
};
|
|
1198
|
-
if (scale === "auto") {
|
|
1199
|
-
this.adaptiveTracker?.reset();
|
|
1200
|
-
this.currentAdaptiveScale = 1;
|
|
1201
|
-
}
|
|
1202
|
-
if (this.presentationMode === "canvas") {
|
|
1203
|
-
console.log("[EFWorkbench] Reinitializing canvas mode with new resolution scale");
|
|
1204
|
-
this.stopCanvasMode();
|
|
1205
|
-
this.initCanvasMode();
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
async updateThumbnailCacheStats() {
|
|
1209
|
-
try {
|
|
1210
|
-
this.thumbnailCacheStats = await sessionThumbnailCache.getStats();
|
|
1211
|
-
} catch (error) {
|
|
1212
|
-
console.warn("Failed to update thumbnail cache stats:", error);
|
|
1213
|
-
}
|
|
1214
1117
|
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
this.updateThumbnailCacheStats();
|
|
1218
|
-
}, 2e3);
|
|
1219
|
-
}
|
|
1220
|
-
stopCacheStatsUpdates() {
|
|
1221
|
-
if (this.cacheStatsUpdateInterval !== null) {
|
|
1222
|
-
clearInterval(this.cacheStatsUpdateInterval);
|
|
1223
|
-
this.cacheStatsUpdateInterval = null;
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
handleThumbnailCacheMaxSizeChange(size) {
|
|
1227
|
-
setThumbnailCacheMaxSize(size);
|
|
1118
|
+
handleShowThumbnailTimestampsToggle(enabled) {
|
|
1119
|
+
setShowThumbnailTimestamps(enabled);
|
|
1228
1120
|
this.previewSettings = {
|
|
1229
1121
|
...this.previewSettings,
|
|
1230
|
-
|
|
1122
|
+
showThumbnailTimestamps: enabled
|
|
1231
1123
|
};
|
|
1232
|
-
sessionThumbnailCache.setMaxSize(size);
|
|
1233
|
-
this.updateThumbnailCacheStats();
|
|
1234
1124
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1125
|
+
/**
|
|
1126
|
+
* Get initial theme from localStorage or default to 'dark'
|
|
1127
|
+
*/
|
|
1128
|
+
getInitialTheme() {
|
|
1129
|
+
if (typeof window === "undefined") return "dark";
|
|
1130
|
+
const stored = localStorage.getItem("ef-theme");
|
|
1131
|
+
if (stored === "light" || stored === "dark" || stored === "system") return stored;
|
|
1132
|
+
return "dark";
|
|
1243
1133
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1134
|
+
/**
|
|
1135
|
+
* Cycle through theme modes: light → dark → system → light
|
|
1136
|
+
*/
|
|
1137
|
+
handleThemeToggle() {
|
|
1138
|
+
const nextTheme = this.themeMode === "light" ? "dark" : this.themeMode === "dark" ? "system" : "light";
|
|
1139
|
+
this.themeMode = nextTheme;
|
|
1140
|
+
localStorage.setItem("ef-theme", nextTheme);
|
|
1141
|
+
this.applyTheme();
|
|
1251
1142
|
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1143
|
+
/**
|
|
1144
|
+
* Apply the current theme to the document and host element
|
|
1145
|
+
*/
|
|
1146
|
+
applyTheme() {
|
|
1147
|
+
const root = document.documentElement;
|
|
1148
|
+
let shouldBeDark = false;
|
|
1149
|
+
if (this.themeMode === "light") shouldBeDark = false;
|
|
1150
|
+
else if (this.themeMode === "dark") shouldBeDark = true;
|
|
1151
|
+
else shouldBeDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
1152
|
+
if (shouldBeDark) {
|
|
1153
|
+
root.classList.add("dark");
|
|
1154
|
+
root.classList.remove("light");
|
|
1155
|
+
} else {
|
|
1156
|
+
root.classList.add("light");
|
|
1157
|
+
root.classList.remove("dark");
|
|
1158
|
+
}
|
|
1159
|
+
if (shouldBeDark) {
|
|
1160
|
+
this.classList.add("dark");
|
|
1161
|
+
this.classList.remove("light");
|
|
1162
|
+
} else {
|
|
1163
|
+
this.classList.add("light");
|
|
1164
|
+
this.classList.remove("dark");
|
|
1165
|
+
}
|
|
1258
1166
|
}
|
|
1259
1167
|
/**
|
|
1260
1168
|
* Reset and fit the preview to show all content centered.
|
|
@@ -1280,77 +1188,33 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1280
1188
|
|
|
1281
1189
|
<!-- Presentation Mode Setting -->
|
|
1282
1190
|
<div style="
|
|
1283
|
-
background:
|
|
1191
|
+
background: var(--ef-color-bg-inset);
|
|
1284
1192
|
border-radius: 8px;
|
|
1285
1193
|
padding: 12px;
|
|
1286
1194
|
margin-bottom: 10px;
|
|
1287
1195
|
">
|
|
1288
|
-
<div
|
|
1196
|
+
<div class="dropdown-label" style="margin-bottom: 10px;">Presentation Mode</div>
|
|
1289
1197
|
|
|
1290
|
-
<div
|
|
1291
|
-
<button
|
|
1292
|
-
@click=${() => this.handlePresentationModeChange("clone")}
|
|
1293
|
-
style="
|
|
1294
|
-
flex: 1;
|
|
1295
|
-
padding: 6px 10px;
|
|
1296
|
-
border: none;
|
|
1297
|
-
border-radius: 4px;
|
|
1298
|
-
font-size: 11px;
|
|
1299
|
-
font-weight: 500;
|
|
1300
|
-
cursor: pointer;
|
|
1301
|
-
transition: all 0.15s ease;
|
|
1302
|
-
background: ${this.presentationMode === "clone" ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1303
|
-
color: ${this.presentationMode === "clone" ? "#60a5fa" : "#94a3b8"};
|
|
1304
|
-
border: 1px solid ${this.presentationMode === "clone" ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1305
|
-
"
|
|
1306
|
-
>Clone</button>
|
|
1198
|
+
<div class="button-group">
|
|
1307
1199
|
<button
|
|
1308
1200
|
@click=${() => this.handlePresentationModeChange("dom")}
|
|
1309
|
-
|
|
1310
|
-
flex: 1;
|
|
1311
|
-
padding: 6px 10px;
|
|
1312
|
-
border: none;
|
|
1313
|
-
border-radius: 4px;
|
|
1314
|
-
font-size: 11px;
|
|
1315
|
-
font-weight: 500;
|
|
1316
|
-
cursor: pointer;
|
|
1317
|
-
transition: all 0.15s ease;
|
|
1318
|
-
background: ${this.presentationMode === "dom" ? "rgba(34, 197, 94, 0.3)" : "transparent"};
|
|
1319
|
-
color: ${this.presentationMode === "dom" ? "#4ade80" : "#94a3b8"};
|
|
1320
|
-
border: 1px solid ${this.presentationMode === "dom" ? "rgba(34, 197, 94, 0.4)" : "transparent"};
|
|
1321
|
-
"
|
|
1201
|
+
class="button-group-btn ${this.presentationMode === "dom" ? "active" : ""}"
|
|
1322
1202
|
>DOM</button>
|
|
1323
1203
|
<button
|
|
1324
1204
|
@click=${() => this.handlePresentationModeChange("canvas")}
|
|
1325
|
-
|
|
1326
|
-
flex: 1;
|
|
1327
|
-
padding: 6px 10px;
|
|
1328
|
-
border: none;
|
|
1329
|
-
border-radius: 4px;
|
|
1330
|
-
font-size: 11px;
|
|
1331
|
-
font-weight: 500;
|
|
1332
|
-
cursor: pointer;
|
|
1333
|
-
transition: all 0.15s ease;
|
|
1334
|
-
background: ${this.presentationMode === "canvas" ? "rgba(168, 85, 247, 0.3)" : "transparent"};
|
|
1335
|
-
color: ${this.presentationMode === "canvas" ? "#c084fc" : "#94a3b8"};
|
|
1336
|
-
border: 1px solid ${this.presentationMode === "canvas" ? "rgba(168, 85, 247, 0.4)" : "transparent"};
|
|
1337
|
-
"
|
|
1205
|
+
class="button-group-btn ${this.presentationMode === "canvas" ? "active" : ""}"
|
|
1338
1206
|
>Canvas</button>
|
|
1339
1207
|
</div>
|
|
1340
1208
|
|
|
1341
|
-
<div
|
|
1342
|
-
${this.presentationMode === "
|
|
1209
|
+
<div class="dropdown-description">
|
|
1210
|
+
${this.presentationMode === "dom" ? "Default. Shows the real timegroup DOM directly." : "Renders to canvas each frame."}
|
|
1343
1211
|
</div>
|
|
1344
1212
|
</div>
|
|
1345
1213
|
|
|
1346
1214
|
<!-- Render Mode Setting -->
|
|
1347
|
-
<div
|
|
1348
|
-
background: rgba(51, 65, 85, 0.4);
|
|
1349
|
-
border-radius: 8px;
|
|
1350
|
-
padding: 12px;
|
|
1351
|
-
">
|
|
1215
|
+
<div class="dropdown-section">
|
|
1352
1216
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
|
1353
|
-
<span
|
|
1217
|
+
<span class="dropdown-label">Render Mode</span>
|
|
1354
1218
|
${isAvailable ? html`
|
|
1355
1219
|
<div style="display: flex; align-items: center; gap: 5px;">
|
|
1356
1220
|
<span style="
|
|
@@ -1358,321 +1222,67 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1358
1222
|
width: 7px;
|
|
1359
1223
|
height: 7px;
|
|
1360
1224
|
border-radius: 50%;
|
|
1361
|
-
background:
|
|
1225
|
+
background: var(--ef-color-success);
|
|
1362
1226
|
"></span>
|
|
1363
|
-
<span style="color:
|
|
1227
|
+
<span style="color: var(--ef-color-success); font-size: 10px; font-weight: 500;">
|
|
1364
1228
|
Native Available
|
|
1365
1229
|
</span>
|
|
1366
1230
|
</div>
|
|
1367
1231
|
` : ""}
|
|
1368
1232
|
</div>
|
|
1369
1233
|
|
|
1370
|
-
<div
|
|
1234
|
+
<div class="button-group">
|
|
1371
1235
|
<button
|
|
1372
1236
|
@click=${() => this.handleRenderModeChange("foreignObject")}
|
|
1373
|
-
|
|
1374
|
-
flex: 1;
|
|
1375
|
-
padding: 6px 8px;
|
|
1376
|
-
border: none;
|
|
1377
|
-
border-radius: 4px;
|
|
1378
|
-
font-size: 10px;
|
|
1379
|
-
font-weight: 500;
|
|
1380
|
-
cursor: pointer;
|
|
1381
|
-
transition: all 0.15s ease;
|
|
1382
|
-
background: ${this.renderMode === "foreignObject" ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1383
|
-
color: ${this.renderMode === "foreignObject" ? "#60a5fa" : "#94a3b8"};
|
|
1384
|
-
border: 1px solid ${this.renderMode === "foreignObject" ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1385
|
-
"
|
|
1237
|
+
class="button-group-btn ${this.renderMode === "foreignObject" ? "active" : ""}"
|
|
1386
1238
|
>foreignObject</button>
|
|
1387
1239
|
<button
|
|
1388
1240
|
@click=${() => this.handleRenderModeChange("native")}
|
|
1389
1241
|
?disabled=${!isAvailable}
|
|
1242
|
+
class="button-group-btn ${this.renderMode === "native" ? "active" : ""}"
|
|
1390
1243
|
style="
|
|
1391
|
-
flex: 1;
|
|
1392
|
-
padding: 6px 8px;
|
|
1393
|
-
border: none;
|
|
1394
|
-
border-radius: 4px;
|
|
1395
|
-
font-size: 10px;
|
|
1396
|
-
font-weight: 500;
|
|
1397
1244
|
cursor: ${isAvailable ? "pointer" : "not-allowed"};
|
|
1398
|
-
transition: all 0.15s ease;
|
|
1399
|
-
background: ${this.renderMode === "native" ? "rgba(34, 197, 94, 0.3)" : "transparent"};
|
|
1400
|
-
color: ${this.renderMode === "native" ? "#4ade80" : isAvailable ? "#94a3b8" : "#64748b"};
|
|
1401
|
-
border: 1px solid ${this.renderMode === "native" ? "rgba(34, 197, 94, 0.4)" : "transparent"};
|
|
1402
1245
|
opacity: ${isAvailable ? "1" : "0.5"};
|
|
1403
1246
|
"
|
|
1404
1247
|
>native</button>
|
|
1405
1248
|
</div>
|
|
1406
1249
|
|
|
1407
|
-
<div
|
|
1250
|
+
<div class="dropdown-description">
|
|
1408
1251
|
${this.renderMode === "foreignObject" ? "SVG foreignObject serialization. Works everywhere but slower." : "Chrome's drawElementImage API. Fastest, requires chrome://flags/#canvas-draw-element."}
|
|
1409
1252
|
</div>
|
|
1410
1253
|
</div>
|
|
1411
1254
|
|
|
1412
|
-
<!--
|
|
1413
|
-
<div style="
|
|
1414
|
-
background: rgba(51, 65, 85, 0.4);
|
|
1415
|
-
border-radius: 8px;
|
|
1416
|
-
padding: 12px;
|
|
1417
|
-
margin-top: 10px;
|
|
1418
|
-
">
|
|
1419
|
-
<div style="color: #e2e8f0; font-size: 12px; font-weight: 500; margin-bottom: 10px;">Preview Resolution</div>
|
|
1420
|
-
|
|
1421
|
-
<div style="display: flex; gap: 4px; background: rgba(30, 41, 59, 0.6); border-radius: 6px; padding: 3px;">
|
|
1422
|
-
<button
|
|
1423
|
-
@click=${() => this.handleResolutionScaleChange("auto")}
|
|
1424
|
-
style="
|
|
1425
|
-
flex: 1;
|
|
1426
|
-
padding: 6px 8px;
|
|
1427
|
-
border: none;
|
|
1428
|
-
border-radius: 4px;
|
|
1429
|
-
font-size: 10px;
|
|
1430
|
-
font-weight: 500;
|
|
1431
|
-
cursor: pointer;
|
|
1432
|
-
transition: all 0.15s ease;
|
|
1433
|
-
background: ${this.previewResolutionScale === "auto" ? "rgba(34, 197, 94, 0.3)" : "transparent"};
|
|
1434
|
-
color: ${this.previewResolutionScale === "auto" ? "#4ade80" : "#94a3b8"};
|
|
1435
|
-
border: 1px solid ${this.previewResolutionScale === "auto" ? "rgba(34, 197, 94, 0.4)" : "transparent"};
|
|
1436
|
-
"
|
|
1437
|
-
>Auto</button>
|
|
1438
|
-
<button
|
|
1439
|
-
@click=${() => this.handleResolutionScaleChange(1)}
|
|
1440
|
-
style="
|
|
1441
|
-
flex: 1;
|
|
1442
|
-
padding: 6px 8px;
|
|
1443
|
-
border: none;
|
|
1444
|
-
border-radius: 4px;
|
|
1445
|
-
font-size: 10px;
|
|
1446
|
-
font-weight: 500;
|
|
1447
|
-
cursor: pointer;
|
|
1448
|
-
transition: all 0.15s ease;
|
|
1449
|
-
background: ${this.previewResolutionScale === 1 ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1450
|
-
color: ${this.previewResolutionScale === 1 ? "#60a5fa" : "#94a3b8"};
|
|
1451
|
-
border: 1px solid ${this.previewResolutionScale === 1 ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1452
|
-
"
|
|
1453
|
-
>Full</button>
|
|
1454
|
-
<button
|
|
1455
|
-
@click=${() => this.handleResolutionScaleChange(.75)}
|
|
1456
|
-
style="
|
|
1457
|
-
flex: 1;
|
|
1458
|
-
padding: 6px 8px;
|
|
1459
|
-
border: none;
|
|
1460
|
-
border-radius: 4px;
|
|
1461
|
-
font-size: 10px;
|
|
1462
|
-
font-weight: 500;
|
|
1463
|
-
cursor: pointer;
|
|
1464
|
-
transition: all 0.15s ease;
|
|
1465
|
-
background: ${this.previewResolutionScale === .75 ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1466
|
-
color: ${this.previewResolutionScale === .75 ? "#60a5fa" : "#94a3b8"};
|
|
1467
|
-
border: 1px solid ${this.previewResolutionScale === .75 ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1468
|
-
"
|
|
1469
|
-
>3/4</button>
|
|
1470
|
-
<button
|
|
1471
|
-
@click=${() => this.handleResolutionScaleChange(.5)}
|
|
1472
|
-
style="
|
|
1473
|
-
flex: 1;
|
|
1474
|
-
padding: 6px 8px;
|
|
1475
|
-
border: none;
|
|
1476
|
-
border-radius: 4px;
|
|
1477
|
-
font-size: 10px;
|
|
1478
|
-
font-weight: 500;
|
|
1479
|
-
cursor: pointer;
|
|
1480
|
-
transition: all 0.15s ease;
|
|
1481
|
-
background: ${this.previewResolutionScale === .5 ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1482
|
-
color: ${this.previewResolutionScale === .5 ? "#60a5fa" : "#94a3b8"};
|
|
1483
|
-
border: 1px solid ${this.previewResolutionScale === .5 ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1484
|
-
"
|
|
1485
|
-
>1/2</button>
|
|
1486
|
-
<button
|
|
1487
|
-
@click=${() => this.handleResolutionScaleChange(.25)}
|
|
1488
|
-
style="
|
|
1489
|
-
flex: 1;
|
|
1490
|
-
padding: 6px 8px;
|
|
1491
|
-
border: none;
|
|
1492
|
-
border-radius: 4px;
|
|
1493
|
-
font-size: 10px;
|
|
1494
|
-
font-weight: 500;
|
|
1495
|
-
cursor: pointer;
|
|
1496
|
-
transition: all 0.15s ease;
|
|
1497
|
-
background: ${this.previewResolutionScale === .25 ? "rgba(59, 130, 246, 0.3)" : "transparent"};
|
|
1498
|
-
color: ${this.previewResolutionScale === .25 ? "#60a5fa" : "#94a3b8"};
|
|
1499
|
-
border: 1px solid ${this.previewResolutionScale === .25 ? "rgba(59, 130, 246, 0.4)" : "transparent"};
|
|
1500
|
-
"
|
|
1501
|
-
>1/4</button>
|
|
1502
|
-
</div>
|
|
1503
|
-
|
|
1504
|
-
<div style="margin-top: 8px; color: #64748b; font-size: 10px; line-height: 1.4;">
|
|
1505
|
-
${this.previewResolutionScale === "auto" ? `Auto: Full resolution at rest, adaptive during playback/scrub.${!this.isAtRest ? ` Currently: ${Math.round(this.currentAdaptiveScale * 100)}%` : ""}` : this.previewResolutionScale === 1 ? "Full: Matches display resolution (1:1 pixels, adapts to zoom)." : `${Math.round(this.previewResolutionScale * 100)}%: Reduced quality for faster rendering.`}
|
|
1506
|
-
Canvas mode only.
|
|
1507
|
-
</div>
|
|
1508
|
-
</div>
|
|
1255
|
+
<!-- This section was already updated earlier in the dropdown-section refactor -->
|
|
1509
1256
|
|
|
1510
1257
|
<!-- Show Performance Stats Setting -->
|
|
1511
|
-
<div
|
|
1512
|
-
|
|
1513
|
-
border-radius: 8px;
|
|
1514
|
-
padding: 12px;
|
|
1515
|
-
margin-top: 10px;
|
|
1516
|
-
">
|
|
1517
|
-
<label style="
|
|
1518
|
-
display: flex;
|
|
1519
|
-
align-items: center;
|
|
1520
|
-
gap: 8px;
|
|
1521
|
-
cursor: pointer;
|
|
1522
|
-
">
|
|
1258
|
+
<div class="dropdown-section">
|
|
1259
|
+
<label class="checkbox-label">
|
|
1523
1260
|
<input
|
|
1524
1261
|
type="checkbox"
|
|
1525
1262
|
?checked=${this.showStats}
|
|
1526
1263
|
@change=${(e) => this.handleShowStatsToggle(e.target.checked)}
|
|
1527
|
-
style="
|
|
1528
|
-
width: 14px;
|
|
1529
|
-
height: 14px;
|
|
1530
|
-
accent-color: #3b82f6;
|
|
1531
|
-
cursor: pointer;
|
|
1532
|
-
"
|
|
1533
1264
|
/>
|
|
1534
|
-
<span
|
|
1265
|
+
<span>Show Performance Stats</span>
|
|
1535
1266
|
</label>
|
|
1536
1267
|
|
|
1537
|
-
<div
|
|
1538
|
-
margin-top: 8px;
|
|
1539
|
-
color: #64748b;
|
|
1540
|
-
font-size: 10px;
|
|
1541
|
-
line-height: 1.4;
|
|
1542
|
-
">
|
|
1268
|
+
<div class="dropdown-description">
|
|
1543
1269
|
Display FPS, CPU pressure, and performance metrics overlay.
|
|
1544
1270
|
</div>
|
|
1545
1271
|
</div>
|
|
1546
1272
|
|
|
1547
|
-
<!-- Thumbnail
|
|
1548
|
-
<div
|
|
1549
|
-
|
|
1550
|
-
style="
|
|
1551
|
-
background: rgba(51, 65, 85, 0.4);
|
|
1552
|
-
border-radius: 8px;
|
|
1553
|
-
padding: 12px;
|
|
1554
|
-
margin-top: 10px;
|
|
1555
|
-
"
|
|
1556
|
-
>
|
|
1557
|
-
<div style="color: #e2e8f0; font-size: 12px; font-weight: 500; margin-bottom: 10px;">Thumbnail Cache</div>
|
|
1558
|
-
|
|
1559
|
-
<!-- Cache Size Input -->
|
|
1560
|
-
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 10px;">
|
|
1561
|
-
<label style="color: #94a3b8; font-size: 11px; min-width: 80px;">Max Size:</label>
|
|
1562
|
-
<input
|
|
1563
|
-
data-testid="thumbnail-cache-size"
|
|
1564
|
-
type="number"
|
|
1565
|
-
min="100"
|
|
1566
|
-
max="5000"
|
|
1567
|
-
step="100"
|
|
1568
|
-
.value=${String(this.thumbnailCacheMaxSize)}
|
|
1569
|
-
@change=${(e) => {
|
|
1570
|
-
const value = parseInt(e.target.value, 10);
|
|
1571
|
-
if (!isNaN(value) && value >= 100 && value <= 5e3) this.handleThumbnailCacheMaxSizeChange(value);
|
|
1572
|
-
}}
|
|
1573
|
-
style="
|
|
1574
|
-
flex: 1;
|
|
1575
|
-
padding: 4px 8px;
|
|
1576
|
-
background: rgba(30, 41, 59, 0.6);
|
|
1577
|
-
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
1578
|
-
border-radius: 4px;
|
|
1579
|
-
color: #e2e8f0;
|
|
1580
|
-
font-size: 11px;
|
|
1581
|
-
"
|
|
1582
|
-
/>
|
|
1583
|
-
<span style="color: #64748b; font-size: 10px;">items</span>
|
|
1584
|
-
</div>
|
|
1585
|
-
|
|
1586
|
-
<!-- Cache Statistics -->
|
|
1587
|
-
${this.thumbnailCacheStats ? html`
|
|
1588
|
-
<div
|
|
1589
|
-
data-testid="thumbnail-cache-stats"
|
|
1590
|
-
style="
|
|
1591
|
-
background: rgba(30, 41, 59, 0.6);
|
|
1592
|
-
border-radius: 6px;
|
|
1593
|
-
padding: 8px;
|
|
1594
|
-
margin-bottom: 10px;
|
|
1595
|
-
font-size: 10px;
|
|
1596
|
-
color: #94a3b8;
|
|
1597
|
-
"
|
|
1598
|
-
>
|
|
1599
|
-
<div style="display: flex; justify-content: space-between; margin-bottom: 4px;">
|
|
1600
|
-
<span>Items:</span>
|
|
1601
|
-
<span style="color: #e2e8f0; font-weight: 500;">${this.thumbnailCacheStats.itemCount} / ${this.thumbnailCacheStats.maxSize}</span>
|
|
1602
|
-
</div>
|
|
1603
|
-
<div style="display: flex; justify-content: space-between;">
|
|
1604
|
-
<span>Size:</span>
|
|
1605
|
-
<span style="color: #e2e8f0; font-weight: 500;">${this.formatBytes(this.thumbnailCacheStats.totalSizeBytes)}</span>
|
|
1606
|
-
</div>
|
|
1607
|
-
</div>
|
|
1608
|
-
` : ""}
|
|
1609
|
-
|
|
1610
|
-
<!-- Clear Cache Button -->
|
|
1611
|
-
<button
|
|
1612
|
-
data-testid="thumbnail-cache-clear"
|
|
1613
|
-
@click=${() => this.handleClearThumbnailCache()}
|
|
1614
|
-
style="
|
|
1615
|
-
width: 100%;
|
|
1616
|
-
padding: 6px 10px;
|
|
1617
|
-
background: rgba(239, 68, 68, 0.2);
|
|
1618
|
-
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
1619
|
-
border-radius: 4px;
|
|
1620
|
-
color: #f87171;
|
|
1621
|
-
font-size: 11px;
|
|
1622
|
-
font-weight: 500;
|
|
1623
|
-
cursor: pointer;
|
|
1624
|
-
transition: all 0.15s ease;
|
|
1625
|
-
"
|
|
1626
|
-
onmouseover="this.style.background='rgba(239, 68, 68, 0.3)'"
|
|
1627
|
-
onmouseout="this.style.background='rgba(239, 68, 68, 0.2)'"
|
|
1628
|
-
>
|
|
1629
|
-
Clear Cache
|
|
1630
|
-
</button>
|
|
1631
|
-
|
|
1632
|
-
<div style="
|
|
1633
|
-
margin-top: 8px;
|
|
1634
|
-
color: #64748b;
|
|
1635
|
-
font-size: 10px;
|
|
1636
|
-
line-height: 1.4;
|
|
1637
|
-
">
|
|
1638
|
-
Persistent cache survives page reloads. Stored in IndexedDB.
|
|
1639
|
-
</div>
|
|
1640
|
-
</div>
|
|
1641
|
-
|
|
1642
|
-
<!-- Debug Thumbnails Setting -->
|
|
1643
|
-
<div style="
|
|
1644
|
-
background: rgba(51, 65, 85, 0.4);
|
|
1645
|
-
border-radius: 8px;
|
|
1646
|
-
padding: 12px;
|
|
1647
|
-
margin-top: 10px;
|
|
1648
|
-
">
|
|
1649
|
-
<label style="
|
|
1650
|
-
display: flex;
|
|
1651
|
-
align-items: center;
|
|
1652
|
-
gap: 8px;
|
|
1653
|
-
cursor: pointer;
|
|
1654
|
-
">
|
|
1273
|
+
<!-- Thumbnail Timestamps -->
|
|
1274
|
+
<div class="dropdown-section">
|
|
1275
|
+
<label class="checkbox-label">
|
|
1655
1276
|
<input
|
|
1656
1277
|
type="checkbox"
|
|
1657
|
-
?checked=${this.
|
|
1658
|
-
@change=${(e) => this.
|
|
1659
|
-
style="
|
|
1660
|
-
width: 14px;
|
|
1661
|
-
height: 14px;
|
|
1662
|
-
accent-color: #f59e0b;
|
|
1663
|
-
cursor: pointer;
|
|
1664
|
-
"
|
|
1278
|
+
?checked=${this.previewSettings.showThumbnailTimestamps}
|
|
1279
|
+
@change=${(e) => this.handleShowThumbnailTimestampsToggle(e.target.checked)}
|
|
1665
1280
|
/>
|
|
1666
|
-
<span
|
|
1281
|
+
<span>Show Thumbnail Timestamps</span>
|
|
1667
1282
|
</label>
|
|
1668
1283
|
|
|
1669
|
-
<div
|
|
1670
|
-
|
|
1671
|
-
color: #64748b;
|
|
1672
|
-
font-size: 10px;
|
|
1673
|
-
line-height: 1.4;
|
|
1674
|
-
">
|
|
1675
|
-
Overlays capture timestamps on timeline thumbnails for debugging.
|
|
1284
|
+
<div class="dropdown-description">
|
|
1285
|
+
Display timestamp overlay on timeline thumbnails for debugging.
|
|
1676
1286
|
</div>
|
|
1677
1287
|
</div>
|
|
1678
1288
|
</div>
|
|
@@ -1694,18 +1304,9 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1694
1304
|
|
|
1695
1305
|
<!-- Scale -->
|
|
1696
1306
|
<div style="margin-bottom: 10px;">
|
|
1697
|
-
<label style="display: block;
|
|
1307
|
+
<label class="dropdown-label" style="display: block; margin-bottom: 4px;">Scale</label>
|
|
1698
1308
|
<select
|
|
1699
|
-
|
|
1700
|
-
width: 100%;
|
|
1701
|
-
padding: 6px 10px;
|
|
1702
|
-
background: rgba(51, 65, 85, 0.8);
|
|
1703
|
-
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
1704
|
-
border-radius: 5px;
|
|
1705
|
-
color: #e2e8f0;
|
|
1706
|
-
font-size: 12px;
|
|
1707
|
-
cursor: pointer;
|
|
1708
|
-
"
|
|
1309
|
+
class="dropdown-select"
|
|
1709
1310
|
.value=${String(this.exportOptions.scale)}
|
|
1710
1311
|
@change=${(e) => this.updateExportOption("scale", Number(e.target.value))}
|
|
1711
1312
|
>
|
|
@@ -1718,77 +1319,59 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1718
1319
|
|
|
1719
1320
|
<!-- Audio -->
|
|
1720
1321
|
<div style="margin-bottom: 10px;">
|
|
1721
|
-
<label
|
|
1322
|
+
<label class="checkbox-label">
|
|
1722
1323
|
<input
|
|
1723
1324
|
type="checkbox"
|
|
1724
1325
|
?checked=${this.exportOptions.includeAudio}
|
|
1725
1326
|
@change=${(e) => this.updateExportOption("includeAudio", e.target.checked)}
|
|
1726
|
-
style="width: 14px; height: 14px; accent-color: #3b82f6;"
|
|
1727
1327
|
/>
|
|
1728
|
-
<span
|
|
1328
|
+
<span>Include Audio</span>
|
|
1729
1329
|
</label>
|
|
1730
1330
|
</div>
|
|
1731
1331
|
|
|
1732
1332
|
<!-- In/Out Range -->
|
|
1733
1333
|
<div style="margin-bottom: 12px;">
|
|
1734
|
-
<label
|
|
1334
|
+
<label class="checkbox-label" style="margin-bottom: 6px;">
|
|
1735
1335
|
<input
|
|
1736
1336
|
type="checkbox"
|
|
1737
1337
|
?checked=${this.exportOptions.useInOut}
|
|
1738
1338
|
@change=${(e) => this.updateExportOption("useInOut", e.target.checked)}
|
|
1739
|
-
style="width: 14px; height: 14px; accent-color: #3b82f6;"
|
|
1740
1339
|
/>
|
|
1741
|
-
<span
|
|
1340
|
+
<span>Custom Range</span>
|
|
1742
1341
|
</label>
|
|
1743
1342
|
|
|
1744
1343
|
${this.exportOptions.useInOut ? html`
|
|
1745
1344
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 6px;">
|
|
1746
1345
|
<div>
|
|
1747
|
-
<label style="display: block;
|
|
1346
|
+
<label class="dropdown-label" style="display: block; margin-bottom: 2px; font-size: 10px;">In (ms)</label>
|
|
1748
1347
|
<input
|
|
1749
1348
|
type="number"
|
|
1349
|
+
class="dropdown-input"
|
|
1350
|
+
style="font-family: ui-monospace, monospace;"
|
|
1750
1351
|
min="0"
|
|
1751
1352
|
max=${durationMs}
|
|
1752
1353
|
.value=${String(this.exportOptions.inMs)}
|
|
1753
1354
|
@change=${(e) => this.updateExportOption("inMs", Number(e.target.value))}
|
|
1754
|
-
style="
|
|
1755
|
-
width: 100%;
|
|
1756
|
-
padding: 5px 7px;
|
|
1757
|
-
background: rgba(51, 65, 85, 0.8);
|
|
1758
|
-
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
1759
|
-
border-radius: 4px;
|
|
1760
|
-
color: #e2e8f0;
|
|
1761
|
-
font-size: 11px;
|
|
1762
|
-
font-family: ui-monospace, monospace;
|
|
1763
|
-
"
|
|
1764
1355
|
/>
|
|
1765
1356
|
</div>
|
|
1766
1357
|
<div>
|
|
1767
|
-
<label style="display: block;
|
|
1358
|
+
<label class="dropdown-label" style="display: block; margin-bottom: 2px; font-size: 10px;">Out (ms)</label>
|
|
1768
1359
|
<input
|
|
1769
1360
|
type="number"
|
|
1361
|
+
class="dropdown-input"
|
|
1362
|
+
style="font-family: ui-monospace, monospace;"
|
|
1770
1363
|
min="0"
|
|
1771
1364
|
max=${durationMs}
|
|
1772
1365
|
.value=${String(this.exportOptions.outMs)}
|
|
1773
1366
|
@change=${(e) => this.updateExportOption("outMs", Number(e.target.value))}
|
|
1774
|
-
style="
|
|
1775
|
-
width: 100%;
|
|
1776
|
-
padding: 5px 7px;
|
|
1777
|
-
background: rgba(51, 65, 85, 0.8);
|
|
1778
|
-
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
1779
|
-
border-radius: 4px;
|
|
1780
|
-
color: #e2e8f0;
|
|
1781
|
-
font-size: 11px;
|
|
1782
|
-
font-family: ui-monospace, monospace;
|
|
1783
|
-
"
|
|
1784
1367
|
/>
|
|
1785
1368
|
</div>
|
|
1786
1369
|
</div>
|
|
1787
|
-
<div
|
|
1370
|
+
<div class="dropdown-description" style="margin-top: 4px;">
|
|
1788
1371
|
Duration: ${this.formatTime(this.exportOptions.outMs - this.exportOptions.inMs)} / ${this.formatTime(durationMs)}
|
|
1789
1372
|
</div>
|
|
1790
1373
|
` : html`
|
|
1791
|
-
<div
|
|
1374
|
+
<div class="dropdown-description">
|
|
1792
1375
|
Full duration: ${this.formatTime(durationMs)}
|
|
1793
1376
|
</div>
|
|
1794
1377
|
`}
|
|
@@ -1821,16 +1404,16 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1821
1404
|
let statusColor;
|
|
1822
1405
|
let statusText;
|
|
1823
1406
|
if (isComplete) {
|
|
1824
|
-
statusColor = "
|
|
1407
|
+
statusColor = "var(--ef-color-success)";
|
|
1825
1408
|
statusText = "Complete!";
|
|
1826
1409
|
} else if (isError) {
|
|
1827
|
-
statusColor = "
|
|
1410
|
+
statusColor = "var(--ef-color-danger)";
|
|
1828
1411
|
statusText = "Failed";
|
|
1829
1412
|
} else if (isCancelled) {
|
|
1830
|
-
statusColor = "
|
|
1413
|
+
statusColor = "var(--ef-color-warning)";
|
|
1831
1414
|
statusText = "Cancelled";
|
|
1832
1415
|
} else {
|
|
1833
|
-
statusColor = "
|
|
1416
|
+
statusColor = "var(--ef-color-primary)";
|
|
1834
1417
|
statusText = `${progressPercent}%`;
|
|
1835
1418
|
}
|
|
1836
1419
|
return html`
|
|
@@ -1845,7 +1428,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1845
1428
|
${isRendering ? html`
|
|
1846
1429
|
<button
|
|
1847
1430
|
class="dropdown-close"
|
|
1848
|
-
style="color:
|
|
1431
|
+
style="color: var(--ef-color-danger);"
|
|
1849
1432
|
@click=${this.handleCancelClick}
|
|
1850
1433
|
>Cancel</button>
|
|
1851
1434
|
` : null}
|
|
@@ -1859,7 +1442,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1859
1442
|
<style>
|
|
1860
1443
|
ef-workbench canvas {
|
|
1861
1444
|
border-radius: 4px;
|
|
1862
|
-
border: 1px solid
|
|
1445
|
+
border: 1px solid var(--ef-color-border);
|
|
1863
1446
|
max-width: 100%;
|
|
1864
1447
|
height: auto;
|
|
1865
1448
|
}
|
|
@@ -1868,25 +1451,25 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1868
1451
|
|
|
1869
1452
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; margin-bottom: 10px; font-family: ui-monospace, monospace; font-size: 10px;">
|
|
1870
1453
|
<div>
|
|
1871
|
-
<div style="color:
|
|
1872
|
-
<div style="color:
|
|
1454
|
+
<div style="color: var(--ef-color-text-subtle);">Frames</div>
|
|
1455
|
+
<div style="color: var(--ef-color-text);">${p.currentFrame} / ${p.totalFrames}</div>
|
|
1873
1456
|
</div>
|
|
1874
1457
|
<div>
|
|
1875
|
-
<div style="color:
|
|
1876
|
-
<div style="color:
|
|
1458
|
+
<div style="color: var(--ef-color-text-subtle);">Time</div>
|
|
1459
|
+
<div style="color: var(--ef-color-text);">${this.formatTime(p.renderedMs)} / ${this.formatTime(p.totalDurationMs)}</div>
|
|
1877
1460
|
</div>
|
|
1878
1461
|
<div>
|
|
1879
|
-
<div style="color:
|
|
1880
|
-
<div style="color: ${p.speedMultiplier >= 1 ? "
|
|
1462
|
+
<div style="color: var(--ef-color-text-subtle);">Speed</div>
|
|
1463
|
+
<div style="color: ${p.speedMultiplier >= 1 ? "var(--ef-color-success)" : "var(--ef-color-warning)"};">${p.speedMultiplier.toFixed(2)}x</div>
|
|
1881
1464
|
</div>
|
|
1882
1465
|
<div>
|
|
1883
|
-
<div style="color:
|
|
1884
|
-
<div style="color:
|
|
1466
|
+
<div style="color: var(--ef-color-text-subtle);">ETA</div>
|
|
1467
|
+
<div style="color: var(--ef-color-text);">${this.formatTime(p.estimatedRemainingMs)}</div>
|
|
1885
1468
|
</div>
|
|
1886
1469
|
</div>
|
|
1887
1470
|
` : null}
|
|
1888
1471
|
|
|
1889
|
-
<div style="height: 4px; background:
|
|
1472
|
+
<div style="height: 4px; background: var(--ef-color-bg-inset); border-radius: 2px; overflow: hidden;">
|
|
1890
1473
|
<div style="
|
|
1891
1474
|
height: 100%;
|
|
1892
1475
|
width: ${progressPercent}%;
|
|
@@ -1910,7 +1493,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1910
1493
|
}
|
|
1911
1494
|
renderToolbar() {
|
|
1912
1495
|
return html`
|
|
1913
|
-
<div class="toolbar">
|
|
1496
|
+
<div class="toolbar" part="toolbar">
|
|
1914
1497
|
<div class="toolbar-left">
|
|
1915
1498
|
<!-- Fit to content button -->
|
|
1916
1499
|
<button
|
|
@@ -1926,14 +1509,43 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1926
1509
|
</div>
|
|
1927
1510
|
|
|
1928
1511
|
<div class="toolbar-right">
|
|
1929
|
-
<!-- Mode indicator
|
|
1930
|
-
${this.presentationMode
|
|
1931
|
-
|
|
1932
|
-
${
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1512
|
+
<!-- Mode indicator -->
|
|
1513
|
+
<span class="mode-indicator ${this.presentationMode}">
|
|
1514
|
+
${this.presentationMode === "dom" ? "DOM" : html`
|
|
1515
|
+
Canvas ${getRenderMode() === "native" ? phosphorIcon(ICONS.lightning, 12) : phosphorIcon(ICONS.code, 12)}
|
|
1516
|
+
`}
|
|
1517
|
+
</span>
|
|
1518
|
+
|
|
1519
|
+
<!-- Theme toggle button -->
|
|
1520
|
+
<button
|
|
1521
|
+
class="toolbar-icon-btn"
|
|
1522
|
+
@click=${this.handleThemeToggle}
|
|
1523
|
+
title="${this.themeMode === "light" ? "Light mode" : this.themeMode === "dark" ? "Dark mode" : "System preference"}"
|
|
1524
|
+
>
|
|
1525
|
+
${this.themeMode === "light" ? html`
|
|
1526
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1527
|
+
<circle cx="12" cy="12" r="5"></circle>
|
|
1528
|
+
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|
1529
|
+
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|
1530
|
+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|
1531
|
+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|
1532
|
+
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|
1533
|
+
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|
1534
|
+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|
1535
|
+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|
1536
|
+
</svg>
|
|
1537
|
+
` : this.themeMode === "dark" ? html`
|
|
1538
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1539
|
+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
|
1540
|
+
</svg>
|
|
1541
|
+
` : html`
|
|
1542
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1543
|
+
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
|
1544
|
+
<line x1="8" y1="21" x2="16" y2="21"></line>
|
|
1545
|
+
<line x1="12" y1="17" x2="12" y2="21"></line>
|
|
1546
|
+
</svg>
|
|
1547
|
+
`}
|
|
1548
|
+
</button>
|
|
1937
1549
|
|
|
1938
1550
|
<!-- Settings button -->
|
|
1939
1551
|
<button
|
|
@@ -1953,7 +1565,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
1953
1565
|
style="min-width: 100px;"
|
|
1954
1566
|
popovertarget="export-progress-popover"
|
|
1955
1567
|
>
|
|
1956
|
-
<div style="width: 12px; height: 12px; border: 2px solid
|
|
1568
|
+
<div style="width: 12px; height: 12px; border: 2px solid var(--ef-color-primary-subtle); border-top-color: var(--ef-color-primary); border-radius: 50%; animation: spin 1s linear infinite;"></div>
|
|
1957
1569
|
Exporting...
|
|
1958
1570
|
</button>
|
|
1959
1571
|
` : html`
|
|
@@ -2001,17 +1613,32 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
2001
1613
|
}
|
|
2002
1614
|
}
|
|
2003
1615
|
renderPlaybackStats() {
|
|
2004
|
-
if (!this.showStats
|
|
2005
|
-
|
|
1616
|
+
if (!this.showStats) return null;
|
|
1617
|
+
let stats = null;
|
|
1618
|
+
if (this.presentationMode === "canvas" && this.renderStats) {
|
|
1619
|
+
const timegroup = this.getTimegroup();
|
|
1620
|
+
if (!timegroup) return null;
|
|
1621
|
+
const compositionWidth = timegroup.offsetWidth || 1920;
|
|
1622
|
+
const compositionHeight = timegroup.offsetHeight || 1080;
|
|
1623
|
+
const resolutionScale = this.canvasPreviewResult ? this.canvasPreviewResult.getResolutionScale() : 1;
|
|
1624
|
+
const renderWidth = Math.floor(compositionWidth * resolutionScale);
|
|
1625
|
+
const renderHeight = Math.floor(compositionHeight * resolutionScale);
|
|
1626
|
+
stats = this.renderStats.getStats(renderWidth, renderHeight, resolutionScale);
|
|
1627
|
+
} else if (this.presentationMode === "dom" && this.domStatsStrategy) stats = this.domStatsStrategy.getStats();
|
|
2006
1628
|
if (!stats) return null;
|
|
2007
1629
|
const fpsClass = stats.fps >= 55 ? "good" : stats.fps >= 25 ? "warning" : "bad";
|
|
2008
1630
|
const renderClass = stats.avgRenderTime !== null ? stats.avgRenderTime <= 20 ? "good" : stats.avgRenderTime <= 30 ? "warning" : "bad" : "";
|
|
2009
1631
|
const headroomClass = stats.headroom !== null ? stats.headroom >= 10 ? "good" : stats.headroom >= 0 ? "warning" : "bad" : "";
|
|
2010
1632
|
const pressureClass = stats.pressureState === "nominal" ? "good" : stats.pressureState === "fair" ? "good" : stats.pressureState === "serious" ? "warning" : "bad";
|
|
2011
1633
|
const scaleClass = stats.resolutionScale !== null ? stats.resolutionScale >= .75 ? "good" : stats.resolutionScale >= .5 ? "warning" : "bad" : "";
|
|
1634
|
+
const isCanvasMode = this.presentationMode === "canvas";
|
|
1635
|
+
const showRenderTime = isCanvasMode;
|
|
1636
|
+
const showHeadroom = isCanvasMode;
|
|
1637
|
+
const showResolutionScale = isCanvasMode;
|
|
1638
|
+
const showAdaptiveResolution = isCanvasMode && this.previewResolutionScale === "auto";
|
|
2012
1639
|
const motionState = this.isAtRest ? "At Rest" : this.isPlaying ? "Playing" : this.isScrubbing ? "Scrubbing" : "Idle";
|
|
2013
1640
|
const renderPressureHistogram = () => {
|
|
2014
|
-
if (stats.pressureHistory.length === 0) return html`<div style="color:
|
|
1641
|
+
if (stats.pressureHistory.length === 0) return html`<div style="color: var(--ef-color-text-subtle); font-size: 9px;">No pressure data (API not available)</div>`;
|
|
2015
1642
|
return html`
|
|
2016
1643
|
<div class="pressure-histogram">
|
|
2017
1644
|
${stats.pressureHistory.map((state$1) => html`
|
|
@@ -2033,13 +1660,13 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
2033
1660
|
<span class="stat-label">FPS</span>
|
|
2034
1661
|
<span class="stat-value ${fpsClass}">${padNum(stats.fps, 1, 5)}</span>
|
|
2035
1662
|
</div>
|
|
2036
|
-
${
|
|
1663
|
+
${showRenderTime && stats.avgRenderTime !== null ? html`
|
|
2037
1664
|
<div class="stat-row">
|
|
2038
1665
|
<span class="stat-label">Render</span>
|
|
2039
1666
|
<span class="stat-value ${renderClass}">${padNum(stats.avgRenderTime, 1, 5)}ms</span>
|
|
2040
1667
|
</div>
|
|
2041
1668
|
` : null}
|
|
2042
|
-
${
|
|
1669
|
+
${showHeadroom && stats.headroom !== null ? html`
|
|
2043
1670
|
<div class="stat-row">
|
|
2044
1671
|
<span class="stat-label">Headroom</span>
|
|
2045
1672
|
<span class="stat-value ${headroomClass}">${stats.headroom >= 0 ? "+" : ""}${padNum(stats.headroom, 1, 4)}ms</span>
|
|
@@ -2049,7 +1676,7 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
2049
1676
|
<span class="stat-label">Resolution</span>
|
|
2050
1677
|
<span class="stat-value">${stats.renderWidth}×${stats.renderHeight}</span>
|
|
2051
1678
|
</div>
|
|
2052
|
-
${
|
|
1679
|
+
${showResolutionScale && stats.resolutionScale !== null ? html`
|
|
2053
1680
|
<div class="stat-row">
|
|
2054
1681
|
<span class="stat-label">Scale</span>
|
|
2055
1682
|
<span class="stat-value ${scaleClass}">${String(Math.round(stats.resolutionScale * 100)).padStart(3, " ")}%</span>
|
|
@@ -2063,8 +1690,8 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
2063
1690
|
<span class="stat-label">State</span>
|
|
2064
1691
|
<span class="stat-value">${motionState}</span>
|
|
2065
1692
|
</div>
|
|
2066
|
-
${
|
|
2067
|
-
<div style="margin-top: 4px; padding-top: 4px; border-top: 1px solid
|
|
1693
|
+
${showAdaptiveResolution && stats.samplesAtCurrentScale !== void 0 ? html`
|
|
1694
|
+
<div style="margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--ef-color-border-subtle);">
|
|
2068
1695
|
<div class="stat-row">
|
|
2069
1696
|
<span class="stat-label">Mode</span>
|
|
2070
1697
|
<span class="stat-value good">Auto</span>
|
|
@@ -2097,56 +1724,45 @@ let EFWorkbench = class EFWorkbench$1 extends ContextMixin(TWMixin(LitElement))
|
|
|
2097
1724
|
<slot class="fixed inset-0 h-full w-full" name="canvas"></slot>
|
|
2098
1725
|
`;
|
|
2099
1726
|
return html`
|
|
1727
|
+
<!-- Top: Full-width Toolbar -->
|
|
1728
|
+
<div style="grid-row: 1 / 2; grid-column: 1 / -1;">
|
|
1729
|
+
${this.renderToolbar()}
|
|
1730
|
+
</div>
|
|
1731
|
+
|
|
1732
|
+
<!-- Left: Hierarchy Panel -->
|
|
2100
1733
|
<div
|
|
2101
|
-
|
|
2102
|
-
style="flex: 1; min-height: 0; width: 100%; grid-template-rows: auto 1fr 280px; grid-template-columns: 280px 1fr; background-color: var(--workbench-bg);"
|
|
1734
|
+
style="grid-row: 2 / 3; grid-column: 1 / 2; background: var(--ef-color-bg-panel); border-right: 1px solid var(--ef-color-border); min-height: 0; overflow: hidden;"
|
|
2103
1735
|
>
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
${this.renderToolbar()}
|
|
2107
|
-
</div>
|
|
2108
|
-
|
|
2109
|
-
<!-- Left: Hierarchy Panel -->
|
|
2110
|
-
<div
|
|
2111
|
-
style="grid-row: 2 / 3; grid-column: 1 / 2; background: rgb(30 41 59); border-right: 1px solid rgba(148, 163, 184, 0.2); min-height: 0; max-height: 100%; display: flex; flex-direction: column; overflow: hidden;"
|
|
2112
|
-
>
|
|
2113
|
-
<slot name="hierarchy"></slot>
|
|
2114
|
-
</div>
|
|
1736
|
+
<slot name="hierarchy"></slot>
|
|
1737
|
+
</div>
|
|
2115
1738
|
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
style="display: ${this.presentationMode === "canvas" ? "block" : "none"}"
|
|
2137
|
-
></div>
|
|
2138
|
-
|
|
2139
|
-
<!-- Playback stats overlay (visible in canvas mode only) -->
|
|
2140
|
-
${this.renderPlaybackStats()}
|
|
2141
|
-
</div>
|
|
1739
|
+
<!-- Center: Canvas area -->
|
|
1740
|
+
<div
|
|
1741
|
+
class="canvas-container"
|
|
1742
|
+
part="canvas"
|
|
1743
|
+
style="grid-row: 2 / 3; grid-column: 2 / 3; min-height: 0; overflow: hidden;"
|
|
1744
|
+
@wheel=${this.handleStageWheel}
|
|
1745
|
+
>
|
|
1746
|
+
<!-- Original timegroup (hidden in clone/canvas mode, visible in dom mode) -->
|
|
1747
|
+
<slot name="canvas"></slot>
|
|
1748
|
+
|
|
1749
|
+
<!-- Canvas preview (visible in canvas mode only) -->
|
|
1750
|
+
<div
|
|
1751
|
+
class="canvas-overlay"
|
|
1752
|
+
${ref(this.canvasPreviewRef)}
|
|
1753
|
+
style="display: ${this.presentationMode === "canvas" ? "block" : "none"}"
|
|
1754
|
+
></div>
|
|
1755
|
+
|
|
1756
|
+
<!-- Playback stats overlay (visible in canvas mode only) -->
|
|
1757
|
+
${this.renderPlaybackStats()}
|
|
1758
|
+
</div>
|
|
2142
1759
|
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
</div>
|
|
1760
|
+
<!-- Bottom: Timeline -->
|
|
1761
|
+
<div
|
|
1762
|
+
class="overflow-hidden"
|
|
1763
|
+
style="grid-row: 3 / 4; grid-column: 1 / -1; height: 100%; border-top: 1px solid var(--ef-color-border);"
|
|
1764
|
+
>
|
|
1765
|
+
<slot name="timeline"></slot>
|
|
2150
1766
|
</div>
|
|
2151
1767
|
`;
|
|
2152
1768
|
}
|
|
@@ -2160,15 +1776,13 @@ __decorate([provide({ context: previewSettingsContext }), state()], EFWorkbench.
|
|
|
2160
1776
|
__decorate([state()], EFWorkbench.prototype, "renderMode", void 0);
|
|
2161
1777
|
__decorate([state()], EFWorkbench.prototype, "presentationMode", void 0);
|
|
2162
1778
|
__decorate([state()], EFWorkbench.prototype, "previewResolutionScale", void 0);
|
|
2163
|
-
__decorate([state()], EFWorkbench.prototype, "debugThumbnailTimestamps", void 0);
|
|
2164
|
-
__decorate([state()], EFWorkbench.prototype, "thumbnailCacheMaxSize", void 0);
|
|
2165
|
-
__decorate([state()], EFWorkbench.prototype, "thumbnailCacheStats", void 0);
|
|
2166
1779
|
__decorate([state()], EFWorkbench.prototype, "exportOptions", void 0);
|
|
2167
1780
|
__decorate([state()], EFWorkbench.prototype, "isPlaying", void 0);
|
|
2168
1781
|
__decorate([state()], EFWorkbench.prototype, "isScrubbing", void 0);
|
|
2169
1782
|
__decorate([state()], EFWorkbench.prototype, "isAtRest", void 0);
|
|
2170
1783
|
__decorate([state()], EFWorkbench.prototype, "currentAdaptiveScale", void 0);
|
|
2171
1784
|
__decorate([state()], EFWorkbench.prototype, "showStats", void 0);
|
|
1785
|
+
__decorate([state()], EFWorkbench.prototype, "themeMode", void 0);
|
|
2172
1786
|
__decorate([eventOptions({
|
|
2173
1787
|
passive: false,
|
|
2174
1788
|
capture: true
|