@liveroom-tech/react-immersive 1.1.0 → 1.1.2
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/README.md +7 -7
- package/dist/index.js +226 -129
- package/dist/index.mjs +331 -232
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/components/ModelViewer/ModelViewer.tsx
|
|
2
2
|
import {
|
|
3
|
-
useRef as
|
|
3
|
+
useRef as useRef11,
|
|
4
4
|
useState as useState10,
|
|
5
5
|
useEffect as useEffect14,
|
|
6
6
|
useCallback as useCallback4,
|
|
@@ -42,7 +42,7 @@ function styleInject(css, { insertAt } = {}) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// src/styles/ModelViewer.css
|
|
45
|
-
styleInject('.ri-viewer--license-checking,\n.ri-viewer--license-invalid {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background-color: #f9f9f9;\n}\n.ri-viewer {\n --ri-font-family:\n Inter,\n "Segoe UI",\n Helvetica,\n Arial,\n sans-serif;\n --ri-viewer-bg: #1c1c1d;\n --ri-viewer-text: #111827;\n --ri-panel-bg: #ffffff;\n --ri-panel-border: #e5e7eb;\n --ri-panel-title: #111827;\n --ri-panel-muted-text: #4b5563;\n --ri-panel-subtle-text: #9ca3af;\n --ri-panel-surface: #f9fafb;\n --ri-panel-surface-hover: #f3f4f6;\n --ri-panel-surface-border: #e5e7eb;\n --ri-panel-button-text: #1f2937;\n --ri-panel-accent: #2563eb;\n --ri-panel-accent-contrast: #ffffff;\n --ri-license-overlay-bg: rgba(0, 0, 0, 0.04);\n --ri-license-overlay-border: rgba(0, 0, 0, 0.08);\n --ri-license-overlay-text: #888;\n --ri-license-overlay-error-bg: rgba(192, 57, 43, 0.06);\n --ri-license-overlay-error-border: rgba(192, 57, 43, 0.2);\n --ri-license-overlay-error-text: #c0392b;\n --ri-sidepanel-font-family:\n Inter,\n "Segoe UI",\n Helvetica,\n Arial,\n sans-serif;\n --ri-sidepanel-bg: #141824;\n --ri-sidepanel-open-btn-bg: rgba(20, 20, 20, 0.82);\n --ri-sidepanel-open-btn-bg-hover: #27282b7e;\n --ri-sidepanel-border: rgba(255, 255, 255, 0.06);\n --ri-sidepanel-divider: rgba(255, 255, 255, 0.04);\n --ri-sidepanel-border-strong: rgba(255, 255, 255, 0.08);\n --ri-sidepanel-border-active: rgba(255, 255, 255, 0.18);\n --ri-sidepanel-shadow-left: 4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-sidepanel-shadow-right: -4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-sidepanel-text: #f1f5f9;\n --ri-sidepanel-text-emphasis: #ffffff;\n --ri-sidepanel-text-muted: #94a3b8;\n --ri-sidepanel-text-subtle: #64748b;\n --ri-sidepanel-placeholder: #475569;\n --ri-sidepanel-surface: rgba(255, 255, 255, 0.05);\n --ri-sidepanel-surface-hover: rgba(255, 255, 255, 0.1);\n --ri-sidepanel-accent: #3b82f6;\n --ri-sidepanel-accent-soft: rgba(59, 130, 246, 0.12);\n --ri-databinding-bg: #111318;\n --ri-databinding-border: rgba(255, 255, 255, 0.06);\n --ri-databinding-border-strong: rgba(255, 255, 255, 0.08);\n --ri-databinding-border-hover: rgba(255, 255, 255, 0.15);\n --ri-databinding-shadow: 4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-databinding-font-family:\n "Inter",\n "Segoe UI",\n sans-serif;\n --ri-databinding-mono-font-family:\n "JetBrains Mono",\n "Fira Code",\n "Menlo",\n monospace;\n --ri-databinding-text: #f1f5f9;\n --ri-databinding-text-muted: #94a3b8;\n --ri-databinding-text-subtle: #64748b;\n --ri-databinding-text-faint: #475569;\n --ri-databinding-text-hover: #cbd5e1;\n --ri-databinding-surface: rgba(255, 255, 255, 0.03);\n --ri-databinding-surface-hover: rgba(255, 255, 255, 0.06);\n --ri-databinding-accent: #93c5fd;\n --ri-databinding-accent-glow: rgba(147, 197, 253, 0.8);\n --ri-databinding-accent-border: rgba(96, 165, 250, 0.55);\n --ri-databinding-accent-gradient:\n linear-gradient(\n \n 135deg,\n #1e3a8a 0%,\n #1d4ed8 60%,\n #2563eb 100% );\n --ri-databinding-accent-gradient-active:\n linear-gradient(\n \n 135deg,\n #1e3a8a 0%,\n #1e40af 100% );\n display: flex;\n flex-direction: row;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n background: var(--ri-viewer-bg);\n position: relative;\n color: var(--ri-viewer-text);\n font-family: var(--ri-font-family);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n font-synthesis: none;\n}\n.ri-viewer * {\n box-sizing: border-box;\n}\n.ri-viewerLeft {\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n position: relative;\n}\n.ri-viewerRight {\n display: flex;\n flex-shrink: 0;\n min-width: 0;\n}\n.ri-panel {\n width: 280px;\n min-height: 0;\n background: var(--ri-panel-bg);\n border-right: 1px solid var(--ri-panel-border);\n display: flex;\n flex-direction: column;\n padding: 20px;\n overflow-y: auto;\n flex-shrink: 0;\n transition: margin-left 0.3s ease, transform 0.3s ease;\n}\n.ri-panel--open {\n transform: translateX(0);\n margin-left: 0;\n}\n.ri-panel--closed {\n transform: translateX(-100%);\n margin-left: -280px;\n}\n.ri-panelHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n}\n.ri-panelTitle {\n margin: 0;\n font-size: 15px;\n font-weight: 700;\n color: var(--ri-panel-title);\n line-height: 1.4;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ri-closeButton {\n border: 0;\n background: transparent;\n color: var(--ri-panel-subtle-text);\n font-size: 22px;\n line-height: 1;\n padding: 0;\n cursor: pointer;\n flex-shrink: 0;\n transition: color 0.2s ease;\n}\n.ri-closeButton:hover {\n color: var(--ri-panel-muted-text);\n}\n.ri-json {\n margin: 0 0 16px;\n padding: 12px;\n background: var(--ri-panel-surface);\n border: 1px solid var(--ri-panel-surface-border);\n border-radius: 12px;\n font-size: 12px;\n line-height: 1.55;\n color: var(--ri-panel-button-text);\n overflow-x: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.ri-divider {\n border-top: 1px solid var(--ri-panel-border);\n margin-bottom: 12px;\n}\n.ri-sectionLabel {\n margin-bottom: 8px;\n font-size: 11px;\n font-weight: 700;\n color: var(--ri-panel-subtle-text);\n text-transform: uppercase;\n letter-spacing: 0.16em;\n}\n.ri-actionList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.ri-actionButton {\n width: 100%;\n border-radius: 8px;\n border: 1px solid var(--ri-panel-surface-border);\n background: var(--ri-panel-surface);\n color: var(--ri-panel-button-text);\n padding: 10px 12px;\n text-align: left;\n font-size: 14px;\n line-height: 1.4;\n cursor: pointer;\n transition:\n background-color 0.2s ease,\n border-color 0.2s ease,\n color 0.2s ease;\n}\n.ri-actionButton:hover {\n background: var(--ri-panel-surface-hover);\n border-color: var(--ri-panel-border);\n}\n.ri-actionButton--active {\n background: var(--ri-panel-accent);\n border-color: var(--ri-panel-accent);\n color: var(--ri-panel-accent-contrast);\n}\n.ri-actionButton--active:hover {\n background: var(--ri-panel-accent);\n border-color: var(--ri-panel-accent);\n}\n.ri-canvasArea {\n flex: 1 1 auto;\n position: relative;\n min-width: 0;\n}\n.ri-canvasArea--measuring {\n cursor: crosshair;\n}\n.ri-canvasArea canvas {\n opacity: 1;\n transition: opacity 0.18s ease;\n}\n.ri-canvasArea--positioning canvas {\n opacity: 0;\n transition: none;\n}\n.ri-bindingsMismatchBanner {\n position: absolute;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 12px 7px 10px;\n border-radius: 8px;\n background: rgba(30, 20, 0, 0.88);\n border: 1px solid rgba(251, 191, 36, 0.35);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n color: rgb(251, 191, 36);\n font-size: 12px;\n font-weight: 500;\n line-height: 1.4;\n white-space: nowrap;\n pointer-events: auto;\n max-width: calc(100% - 32px);\n white-space: normal;\n text-align: center;\n}\n.ri-bindingsMismatchBanner__icon {\n flex-shrink: 0;\n}\n.ri-bindingsMismatchBanner__dismiss {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: 4px;\n padding: 2px;\n background: none;\n border: none;\n border-radius: 4px;\n color: rgba(251, 191, 36, 0.7);\n cursor: pointer;\n transition: color 0.15s ease, background 0.15s ease;\n}\n.ri-bindingsMismatchBanner__dismiss:hover {\n color: rgb(251, 191, 36);\n background: rgba(251, 191, 36, 0.12);\n}\n.ri-measureTools {\n position: absolute;\n top: 16px;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-measureButton {\n width: 34px;\n height: 34px;\n padding: 0;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.75);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: manipulation;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease;\n}\n.ri-measureButton:hover {\n background: rgba(40, 40, 40, 0.92);\n color: #fff;\n border-color: rgba(255, 255, 255, 0.25);\n}\n.ri-measureButton:active {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-measureButton--active {\n background: #22d3ee;\n border-color: #22d3ee;\n color: #06343c;\n}\n.ri-measureButton--active:hover {\n background: #38dbf0;\n color: #06343c;\n}\n.ri-measureHint {\n padding: 6px 10px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 1;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n white-space: nowrap;\n}\n.ri-explodeTools {\n position: absolute;\n top: 16px;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-explodeTools--stacked {\n top: 58px;\n}\n.ri-explodeSlider {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 12px;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n}\n.ri-explodeSlider input[type=range] {\n width: 120px;\n accent-color: #22d3ee;\n cursor: pointer;\n}\n.ri-cinematicTools {\n position: absolute;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-measureDot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #22d3ee;\n border: 2px solid #fff;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);\n pointer-events: none;\n}\n.ri-measureLabel {\n padding: 3px 7px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n color: #06343c;\n background: #22d3ee;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n pointer-events: none;\n user-select: none;\n}\n.ri-xrTools {\n position: absolute;\n top: 16px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-xrButton {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 10px;\n font-size: 13px;\n font-weight: 500;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.16);\n border-radius: 10px;\n cursor: pointer;\n touch-action: manipulation;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.ri-xrButton:hover {\n background: rgba(40, 40, 40, 0.92);\n border-color: rgba(255, 255, 255, 0.3);\n}\n.ri-arHintOverlay {\n position: absolute;\n top: 18px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n width: min(calc(100% - 32px), 360px);\n pointer-events: none;\n}\n.ri-arHint {\n margin: 0 auto;\n width: fit-content;\n max-width: 100%;\n padding: 6px 12px;\n font-size: 11px;\n font-weight: 500;\n line-height: 1.2;\n text-align: center;\n color: rgba(255, 255, 255, 0.92);\n background: rgba(20, 20, 20, 0.58);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 999px;\n user-select: none;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n.ri-arOverlay {\n position: absolute;\n bottom: 24px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n width: min(calc(100% - 32px), 420px);\n pointer-events: none;\n}\n.ri-arControls {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n}\n.ri-arStatus,\n.ri-arActionButton {\n max-width: 100%;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.3;\n text-align: center;\n white-space: nowrap;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.16);\n border-radius: 19px;\n user-select: none;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n}\n.ri-arStatus {\n pointer-events: none;\n}\n.ri-arActionButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n cursor: pointer;\n pointer-events: auto;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n transition:\n background 0.15s ease,\n border-color 0.15s ease,\n color 0.15s ease,\n transform 0.15s ease;\n}\n.ri-arActionButton svg {\n flex-shrink: 0;\n}\n.ri-arActionButton:hover {\n background: rgba(40, 40, 40, 0.92);\n border-color: rgba(255, 255, 255, 0.3);\n}\n.ri-arActionButton:active {\n transform: scale(0.98);\n}\n.ri-arActionButton--primary {\n color: #06343c;\n background: #22d3ee;\n border-color: transparent;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n}\n.ri-arActionButton--primary:hover {\n background: #67e8f9;\n border-color: transparent;\n}\n.ri-arActionButton.ri-arActionButton--active,\n.ri-arActionButton[aria-pressed=true],\n.ri-arActionButton.ri-arActionButton--active:hover,\n.ri-arActionButton[aria-pressed=true]:hover,\n.ri-arActionButton.ri-arActionButton--active:active,\n.ri-arActionButton[aria-pressed=true]:active {\n color: #06343c;\n background: #22d3ee;\n border-color: transparent;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n}\n.ri-hiddenInput {\n display: none;\n}\n.ri-popover {\n position: absolute;\n z-index: 50;\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 16px;\n box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);\n color: #111827;\n}\n.ri-popoverHeader {\n padding: 12px 16px;\n border-bottom: 1px solid #f3f4f6;\n}\n.ri-popoverLabel {\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 700;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.16em;\n}\n.ri-inlineRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-top: 8px;\n}\n.ri-colorCode {\n font-size: 12px;\n color: #9ca3af;\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n monospace;\n text-transform: uppercase;\n}\n.ri-secondaryButton {\n border: 1px solid #e5e7eb;\n background: #f3f4f6;\n color: #374151;\n border-radius: 8px;\n padding: 6px 10px;\n font-size: 12px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-secondaryButton:hover {\n background: #e5e7eb;\n}\n.ri-materialBody {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n}\n.ri-previewFrame {\n position: relative;\n height: 112px;\n border-radius: 12px;\n overflow: hidden;\n border: 1px solid #e5e7eb;\n}\n.ri-previewImage {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n.ri-previewCaption {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n padding: 4px 8px;\n color: #ffffff;\n font-size: 10px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-emptyState {\n height: 112px;\n border-radius: 12px;\n border: 2px dashed #e5e7eb;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n color: #d1d5db;\n text-align: center;\n}\n.ri-uploadButton {\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #111827;\n color: #ffffff;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-uploadButton:hover {\n background: #374151;\n}\n.ri-removeButton {\n width: 100%;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n background: #ffffff;\n color: #6b7280;\n padding: 8px 12px;\n font-size: 12px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-removeButton:hover {\n background: #f9fafb;\n}\n.ri-formatHint {\n margin: 0;\n text-align: center;\n font-size: 10px;\n color: #d1d5db;\n}\n.ri-buttonContainer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n gap: 8px;\n position: absolute;\n bottom: 12px;\n left: 12px;\n right: 12px;\n z-index: 10;\n}\n.ri-tourControls {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-shrink: 0;\n}\n.ri-rightControls {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-shrink: 0;\n margin-left: auto;\n}\n.ri-rightControls:only-child {\n margin-left: auto;\n}\n.ri-navButtonSingle,\n.ri-tourButton,\n.ri-resetButton,\n.ri-downloadButton {\n height: 34px;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.75);\n border-radius: 8px;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n cursor: pointer;\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease,\n transform 0.15s ease;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n.ri-navButtonSingle:hover:not(:disabled),\n.ri-tourButton:hover:not(:disabled),\n.ri-resetButton:hover:not(:disabled) {\n background: rgba(40, 40, 40, 0.92);\n color: #fff;\n border-color: rgba(255, 255, 255, 0.25);\n}\n.ri-navButtonSingle:active:not(:disabled),\n.ri-tourButton:active:not(:disabled),\n.ri-resetButton:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-navButtonSingle:disabled,\n.ri-tourButton:disabled,\n.ri-resetButton:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ri-navButtonSingle {\n padding: 0 16px;\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n}\n.ri-tourButton {\n padding: 0 12px;\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n.ri-tourButton svg {\n width: 15px;\n height: 15px;\n flex-shrink: 0;\n}\n.ri-tourButton--stop {\n border-color: rgba(255, 68, 68, 0.4);\n color: #ff6b6b;\n}\n.ri-tourButton--stop:hover:not(:disabled) {\n background: rgba(255, 68, 68, 0.15);\n border-color: rgba(255, 68, 68, 0.6);\n color: #ff6b6b;\n}\n.ri-tourButton--stop:active:not(:disabled) {\n background: #ff4444;\n color: #fff;\n border-color: #ff4444;\n}\n.ri-tourButton--next {\n border-color: rgba(56, 219, 240, 0.3);\n color: #38dbf0;\n}\n.ri-tourButton--next:hover:not(:disabled) {\n background: rgba(56, 219, 240, 0.12);\n border-color: rgba(56, 219, 240, 0.5);\n color: #38dbf0;\n}\n.ri-tourButton--next:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-resetButton {\n width: 34px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.ri-resetButton svg {\n width: 15px;\n height: 15px;\n pointer-events: none;\n flex-shrink: 0;\n}\n.ri-resetButton:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.5);\n outline-offset: 2px;\n}\n.ri-downloadWrapper {\n position: relative;\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n}\n.ri-downloadButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 16px;\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n}\n.ri-downloadButton:hover:not(:disabled) {\n background: rgba(0, 0, 0, 0.72);\n border-color: rgba(255, 255, 255, 0.3);\n color: #fff;\n}\n.ri-downloadButton:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-downloadButton:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ri-downloadButton__spinner {\n display: inline-block;\n width: 13px;\n height: 13px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ri-spin 0.7s linear infinite;\n flex-shrink: 0;\n}\n.ri-downloadMenu {\n position: absolute;\n bottom: calc(100% + 6px);\n right: 0;\n min-width: 168px;\n background: rgba(20, 20, 20, 0.92);\n border: 1px solid rgba(255, 255, 255, 0.14);\n border-radius: 10px;\n overflow: hidden;\n z-index: 100;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n animation: ri-menuReveal 0.12s ease;\n}\n@keyframes ri-menuReveal {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ri-downloadMenuItem {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 400;\n color: #fff;\n background: transparent;\n border: none;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s ease;\n}\n.ri-downloadMenuItem:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n}\n.ri-downloadMenuItem:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.ri-downloadMenuDivider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 0 10px;\n}\n@keyframes ri-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ri-annotationMarker {\n position: relative;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(20, 20, 20, 0.82);\n border: 2px solid rgba(255, 255, 255, 0.9);\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n font-weight: 700;\n cursor: pointer;\n z-index: 20;\n user-select: none;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);\n pointer-events: auto;\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n.ri-annotationMarker:hover {\n transform: scale(1.08);\n box-shadow: 0 12px 28px rgba(15, 23, 42, 0.18);\n background: rgba(40, 40, 40, 0.92);\n}\n.ri-annotationPopup {\n position: absolute;\n width: min(270px, calc(100vw - 32px));\n background: rgba(20, 20, 20, 0.85);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 16px;\n padding: 16px;\n z-index: 30;\n display: flex;\n flex-direction: column;\n gap: 12px;\n box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n}\n.ri-annotationInput,\n.ri-annotationTextarea {\n width: 100%;\n border: 1px solid rgba(255, 255, 255, 0.12);\n background: rgba(255, 255, 255, 0.05);\n color: #e5e7eb;\n border-radius: 10px;\n padding: 10px 12px;\n outline: none;\n font-family: inherit;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n}\n.ri-annotationInput {\n font-size: 14px;\n font-weight: 500;\n}\n.ri-annotationTextarea {\n font-size: 13px;\n resize: vertical;\n min-height: 110px;\n}\n.ri-annotationInput:focus,\n.ri-annotationTextarea:focus {\n border-color: #38dbf0;\n box-shadow: 0 0 0 3px rgba(56, 219, 240, 0.12);\n}\n.ri-annotationActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.ri-annotationOkBtn {\n border: 0;\n border-radius: 8px;\n background: rgba(56, 219, 240, 0.8);\n color: #06343c;\n padding: 8px 18px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.2s ease, opacity 0.2s ease;\n}\n.ri-annotationOkBtn:hover:not(:disabled) {\n background: #38dbf0;\n}\n.ri-annotationOkBtn:disabled,\n.ri-annotationOkBtn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ri-annotationCancelBtn {\n border: 1px solid rgba(255, 255, 255, 0.12);\n background: transparent;\n color: #9ca3af;\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease;\n}\n.ri-annotationCancelBtn:hover {\n background: rgba(255, 255, 255, 0.05);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ri-annotationIcons {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 12px;\n color: #9ca3af;\n}\n.ri-annotationIcons svg {\n flex-shrink: 0;\n}\n.ri-viewAnnotationPopup {\n position: relative;\n background: rgba(20, 20, 20, 0.85);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n padding: 12px 16px;\n min-width: 200px;\n max-width: min(280px, calc(100vw - 48px));\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);\n pointer-events: auto;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n animation: ri-viewAnnotationFadeIn 0.15s ease-out;\n margin-left: 24px;\n margin-top: -20px;\n isolation: isolate;\n z-index: 1000;\n}\n.ri-viewAnnotationHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n.ri-viewAnnotationTitle {\n margin: 0;\n color: #e2e8f0;\n font-size: 14px;\n font-weight: 600;\n}\n.ri-viewAnnotationClose {\n background: transparent;\n border: none;\n color: #b7bdc6;\n cursor: pointer;\n font-size: 18px;\n padding: 0 4px;\n transition: color 0.2s;\n line-height: 1;\n}\n.ri-viewAnnotationClose:hover {\n color: #e2e8f0;\n}\n.ri-viewAnnotationDescription {\n margin: 0;\n color: #cbd5e1;\n font-size: 13px;\n line-height: 1.4;\n word-wrap: break-word;\n}\n@keyframes ri-viewAnnotationFadeIn {\n from {\n opacity: 0;\n transform: translateY(-6px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ri-annotationNavSingle {\n position: absolute;\n bottom: 120px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n pointer-events: none;\n}\n.ri-annotationNavSingle > * {\n pointer-events: auto;\n}\n.ri-navBadge {\n background: rgba(255, 255, 255, 0.1);\n padding: 2px 10px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 400;\n color: rgba(255, 255, 255, 0.7);\n}\n.ri-annotationTitleHint {\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n padding: 8px 20px;\n border-radius: 8px;\n font-size: 13px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n text-align: center;\n max-width: 350px;\n animation: slideUp 0.3s ease;\n}\n.ri-annotationHintTitle {\n font-weight: 600;\n color: #e5e7eb;\n}\n.ri-annotationHintDesc {\n font-size: 12px;\n opacity: 0.6;\n margin-top: 2px;\n color: #d1d5db;\n}\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@media (max-width: 768px) {\n .ri-xrTools {\n gap: 6px;\n }\n .ri-xrButton {\n height: 30px;\n gap: 6px;\n padding: 0 8px;\n font-size: 11px;\n }\n .ri-xrButton svg {\n width: 14px;\n height: 14px;\n }\n .ri-xrButtonPrefix {\n display: none;\n }\n .ri-annotationNavSingle {\n bottom: 100px;\n }\n .ri-navButtonSingle {\n padding: 8px 20px;\n font-size: 13px;\n min-width: 110px;\n }\n .ri-annotationTitleHint {\n padding: 6px 14px;\n font-size: 12px;\n max-width: 250px;\n }\n .ri-viewAnnotationPopup {\n min-width: 160px;\n max-width: 220px;\n padding: 10px 12px;\n }\n .ri-viewAnnotationTitle {\n font-size: 13px;\n }\n .ri-viewAnnotationDescription {\n font-size: 12px;\n }\n .ri-buttonContainer {\n flex-wrap: wrap;\n gap: 6px;\n }\n .ri-tourControls {\n flex-wrap: wrap;\n }\n .ri-rightControls {\n flex-wrap: wrap;\n }\n}\n@media (max-width: 480px) {\n .ri-xrTools {\n top: 12px;\n gap: 5px;\n }\n .ri-xrButton {\n height: 28px;\n gap: 5px;\n padding: 0 7px;\n font-size: 10px;\n }\n .ri-xrButton svg {\n width: 13px;\n height: 13px;\n }\n .ri-annotationNavSingle {\n bottom: 80px;\n }\n .ri-navButtonSingle {\n padding: 6px 16px;\n font-size: 12px;\n min-width: 90px;\n gap: 6px;\n }\n .ri-annotationTitleHint {\n padding: 4px 10px;\n font-size: 11px;\n max-width: 200px;\n }\n .ri-navBadge {\n font-size: 10px;\n padding: 1px 6px;\n }\n .ri-tourButton {\n padding: 0 8px;\n font-size: 12px;\n }\n .ri-tourButton span {\n display: none;\n }\n .ri-downloadButton {\n padding: 0 10px;\n font-size: 12px;\n }\n .ri-downloadButton span {\n display: none;\n }\n}\n.ri-canvasArea .bb-loadingOverlay {\n position: absolute;\n inset: 0;\n z-index: 12;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n padding: 24px;\n text-align: center;\n border-radius: 14px;\n background: rgba(15, 23, 42, 0.46);\n backdrop-filter: blur(1px);\n}\n.ri-canvasArea .bb-loadingSpinner {\n width: 40px;\n height: 40px;\n border-radius: 999px;\n border: 3px solid rgba(226, 232, 240, 0.24);\n border-top-color: #93c5fd;\n animation: bb-spin 0.8s linear infinite;\n}\n.ri-canvasArea .bb-loadingMessage {\n max-width: 320px;\n color: #f7f8f9;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.5;\n}\n@keyframes bb-spin {\n to {\n transform: rotate(360deg);\n }\n}\n');
|
|
45
|
+
styleInject('.ri-viewer--license-checking,\n.ri-viewer--license-invalid {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n background-color: #f9f9f9;\n}\n.ri-viewer {\n --ri-font-family:\n Inter,\n "Segoe UI",\n Helvetica,\n Arial,\n sans-serif;\n --ri-viewer-bg: #1c1c1d;\n --ri-viewer-text: #111827;\n --ri-panel-bg: #ffffff;\n --ri-panel-border: #e5e7eb;\n --ri-panel-title: #111827;\n --ri-panel-muted-text: #4b5563;\n --ri-panel-subtle-text: #9ca3af;\n --ri-panel-surface: #f9fafb;\n --ri-panel-surface-hover: #f3f4f6;\n --ri-panel-surface-border: #e5e7eb;\n --ri-panel-button-text: #1f2937;\n --ri-panel-accent: #2563eb;\n --ri-panel-accent-contrast: #ffffff;\n --ri-license-overlay-bg: rgba(0, 0, 0, 0.04);\n --ri-license-overlay-border: rgba(0, 0, 0, 0.08);\n --ri-license-overlay-text: #888;\n --ri-license-overlay-error-bg: rgba(192, 57, 43, 0.06);\n --ri-license-overlay-error-border: rgba(192, 57, 43, 0.2);\n --ri-license-overlay-error-text: #c0392b;\n --ri-sidepanel-font-family:\n Inter,\n "Segoe UI",\n Helvetica,\n Arial,\n sans-serif;\n --ri-sidepanel-bg: #141824;\n --ri-sidepanel-open-btn-bg: rgba(20, 20, 20, 0.82);\n --ri-sidepanel-open-btn-bg-hover: #27282b7e;\n --ri-sidepanel-border: rgba(255, 255, 255, 0.06);\n --ri-sidepanel-divider: rgba(255, 255, 255, 0.04);\n --ri-sidepanel-border-strong: rgba(255, 255, 255, 0.08);\n --ri-sidepanel-border-active: rgba(255, 255, 255, 0.18);\n --ri-sidepanel-shadow-left: 4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-sidepanel-shadow-right: -4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-sidepanel-text: #f1f5f9;\n --ri-sidepanel-text-emphasis: #ffffff;\n --ri-sidepanel-text-muted: #94a3b8;\n --ri-sidepanel-text-subtle: #64748b;\n --ri-sidepanel-placeholder: #475569;\n --ri-sidepanel-surface: rgba(255, 255, 255, 0.05);\n --ri-sidepanel-surface-hover: rgba(255, 255, 255, 0.1);\n --ri-sidepanel-accent: #3b82f6;\n --ri-sidepanel-accent-soft: rgba(59, 130, 246, 0.12);\n --ri-databinding-bg: #111318;\n --ri-databinding-border: rgba(255, 255, 255, 0.06);\n --ri-databinding-border-strong: rgba(255, 255, 255, 0.08);\n --ri-databinding-border-hover: rgba(255, 255, 255, 0.15);\n --ri-databinding-shadow: 4px 0 24px rgba(0, 0, 0, 0.35);\n --ri-databinding-font-family:\n "Inter",\n "Segoe UI",\n sans-serif;\n --ri-databinding-mono-font-family:\n "JetBrains Mono",\n "Fira Code",\n "Menlo",\n monospace;\n --ri-databinding-text: #f1f5f9;\n --ri-databinding-text-muted: #94a3b8;\n --ri-databinding-text-subtle: #64748b;\n --ri-databinding-text-faint: #475569;\n --ri-databinding-text-hover: #cbd5e1;\n --ri-databinding-surface: rgba(255, 255, 255, 0.03);\n --ri-databinding-surface-hover: rgba(255, 255, 255, 0.06);\n --ri-databinding-accent: #93c5fd;\n --ri-databinding-accent-glow: rgba(147, 197, 253, 0.8);\n --ri-databinding-accent-border: rgba(96, 165, 250, 0.55);\n --ri-databinding-accent-gradient:\n linear-gradient(\n \n 135deg,\n #1e3a8a 0%,\n #1d4ed8 60%,\n #2563eb 100% );\n --ri-databinding-accent-gradient-active:\n linear-gradient(\n \n 135deg,\n #1e3a8a 0%,\n #1e40af 100% );\n display: flex;\n flex-direction: row;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n background: var(--ri-viewer-bg);\n position: relative;\n color: var(--ri-viewer-text);\n font-family: var(--ri-font-family);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n font-synthesis: none;\n}\n.ri-viewer * {\n box-sizing: border-box;\n}\n.ri-viewerLeft {\n display: flex;\n flex: 1;\n min-height: 0;\n min-width: 0;\n position: relative;\n}\n.ri-viewerRight {\n display: flex;\n flex-shrink: 0;\n min-width: 0;\n}\n.ri-panel {\n width: 280px;\n min-height: 0;\n background: var(--ri-panel-bg);\n border-right: 1px solid var(--ri-panel-border);\n display: flex;\n flex-direction: column;\n padding: 20px;\n overflow-y: auto;\n flex-shrink: 0;\n transition: margin-left 0.3s ease, transform 0.3s ease;\n}\n.ri-panel--open {\n transform: translateX(0);\n margin-left: 0;\n}\n.ri-panel--closed {\n transform: translateX(-100%);\n margin-left: -280px;\n}\n.ri-panelHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n}\n.ri-panelTitle {\n margin: 0;\n font-size: 15px;\n font-weight: 700;\n color: var(--ri-panel-title);\n line-height: 1.4;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ri-closeButton {\n border: 0;\n background: transparent;\n color: var(--ri-panel-subtle-text);\n font-size: 22px;\n line-height: 1;\n padding: 0;\n cursor: pointer;\n flex-shrink: 0;\n transition: color 0.2s ease;\n}\n.ri-closeButton:hover {\n color: var(--ri-panel-muted-text);\n}\n.ri-json {\n margin: 0 0 16px;\n padding: 12px;\n background: var(--ri-panel-surface);\n border: 1px solid var(--ri-panel-surface-border);\n border-radius: 12px;\n font-size: 12px;\n line-height: 1.55;\n color: var(--ri-panel-button-text);\n overflow-x: auto;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.ri-divider {\n border-top: 1px solid var(--ri-panel-border);\n margin-bottom: 12px;\n}\n.ri-sectionLabel {\n margin-bottom: 8px;\n font-size: 11px;\n font-weight: 700;\n color: var(--ri-panel-subtle-text);\n text-transform: uppercase;\n letter-spacing: 0.16em;\n}\n.ri-actionList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.ri-actionButton {\n width: 100%;\n border-radius: 8px;\n border: 1px solid var(--ri-panel-surface-border);\n background: var(--ri-panel-surface);\n color: var(--ri-panel-button-text);\n padding: 10px 12px;\n text-align: left;\n font-size: 14px;\n line-height: 1.4;\n cursor: pointer;\n transition:\n background-color 0.2s ease,\n border-color 0.2s ease,\n color 0.2s ease;\n}\n.ri-actionButton:hover {\n background: var(--ri-panel-surface-hover);\n border-color: var(--ri-panel-border);\n}\n.ri-actionButton--active {\n background: var(--ri-panel-accent);\n border-color: var(--ri-panel-accent);\n color: var(--ri-panel-accent-contrast);\n}\n.ri-actionButton--active:hover {\n background: var(--ri-panel-accent);\n border-color: var(--ri-panel-accent);\n}\n.ri-canvasArea {\n flex: 1 1 auto;\n position: relative;\n min-width: 0;\n}\n.ri-canvasArea--measuring {\n cursor: crosshair;\n}\n.ri-canvasArea canvas {\n opacity: 1;\n transition: opacity 0.18s ease;\n}\n.ri-canvasArea--positioning canvas {\n opacity: 0;\n transition: none;\n}\n.ri-bindingsMismatchBanner {\n position: absolute;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 20;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 12px 7px 10px;\n border-radius: 8px;\n background: rgba(30, 20, 0, 0.88);\n border: 1px solid rgba(251, 191, 36, 0.35);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n color: rgb(251, 191, 36);\n font-size: 12px;\n font-weight: 500;\n line-height: 1.4;\n white-space: nowrap;\n pointer-events: auto;\n max-width: calc(100% - 32px);\n white-space: normal;\n text-align: center;\n}\n.ri-bindingsMismatchBanner__icon {\n flex-shrink: 0;\n}\n.ri-bindingsMismatchBanner__dismiss {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-left: 4px;\n padding: 2px;\n background: none;\n border: none;\n border-radius: 4px;\n color: rgba(251, 191, 36, 0.7);\n cursor: pointer;\n transition: color 0.15s ease, background 0.15s ease;\n}\n.ri-bindingsMismatchBanner__dismiss:hover {\n color: rgb(251, 191, 36);\n background: rgba(251, 191, 36, 0.12);\n}\n.ri-measureTools {\n position: absolute;\n top: 16px;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-measureButton {\n width: 34px;\n height: 34px;\n padding: 0;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.75);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: manipulation;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease;\n}\n.ri-measureButton:hover {\n background: rgba(40, 40, 40, 0.92);\n color: #fff;\n border-color: rgba(255, 255, 255, 0.25);\n}\n.ri-measureButton:active {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-measureButton--active {\n background: #22d3ee;\n border-color: #22d3ee;\n color: #06343c;\n}\n.ri-measureButton--active:hover {\n background: #38dbf0;\n color: #06343c;\n}\n.ri-measureHint {\n padding: 6px 10px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 1;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n white-space: nowrap;\n}\n.ri-explodeTools {\n position: absolute;\n top: 16px;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-explodeSlider {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 12px;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n}\n.ri-explodeSlider input[type=range] {\n width: 120px;\n accent-color: #22d3ee;\n cursor: pointer;\n}\n.ri-cinematicTools {\n position: absolute;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-measureDot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n background: #22d3ee;\n border: 2px solid #fff;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);\n pointer-events: none;\n}\n.ri-measureLabel {\n padding: 3px 7px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n white-space: nowrap;\n color: #06343c;\n background: #22d3ee;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n pointer-events: none;\n user-select: none;\n}\n.ri-xrTools {\n position: absolute;\n left: 16px;\n z-index: 10;\n display: flex;\n gap: 8px;\n align-items: center;\n}\n.ri-xrButton {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 34px;\n padding: 0 10px;\n font-size: 13px;\n font-weight: 500;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.16);\n border-radius: 8px;\n cursor: pointer;\n touch-action: manipulation;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.ri-xrButton:hover {\n background: rgba(40, 40, 40, 0.92);\n border-color: rgba(255, 255, 255, 0.3);\n}\n.ri-arHintOverlay {\n position: absolute;\n top: 18px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n width: min(calc(100% - 32px), 360px);\n pointer-events: none;\n}\n.ri-arHint {\n margin: 0 auto;\n width: fit-content;\n max-width: 100%;\n padding: 6px 12px;\n font-size: 11px;\n font-weight: 500;\n line-height: 1.2;\n text-align: center;\n color: rgba(255, 255, 255, 0.92);\n background: rgba(20, 20, 20, 0.58);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 999px;\n user-select: none;\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n.ri-arOverlay {\n position: absolute;\n bottom: 24px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n width: min(calc(100% - 32px), 420px);\n pointer-events: none;\n}\n.ri-arControls {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n}\n.ri-arStatus,\n.ri-arActionButton {\n max-width: 100%;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.3;\n text-align: center;\n white-space: nowrap;\n color: #fff;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.16);\n border-radius: 19px;\n user-select: none;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n}\n.ri-arStatus {\n pointer-events: none;\n}\n.ri-arActionButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n cursor: pointer;\n pointer-events: auto;\n touch-action: manipulation;\n -webkit-tap-highlight-color: transparent;\n transition:\n background 0.15s ease,\n border-color 0.15s ease,\n color 0.15s ease,\n transform 0.15s ease;\n}\n.ri-arActionButton svg {\n flex-shrink: 0;\n}\n.ri-arActionButton:hover {\n background: rgba(40, 40, 40, 0.92);\n border-color: rgba(255, 255, 255, 0.3);\n}\n.ri-arActionButton:active {\n transform: scale(0.98);\n}\n.ri-arActionButton--primary {\n color: #06343c;\n background: #22d3ee;\n border-color: transparent;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n}\n.ri-arActionButton--primary:hover {\n background: #67e8f9;\n border-color: transparent;\n}\n.ri-arActionButton.ri-arActionButton--active,\n.ri-arActionButton[aria-pressed=true],\n.ri-arActionButton.ri-arActionButton--active:hover,\n.ri-arActionButton[aria-pressed=true]:hover,\n.ri-arActionButton.ri-arActionButton--active:active,\n.ri-arActionButton[aria-pressed=true]:active {\n color: #06343c;\n background: #22d3ee;\n border-color: transparent;\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);\n}\n.ri-hiddenInput {\n display: none;\n}\n.ri-popover {\n position: absolute;\n z-index: 50;\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 16px;\n box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);\n color: #111827;\n}\n.ri-popover--inline {\n position: static;\n z-index: auto;\n width: 100%;\n border-radius: 10px;\n box-shadow: none;\n}\n.ri-popover--inline .react-colorful {\n width: 100%;\n}\n.ri-popover--inline {\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n color: var(--ri-databinding-text, #f1f5f9);\n}\n.ri-popover--inline .ri-popoverHeader {\n border-bottom-color: var( --ri-databinding-border-strong, rgba(255, 255, 255, 0.08) );\n}\n.ri-popover--inline .ri-popoverLabel {\n color: var(--ri-databinding-text-muted, #94a3b8);\n}\n.ri-popover--inline .ri-colorCode {\n color: var(--ri-databinding-text-muted, #94a3b8);\n}\n.ri-popover--inline .ri-secondaryButton {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n color: var(--ri-databinding-text, #f1f5f9);\n}\n.ri-popover--inline .ri-secondaryButton:hover {\n background: rgba(255, 255, 255, 0.12);\n}\n.ri-popover--inline .ri-previewFrame {\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.ri-popover--inline .ri-emptyState {\n border-color: var(--ri-databinding-border-hover, rgba(255, 255, 255, 0.15));\n color: var(--ri-databinding-text-subtle, #64748b);\n}\n.ri-popover--inline .ri-uploadButton {\n background: var(--ri-databinding-accent-gradient, #2563eb);\n color: #ffffff;\n}\n.ri-popover--inline .ri-uploadButton:hover {\n background: var(--ri-databinding-accent-gradient-active, #1d4ed8);\n}\n.ri-popover--inline .ri-removeButton {\n background: transparent;\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n color: var(--ri-databinding-text-muted, #94a3b8);\n}\n.ri-popover--inline .ri-removeButton:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n}\n.ri-popover--inline .ri-formatHint {\n color: var(--ri-databinding-text-subtle, #64748b);\n}\n.ri-popoverHeader {\n padding: 12px 16px;\n}\n.ri-popoverLabel {\n margin: 0 0 8px;\n font-size: 11px;\n font-weight: 700;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.16em;\n}\n.ri-inlineRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-top: 8px;\n}\n.ri-colorCode {\n font-size: 12px;\n color: #9ca3af;\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n monospace;\n text-transform: uppercase;\n}\n.ri-secondaryButton {\n border: 1px solid #e5e7eb;\n background: #f3f4f6;\n color: #374151;\n border-radius: 8px;\n padding: 6px 10px;\n font-size: 12px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-secondaryButton:hover {\n background: #e5e7eb;\n}\n.ri-materialBody {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-left: 12px;\n padding-right: 12px;\n padding-bottom: 12px;\n}\n.ri-previewFrame {\n position: relative;\n height: 112px;\n border-radius: 12px;\n overflow: hidden;\n border: 1px solid #e5e7eb;\n}\n.ri-previewImage {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n.ri-previewCaption {\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n padding: 4px 8px;\n color: #ffffff;\n font-size: 10px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-emptyState {\n height: 112px;\n border-radius: 12px;\n border: 2px dashed #e5e7eb;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 4px;\n color: #d1d5db;\n text-align: center;\n}\n.ri-uploadButton {\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #111827;\n color: #ffffff;\n padding: 10px 12px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-uploadButton:hover {\n background: #374151;\n}\n.ri-removeButton {\n width: 100%;\n border-radius: 10px;\n border: 1px solid #e5e7eb;\n background: #ffffff;\n color: #6b7280;\n padding: 8px 12px;\n font-size: 12px;\n cursor: pointer;\n transition: background-color 0.2s ease;\n}\n.ri-removeButton:hover {\n background: #f9fafb;\n}\n.ri-formatHint {\n margin: 0;\n text-align: center;\n font-size: 10px;\n color: #d1d5db;\n}\n.ri-buttonContainer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 12px;\n gap: 8px;\n position: absolute;\n bottom: 12px;\n left: 12px;\n right: 12px;\n z-index: 10;\n}\n.ri-tourControls {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-shrink: 0;\n}\n.ri-rightControls {\n display: flex;\n gap: 6px;\n align-items: center;\n flex-shrink: 0;\n margin-left: auto;\n}\n.ri-rightControls:only-child {\n margin-left: auto;\n}\n.ri-navButtonSingle,\n.ri-tourButton,\n.ri-resetButton,\n.ri-downloadButton {\n height: 34px;\n background: rgba(20, 20, 20, 0.82);\n border: 1px solid rgba(255, 255, 255, 0.12);\n color: rgba(255, 255, 255, 0.75);\n border-radius: 8px;\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n cursor: pointer;\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease,\n transform 0.15s ease;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n.ri-navButtonSingle:hover:not(:disabled),\n.ri-tourButton:hover:not(:disabled),\n.ri-resetButton:hover:not(:disabled) {\n background: rgba(40, 40, 40, 0.92);\n color: #fff;\n border-color: rgba(255, 255, 255, 0.25);\n}\n.ri-navButtonSingle:active:not(:disabled),\n.ri-tourButton:active:not(:disabled),\n.ri-resetButton:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-navButtonSingle:disabled,\n.ri-tourButton:disabled,\n.ri-resetButton:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ri-navButtonSingle {\n padding: 0 16px;\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 8px;\n white-space: nowrap;\n}\n.ri-tourButton {\n padding: 0 12px;\n font-size: 13px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 4px;\n white-space: nowrap;\n}\n.ri-tourButton svg {\n width: 15px;\n height: 15px;\n flex-shrink: 0;\n}\n.ri-tourButton--stop {\n border-color: rgba(255, 68, 68, 0.4);\n color: #ff6b6b;\n}\n.ri-tourButton--stop:hover:not(:disabled) {\n background: rgba(255, 68, 68, 0.15);\n border-color: rgba(255, 68, 68, 0.6);\n color: #ff6b6b;\n}\n.ri-tourButton--stop:active:not(:disabled) {\n background: #ff4444;\n color: #fff;\n border-color: #ff4444;\n}\n.ri-tourButton--next {\n border-color: rgba(56, 219, 240, 0.3);\n color: #38dbf0;\n}\n.ri-tourButton--next:hover:not(:disabled) {\n background: rgba(56, 219, 240, 0.12);\n border-color: rgba(56, 219, 240, 0.5);\n color: #38dbf0;\n}\n.ri-tourButton--next:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-resetButton {\n width: 34px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.ri-resetButton svg {\n width: 15px;\n height: 15px;\n pointer-events: none;\n flex-shrink: 0;\n}\n.ri-resetButton:focus-visible {\n outline: 2px solid rgba(255, 255, 255, 0.5);\n outline-offset: 2px;\n}\n.ri-downloadWrapper {\n position: relative;\n display: inline-flex;\n flex-direction: column;\n align-items: stretch;\n}\n.ri-downloadButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 16px;\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n}\n.ri-downloadButton:hover:not(:disabled) {\n background: rgba(0, 0, 0, 0.72);\n border-color: rgba(255, 255, 255, 0.3);\n color: #fff;\n}\n.ri-downloadButton:active:not(:disabled) {\n background: #38dbf0;\n color: #06343c;\n border-color: #38dbf0;\n}\n.ri-downloadButton:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n}\n.ri-downloadButton__spinner {\n display: inline-block;\n width: 13px;\n height: 13px;\n border: 2px solid rgba(255, 255, 255, 0.3);\n border-top-color: #fff;\n border-radius: 50%;\n animation: ri-spin 0.7s linear infinite;\n flex-shrink: 0;\n}\n.ri-downloadMenu {\n position: absolute;\n bottom: calc(100% + 6px);\n right: 0;\n min-width: 168px;\n background: rgba(20, 20, 20, 0.92);\n border: 1px solid rgba(255, 255, 255, 0.14);\n border-radius: 10px;\n overflow: hidden;\n z-index: 100;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n animation: ri-menuReveal 0.12s ease;\n}\n@keyframes ri-menuReveal {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ri-downloadMenuItem {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n padding: 10px 14px;\n font-size: 13px;\n font-weight: 400;\n color: #fff;\n background: transparent;\n border: none;\n cursor: pointer;\n text-align: left;\n transition: background 0.1s ease;\n}\n.ri-downloadMenuItem:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n}\n.ri-downloadMenuItem:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.ri-downloadMenuDivider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 0 10px;\n}\n@keyframes ri-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.ri-annotationMarker {\n position: relative;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: rgba(20, 20, 20, 0.82);\n border: 2px solid rgba(255, 255, 255, 0.9);\n color: #fff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n font-weight: 700;\n cursor: pointer;\n z-index: 20;\n user-select: none;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);\n pointer-events: auto;\n transition: opacity 0.3s ease, transform 0.3s ease;\n}\n.ri-annotationMarker:hover {\n transform: scale(1.08);\n box-shadow: 0 12px 28px rgba(15, 23, 42, 0.18);\n background: rgba(40, 40, 40, 0.92);\n}\n.ri-annotationPopup {\n position: absolute;\n width: min(270px, calc(100vw - 32px));\n background: rgba(20, 20, 20, 0.85);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 16px;\n padding: 16px;\n z-index: 30;\n display: flex;\n flex-direction: column;\n gap: 12px;\n box-shadow: 0 24px 48px rgba(15, 23, 42, 0.18);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n}\n.ri-annotationInput,\n.ri-annotationTextarea {\n width: 100%;\n border: 1px solid rgba(255, 255, 255, 0.12);\n background: rgba(255, 255, 255, 0.05);\n color: #e5e7eb;\n border-radius: 10px;\n padding: 10px 12px;\n outline: none;\n font-family: inherit;\n transition: border-color 0.2s ease, box-shadow 0.2s ease;\n}\n.ri-annotationInput {\n font-size: 14px;\n font-weight: 500;\n}\n.ri-annotationTextarea {\n font-size: 13px;\n resize: vertical;\n min-height: 110px;\n}\n.ri-annotationInput:focus,\n.ri-annotationTextarea:focus {\n border-color: #38dbf0;\n box-shadow: 0 0 0 3px rgba(56, 219, 240, 0.12);\n}\n.ri-annotationActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.ri-annotationOkBtn {\n border: 0;\n border-radius: 8px;\n background: rgba(56, 219, 240, 0.8);\n color: #06343c;\n padding: 8px 18px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.2s ease, opacity 0.2s ease;\n}\n.ri-annotationOkBtn:hover:not(:disabled) {\n background: #38dbf0;\n}\n.ri-annotationOkBtn:disabled,\n.ri-annotationOkBtn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.ri-annotationCancelBtn {\n border: 1px solid rgba(255, 255, 255, 0.12);\n background: transparent;\n color: #9ca3af;\n border-radius: 8px;\n padding: 8px 12px;\n font-size: 13px;\n cursor: pointer;\n transition: background-color 0.2s ease, border-color 0.2s ease;\n}\n.ri-annotationCancelBtn:hover {\n background: rgba(255, 255, 255, 0.05);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ri-annotationIcons {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 12px;\n color: #9ca3af;\n}\n.ri-annotationIcons svg {\n flex-shrink: 0;\n}\n.ri-viewAnnotationPopup {\n position: relative;\n background: rgba(20, 20, 20, 0.85);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 8px;\n padding: 12px 16px;\n min-width: 200px;\n max-width: min(280px, calc(100vw - 48px));\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);\n pointer-events: auto;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n animation: ri-viewAnnotationFadeIn 0.15s ease-out;\n margin-left: 24px;\n margin-top: -20px;\n isolation: isolate;\n z-index: 1000;\n}\n.ri-viewAnnotationHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n.ri-viewAnnotationTitle {\n margin: 0;\n color: #e2e8f0;\n font-size: 14px;\n font-weight: 600;\n}\n.ri-viewAnnotationClose {\n background: transparent;\n border: none;\n color: #b7bdc6;\n cursor: pointer;\n font-size: 18px;\n padding: 0 4px;\n transition: color 0.2s;\n line-height: 1;\n}\n.ri-viewAnnotationClose:hover {\n color: #e2e8f0;\n}\n.ri-viewAnnotationDescription {\n margin: 0;\n color: #cbd5e1;\n font-size: 13px;\n line-height: 1.4;\n word-wrap: break-word;\n}\n@keyframes ri-viewAnnotationFadeIn {\n from {\n opacity: 0;\n transform: translateY(-6px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n.ri-annotationNavSingle {\n position: absolute;\n bottom: 120px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n pointer-events: none;\n}\n.ri-annotationNavSingle > * {\n pointer-events: auto;\n}\n.ri-navBadge {\n background: rgba(255, 255, 255, 0.1);\n padding: 2px 10px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: 400;\n color: rgba(255, 255, 255, 0.7);\n}\n.ri-annotationTitleHint {\n background: rgba(0, 0, 0, 0.7);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n padding: 8px 20px;\n border-radius: 8px;\n font-size: 13px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n text-align: center;\n max-width: 350px;\n animation: slideUp 0.3s ease;\n}\n.ri-annotationHintTitle {\n font-weight: 600;\n color: #e5e7eb;\n}\n.ri-annotationHintDesc {\n font-size: 12px;\n opacity: 0.6;\n margin-top: 2px;\n color: #d1d5db;\n}\n@keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@media (max-width: 768px) {\n .ri-xrTools {\n gap: 6px;\n }\n .ri-xrButton {\n height: 34px;\n gap: 6px;\n padding: 0 8px;\n font-size: 11px;\n }\n .ri-xrButton svg {\n width: 14px;\n height: 14px;\n }\n .ri-xrButtonPrefix {\n display: none;\n }\n .ri-annotationNavSingle {\n bottom: 100px;\n }\n .ri-navButtonSingle {\n padding: 8px 20px;\n font-size: 13px;\n min-width: 110px;\n }\n .ri-annotationTitleHint {\n padding: 6px 14px;\n font-size: 12px;\n max-width: 250px;\n }\n .ri-viewAnnotationPopup {\n min-width: 160px;\n max-width: 220px;\n padding: 10px 12px;\n }\n .ri-viewAnnotationTitle {\n font-size: 13px;\n }\n .ri-viewAnnotationDescription {\n font-size: 12px;\n }\n .ri-buttonContainer {\n flex-wrap: wrap;\n gap: 6px;\n }\n .ri-tourControls {\n flex-wrap: wrap;\n }\n .ri-rightControls {\n flex-wrap: wrap;\n }\n}\n@media (max-width: 480px) {\n .ri-xrTools {\n gap: 5px;\n }\n .ri-xrButton {\n height: 34px;\n gap: 5px;\n font-size: 10px;\n }\n .ri-xrButton svg {\n width: 13px;\n height: 13px;\n }\n .ri-annotationNavSingle {\n bottom: 80px;\n }\n .ri-navButtonSingle {\n padding: 6px 16px;\n font-size: 12px;\n min-width: 90px;\n gap: 6px;\n }\n .ri-annotationTitleHint {\n padding: 4px 10px;\n font-size: 11px;\n max-width: 200px;\n }\n .ri-navBadge {\n font-size: 10px;\n padding: 1px 6px;\n }\n .ri-tourButton {\n padding: 0 8px;\n font-size: 12px;\n }\n .ri-tourButton span {\n display: none;\n }\n .ri-downloadButton {\n padding: 0 10px;\n font-size: 12px;\n }\n .ri-downloadButton span {\n display: none;\n }\n}\n.ri-canvasArea .bb-loadingOverlay {\n position: absolute;\n inset: 0;\n z-index: 12;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n padding: 24px;\n text-align: center;\n border-radius: 14px;\n background: rgba(15, 23, 42, 0.46);\n backdrop-filter: blur(1px);\n}\n.ri-canvasArea .bb-loadingSpinner {\n width: 40px;\n height: 40px;\n border-radius: 999px;\n border: 3px solid rgba(226, 232, 240, 0.24);\n border-top-color: #93c5fd;\n animation: bb-spin 0.8s linear infinite;\n}\n.ri-canvasArea .bb-loadingMessage {\n max-width: 320px;\n color: #f7f8f9;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.5;\n}\n@keyframes bb-spin {\n to {\n transform: rotate(360deg);\n }\n}\n');
|
|
46
46
|
|
|
47
47
|
// src/components/LicenseOverlay.tsx
|
|
48
48
|
import { AlertTriangle } from "lucide-react";
|
|
@@ -4584,13 +4584,14 @@ var ColorPicker = ({
|
|
|
4584
4584
|
colorPicker,
|
|
4585
4585
|
onClose,
|
|
4586
4586
|
itemMaterials,
|
|
4587
|
-
setItemMaterials
|
|
4587
|
+
setItemMaterials,
|
|
4588
|
+
inline = false
|
|
4588
4589
|
}) => {
|
|
4589
4590
|
return /* @__PURE__ */ jsxs9(
|
|
4590
4591
|
"div",
|
|
4591
4592
|
{
|
|
4592
|
-
className: "ri-popover"
|
|
4593
|
-
style: {
|
|
4593
|
+
className: `ri-popover${inline ? " ri-popover--inline" : ""}`,
|
|
4594
|
+
style: inline ? { padding: 12 } : {
|
|
4594
4595
|
left: colorPicker.x,
|
|
4595
4596
|
top: colorPicker.y,
|
|
4596
4597
|
width: "min(225px, calc(100vw - 24px))",
|
|
@@ -4627,13 +4628,14 @@ var MaterialPicker = ({
|
|
|
4627
4628
|
materialPopup,
|
|
4628
4629
|
textureUrl,
|
|
4629
4630
|
triggerFileUpload,
|
|
4630
|
-
clearTexture
|
|
4631
|
+
clearTexture,
|
|
4632
|
+
inline = false
|
|
4631
4633
|
}) => {
|
|
4632
4634
|
return /* @__PURE__ */ jsxs10(
|
|
4633
4635
|
"div",
|
|
4634
4636
|
{
|
|
4635
|
-
className: "ri-popover"
|
|
4636
|
-
style: {
|
|
4637
|
+
className: `ri-popover${inline ? " ri-popover--inline" : ""}`,
|
|
4638
|
+
style: inline ? { overflow: "hidden" } : {
|
|
4637
4639
|
left: materialPopup.x,
|
|
4638
4640
|
top: materialPopup.y,
|
|
4639
4641
|
width: "min(300px, calc(100vw - 24px))",
|
|
@@ -4696,19 +4698,74 @@ var MaterialPicker = ({
|
|
|
4696
4698
|
};
|
|
4697
4699
|
|
|
4698
4700
|
// src/components/ModelViewer/ObjectBindingDataPanel.tsx
|
|
4699
|
-
import { useEffect as useEffect13, useState as useState7 } from "react";
|
|
4701
|
+
import { Fragment as Fragment5, useEffect as useEffect13, useRef as useRef10, useState as useState7 } from "react";
|
|
4700
4702
|
|
|
4701
4703
|
// src/styles/ObjectBindingDataPanel.css
|
|
4702
|
-
styleInject('.left-panel {\n width: 280px;\n min-height: 0;\n background: var(--ri-databinding-bg, #111318);\n border-right: 1px solid var(--ri-databinding-border, rgba(255, 255, 255, 0.06));\n display: flex;\n flex-direction: column;\n padding: 24px 18px;\n overflow-y: auto;\n font-family: var( --ri-databinding-font-family, "Inter", "Segoe UI", sans-serif );\n flex-shrink: 0;\n transition: margin-left 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: var(--ri-databinding-shadow, 4px 0 24px rgba(0, 0, 0, 0.35));\n}\n.left-panel--open {\n margin-left: 0;\n}\n.left-panel--closed {\n margin-left: -280px;\n}\n.left-panel::-webkit-scrollbar {\n width: 4px;\n}\n.left-panel::-webkit-scrollbar-track {\n background: transparent;\n}\n.left-panel::-webkit-scrollbar-thumb {\n background: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 4px;\n}\n.left-panel__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__title {\n font-size: 14px;\n font-weight: 600;\n color: var(--ri-databinding-text, #f1f5f9);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-right: 8px;\n margin: 0;\n letter-spacing: 0.02em;\n}\n.left-panel__close-btn {\n width: 26px;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 6px;\n color: var(--ri-databinding-text-subtle, #64748b);\n font-size: 13px;\n flex-shrink: 0;\n cursor: pointer;\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease;\n}\n.left-panel__close-btn:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n color: var(--ri-databinding-text-hover, #cbd5e1);\n border-color: var(--ri-databinding-border-hover, rgba(255, 255, 255, 0.15));\n}\n.left-panel__data {\n padding: 12px 6px;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 10px;\n font-size: 11px;\n font-family: var( --ri-databinding-mono-font-family, "JetBrains Mono", "Fira Code", "Menlo", monospace );\n color: var(--ri-databinding-text-muted, #94a3b8);\n line-height: 1.7;\n overflow-x: auto;\n margin-bottom: 18px;\n}\n.left-panel__divider {\n border: none;\n border-top: 1px solid var(--ri-databinding-border, rgba(255, 255, 255, 0.06));\n margin-bottom: 16px;\n}\n.left-panel__actions-label {\n font-size: 10px;\n font-weight: 600;\n color: var(--ri-databinding-text-faint, #475569);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n margin-bottom: 10px;\n}\n.left-panel__actions-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.left-panel__action-btn {\n position: relative;\n padding: 9px 14px;\n border-radius: 8px;\n text-align: left;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n overflow: hidden;\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n color: var(--ri-databinding-text-muted, #94a3b8);\n letter-spacing: 0.01em;\n}\n.left-panel__action-btn:active {\n transform: scale(0.97);\n}\n.left-panel__action-btn--active::before {\n content: "";\n position: absolute;\n left: 0;\n top: 20%;\n bottom: 20%;\n width: 3px;\n background: var(--ri-databinding-accent, #93c5fd);\n border-radius: 0 3px 3px 0;\n box-shadow: 0 0 8px var(--ri-databinding-accent-glow, rgba(147, 197, 253, 0.8));\n}\n.left-panel__action-btn--active:hover {\n background: var( --ri-databinding-accent-gradient, linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 60%, #2563eb 100%) );\n border-color: var(--ri-databinding-accent-border, rgba(96, 165, 250, 0.55));\n}\n.left-panel__action-btn--active:active {\n transform: scale(0.97);\n background: var( --ri-databinding-accent-gradient-active, linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%) );\n}\n.left-panel__data {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-bottom: 18px;\n}\n.left-panel__data-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 10px;\n padding: 7px 10px;\n border-radius: 7px;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid transparent;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.left-panel__data-row:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__data-key {\n font-size: 11px;\n font-weight: 600;\n color: var(--ri-databinding-text-faint, #475569);\n text-transform: uppercase;\n letter-spacing: 0.07em;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.left-panel__data-value {\n font-size: 12px;\n font-family: var( --ri-databinding-mono-font-family, "JetBrains Mono", "Fira Code", "Menlo", monospace );\n text-align: right;\n word-break: break-
|
|
4704
|
+
styleInject('.left-panel {\n width: 280px;\n min-height: 0;\n background: var(--ri-databinding-bg, #111318);\n border-right: 1px solid var(--ri-databinding-border, rgba(255, 255, 255, 0.06));\n display: flex;\n flex-direction: column;\n padding: 24px 18px;\n overflow-y: auto;\n font-family: var( --ri-databinding-font-family, "Inter", "Segoe UI", sans-serif );\n flex-shrink: 0;\n transition: margin-left 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: var(--ri-databinding-shadow, 4px 0 24px rgba(0, 0, 0, 0.35));\n}\n.left-panel--open {\n margin-left: 0;\n}\n.left-panel--closed {\n margin-left: -280px;\n}\n.left-panel::-webkit-scrollbar {\n width: 4px;\n}\n.left-panel::-webkit-scrollbar-track {\n background: transparent;\n}\n.left-panel::-webkit-scrollbar-thumb {\n background: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 4px;\n}\n.left-panel__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__title {\n font-size: 14px;\n font-weight: 600;\n color: var(--ri-databinding-text, #f1f5f9);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n padding-right: 8px;\n margin: 0;\n letter-spacing: 0.02em;\n}\n.left-panel__close-btn {\n width: 26px;\n height: 26px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 6px;\n color: var(--ri-databinding-text-subtle, #64748b);\n font-size: 13px;\n flex-shrink: 0;\n cursor: pointer;\n transition:\n background 0.15s ease,\n color 0.15s ease,\n border-color 0.15s ease;\n}\n.left-panel__close-btn:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n color: var(--ri-databinding-text-hover, #cbd5e1);\n border-color: var(--ri-databinding-border-hover, rgba(255, 255, 255, 0.15));\n}\n.left-panel__data {\n padding: 12px 6px;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n border-radius: 10px;\n font-size: 11px;\n font-family: var( --ri-databinding-mono-font-family, "JetBrains Mono", "Fira Code", "Menlo", monospace );\n color: var(--ri-databinding-text-muted, #94a3b8);\n line-height: 1.7;\n overflow-x: auto;\n margin-bottom: 18px;\n}\n.left-panel__divider {\n border: none;\n border-top: 1px solid var(--ri-databinding-border, rgba(255, 255, 255, 0.06));\n margin-bottom: 16px;\n}\n.left-panel__actions-label {\n font-size: 10px;\n font-weight: 600;\n color: var(--ri-databinding-text-faint, #475569);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n margin-bottom: 10px;\n}\n.left-panel__actions-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.left-panel__action-extra {\n display: grid;\n grid-template-rows: 0fr;\n opacity: 0;\n margin-top: 0;\n transition:\n grid-template-rows 0.28s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s ease,\n margin-top 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.left-panel__action-extra--open {\n grid-template-rows: 1fr;\n opacity: 1;\n margin-top: 4px;\n}\n.left-panel__action-extra-inner {\n overflow: hidden;\n min-height: 0;\n}\n.left-panel__action-btn {\n position: relative;\n padding: 9px 14px;\n border-radius: 8px;\n text-align: left;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n overflow: hidden;\n border: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n color: var(--ri-databinding-text-muted, #94a3b8);\n letter-spacing: 0.01em;\n}\n.left-panel__action-btn:active {\n transform: scale(0.97);\n}\n.left-panel__action-btn--active::before {\n content: "";\n position: absolute;\n left: 0;\n top: 20%;\n bottom: 20%;\n width: 3px;\n background: var(--ri-databinding-accent, #93c5fd);\n border-radius: 0 3px 3px 0;\n box-shadow: 0 0 8px var(--ri-databinding-accent-glow, rgba(147, 197, 253, 0.8));\n}\n.left-panel__action-btn--active:hover {\n background: var( --ri-databinding-accent-gradient, linear-gradient(135deg, #1e3a8a 0%, #1d4ed8 60%, #2563eb 100%) );\n border-color: var(--ri-databinding-accent-border, rgba(96, 165, 250, 0.55));\n}\n.left-panel__action-btn--active:active {\n transform: scale(0.97);\n background: var( --ri-databinding-accent-gradient-active, linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%) );\n}\n.left-panel__data {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-bottom: 18px;\n}\n.left-panel__data-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 10px;\n padding: 7px 10px;\n border-radius: 7px;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid transparent;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.left-panel__data-row:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__data-key {\n font-size: 11px;\n font-weight: 600;\n color: var(--ri-databinding-text-faint, #475569);\n text-transform: uppercase;\n letter-spacing: 0.07em;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.left-panel__data-value {\n font-size: 12px;\n font-family: var( --ri-databinding-mono-font-family, "JetBrains Mono", "Fira Code", "Menlo", monospace );\n text-align: right;\n overflow-wrap: anywhere;\n word-break: break-word;\n min-width: 0;\n}\n.left-panel__data-group {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 7px 10px;\n border-radius: 7px;\n background: var(--ri-databinding-surface, rgba(255, 255, 255, 0.03));\n border: 1px solid transparent;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n.left-panel__data-group:hover {\n background: var(--ri-databinding-surface-hover, rgba(255, 255, 255, 0.06));\n border-color: var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__data-children {\n display: flex;\n flex-direction: column;\n gap: 2px;\n margin-top: 4px;\n padding-left: 10px;\n border-left: 1px solid var(--ri-databinding-border-strong, rgba(255, 255, 255, 0.08));\n}\n.left-panel__data-children .left-panel__data-row,\n.left-panel__data-children .left-panel__data-group {\n padding: 3px 0;\n background: transparent;\n border-color: transparent;\n}\n.left-panel__data-children .left-panel__data-row:hover,\n.left-panel__data-children .left-panel__data-group:hover {\n background: transparent;\n}\n@media (max-width: 900px) {\n .left-panel {\n width: 50vw;\n }\n .left-panel--open {\n margin-left: 0;\n }\n .left-panel--closed {\n margin-left: -50vw;\n }\n .left-panel {\n padding: 18px 12px;\n }\n .left-panel__data-row {\n flex-direction: column;\n align-items: stretch;\n gap: 2px;\n padding: 6px 8px;\n }\n .left-panel__data-group {\n padding: 6px 8px;\n }\n .left-panel__data-value {\n text-align: left;\n font-size: 11.5px;\n }\n .left-panel__data-children {\n padding-left: 8px;\n }\n}\n');
|
|
4703
4705
|
|
|
4704
4706
|
// src/components/ModelViewer/ObjectBindingDataPanel.tsx
|
|
4705
|
-
import { Fragment as
|
|
4707
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4708
|
+
function DataEntries({ entries }) {
|
|
4709
|
+
return /* @__PURE__ */ jsx15(Fragment6, { children: entries.map(([key, value]) => {
|
|
4710
|
+
const isObject = value !== null && typeof value === "object";
|
|
4711
|
+
const childEntries = isObject ? Object.entries(value) : [];
|
|
4712
|
+
if (isObject && childEntries.length > 0) {
|
|
4713
|
+
return /* @__PURE__ */ jsxs11("div", { className: "left-panel__data-group", children: [
|
|
4714
|
+
/* @__PURE__ */ jsx15("span", { className: "left-panel__data-key", children: key }),
|
|
4715
|
+
/* @__PURE__ */ jsx15("div", { className: "left-panel__data-children", children: /* @__PURE__ */ jsx15(DataEntries, { entries: childEntries }) })
|
|
4716
|
+
] }, key);
|
|
4717
|
+
}
|
|
4718
|
+
return /* @__PURE__ */ jsxs11("div", { className: "left-panel__data-row", children: [
|
|
4719
|
+
/* @__PURE__ */ jsx15("span", { className: "left-panel__data-key", children: key }),
|
|
4720
|
+
/* @__PURE__ */ jsx15(
|
|
4721
|
+
"span",
|
|
4722
|
+
{
|
|
4723
|
+
className: `left-panel__data-value left-panel__data-value--${typeof value}`,
|
|
4724
|
+
children: isObject ? Array.isArray(value) ? "[]" : "{}" : String(value)
|
|
4725
|
+
}
|
|
4726
|
+
)
|
|
4727
|
+
] }, key);
|
|
4728
|
+
}) });
|
|
4729
|
+
}
|
|
4730
|
+
function ActionExtra({ content }) {
|
|
4731
|
+
const hasContent = content != null;
|
|
4732
|
+
const [mounted, setMounted] = useState7(hasContent);
|
|
4733
|
+
const [expanded, setExpanded] = useState7(hasContent);
|
|
4734
|
+
const cachedRef = useRef10(content);
|
|
4735
|
+
if (hasContent) cachedRef.current = content;
|
|
4736
|
+
useEffect13(() => {
|
|
4737
|
+
if (hasContent) {
|
|
4738
|
+
setMounted(true);
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4741
|
+
if (mounted) {
|
|
4742
|
+
setExpanded(false);
|
|
4743
|
+
const timer = setTimeout(() => setMounted(false), 300);
|
|
4744
|
+
return () => clearTimeout(timer);
|
|
4745
|
+
}
|
|
4746
|
+
}, [hasContent, mounted]);
|
|
4747
|
+
useEffect13(() => {
|
|
4748
|
+
if (mounted && hasContent) {
|
|
4749
|
+
const frame = requestAnimationFrame(() => setExpanded(true));
|
|
4750
|
+
return () => cancelAnimationFrame(frame);
|
|
4751
|
+
}
|
|
4752
|
+
}, [mounted, hasContent]);
|
|
4753
|
+
if (!mounted) return null;
|
|
4754
|
+
return /* @__PURE__ */ jsx15(
|
|
4755
|
+
"div",
|
|
4756
|
+
{
|
|
4757
|
+
className: `left-panel__action-extra${expanded ? " left-panel__action-extra--open" : ""}`,
|
|
4758
|
+
children: /* @__PURE__ */ jsx15("div", { className: "left-panel__action-extra-inner", children: content ?? cachedRef.current })
|
|
4759
|
+
}
|
|
4760
|
+
);
|
|
4761
|
+
}
|
|
4706
4762
|
function ObjectBindingDataPanel({
|
|
4707
4763
|
isOpen,
|
|
4708
4764
|
selectedObject,
|
|
4709
4765
|
currentAction,
|
|
4710
4766
|
onClose,
|
|
4711
|
-
onAction
|
|
4767
|
+
onAction,
|
|
4768
|
+
renderActionExtra
|
|
4712
4769
|
}) {
|
|
4713
4770
|
const [displayedObject, setDisplayedObject] = useState7(selectedObject);
|
|
4714
4771
|
useEffect13(() => {
|
|
@@ -4720,7 +4777,7 @@ function ObjectBindingDataPanel({
|
|
|
4720
4777
|
"div",
|
|
4721
4778
|
{
|
|
4722
4779
|
className: `left-panel ${isOpen ? "left-panel--open" : "left-panel--closed"}`,
|
|
4723
|
-
children: objectToRender && /* @__PURE__ */ jsxs11(
|
|
4780
|
+
children: objectToRender && /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
4724
4781
|
/* @__PURE__ */ jsxs11("div", { className: "left-panel__header", children: [
|
|
4725
4782
|
/* @__PURE__ */ jsx15("p", { className: "left-panel__title", children: objectToRender.label }),
|
|
4726
4783
|
/* @__PURE__ */ jsx15(
|
|
@@ -4733,42 +4790,36 @@ function ObjectBindingDataPanel({
|
|
|
4733
4790
|
}
|
|
4734
4791
|
)
|
|
4735
4792
|
] }),
|
|
4736
|
-
dataEntries.length > 0 && /* @__PURE__ */ jsx15("div", { className: "left-panel__data", children:
|
|
4737
|
-
/* @__PURE__ */ jsx15("span", { className: "left-panel__data-key", children: key }),
|
|
4738
|
-
/* @__PURE__ */ jsx15(
|
|
4739
|
-
"span",
|
|
4740
|
-
{
|
|
4741
|
-
className: `left-panel__data-value left-panel__data-value--${typeof value}`,
|
|
4742
|
-
children: typeof value === "object" ? JSON.stringify(value) : String(value)
|
|
4743
|
-
}
|
|
4744
|
-
)
|
|
4745
|
-
] }, key)) }),
|
|
4793
|
+
dataEntries.length > 0 && /* @__PURE__ */ jsx15("div", { className: "left-panel__data", children: /* @__PURE__ */ jsx15(DataEntries, { entries: dataEntries }) }),
|
|
4746
4794
|
/* @__PURE__ */ jsx15("hr", { className: "left-panel__divider" }),
|
|
4747
|
-
objectToRender.actions && objectToRender.actions.length > 0 && /* @__PURE__ */ jsxs11(
|
|
4795
|
+
objectToRender.actions && objectToRender.actions.length > 0 && /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
4748
4796
|
/* @__PURE__ */ jsx15("div", { className: "left-panel__actions-label", children: "Actions" }),
|
|
4749
4797
|
/* @__PURE__ */ jsx15("div", { className: "left-panel__actions-list", children: objectToRender.actions.map((action) => {
|
|
4750
4798
|
const isActive = currentAction?.action.id === action.id && (currentAction.binding === objectToRender || currentAction.binding?.id === objectToRender.id || currentAction.binding?.modelObjectId === objectToRender.modelObjectId || currentAction.objectId === objectToRender.id || currentAction.objectId === objectToRender.modelObjectId);
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4799
|
+
const extra = renderActionExtra?.(action.id);
|
|
4800
|
+
return /* @__PURE__ */ jsxs11(Fragment5, { children: [
|
|
4801
|
+
/* @__PURE__ */ jsx15(
|
|
4802
|
+
"button",
|
|
4803
|
+
{
|
|
4804
|
+
onClick: (e) => onAction({
|
|
4805
|
+
objectId: objectToRender.modelObjectId || objectToRender.id || "",
|
|
4806
|
+
action,
|
|
4807
|
+
binding: objectToRender,
|
|
4808
|
+
screenX: e.clientX,
|
|
4809
|
+
screenY: e.clientY
|
|
4810
|
+
}),
|
|
4811
|
+
className: [
|
|
4812
|
+
"left-panel__action-btn",
|
|
4813
|
+
`left-panel__action-btn--${action.id}`,
|
|
4814
|
+
isActive ? "left-panel__action-btn--active" : ""
|
|
4815
|
+
].filter(Boolean).join(" "),
|
|
4816
|
+
"data-action-id": action.id,
|
|
4817
|
+
"data-label": action.label,
|
|
4818
|
+
children: action.label
|
|
4819
|
+
}
|
|
4820
|
+
),
|
|
4821
|
+
/* @__PURE__ */ jsx15(ActionExtra, { content: extra })
|
|
4822
|
+
] }, action.id);
|
|
4772
4823
|
}) })
|
|
4773
4824
|
] })
|
|
4774
4825
|
] })
|
|
@@ -4784,7 +4835,7 @@ import { Boxes } from "lucide-react";
|
|
|
4784
4835
|
import { useState as useState8 } from "react";
|
|
4785
4836
|
|
|
4786
4837
|
// src/styles/SceneObjectsPanel.css
|
|
4787
|
-
styleInject('.ri-sidepanel-wrap {\n height: 100%;\n transition: width 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: visible;\n}\n.ri-sidepanel-wrap--open {\n width: 300px;\n flex-shrink: 0;\n}\n.ri-sidepanel-wrap--closed {\n width: 0;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ri-sidepanel__open-btn {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 7px 13px;\n border-radius: 7px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-open-btn-bg, rgba(20, 20, 20, 0.82));\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--ri-sidepanel-text, #e2e8f0);\n z-index: 190;\n transition: background 0.15s;\n}\n.ri-sidepanel__open-btn:hover {\n background: var(--ri-sidepanel-open-btn-bg-hover, #27282b7e);\n}\n.ri-sidepanel {\n position: absolute;\n top: 0;\n right: 0;\n width: 300px;\n height: 100%;\n background: var(--ri-sidepanel-bg, #141824);\n display: flex;\n flex-direction: column;\n font-family: var( --ri-sidepanel-font-family, Inter, "Segoe UI", Helvetica, Arial, sans-serif );\n transform: translateX(100%);\n transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n z-index: 200;\n border-left: 1px solid var(--ri-sidepanel-border, rgba(255, 255, 255, 0.06));\n box-shadow: var(--ri-sidepanel-shadow-right, -4px 0 24px rgba(0, 0, 0, 0.35));\n}\n.ri-sidepanel--open {\n transform: translateX(0);\n}\n.ri-sidepanel--closed {\n transform: translateX(100%);\n}\n.ri-sidepanel__header {\n padding: 24px 20px 16px 20px;\n border-bottom: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n}\n.ri-sidepanel__eyebrow {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.12em;\n color: var(--ri-sidepanel-text-subtle, #64748b);\n text-transform: uppercase;\n}\n.ri-sidepanel__title {\n font-size: 22px;\n font-weight: 700;\n color: var(--ri-sidepanel-text, #f1f5f9);\n margin: 0;\n line-height: 1.2;\n}\n.ri-sidepanel__close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n border-radius: 8px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n cursor: pointer;\n color: var(--ri-sidepanel-text-muted, #94a3b8);\n transition: background 0.15s, color 0.15s;\n flex-shrink: 0;\n}\n.ri-sidepanel__close-btn:hover {\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.1));\n color: var(--ri-sidepanel-text, #f1f5f9);\n}\n.ri-sidepanel__search-wrap {\n padding: 14px 16px;\n border-bottom: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__search {\n width: 100%;\n padding: 10px 14px;\n border-radius: 10px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n color: var(--ri-sidepanel-text, #e2e8f0);\n font-size: 13px;\n outline: none;\n box-sizing: border-box;\n transition: border-color 0.15s, background 0.15s;\n}\n.ri-sidepanel__search::placeholder {\n color: var(--ri-sidepanel-placeholder, #475569);\n}\n.ri-sidepanel__search:focus {\n border-color: var(--ri-sidepanel-border-active, rgba(255, 255, 255, 0.18));\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__list {\n display: flex;\n flex-direction: column;\n padding: 10px 0;\n overflow-y: auto;\n flex: 1;\n}\n.ri-sidepanel__list::-webkit-scrollbar {\n width: 4px;\n}\n.ri-sidepanel__list::-webkit-scrollbar-track {\n background: transparent;\n}\n.ri-sidepanel__list::-webkit-scrollbar-thumb {\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.1));\n border-radius: 4px;\n}\n.ri-sidepanel__row {\n display: flex;\n justify-content: space-between;\n padding: 12px 20px;\n cursor: pointer;\n width: 100%;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n appearance: none;\n -webkit-appearance: none;\n transition: background 0.12s;\n border-bottom: 1px solid var(--ri-sidepanel-divider, rgba(255, 255, 255, 0.04));\n}\n.ri-sidepanel__row:hover,\n.ri-sidepanel__row--hovered {\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n}\n.ri-sidepanel__row--selected {\n background: var(--ri-sidepanel-accent-soft, rgba(59, 130, 246, 0.12));\n}\n.ri-sidepanel__label {\n font-size: 14px;\n font-weight: 600;\n color: var(--ri-sidepanel-text, #e2e8f0);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-sidepanel__label--hovered {\n color: var(--ri-sidepanel-text-emphasis, #ffffff);\n}\n.ri-sidepanel__label--selected {\n color: var(--ri-sidepanel-text-emphasis, #ffffff);\n}\n.ri-sidepanel__meta {\n font-size: 12px;\n color: var(--ri-sidepanel-text-muted, #94a3b8);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-sidepanel__vis-btn {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n margin-left: 10px;\n}\n.ri-sidepanel__checkbox {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1.5px solid var(--ri-sidepanel-border-active, rgba(255, 255, 255, 0.2));\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, border-color 0.15s;\n}\n.ri-sidepanel__checkbox--checked {\n background: var(--ri-sidepanel-accent, #3b82f6);\n border-color: var(--ri-sidepanel-accent, #3b82f6);\n}\n@media (max-width: 900px) {\n .ri-sidepanel-wrap--open {\n width:
|
|
4838
|
+
styleInject('.ri-sidepanel-wrap {\n height: 100%;\n transition: width 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: visible;\n}\n.ri-sidepanel-wrap--open {\n width: 300px;\n flex-shrink: 0;\n}\n.ri-sidepanel-wrap--closed {\n width: 0;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ri-sidepanel__open-btn {\n position: absolute;\n top: 12px;\n right: 12px;\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 7px 13px;\n border-radius: 7px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-open-btn-bg, rgba(20, 20, 20, 0.82));\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n color: var(--ri-sidepanel-text, #e2e8f0);\n z-index: 190;\n transition: background 0.15s;\n}\n.ri-sidepanel__open-btn:hover {\n background: var(--ri-sidepanel-open-btn-bg-hover, #27282b7e);\n}\n.ri-sidepanel {\n position: absolute;\n top: 0;\n right: 0;\n width: 300px;\n height: 100%;\n background: var(--ri-sidepanel-bg, #141824);\n display: flex;\n flex-direction: column;\n font-family: var( --ri-sidepanel-font-family, Inter, "Segoe UI", Helvetica, Arial, sans-serif );\n transform: translateX(100%);\n transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);\n z-index: 200;\n border-left: 1px solid var(--ri-sidepanel-border, rgba(255, 255, 255, 0.06));\n box-shadow: var(--ri-sidepanel-shadow-right, -4px 0 24px rgba(0, 0, 0, 0.35));\n}\n.ri-sidepanel--open {\n transform: translateX(0);\n}\n.ri-sidepanel--closed {\n transform: translateX(100%);\n}\n.ri-sidepanel__header {\n padding: 24px 20px 16px 20px;\n border-bottom: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n}\n.ri-sidepanel__eyebrow {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.12em;\n color: var(--ri-sidepanel-text-subtle, #64748b);\n text-transform: uppercase;\n}\n.ri-sidepanel__title {\n font-size: 22px;\n font-weight: 700;\n color: var(--ri-sidepanel-text, #f1f5f9);\n margin: 0;\n line-height: 1.2;\n}\n.ri-sidepanel__close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n border-radius: 8px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n cursor: pointer;\n color: var(--ri-sidepanel-text-muted, #94a3b8);\n transition: background 0.15s, color 0.15s;\n flex-shrink: 0;\n}\n.ri-sidepanel__close-btn:hover {\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.1));\n color: var(--ri-sidepanel-text, #f1f5f9);\n}\n.ri-sidepanel__search-wrap {\n padding: 14px 16px;\n border-bottom: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__search {\n width: 100%;\n padding: 10px 14px;\n border-radius: 10px;\n border: 1px solid var(--ri-sidepanel-border-strong, rgba(255, 255, 255, 0.08));\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n color: var(--ri-sidepanel-text, #e2e8f0);\n font-size: 13px;\n outline: none;\n box-sizing: border-box;\n transition: border-color 0.15s, background 0.15s;\n}\n.ri-sidepanel__search::placeholder {\n color: var(--ri-sidepanel-placeholder, #475569);\n}\n.ri-sidepanel__search:focus {\n border-color: var(--ri-sidepanel-border-active, rgba(255, 255, 255, 0.18));\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.08));\n}\n.ri-sidepanel__list {\n display: flex;\n flex-direction: column;\n padding: 10px 0;\n overflow-y: auto;\n flex: 1;\n}\n.ri-sidepanel__list::-webkit-scrollbar {\n width: 4px;\n}\n.ri-sidepanel__list::-webkit-scrollbar-track {\n background: transparent;\n}\n.ri-sidepanel__list::-webkit-scrollbar-thumb {\n background: var(--ri-sidepanel-surface-hover, rgba(255, 255, 255, 0.1));\n border-radius: 4px;\n}\n.ri-sidepanel__row {\n display: flex;\n justify-content: space-between;\n padding: 12px 20px;\n cursor: pointer;\n width: 100%;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n appearance: none;\n -webkit-appearance: none;\n transition: background 0.12s;\n border-bottom: 1px solid var(--ri-sidepanel-divider, rgba(255, 255, 255, 0.04));\n}\n.ri-sidepanel__row:hover,\n.ri-sidepanel__row--hovered {\n background: var(--ri-sidepanel-surface, rgba(255, 255, 255, 0.05));\n}\n.ri-sidepanel__row--selected {\n background: var(--ri-sidepanel-accent-soft, rgba(59, 130, 246, 0.12));\n}\n.ri-sidepanel__label {\n font-size: 14px;\n font-weight: 600;\n color: var(--ri-sidepanel-text, #e2e8f0);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-sidepanel__label--hovered {\n color: var(--ri-sidepanel-text-emphasis, #ffffff);\n}\n.ri-sidepanel__label--selected {\n color: var(--ri-sidepanel-text-emphasis, #ffffff);\n}\n.ri-sidepanel__meta {\n font-size: 12px;\n color: var(--ri-sidepanel-text-muted, #94a3b8);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ri-sidepanel__vis-btn {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n margin-left: 10px;\n}\n.ri-sidepanel__checkbox {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1.5px solid var(--ri-sidepanel-border-active, rgba(255, 255, 255, 0.2));\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.15s, border-color 0.15s;\n}\n.ri-sidepanel__checkbox--checked {\n background: var(--ri-sidepanel-accent, #3b82f6);\n border-color: var(--ri-sidepanel-accent, #3b82f6);\n}\n@media (max-width: 900px) {\n .ri-sidepanel-wrap--open {\n width: 50vw;\n }\n .ri-sidepanel {\n width: 50vw;\n }\n}\n');
|
|
4788
4839
|
|
|
4789
4840
|
// src/components/shared/SearchableSidePanel.tsx
|
|
4790
4841
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
@@ -5000,7 +5051,6 @@ import {
|
|
|
5000
5051
|
Download,
|
|
5001
5052
|
Eraser,
|
|
5002
5053
|
MapPin,
|
|
5003
|
-
Ruler,
|
|
5004
5054
|
RotateCcw,
|
|
5005
5055
|
ChevronLeft,
|
|
5006
5056
|
Square,
|
|
@@ -5009,7 +5059,10 @@ import {
|
|
|
5009
5059
|
X,
|
|
5010
5060
|
Expand,
|
|
5011
5061
|
Play,
|
|
5012
|
-
Pause
|
|
5062
|
+
Pause,
|
|
5063
|
+
Smartphone,
|
|
5064
|
+
PencilRuler,
|
|
5065
|
+
RulerDimensionLine
|
|
5013
5066
|
} from "lucide-react";
|
|
5014
5067
|
|
|
5015
5068
|
// src/components/BindingBuilder/BindingBuilderContext.tsx
|
|
@@ -5053,7 +5106,7 @@ function consumeInitialAutoFitOverride(controls) {
|
|
|
5053
5106
|
}
|
|
5054
5107
|
|
|
5055
5108
|
// src/components/ModelViewer/ModelViewer.tsx
|
|
5056
|
-
import { Fragment as
|
|
5109
|
+
import { Fragment as Fragment7, jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5057
5110
|
function findInfluencingBone(hit) {
|
|
5058
5111
|
const mesh = hit.object;
|
|
5059
5112
|
if (!mesh.isSkinnedMesh || !hit.face || !mesh.skeleton) return null;
|
|
@@ -5112,8 +5165,8 @@ function GuidedTourCameraFollow({
|
|
|
5112
5165
|
offsetRef
|
|
5113
5166
|
}) {
|
|
5114
5167
|
const scene = useThree10((state) => state.scene);
|
|
5115
|
-
const nodeRef =
|
|
5116
|
-
const hasPrev =
|
|
5168
|
+
const nodeRef = useRef11(null);
|
|
5169
|
+
const hasPrev = useRef11(false);
|
|
5117
5170
|
const live = useMemo13(() => new Vector37(), []);
|
|
5118
5171
|
const prev = useMemo13(() => new Vector37(), []);
|
|
5119
5172
|
const goal = useMemo13(() => new Vector37(), []);
|
|
@@ -5262,17 +5315,17 @@ function ModelViewer({
|
|
|
5262
5315
|
() => shouldReduceGpuLoad(performanceProfile),
|
|
5263
5316
|
[performanceProfile]
|
|
5264
5317
|
);
|
|
5265
|
-
const controlsRef =
|
|
5318
|
+
const controlsRef = useRef11(null);
|
|
5266
5319
|
useEffect14(() => {
|
|
5267
5320
|
if (!controlsRef.current) return;
|
|
5268
5321
|
controlsRef.current.dollySpeed = Math.max(zoomSensitivity, 0);
|
|
5269
5322
|
}, [zoomSensitivity]);
|
|
5270
|
-
const tourCameraOffsetRef =
|
|
5271
|
-
const annotationWorldPositionsRef =
|
|
5272
|
-
const fileInputRef =
|
|
5273
|
-
const pendingObjectId =
|
|
5274
|
-
const rendererCaptureRef =
|
|
5275
|
-
const createdBlobUrls =
|
|
5323
|
+
const tourCameraOffsetRef = useRef11(null);
|
|
5324
|
+
const annotationWorldPositionsRef = useRef11(/* @__PURE__ */ new Map());
|
|
5325
|
+
const fileInputRef = useRef11(null);
|
|
5326
|
+
const pendingObjectId = useRef11(null);
|
|
5327
|
+
const rendererCaptureRef = useRef11(null);
|
|
5328
|
+
const createdBlobUrls = useRef11({});
|
|
5276
5329
|
useEffect14(() => {
|
|
5277
5330
|
return () => {
|
|
5278
5331
|
for (const url of Object.values(createdBlobUrls.current)) {
|
|
@@ -5280,12 +5333,12 @@ function ModelViewer({
|
|
|
5280
5333
|
}
|
|
5281
5334
|
};
|
|
5282
5335
|
}, []);
|
|
5283
|
-
const nodeRefsMap =
|
|
5284
|
-
const materialRefsOut =
|
|
5285
|
-
const viewerLeftRef =
|
|
5286
|
-
const canvasAreaRef =
|
|
5287
|
-
const xrPresenterRef =
|
|
5288
|
-
const viewAnnotationPopupRef =
|
|
5336
|
+
const nodeRefsMap = useRef11({});
|
|
5337
|
+
const materialRefsOut = useRef11({});
|
|
5338
|
+
const viewerLeftRef = useRef11(null);
|
|
5339
|
+
const canvasAreaRef = useRef11(null);
|
|
5340
|
+
const xrPresenterRef = useRef11(null);
|
|
5341
|
+
const viewAnnotationPopupRef = useRef11(null);
|
|
5289
5342
|
const [internalObjectBindings, setInternalObjectBindings] = useState10(objectBindings);
|
|
5290
5343
|
const [itemMaterials, setItemMaterials] = useState10({});
|
|
5291
5344
|
const [currentAction, setCurrentAction] = useState10(
|
|
@@ -5299,12 +5352,12 @@ function ModelViewer({
|
|
|
5299
5352
|
null
|
|
5300
5353
|
);
|
|
5301
5354
|
const [isDownloading, setIsDownloading] = useState10(false);
|
|
5302
|
-
const sceneRef =
|
|
5303
|
-
const fitAttemptedRef =
|
|
5304
|
-
const fitInFlightRef =
|
|
5305
|
-
const cameraProvidedRef =
|
|
5355
|
+
const sceneRef = useRef11(null);
|
|
5356
|
+
const fitAttemptedRef = useRef11(false);
|
|
5357
|
+
const fitInFlightRef = useRef11(false);
|
|
5358
|
+
const cameraProvidedRef = useRef11(Boolean(camera));
|
|
5306
5359
|
cameraProvidedRef.current = Boolean(camera);
|
|
5307
|
-
const initialCameraStateRef =
|
|
5360
|
+
const initialCameraStateRef = useRef11(null);
|
|
5308
5361
|
const [isAutoFraming, setIsAutoFraming] = useState10(Boolean(modelUrl));
|
|
5309
5362
|
const [cameraPositioned, setCameraPositioned] = useState10(
|
|
5310
5363
|
!modelUrl || Boolean(onAutoFit) || Boolean(camera)
|
|
@@ -5314,7 +5367,7 @@ function ModelViewer({
|
|
|
5314
5367
|
const [modelLoadFailed, setModelLoadFailed] = useState10(false);
|
|
5315
5368
|
const [bindingsMismatch, setBindingsMismatch] = useState10(false);
|
|
5316
5369
|
const [mismatchDismissed, setMismatchDismissed] = useState10(false);
|
|
5317
|
-
const currentObjectBindingsRef =
|
|
5370
|
+
const currentObjectBindingsRef = useRef11({});
|
|
5318
5371
|
const captureInitialCameraState = useCallback4(() => {
|
|
5319
5372
|
const controls = controlsRef.current;
|
|
5320
5373
|
if (!controls || initialCameraStateRef.current) {
|
|
@@ -5332,10 +5385,10 @@ function ModelViewer({
|
|
|
5332
5385
|
const [measurePoints, setMeasurePoints] = useState10([]);
|
|
5333
5386
|
const [showDimensions, setShowDimensions] = useState10(false);
|
|
5334
5387
|
const [measureBox, setMeasureBox] = useState10(null);
|
|
5335
|
-
const measureModeRef =
|
|
5388
|
+
const measureModeRef = useRef11(false);
|
|
5336
5389
|
measureModeRef.current = measureMode;
|
|
5337
|
-
const measurePointCounter =
|
|
5338
|
-
const measureDownRef =
|
|
5390
|
+
const measurePointCounter = useRef11(0);
|
|
5391
|
+
const measureDownRef = useRef11(null);
|
|
5339
5392
|
const [explodeFactor, setExplodeFactor] = useState10(0);
|
|
5340
5393
|
const [explodeOpen, setExplodeOpen] = useState10(false);
|
|
5341
5394
|
useEffect14(() => {
|
|
@@ -5358,7 +5411,7 @@ function ModelViewer({
|
|
|
5358
5411
|
return { ...base ?? {}, ...cinematic };
|
|
5359
5412
|
}, [cinematic, resolvedSceneConfig]);
|
|
5360
5413
|
const [cinematicPlaying, setCinematicPlaying] = useState10(false);
|
|
5361
|
-
const cinematicAutoStartedRef =
|
|
5414
|
+
const cinematicAutoStartedRef = useRef11(false);
|
|
5362
5415
|
useEffect14(() => {
|
|
5363
5416
|
setCinematicPlaying(false);
|
|
5364
5417
|
cinematicAutoStartedRef.current = false;
|
|
@@ -5453,7 +5506,7 @@ function ModelViewer({
|
|
|
5453
5506
|
const arHintText = arOverlayState.isModelPlaced && !arOverlayState.isPlacementMode ? "Pinch to resize \xB7 Twist to rotate" : null;
|
|
5454
5507
|
const arOverlayRoot = xrStore?.getState().domOverlayRoot ?? null;
|
|
5455
5508
|
const arOverlay = inARSession && arOverlayRoot ? createPortal(
|
|
5456
|
-
/* @__PURE__ */ jsxs15(
|
|
5509
|
+
/* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
5457
5510
|
arHintText && /* @__PURE__ */ jsx19("div", { className: "ri-arHintOverlay", children: /* @__PURE__ */ jsx19("div", { className: "ri-arHint", children: arHintText }) }),
|
|
5458
5511
|
/* @__PURE__ */ jsx19("div", { className: "ri-arOverlay", children: /* @__PURE__ */ jsxs15("div", { className: "ri-arControls", children: [
|
|
5459
5512
|
arStatusText && /* @__PURE__ */ jsx19("div", { className: "ri-arStatus", children: arStatusText }),
|
|
@@ -5514,11 +5567,11 @@ function ModelViewer({
|
|
|
5514
5567
|
title: "",
|
|
5515
5568
|
description: ""
|
|
5516
5569
|
});
|
|
5517
|
-
const annotationCounterRef =
|
|
5570
|
+
const annotationCounterRef = useRef11(0);
|
|
5518
5571
|
const [internalViewingAnnotation, setInternalViewingAnnotation] = useState10(null);
|
|
5519
5572
|
const [currentAnnotationIndex, setCurrentAnnotationIndex] = useState10(-1);
|
|
5520
5573
|
const [isNavigating, setIsNavigating] = useState10(false);
|
|
5521
|
-
const annotationSmoothRestoreTimeoutRef =
|
|
5574
|
+
const annotationSmoothRestoreTimeoutRef = useRef11(null);
|
|
5522
5575
|
const sortedAnnotations = useMemo13(() => {
|
|
5523
5576
|
return [...annotations].sort((a, b) => a.id - b.id);
|
|
5524
5577
|
}, [annotations]);
|
|
@@ -6078,7 +6131,7 @@ function ModelViewer({
|
|
|
6078
6131
|
delete createdBlobUrls.current[targetKey];
|
|
6079
6132
|
}
|
|
6080
6133
|
};
|
|
6081
|
-
const onViewerReadyRef =
|
|
6134
|
+
const onViewerReadyRef = useRef11(onViewerReady);
|
|
6082
6135
|
onViewerReadyRef.current = onViewerReady;
|
|
6083
6136
|
const notifyViewerReady = useCallback4(() => {
|
|
6084
6137
|
const controls = controlsRef.current;
|
|
@@ -6582,6 +6635,8 @@ function ModelViewer({
|
|
|
6582
6635
|
const pendingPopupX = pendingAnnotation ? Math.min(pendingAnnotation.screenX + 12, canvasW - popupW - 8) : 0;
|
|
6583
6636
|
const pendingPopupY = pendingAnnotation ? Math.min(pendingAnnotation.screenY, canvasH - popupH - 8) : 0;
|
|
6584
6637
|
const showModelLoader = showLoadingOverlay && Boolean(modelUrl) && !modelLoadFailed && (!modelLoaded || !cameraPositioned || isAutoFraming);
|
|
6638
|
+
const xrToolsVisible = enableXR && (xrStore && (arSupported || vrSupported) || quickLookSupported);
|
|
6639
|
+
const topLeftRow = (top) => 16 + top * 42;
|
|
6585
6640
|
return /* @__PURE__ */ jsxs15("div", { className: "ri-viewer", style: { background: viewerBackdropColor }, children: [
|
|
6586
6641
|
/* @__PURE__ */ jsxs15("div", { className: "ri-viewerLeft", ref: viewerLeftRef, children: [
|
|
6587
6642
|
customObjectBindingDataPanel ? customObjectBindingDataPanel({
|
|
@@ -6597,7 +6652,34 @@ function ModelViewer({
|
|
|
6597
6652
|
selectedObject: currentPanelObject,
|
|
6598
6653
|
currentAction,
|
|
6599
6654
|
onClose: handleClosePanel,
|
|
6600
|
-
onAction: handleAction
|
|
6655
|
+
onAction: handleAction,
|
|
6656
|
+
renderActionExtra: (actionId) => {
|
|
6657
|
+
if (actionId === "change-color" && colorPicker) {
|
|
6658
|
+
return /* @__PURE__ */ jsx19(
|
|
6659
|
+
ColorPicker,
|
|
6660
|
+
{
|
|
6661
|
+
inline: true,
|
|
6662
|
+
colorPicker,
|
|
6663
|
+
onClose: closeColorPicker,
|
|
6664
|
+
itemMaterials,
|
|
6665
|
+
setItemMaterials
|
|
6666
|
+
}
|
|
6667
|
+
);
|
|
6668
|
+
}
|
|
6669
|
+
if (actionId === "change-material" && materialPopup) {
|
|
6670
|
+
return /* @__PURE__ */ jsx19(
|
|
6671
|
+
MaterialPicker,
|
|
6672
|
+
{
|
|
6673
|
+
inline: true,
|
|
6674
|
+
triggerFileUpload,
|
|
6675
|
+
materialPopup,
|
|
6676
|
+
textureUrl: materialTextureUrl,
|
|
6677
|
+
clearTexture
|
|
6678
|
+
}
|
|
6679
|
+
);
|
|
6680
|
+
}
|
|
6681
|
+
return null;
|
|
6682
|
+
}
|
|
6601
6683
|
}
|
|
6602
6684
|
),
|
|
6603
6685
|
/* @__PURE__ */ jsxs15(
|
|
@@ -6680,7 +6762,7 @@ function ModelViewer({
|
|
|
6680
6762
|
{
|
|
6681
6763
|
onLoadError: handleLoadErrorInternal,
|
|
6682
6764
|
children: /* @__PURE__ */ jsx19(Suspense2, { fallback: null, children: /* @__PURE__ */ (() => {
|
|
6683
|
-
const modelContent = /* @__PURE__ */ jsxs15(
|
|
6765
|
+
const modelContent = /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
6684
6766
|
/* @__PURE__ */ jsx19(
|
|
6685
6767
|
Model,
|
|
6686
6768
|
{
|
|
@@ -6770,45 +6852,110 @@ function ModelViewer({
|
|
|
6770
6852
|
message: "Loading model..."
|
|
6771
6853
|
}
|
|
6772
6854
|
),
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6855
|
+
xrToolsVisible && /* @__PURE__ */ jsxs15(
|
|
6856
|
+
"div",
|
|
6857
|
+
{
|
|
6858
|
+
className: "ri-xrTools",
|
|
6859
|
+
style: { top: `${topLeftRow(0)}px` },
|
|
6860
|
+
children: [
|
|
6861
|
+
!arSupported && quickLookSupported && /* @__PURE__ */ jsxs15(
|
|
6862
|
+
"button",
|
|
6863
|
+
{
|
|
6864
|
+
type: "button",
|
|
6865
|
+
className: "ri-xrButton",
|
|
6866
|
+
onClick: openQuickLook,
|
|
6867
|
+
title: "View this model in AR with Apple Quick Look",
|
|
6868
|
+
children: [
|
|
6869
|
+
/* @__PURE__ */ jsx19(Box, { size: 16 }),
|
|
6870
|
+
"View in AR"
|
|
6871
|
+
]
|
|
6872
|
+
}
|
|
6873
|
+
),
|
|
6874
|
+
xrStore && arSupported && /* @__PURE__ */ jsxs15(
|
|
6875
|
+
"button",
|
|
6876
|
+
{
|
|
6877
|
+
type: "button",
|
|
6878
|
+
className: "ri-xrButton",
|
|
6879
|
+
onClick: () => xrStore.enterAR().catch((err) => {
|
|
6880
|
+
console.error("Failed to enter AR session:", err);
|
|
6881
|
+
}),
|
|
6882
|
+
title: "View this model in your space",
|
|
6883
|
+
children: [
|
|
6884
|
+
/* @__PURE__ */ jsx19(Smartphone, { size: 16 }),
|
|
6885
|
+
/* @__PURE__ */ jsx19("span", { className: "ri-xrButtonPrefix", children: "Enter" }),
|
|
6886
|
+
/* @__PURE__ */ jsx19("span", { children: "AR" })
|
|
6887
|
+
]
|
|
6888
|
+
}
|
|
6889
|
+
),
|
|
6890
|
+
xrStore && vrSupported && /* @__PURE__ */ jsxs15(
|
|
6891
|
+
"button",
|
|
6892
|
+
{
|
|
6893
|
+
type: "button",
|
|
6894
|
+
className: "ri-xrButton",
|
|
6895
|
+
onClick: () => xrStore.enterVR().catch((err) => {
|
|
6896
|
+
console.error("Failed to enter VR session:", err);
|
|
6897
|
+
}),
|
|
6898
|
+
title: "View this model in VR",
|
|
6899
|
+
children: [
|
|
6900
|
+
/* @__PURE__ */ jsx19(RectangleGoggles, { size: 16 }),
|
|
6901
|
+
/* @__PURE__ */ jsx19("span", { className: "ri-xrButtonPrefix", children: "Enter" }),
|
|
6902
|
+
/* @__PURE__ */ jsx19("span", { children: "VR" })
|
|
6903
|
+
]
|
|
6904
|
+
}
|
|
6905
|
+
)
|
|
6906
|
+
]
|
|
6907
|
+
}
|
|
6908
|
+
),
|
|
6909
|
+
arOverlay,
|
|
6910
|
+
showMeasureTools && /* @__PURE__ */ jsxs15(
|
|
6911
|
+
"div",
|
|
6912
|
+
{
|
|
6913
|
+
className: "ri-measureTools",
|
|
6914
|
+
style: { top: `${topLeftRow(xrToolsVisible ? 1 : 0)}px` },
|
|
6915
|
+
children: [
|
|
6916
|
+
/* @__PURE__ */ jsx19(
|
|
6917
|
+
"button",
|
|
6918
|
+
{
|
|
6919
|
+
type: "button",
|
|
6920
|
+
className: `ri-measureButton ${measureMode ? "ri-measureButton--active" : ""}`,
|
|
6921
|
+
onClick: () => setMeasureMode((prev) => !prev),
|
|
6922
|
+
title: measureMode ? "Stop measuring" : "Measure distance",
|
|
6923
|
+
"aria-pressed": measureMode,
|
|
6924
|
+
children: /* @__PURE__ */ jsx19(PencilRuler, { size: 16 })
|
|
6925
|
+
}
|
|
6926
|
+
),
|
|
6927
|
+
/* @__PURE__ */ jsx19(
|
|
6928
|
+
"button",
|
|
6929
|
+
{
|
|
6930
|
+
type: "button",
|
|
6931
|
+
className: `ri-measureButton ${showDimensions ? "ri-measureButton--active" : ""}`,
|
|
6932
|
+
onClick: () => setShowDimensions((prev) => !prev),
|
|
6933
|
+
title: "Toggle bounding dimensions",
|
|
6934
|
+
"aria-pressed": showDimensions,
|
|
6935
|
+
children: /* @__PURE__ */ jsx19(RulerDimensionLine, { size: 16 })
|
|
6936
|
+
}
|
|
6937
|
+
),
|
|
6938
|
+
measurePoints.length > 0 && /* @__PURE__ */ jsx19(
|
|
6939
|
+
"button",
|
|
6940
|
+
{
|
|
6941
|
+
type: "button",
|
|
6942
|
+
className: "ri-measureButton",
|
|
6943
|
+
onClick: clearMeasurements,
|
|
6944
|
+
title: "Clear measurements",
|
|
6945
|
+
children: /* @__PURE__ */ jsx19(Eraser, { size: 16 })
|
|
6946
|
+
}
|
|
6947
|
+
),
|
|
6948
|
+
measureMode && /* @__PURE__ */ jsx19("span", { className: "ri-measureHint", children: "Click points on the model to measure" })
|
|
6949
|
+
]
|
|
6950
|
+
}
|
|
6951
|
+
),
|
|
6808
6952
|
showExplodeControls && /* @__PURE__ */ jsxs15(
|
|
6809
6953
|
"div",
|
|
6810
6954
|
{
|
|
6811
|
-
className:
|
|
6955
|
+
className: "ri-explodeTools",
|
|
6956
|
+
style: {
|
|
6957
|
+
top: `${topLeftRow((xrToolsVisible ? 1 : 0) + (showMeasureTools ? 1 : 0))}px`
|
|
6958
|
+
},
|
|
6812
6959
|
children: [
|
|
6813
6960
|
/* @__PURE__ */ jsx19(
|
|
6814
6961
|
"button",
|
|
@@ -6847,7 +6994,7 @@ function ModelViewer({
|
|
|
6847
6994
|
{
|
|
6848
6995
|
className: "ri-cinematicTools",
|
|
6849
6996
|
style: {
|
|
6850
|
-
top: `${
|
|
6997
|
+
top: `${topLeftRow((xrToolsVisible ? 1 : 0) + (showMeasureTools ? 1 : 0) + (showExplodeControls ? 1 : 0))}px`
|
|
6851
6998
|
},
|
|
6852
6999
|
children: /* @__PURE__ */ jsx19(
|
|
6853
7000
|
"button",
|
|
@@ -6862,56 +7009,8 @@ function ModelViewer({
|
|
|
6862
7009
|
)
|
|
6863
7010
|
}
|
|
6864
7011
|
),
|
|
6865
|
-
enableXR && (xrStore && (arSupported || vrSupported) || quickLookSupported) && /* @__PURE__ */ jsxs15("div", { className: "ri-xrTools", children: [
|
|
6866
|
-
!arSupported && quickLookSupported && /* @__PURE__ */ jsxs15(
|
|
6867
|
-
"button",
|
|
6868
|
-
{
|
|
6869
|
-
type: "button",
|
|
6870
|
-
className: "ri-xrButton",
|
|
6871
|
-
onClick: openQuickLook,
|
|
6872
|
-
title: "View this model in AR with Apple Quick Look",
|
|
6873
|
-
children: [
|
|
6874
|
-
/* @__PURE__ */ jsx19(Box, { size: 16 }),
|
|
6875
|
-
"View in AR"
|
|
6876
|
-
]
|
|
6877
|
-
}
|
|
6878
|
-
),
|
|
6879
|
-
xrStore && arSupported && /* @__PURE__ */ jsxs15(
|
|
6880
|
-
"button",
|
|
6881
|
-
{
|
|
6882
|
-
type: "button",
|
|
6883
|
-
className: "ri-xrButton",
|
|
6884
|
-
onClick: () => xrStore.enterAR().catch((err) => {
|
|
6885
|
-
console.error("Failed to enter AR session:", err);
|
|
6886
|
-
}),
|
|
6887
|
-
title: "View this model in your space",
|
|
6888
|
-
children: [
|
|
6889
|
-
/* @__PURE__ */ jsx19(Box, { size: 16 }),
|
|
6890
|
-
/* @__PURE__ */ jsx19("span", { className: "ri-xrButtonPrefix", children: "Enter" }),
|
|
6891
|
-
/* @__PURE__ */ jsx19("span", { children: "AR" })
|
|
6892
|
-
]
|
|
6893
|
-
}
|
|
6894
|
-
),
|
|
6895
|
-
xrStore && vrSupported && /* @__PURE__ */ jsxs15(
|
|
6896
|
-
"button",
|
|
6897
|
-
{
|
|
6898
|
-
type: "button",
|
|
6899
|
-
className: "ri-xrButton",
|
|
6900
|
-
onClick: () => xrStore.enterVR().catch((err) => {
|
|
6901
|
-
console.error("Failed to enter VR session:", err);
|
|
6902
|
-
}),
|
|
6903
|
-
title: "View this model in VR",
|
|
6904
|
-
children: [
|
|
6905
|
-
/* @__PURE__ */ jsx19(RectangleGoggles, { size: 16 }),
|
|
6906
|
-
/* @__PURE__ */ jsx19("span", { className: "ri-xrButtonPrefix", children: "Enter" }),
|
|
6907
|
-
/* @__PURE__ */ jsx19("span", { children: "VR" })
|
|
6908
|
-
]
|
|
6909
|
-
}
|
|
6910
|
-
)
|
|
6911
|
-
] }),
|
|
6912
|
-
arOverlay,
|
|
6913
7012
|
(showResetButton || showDownloadButtons || showAnnotationNavigation && sortedAnnotations.length > 0) && /* @__PURE__ */ jsxs15("div", { className: "ri-buttonContainer", children: [
|
|
6914
|
-
/* @__PURE__ */ jsx19("div", { className: "ri-tourControls", children: showAnnotationNavigation && sortedAnnotations.length > 0 && /* @__PURE__ */ jsx19(
|
|
7013
|
+
/* @__PURE__ */ jsx19("div", { className: "ri-tourControls", children: showAnnotationNavigation && sortedAnnotations.length > 0 && /* @__PURE__ */ jsx19(Fragment7, { children: !isGuidedTourActive ? (
|
|
6915
7014
|
// Show "Guided Tour" button when tour is not active
|
|
6916
7015
|
/* @__PURE__ */ jsx19(
|
|
6917
7016
|
"button",
|
|
@@ -6925,7 +7024,7 @@ function ModelViewer({
|
|
|
6925
7024
|
)
|
|
6926
7025
|
) : (
|
|
6927
7026
|
// Show Previous, Next, Stop, Reset buttons when tour is active
|
|
6928
|
-
/* @__PURE__ */ jsxs15(
|
|
7027
|
+
/* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
6929
7028
|
/* @__PURE__ */ jsxs15(
|
|
6930
7029
|
"button",
|
|
6931
7030
|
{
|
|
@@ -7019,10 +7118,10 @@ function ModelViewer({
|
|
|
7019
7118
|
onClick: () => setDownloadMenuOpen((v) => !v),
|
|
7020
7119
|
disabled: isDownloading || !sceneRef.current,
|
|
7021
7120
|
title: "Download options",
|
|
7022
|
-
children: isDownloading ? /* @__PURE__ */ jsxs15(
|
|
7121
|
+
children: isDownloading ? /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
7023
7122
|
/* @__PURE__ */ jsx19("span", { className: "ri-downloadButton__spinner" }),
|
|
7024
7123
|
"Exporting\u2026"
|
|
7025
|
-
] }) : /* @__PURE__ */ jsxs15(
|
|
7124
|
+
] }) : /* @__PURE__ */ jsxs15(Fragment7, { children: [
|
|
7026
7125
|
/* @__PURE__ */ jsx19(Download, { size: 15 }),
|
|
7027
7126
|
"Download"
|
|
7028
7127
|
] })
|
|
@@ -7100,7 +7199,7 @@ function ModelViewer({
|
|
|
7100
7199
|
]
|
|
7101
7200
|
}
|
|
7102
7201
|
),
|
|
7103
|
-
colorPicker && /* @__PURE__ */ jsx19(
|
|
7202
|
+
customObjectBindingDataPanel && colorPicker && /* @__PURE__ */ jsx19(
|
|
7104
7203
|
ColorPicker,
|
|
7105
7204
|
{
|
|
7106
7205
|
colorPicker,
|
|
@@ -7109,7 +7208,7 @@ function ModelViewer({
|
|
|
7109
7208
|
setItemMaterials
|
|
7110
7209
|
}
|
|
7111
7210
|
),
|
|
7112
|
-
materialPopup && /* @__PURE__ */ jsx19(
|
|
7211
|
+
customObjectBindingDataPanel && materialPopup && /* @__PURE__ */ jsx19(
|
|
7113
7212
|
MaterialPicker,
|
|
7114
7213
|
{
|
|
7115
7214
|
triggerFileUpload,
|
|
@@ -7147,7 +7246,7 @@ function ModelViewer({
|
|
|
7147
7246
|
}
|
|
7148
7247
|
|
|
7149
7248
|
// src/components/BindingBuilder/BindingBuilder.tsx
|
|
7150
|
-
import { useCallback as useCallback8, useEffect as useEffect19, useMemo as useMemo16, useRef as
|
|
7249
|
+
import { useCallback as useCallback8, useEffect as useEffect19, useMemo as useMemo16, useRef as useRef18, useState as useState24 } from "react";
|
|
7151
7250
|
import {
|
|
7152
7251
|
Redo2,
|
|
7153
7252
|
Undo2,
|
|
@@ -7161,7 +7260,7 @@ import {
|
|
|
7161
7260
|
styleInject('.bb-root {\n --bb-font-family:\n Inter,\n "Segoe UI",\n Helvetica,\n Arial,\n sans-serif;\n --bb-app-bg:\n radial-gradient(\n \n circle at top left,\n rgba(226, 232, 240, 0.8),\n transparent 30% ),\n linear-gradient(\n 135deg,\n #f6f1e8 0%,\n #ebe8df 40%,\n #e9edf2 100%);\n --bb-app-text: #111827;\n --bb-sidebar-bg:\n linear-gradient(\n 180deg,\n rgba(20, 27, 45, 0.98),\n rgba(25, 34, 57, 0.95)),\n #121826;\n --bb-sidebar-text: #f8fafc;\n --bb-sidebar-muted-text: #b3bfd2;\n --bb-sidebar-subtle-text: #94a3b8;\n --bb-sidebar-border: rgba(148, 163, 184, 0.18);\n --bb-sidebar-border-hover: rgba(148, 163, 184, 0.32);\n --bb-sidebar-divider: rgba(148, 163, 184, 0.14);\n --bb-sidebar-surface: rgba(255, 255, 255, 0.04);\n --bb-sidebar-surface-hover: rgba(255, 255, 255, 0.08);\n --bb-sidebar-surface-strong: rgba(255, 255, 255, 0.05);\n --bb-sidebar-eyebrow-bg: rgba(148, 163, 184, 0.16);\n --bb-sidebar-eyebrow-text: #cbd5e1;\n --bb-sidebar-left-shadow: 18px 0 42px rgba(15, 23, 42, 0.12);\n --bb-sidebar-right-shadow: -4px 0 24px rgba(0, 0, 0, 0.35);\n --bb-sidebar-chip-bg: rgba(15, 23, 42, 0.42);\n --bb-sidebar-chip-border: rgba(148, 163, 184, 0.14);\n --bb-sidebar-accent: rgba(99, 102, 241, 0.18);\n --bb-sidebar-accent-border: rgba(99, 102, 241, 0.4);\n --bb-sidebar-accent-text: #f8fafc;\n --bb-menu-bg: #1a1f2e;\n --bb-menu-shadow: 0 16px 32px rgba(15, 23, 42, 0.4);\n display: flex;\n height: 100%;\n min-height: 0;\n width: 100%;\n background: var(--bb-app-bg);\n color: var(--bb-app-text);\n font-family: var(--bb-font-family);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: optimizeLegibility;\n font-synthesis: none;\n}\n.bb-root * {\n box-sizing: border-box;\n}\n.bb-root input,\n.bb-root select,\n.bb-root textarea,\n.bb-root button {\n font-family: inherit;\n}\n.bb-sidebar {\n width: 400px;\n min-height: 0;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n background: var(--bb-sidebar-bg);\n color: var(--bb-sidebar-text);\n transition: width 0.24s ease;\n}\n.bb-sidebar--left {\n border-right: 1px solid var(--bb-sidebar-border);\n box-shadow: var(--bb-sidebar-left-shadow);\n}\n.bb-sidebar--right {\n width: 300px;\n border-left: 1px solid var(--bb-sidebar-border);\n box-shadow: var(--bb-sidebar-right-shadow);\n}\n.bb-sidebar--collapsed {\n width: 36px;\n}\n.bb-sidebar--collapsed .bb-header {\n padding: 5px;\n display: flex;\n justify-content: center;\n}\n.bb-sidebar--collapsed .bb-header--sidebar {\n min-height: 36px;\n}\n.bb-sidebar--collapsed .bb-sidebarToggle {\n width: 26px;\n height: 26px;\n font-size: 12px;\n}\n.bb-header {\n padding: 5px 20px;\n border-bottom: 1px solid var(--bb-sidebar-divider);\n}\n.bb-header--sidebar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n min-height: 55px;\n}\n.bb-eyebrow {\n display: inline-block;\n margin-bottom: 12px;\n padding: 6px 10px;\n border-radius: 999px;\n background: var(--bb-sidebar-eyebrow-bg);\n color: var(--bb-sidebar-eyebrow-text);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.18em;\n text-transform: uppercase;\n}\n.bb-title {\n margin: 0 0 0px;\n font-size: 20px;\n line-height: 0.95;\n letter-spacing: -0.04em;\n font-weight: 800;\n color: var(--bb-sidebar-text);\n}\n.bb-sidebarToggle {\n width: 36px;\n height: 36px;\n flex-shrink: 0;\n border-radius: 6px;\n border: 1px solid var(--bb-sidebar-border);\n background: var(--bb-sidebar-surface-strong);\n color: var(--bb-sidebar-text);\n font-size: 16px;\n font-weight: 800;\n cursor: pointer;\n transition:\n transform 0.18s ease,\n background-color 0.18s ease,\n border-color 0.18s ease;\n}\n.bb-sidebarToggle:hover {\n transform: translateY(-1px);\n background: var(--bb-sidebar-surface-hover);\n border-color: var(--bb-sidebar-border-hover);\n}\n.bb-subtitle {\n margin: 0;\n max-width: 32ch;\n font-size: 15px;\n line-height: 1.7;\n color: var(--bb-sidebar-muted-text);\n}\n.bb-statRow {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 10px;\n margin-top: 22px;\n}\n.bb-statChip {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n padding: 12px 14px;\n border-radius: 8px;\n background: var(--bb-sidebar-chip-bg);\n border: 1px solid var(--bb-sidebar-chip-border);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);\n}\n.bb-statChip strong {\n font-size: 13px;\n color: var(--bb-sidebar-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.bb-statLabel {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--bb-sidebar-subtle-text);\n}\n.bb-tabRow {\n display: flex;\n gap: 6px;\n padding: 10px 20px 10px;\n}\n.bb-tab {\n flex: 1;\n padding: 6px 10px;\n border-radius: 6px;\n border: 1px solid var(--bb-sidebar-border);\n background: var(--bb-sidebar-surface);\n color: var(--bb-sidebar-muted-text);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n cursor: pointer;\n transition:\n background-color 0.18s ease,\n border-color 0.18s ease,\n color 0.18s ease;\n}\n.bb-tab:hover {\n background: var(--bb-sidebar-surface-hover);\n border-color: var(--bb-sidebar-border-hover);\n}\n.bb-tab--active {\n background: var(--bb-sidebar-accent);\n border-color: var(--bb-sidebar-accent-border);\n color: var(--bb-sidebar-accent-text);\n}\n.bb-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 10px;\n padding: 8px 20px 8px;\n border-bottom: 1px solid var(--bb-sidebar-divider);\n flex-wrap: wrap;\n}\n.bb-toolbarGroup {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.bb-toolbarDivider {\n width: 1px;\n align-self: stretch;\n background: var(--bb-sidebar-divider);\n margin: 0;\n}\n.bb-iconButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border-radius: 7px;\n border: 1px solid var(--bb-sidebar-border);\n background: var(--bb-sidebar-surface);\n color: var(--bb-sidebar-text);\n cursor: pointer;\n transition: background-color 0.18s ease, border-color 0.18s ease;\n}\n.bb-iconButton:hover:not(:disabled) {\n background: var(--bb-sidebar-surface-hover);\n border-color: var(--bb-sidebar-border-hover);\n}\n.bb-iconButton:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.bb-exportMenuWrapper {\n position: relative;\n display: inline-flex;\n}\n.bb-exportMenu {\n position: absolute;\n bottom: calc(100% + 6px);\n right: 0;\n z-index: 20;\n display: flex;\n flex-direction: column;\n min-width: 150px;\n padding: 6px;\n border-radius: 9px;\n border: 1px solid var(--bb-sidebar-border);\n background: var(--bb-menu-bg);\n box-shadow: var(--bb-menu-shadow);\n}\n.bb-exportMenuItem {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n border: none;\n border-radius: 6px;\n background: transparent;\n color: var(--bb-sidebar-text);\n font-size: 12px;\n font-weight: 600;\n text-align: left;\n cursor: pointer;\n}\n.bb-exportMenuItem:hover {\n background: var(--bb-sidebar-surface-hover);\n}\n@media (max-width: 640px) {\n .bb-toolbarDivider {\n width: 100%;\n height: 1px;\n }\n}\n.bb-button,\n.bb-fileLabel {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-height: 32px;\n padding: 0 12px;\n border-radius: 7px;\n border: 1px solid var(--bb-sidebar-border);\n background: var(--bb-sidebar-surface);\n color: var(--bb-sidebar-text);\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n transition:\n transform 0.18s ease,\n background-color 0.18s ease,\n border-color 0.18s ease,\n box-shadow 0.18s ease;\n}\n.bb-button:hover,\n.bb-fileLabel:hover {\n transform: translateY(-1px);\n background: rgba(255, 255, 255, 0.08);\n border-color: rgba(148, 163, 184, 0.32);\n box-shadow: 0 10px 18px rgba(15, 23, 42, 0.18);\n}\n.bb-button:disabled,\n.bb-fileLabel:has(.bb-hiddenInput:disabled) {\n opacity: 0.55;\n cursor: not-allowed;\n transform: none;\n box-shadow: none;\n}\n.bb-button--primary {\n background: #135bc0;\n border-color: transparent;\n color: #ffffff;\n}\n.bb-button--primary:hover {\n background: #1a68d6;\n}\n.bb-button--ghost {\n background: rgba(248, 250, 252, 0.08);\n}\n.bb-hiddenInput {\n display: none;\n}\n.bb-statusCard {\n margin-top: 4px;\n padding: 14px 16px;\n border-radius: 9px;\n background: rgba(15, 23, 42, 0.44);\n border: 1px solid rgba(148, 163, 184, 0.15);\n}\n.bb-statusCard--error {\n background: rgba(127, 29, 29, 0.32);\n border-color: rgba(248, 113, 113, 0.24);\n}\n.bb-statusCard--success {\n background: rgba(6, 78, 59, 0.34);\n border-color: rgba(52, 211, 153, 0.24);\n}\n.bb-statusTitle {\n margin-bottom: 6px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: #cbd5e1;\n}\n.bb-status {\n font-size: 13px;\n line-height: 1.55;\n color: #e2e8f0;\n}\n.bb-status--error {\n color: #fecaca;\n}\n.bb-status--success {\n color: #bbf7d0;\n}\n.bb-input--error {\n border-color: #dc2626;\n}\n.bb-nodeList {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-height: 0;\n overflow: hidden;\n background: #141824;\n}\n.bb-sectionHead {\n padding: 24px 20px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\n}\n.bb-sectionKicker {\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: #64748b;\n}\n.bb-sectionHeading {\n margin-top: 4px;\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: #f1f5f9;\n}\n.bb-search {\n padding: 14px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\n}\n.bb-input,\n.bb-select,\n.bb-textarea {\n width: 100%;\n border-radius: 10px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n background: rgba(255, 255, 255, 0.05);\n color: #e2e8f0;\n padding: 10px 14px;\n font-size: 13px;\n line-height: 1.45;\n}\n.bb-input::placeholder,\n.bb-textarea::placeholder {\n color: #475569;\n}\n.bb-input--compact {\n width: 64px;\n max-width: 64px;\n flex: 0 0 auto;\n padding: 7px 4px;\n text-align: center;\n}\n.bb-input:focus,\n.bb-select:focus,\n.bb-textarea:focus {\n outline: none;\n border-color: rgba(255, 255, 255, 0.18);\n background: rgba(255, 255, 255, 0.08);\n box-shadow: none;\n}\n.bb-textarea {\n min-height: 110px;\n resize: vertical;\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Monaco,\n Consolas,\n monospace;\n}\n.bb-nodeItems {\n min-height: 0;\n overflow-y: auto;\n padding: 10px 0;\n}\n.bb-nodeButton {\n width: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n padding: 12px 20px;\n margin-bottom: 0;\n text-align: left;\n cursor: pointer;\n transition: background-color 0.12s ease, color 0.12s ease;\n border-bottom: 1px solid rgba(255, 255, 255, 0.04);\n}\n.bb-nodeButton:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.bb-nodeButton--active {\n background: rgba(255, 255, 255, 0.05);\n box-shadow: none;\n}\n.bb-nodeName {\n display: block;\n margin-bottom: 2px;\n font-size: 14px;\n font-weight: 600;\n color: #e2e8f0;\n}\n.bb-nodeMeta {\n display: block;\n font-size: 11px;\n color: #94a3b8;\n}\n.bb-editor {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n overflow-y: auto;\n padding: 16px 16px 28px;\n overscroll-behavior: contain;\n}\n.bb-editorHeader {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 18px;\n padding: 18px;\n border-radius: 11px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(148, 163, 184, 0.12);\n}\n.bb-editorTitle {\n margin: 8px 0 0;\n font-size: 24px;\n line-height: 1.1;\n color: #f8fafc;\n}\n.bb-editorMeta {\n display: flex;\n flex-wrap: wrap;\n gap: 8px 12px;\n margin-top: 10px;\n font-size: 12px;\n color: #94a3b8;\n}\n.bb-editorBadge {\n flex-shrink: 0;\n padding: 8px 12px;\n border-radius: 999px;\n background: rgba(251, 191, 36, 0.12);\n border: 1px solid rgba(251, 191, 36, 0.2);\n color: #fcd34d;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n.bb-emptyEditor {\n padding: 28px 8px;\n font-size: 14px;\n color: #a7b1c3;\n}\n.bb-section {\n margin-bottom: 10px;\n border-radius: 7px;\n background: rgba(255, 255, 255, 0.03);\n border: 1px solid rgba(148, 163, 184, 0.12);\n overflow: hidden;\n}\n.bb-sectionHeaderButton {\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n border: none;\n background: rgba(255, 255, 255, 0.03);\n padding: 11px 14px;\n cursor: pointer;\n text-align: left;\n color: inherit;\n}\n.bb-sectionHeaderButton:hover {\n background: rgba(255, 255, 255, 0.06);\n}\n.bb-sectionHeaderMain {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: 8px;\n}\n.bb-sectionChevron {\n flex-shrink: 0;\n color: #8b97ab;\n transform: rotate(-90deg);\n transition: transform 0.18s ease;\n}\n.bb-sectionChevron--open {\n transform: rotate(0deg);\n}\n.bb-sectionBody {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 14px;\n border-top: 1px solid rgba(148, 163, 184, 0.1);\n}\n.bb-sectionTitle {\n margin: 0;\n font-size: 11px;\n font-weight: 700;\n color: #c3cbdb;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n}\n.bb-sectionHelp {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-left: 2px;\n border-radius: 999px;\n color: #b9c0ca;\n cursor: help;\n transition:\n background 0.18s ease,\n color 0.18s ease,\n transform 0.18s ease;\n}\n.bb-sectionHelp:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #eef2ff;\n transform: translateY(-0.5px);\n}\n.bb-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 10px;\n}\n.bb-presetGallery {\n display: flex;\n justify-items: center;\n flex-wrap: wrap;\n gap: 4px;\n margin-bottom: 14px;\n}\n.bb-presetSwatch {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 5px;\n width: 64px;\n padding: 6px 4px;\n border-radius: 8px;\n border: 1px solid rgba(148, 163, 184, 0.18);\n background: rgba(148, 163, 184, 0.06);\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n}\n.bb-presetSwatch:hover:not(:disabled) {\n border-color: rgba(148, 163, 184, 0.4);\n background: rgba(148, 163, 184, 0.12);\n}\n.bb-presetSwatch:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.bb-presetSwatchColor {\n width: 32px;\n height: 32px;\n border-radius: 999px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n}\n.bb-presetSwatchLabel {\n font-size: 10px;\n font-weight: 600;\n color: #cbd5e1;\n text-align: center;\n line-height: 1.2;\n}\n.bb-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n.bb-field--full {\n grid-column: 1 / -1;\n}\n.bb-label {\n font-size: 12px;\n font-weight: 700;\n color: #d7dee9;\n}\n.bb-note {\n font-size: 11px;\n color: #8b97ab;\n}\n.bb-tierLock {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 16px 14px;\n border-radius: 7px;\n background: rgba(251, 191, 36, 0.08);\n border: 1px dashed rgba(251, 191, 36, 0.3);\n color: #fcd34d;\n}\n.bb-tierLockMessage {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n}\n.bb-root--licenseChecking,\n.bb-root--licenseInvalid {\n align-items: center;\n justify-content: center;\n}\n.bb-readonly {\n background: rgba(148, 163, 184, 0.08);\n color: #9ca3af;\n}\n.bb-checkboxRow {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n}\n.bb-checkbox {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 6px 5px;\n border-radius: 7px;\n background: rgba(15, 23, 42, 0.22);\n border: 1px solid rgba(148, 163, 184, 0.12);\n font-size: 13px;\n color: #d7dee9;\n}\n.bb-checkbox input {\n accent-color: #f59e0b;\n}\n.bb-sliderField {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n.bb-slider {\n flex: 1 1 auto;\n min-width: 0;\n accent-color: #2aa8d8;\n}\n.bb-slider--unset {\n opacity: 0.45;\n}\n.bb-fileField {\n position: relative;\n display: flex;\n align-items: center;\n}\n.bb-fileField-input {\n width: 100%;\n padding-right: 40px;\n}\n.bb-fileFieldButton {\n position: absolute;\n right: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: none;\n border-radius: 5px;\n background: transparent;\n color: #aab4c5;\n cursor: pointer;\n}\n.bb-fileFieldButton:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #f8fafc;\n}\n.bb-materialPanel {\n margin-top: 8px;\n border: 1px solid rgba(148, 163, 184, 0.14);\n border-radius: 6px;\n background: rgba(15, 23, 42, 0.28);\n overflow: hidden;\n}\n.bb-materialPanel:first-of-type {\n margin-top: 0;\n}\n.bb-materialPanelHeader {\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n border: none;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.03);\n cursor: pointer;\n text-align: left;\n color: inherit;\n}\n.bb-materialPanelHeader:hover {\n background: rgba(255, 255, 255, 0.06);\n}\n.bb-materialPanelTitleWrap {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: #dbe4f0;\n}\n.bb-materialPanelChevron {\n flex-shrink: 0;\n color: #8b97ab;\n transform: rotate(-90deg);\n transition: transform 0.18s ease;\n}\n.bb-materialPanelChevron--open {\n transform: rotate(0deg);\n}\n.bb-materialPanelTitle {\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.1em;\n text-transform: uppercase;\n}\n.bb-materialPanelHelp {\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-left: 2px;\n border-radius: 999px;\n color: #b9c0ca;\n cursor: help;\n transition:\n background 0.18s ease,\n color 0.18s ease,\n transform 0.18s ease;\n}\n.bb-materialPanelHelp:hover {\n background: rgba(255, 255, 255, 0.08);\n color: #eef2ff;\n transform: translateY(-0.5px);\n}\n.bb-materialPanelBody {\n padding: 12px;\n border-top: 1px solid rgba(148, 163, 184, 0.1);\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n.bb-actionList {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.bb-actionCard {\n border: 1px solid rgba(148, 163, 184, 0.14);\n border-radius: 9px;\n padding: 14px;\n background: rgba(15, 23, 42, 0.2);\n}\n.bb-actionCardHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n margin-bottom: 12px;\n}\n.bb-actionCardTitle {\n font-size: 13px;\n font-weight: 700;\n color: #f8fafc;\n}\n.bb-actionCardMeta {\n flex-shrink: 0;\n padding: 5px 9px;\n border-radius: 999px;\n background: rgba(148, 163, 184, 0.12);\n color: #94a3b8;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n.bb-actionGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 10px;\n}\n.bb-actionFooter {\n margin-top: 12px;\n}\n.bb-actionRemove {\n width: 100%;\n}\n.bb-previewShell {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding: 5px;\n overflow: hidden;\n}\n.bb-previewHeader {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n padding: 0 4px 10px;\n}\n.bb-previewControls {\n display: flex;\n align-items: flex-start;\n justify-content: flex-end;\n gap: 10px;\n flex-wrap: wrap;\n}\n.bb-previewTitle {\n margin: 2px 0 0;\n font-size: 20px;\n line-height: 1.05;\n letter-spacing: -0.03em;\n color: #1f2937;\n}\n.bb-previewToggles {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n}\n.bb-checkbox--compact {\n gap: 5px;\n padding: 0;\n background: transparent;\n border: none;\n font-size: 10px;\n font-weight: 500;\n line-height: 1;\n color: #4b5563;\n}\n.bb-checkbox--compact:hover {\n background: transparent;\n transform: none;\n}\n.bb-checkbox--compact input[type=checkbox] {\n width: 11px;\n height: 11px;\n}\n.bb-previewMeta {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 8px;\n}\n.bb-removeModelButton {\n background-color: rgb(174, 54, 54);\n min-height: 34px;\n padding: 0 14px;\n}\n.bb-removeModelButton:hover {\n background-color: rgb(163, 20, 20);\n}\n.bb-previewMeta span {\n display: inline-flex;\n align-items: center;\n min-height: 34px;\n padding: 0 12px;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.7);\n border: 1px solid rgba(148, 163, 184, 0.18);\n color: #475569;\n font-size: 12px;\n font-weight: 700;\n}\n.bb-preview {\n position: relative;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n border-radius: 14px;\n background:\n radial-gradient(\n circle at top left,\n rgba(255, 255, 255, 0.92),\n rgba(236, 240, 244, 0.82)),\n #f8fafc;\n border: 1px solid rgba(148, 163, 184, 0.24);\n box-shadow: 0 24px 48px rgba(148, 163, 184, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.7);\n}\n.bb-loadingOverlay {\n position: absolute;\n inset: 0;\n z-index: 5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 16px;\n padding: 24px;\n text-align: center;\n border-radius: 14px;\n background: rgba(248, 250, 252, 0.82);\n backdrop-filter: blur(2px);\n}\n.bb-loadingSpinner {\n width: 40px;\n height: 40px;\n border-radius: 999px;\n border: 3px solid rgba(148, 163, 184, 0.3);\n border-top-color: #2563eb;\n animation: bb-spin 0.8s linear infinite;\n}\n@keyframes bb-spin {\n to {\n transform: rotate(360deg);\n }\n}\n.bb-loadingMessage {\n max-width: 320px;\n color: #475569;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.5;\n}\n.bb-previewStatus {\n max-width: 280px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bb-previewStatus--success {\n background: rgba(34, 197, 94, 0.12) !important;\n border-color: rgba(34, 197, 94, 0.3) !important;\n color: #15803d !important;\n}\n.bb-previewStatus--error {\n background: rgba(239, 68, 68, 0.12) !important;\n border-color: rgba(239, 68, 68, 0.3) !important;\n color: #b91c1c !important;\n}\n.bb-previewModelName {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.bb-previewPlaceholder {\n position: relative;\n display: flex;\n height: 100%;\n width: 100%;\n align-items: center;\n justify-content: center;\n padding: 40px;\n text-align: center;\n color: #64748b;\n font-size: 15px;\n line-height: 1.7;\n border-radius: 14px;\n border: 2px dashed rgba(148, 163, 184, 0.24);\n background:\n radial-gradient(\n circle at top,\n rgba(251, 191, 36, 0.12),\n transparent 30%),\n linear-gradient(\n 180deg,\n rgba(255, 255, 255, 0.82),\n rgba(238, 242, 248, 0.9));\n transition:\n border-color 0.2s ease,\n background 0.2s ease,\n transform 0.2s ease,\n box-shadow 0.2s ease;\n}\n.bb-previewPlaceholder > div {\n max-width: 420px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 14px;\n}\n.bb-previewPlaceholderTitle {\n font-size: 28px;\n line-height: 1.05;\n letter-spacing: -0.03em;\n font-weight: 800;\n color: #1f2937;\n}\n.bb-previewPlaceholderButton {\n margin-top: 8px;\n border: 0;\n border-radius: 999px;\n padding: 13px 22px;\n background: #135bc0;\n color: #ffffff;\n font-size: 14px;\n font-weight: 800;\n cursor: pointer;\n transition:\n transform 0.18s ease,\n box-shadow 0.18s ease,\n opacity 0.18s ease;\n}\n.bb-previewPlaceholderButton:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 14px 30px rgba(19, 91, 192, 0.28);\n}\n.bb-previewPlaceholderButton:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n.bb-previewPlaceholder--dragActive {\n border-color: rgba(245, 158, 11, 0.75);\n background:\n radial-gradient(\n circle at top,\n rgba(251, 191, 36, 0.22),\n transparent 32%),\n linear-gradient(\n 180deg,\n rgba(255, 252, 245, 0.95),\n rgba(255, 244, 230, 0.92));\n transform: scale(0.995);\n box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.14);\n}\n.bb-sectionHeader {\n cursor: pointer;\n user-select: none;\n}\n.bb-iconButton {\n background: none;\n border: none;\n cursor: pointer;\n font-size: 16px;\n color: var(--bb-sidebar-subtle-text);\n transition: color 0.2s ease;\n padding: 4px 8px;\n border-radius: 4px;\n}\n.bb-iconButton:hover {\n color: var(--bb-sidebar-text);\n background: var(--bb-sidebar-surface-strong);\n}\n.bb-cameraLive,\n.bb-cameraSaved {\n background: rgba(15, 23, 42, 0.44);\n border-radius: 8px;\n padding: 14px;\n margin-bottom: 16px;\n border: 1px solid rgba(148, 163, 184, 0.15);\n transition: all 0.2s ease;\n}\n.bb-cameraLive:hover,\n.bb-cameraSaved:hover {\n border-color: rgba(148, 163, 184, 0.25);\n background: rgba(15, 23, 42, 0.52);\n}\n.bb-cameraLiveHeader,\n.bb-cameraSavedHeader {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 12px;\n padding-bottom: 8px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.15);\n}\n.bb-cameraLiveBadge {\n background:\n linear-gradient(\n 135deg,\n #10b981,\n #059669);\n color: white;\n font-size: 10px;\n font-weight: 700;\n padding: 3px 8px;\n border-radius: 10px;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n}\n.bb-cameraSavedBadge {\n background:\n linear-gradient(\n 135deg,\n #3b82f6,\n #2563eb);\n color: white;\n font-size: 10px;\n font-weight: 700;\n padding: 3px 8px;\n border-radius: 10px;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n}\n.bb-cameraLiveLabel,\n.bb-cameraSavedLabel {\n font-size: 12px;\n font-weight: 600;\n color: #cbd5e1;\n}\n.bb-cameraValues {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.bb-cameraRow {\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 12px;\n flex-wrap: wrap;\n}\n.bb-cameraLabel {\n font-weight: 600;\n color: #94a3b8;\n min-width: 58px;\n font-size: 11px;\n letter-spacing: 0.02em;\n}\n.bb-cameraCode {\n font-family:\n "Monaco",\n "Menlo",\n "Ubuntu Mono",\n "Consolas",\n monospace;\n font-size: 11px;\n background: rgba(0, 0, 0, 0.3);\n padding: 3px 8px;\n border-radius: 4px;\n color: #fcd34d;\n letter-spacing: 0.02em;\n word-break: break-all;\n}\n.bb-cameraPlaceholder {\n color: #94a3b8;\n font-size: 12px;\n text-align: center;\n padding: 16px;\n font-style: italic;\n}\n.bb-cameraControls {\n display: flex;\n gap: 10px;\n margin-bottom: 14px;\n flex-wrap: wrap;\n}\n.bb-button--primary {\n background: #135bc0;\n border-color: transparent;\n color: #ffffff;\n}\n.bb-button--primary:hover:not(:disabled) {\n background: #1a68d6;\n transform: translateY(-1px);\n}\n.bb-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n}\n.bb-cameraMessage {\n padding: 10px 14px;\n border-radius: 6px;\n margin-bottom: 14px;\n font-size: 12px;\n font-weight: 500;\n animation: slideIn 0.3s ease-out;\n}\n.bb-cameraMessage--success {\n background: rgba(16, 185, 129, 0.15);\n color: #6ee7b7;\n border: 1px solid rgba(16, 185, 129, 0.3);\n}\n.bb-cameraMessage--error {\n background: rgba(239, 68, 68, 0.15);\n color: #ffe5e55c;\n border: 1px solid rgba(255, 248, 248, 0.3);\n}\n@keyframes slideIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.bb-readonly {\n background: rgba(148, 163, 184, 0.08);\n color: #9ca3af;\n cursor: default;\n}\n@media (max-width: 1280px) {\n .bb-cameraRow {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n .bb-cameraLabel {\n min-width: auto;\n }\n .bb-cameraControls {\n flex-direction: column;\n }\n .bb-cameraControls .bb-button {\n width: 100%;\n }\n}\n@media (max-width: 980px) {\n .bb-sidebar--left {\n width: 100%;\n max-height: 42vh;\n }\n .bb-sidebar--collapsed {\n width: 100%;\n }\n .bb-previewShell {\n padding: 14px;\n }\n .bb-preview {\n min-height: 44vh;\n }\n .bb-previewHeader {\n flex-direction: column;\n align-items: flex-start;\n }\n .bb-previewControls {\n width: 100%;\n justify-content: flex-start;\n }\n .bb-previewMeta {\n justify-content: flex-start;\n }\n .bb-grid,\n .bb-actionGrid,\n .bb-statRow {\n grid-template-columns: 1fr;\n }\n}\n.bb-annotationsInfo {\n margin-top: 8px;\n}\n.bb-emptyAnnotations {\n padding: 32px;\n text-align: center;\n background: #f5f5f5;\n border-radius: 4px;\n color: #666;\n font-size: 14px;\n}\n.bb-annotationsList {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.bb-annotationCard {\n background: #f9f9f9;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n padding: 12px;\n transition: all 0.2s ease;\n}\n.bb-annotationCard:hover {\n background: #ffffff;\n border-color: #4caf50;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.bb-annotationHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n.bb-annotationBadge {\n background: #4caf50;\n color: white;\n padding: 2px 8px;\n border-radius: 2px;\n font-size: 11px;\n font-weight: 600;\n}\n.bb-annotationActions {\n display: flex;\n gap: 8px;\n}\n.bb-annotationEdit,\n.bb-annotationDelete {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 4px;\n border-radius: 2px;\n font-size: 14px;\n transition: all 0.2s ease;\n}\n.bb-annotationEdit:hover {\n background: #e8f5e9;\n transform: scale(1.05);\n}\n.bb-annotationDelete:hover {\n background: #ffebee;\n transform: scale(1.05);\n}\n.bb-annotationTitle {\n font-weight: 600;\n font-size: 14px;\n color: #333;\n margin-bottom: 6px;\n}\n.bb-annotationDescription {\n font-size: 13px;\n color: #666;\n margin-bottom: 8px;\n line-height: 1.4;\n}\n.bb-annotationPosition {\n font-size: 11px;\n font-family: monospace;\n color: #999;\n background: #f0f0f0;\n padding: 4px 6px;\n border-radius: 2px;\n display: inline-block;\n}\n.bb-modalOverlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n.bb-modal {\n background: white;\n border-radius: 6px;\n width: 500px;\n max-width: 90%;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\n animation: modalSlideIn 0.2s ease;\n}\n@keyframes modalSlideIn {\n from {\n transform: translateY(-20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n.bb-modalHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px 20px;\n border-bottom: 1px solid #e0e0e0;\n}\n.bb-modalHeader h3 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n}\n.bb-modalClose {\n background: transparent;\n border: none;\n font-size: 20px;\n cursor: pointer;\n color: #999;\n transition: color 0.2s ease;\n}\n.bb-modalClose:hover {\n color: #333;\n}\n.bb-modalBody {\n padding: 20px;\n}\n.bb-modalFooter {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 16px 20px;\n border-top: 1px solid #e0e0e0;\n}\n.bb-annotationsInfo {\n margin-top: 8px;\n}\n.bb-emptyAnnotations {\n padding: 32px;\n text-align: center;\n background: rgba(15, 23, 42, 0.44);\n border-radius: 10px;\n border: 1px solid rgba(148, 163, 184, 0.15);\n color: #94a3b8;\n font-size: 14px;\n}\n.bb-annotationsList {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.bb-annotationCard {\n background: rgba(15, 23, 42, 0.44);\n border-left: 4px solid #22d3ee;\n border-radius: 8px;\n padding: 16px;\n transition: all 0.2s ease;\n border: 1px solid rgba(148, 163, 184, 0.15);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n}\n.bb-annotationCard:hover {\n transform: translateX(4px);\n background: rgba(15, 23, 42, 0.6);\n border-color: rgba(148, 163, 184, 0.25);\n box-shadow: 0 4px 12px rgba(15, 23, 42, 0.3);\n}\n.bb-annotationBadge {\n display: inline-block;\n background: #22d3ee;\n color: #06343c;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n text-transform: uppercase;\n}\n.bb-annotationTitle {\n font-weight: 700;\n font-size: 15px;\n color: #f8fafc;\n margin-bottom: 8px;\n line-height: 1.3;\n}\n.bb-annotationDescription {\n font-size: 13px;\n color: #cbd5e1;\n margin-bottom: 12px;\n line-height: 1.5;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n.bb-annotationPosition {\n font-size: 11px;\n font-family:\n "Monaco",\n "Menlo",\n "Ubuntu Mono",\n "Consolas",\n monospace;\n color: #94a3b8;\n background: rgba(0, 0, 0, 0.3);\n padding: 4px 8px;\n border-radius: 4px;\n display: inline-block;\n margin-top: 4px;\n letter-spacing: 0.02em;\n}\n.bb-annotationHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n.bb-annotationActions {\n display: flex;\n gap: 4px;\n}\n.bb-annotationAction {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 4px;\n border-radius: 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n}\n.bb-annotationAction--edit:hover {\n border-radius: 50%;\n background: rgba(59, 130, 246, 0.2);\n color: #3b82f6;\n}\n.bb-annotationAction--delete:hover {\n border-radius: 50%;\n background: rgba(239, 68, 68, 0.2);\n color: #ef4444;\n}\n.bb-editSpotOverlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n.bb-editSpotPopup {\n background:\n linear-gradient(\n 180deg,\n rgba(20, 27, 45, 0.98),\n rgba(25, 34, 57, 0.95)),\n #121826;\n border-radius: 8px;\n padding: 24px;\n min-width: 400px;\n max-width: 500px;\n border: 1px solid rgba(148, 163, 184, 0.18);\n box-shadow: 0 24px 48px rgba(15, 23, 42, 0.3);\n}\n.bb-editSpotHeader {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n.bb-editSpotTitle {\n color: #f8fafc;\n font-size: 18px;\n font-weight: 600;\n margin: 0;\n}\n.bb-editSpotClose {\n background: none;\n border: none;\n color: #94a3b8;\n font-size: 24px;\n cursor: pointer;\n padding: 0 4px;\n transition: color 0.2s ease;\n}\n.bb-editSpotClose:hover {\n color: #f8fafc;\n}\n.bb-editSpotBody {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.bb-editSpotBody .bb-input,\n.bb-editSpotBody .bb-textarea {\n background: rgba(15, 23, 42, 0.4);\n border-color: rgba(148, 163, 184, 0.2);\n color: #f8fafc;\n}\n.bb-editSpotBody .bb-input:focus,\n.bb-editSpotBody .bb-textarea:focus {\n border-color: rgba(251, 191, 36, 0.65);\n box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.12);\n}\n.bb-editSpotBody .bb-label {\n color: #d7dee9;\n}\n.bb-editSpotActions {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n}\n.bb-editSpotActions .bb-button {\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(148, 163, 184, 0.18);\n color: #e5edf7;\n}\n.bb-editSpotActions .bb-button:hover {\n background: rgba(255, 255, 255, 0.08);\n border-color: rgba(148, 163, 184, 0.32);\n transform: translateY(-1px);\n}\n.bb-button--danger {\n background: #ef4444;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 7px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 4px;\n transition: all 0.2s ease;\n}\n.bb-button--danger:hover {\n background: #dc2626;\n transform: translateY(-1px);\n box-shadow: 0 10px 18px rgba(239, 68, 68, 0.25);\n}\n.bb-button--primary {\n background: #135bc0;\n border-color: transparent;\n color: #ffffff;\n}\n.bb-button--primary:hover {\n background: #1a68d6;\n}\n.bb-annotationCard {\n background: rgba(15, 23, 42, 0.44);\n border-left: 4px solid #22d3ee;\n border-radius: 8px;\n padding: 16px;\n transition: all 0.2s ease;\n border: 1px solid rgba(148, 163, 184, 0.15);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);\n}\n.bb-annotationCard:hover {\n transform: translateX(4px);\n background: rgba(15, 23, 42, 0.6);\n border-color: rgba(148, 163, 184, 0.25);\n box-shadow: 0 4px 12px rgba(15, 23, 42, 0.3);\n}\n.bb-annotationBadge {\n display: inline-block;\n background: #22d3ee;\n color: #06343c;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 0.5px;\n margin-bottom: 12px;\n text-transform: uppercase;\n}\n.bb-annotationTitle {\n font-weight: 700;\n font-size: 15px;\n color: #f8fafc;\n margin-bottom: 8px;\n line-height: 1.3;\n}\n.bb-annotationDescription {\n font-size: 13px;\n color: #cbd5e1;\n margin-bottom: 12px;\n line-height: 1.5;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n.bb-annotationPosition {\n font-size: 11px;\n font-family:\n "Monaco",\n "Menlo",\n "Ubuntu Mono",\n "Consolas",\n monospace;\n color: #94a3b8;\n background: rgba(0, 0, 0, 0.3);\n padding: 4px 8px;\n border-radius: 4px;\n display: inline-block;\n margin-top: 4px;\n letter-spacing: 0.02em;\n}\n.bb-emptyAnnotations {\n padding: 32px;\n text-align: center;\n background: rgba(15, 23, 42, 0.44);\n border-radius: 10px;\n border: 1px solid rgba(148, 163, 184, 0.15);\n color: #94a3b8;\n font-size: 14px;\n}\n@media (max-width: 1280px) {\n .bb-cameraRow {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n .bb-cameraLabel {\n min-width: auto;\n }\n .bb-cameraControls {\n flex-direction: column;\n }\n .bb-cameraControls .bb-button {\n width: 100%;\n }\n}\n@media (max-width: 1120px) {\n .bb-sidebar--left {\n width: 320px;\n }\n .bb-sidebar--right {\n width: 220px;\n }\n .bb-grid {\n grid-template-columns: 1fr;\n }\n .bb-statRow {\n grid-template-columns: 1fr;\n }\n}\n@media (max-width: 980px) {\n .bb-root {\n flex-direction: column;\n height: auto;\n min-height: 0;\n }\n .bb-sidebar--left {\n width: 100% !important;\n max-height: 45vh;\n border-right: none;\n border-bottom: 1px solid rgba(148, 163, 184, 0.18);\n box-shadow: 0 18px 42px rgba(15, 23, 42, 0.12);\n }\n .bb-sidebar--right {\n width: 100% !important;\n max-height: 45vh;\n border-left: none;\n border-top: 1px solid rgba(148, 163, 184, 0.18);\n box-shadow: 0 -18px 42px rgba(15, 23, 42, 0.12);\n order: 3;\n }\n .bb-sidebar--collapsed {\n width: 100% !important;\n max-height: 72px;\n overflow: hidden;\n }\n .bb-sidebar--collapsed .bb-nodeList,\n .bb-sidebar--collapsed .bb-tabRow,\n .bb-sidebar--collapsed .bb-toolbar {\n display: none;\n }\n .bb-previewShell {\n flex: 1 1 auto;\n min-height: 50vh;\n padding: 14px;\n order: 2;\n }\n .bb-preview {\n min-height: 44vh;\n border-radius: 10px;\n }\n .bb-previewHeader {\n flex-direction: column;\n align-items: flex-start;\n gap: 12px;\n }\n .bb-previewControls {\n width: 100%;\n justify-content: flex-start;\n flex-wrap: wrap;\n }\n .bb-previewMeta {\n justify-content: flex-start;\n }\n .bb-previewMeta span {\n font-size: 11px;\n padding: 0 10px;\n min-height: 30px;\n }\n .bb-grid,\n .bb-actionGrid,\n .bb-statRow {\n grid-template-columns: 1fr;\n }\n .bb-editor {\n padding: 12px 12px 20px;\n }\n .bb-editorHeader {\n flex-direction: column;\n align-items: stretch;\n padding: 14px;\n }\n .bb-editorTitle {\n font-size: 20px;\n }\n .bb-editorBadge {\n align-self: flex-start;\n }\n .bb-toolbar {\n flex-direction: column;\n gap: 12px;\n padding: 16px 20px 18px;\n }\n .bb-toolbarDivider {\n width: 100%;\n height: 1px;\n margin: 0;\n }\n .bb-tabRow {\n padding: 12px 16px 0;\n gap: 6px;\n }\n .bb-tab {\n font-size: 10px;\n padding: 8px 10px;\n }\n .bb-header {\n padding: 14px 16px 12px;\n }\n .bb-header--sidebar {\n min-height: 60px;\n }\n .bb-title {\n font-size: 17px;\n }\n .bb-subtitle {\n font-size: 13px;\n }\n .bb-statChip {\n padding: 10px 12px;\n }\n .bb-statChip strong {\n font-size: 12px;\n }\n .bb-nodeButton {\n padding: 10px 12px;\n }\n .bb-nodeName {\n font-size: 12px;\n }\n .bb-nodeMeta {\n font-size: 10px;\n }\n .bb-section {\n padding: 14px;\n }\n .bb-sectionTitle {\n font-size: 9px;\n }\n .bb-field {\n gap: 4px;\n }\n .bb-label {\n font-size: 11px;\n }\n .bb-input,\n .bb-select,\n .bb-textarea {\n padding: 9px 11px;\n font-size: 12px;\n }\n .bb-textarea {\n min-height: 80px;\n }\n .bb-button,\n .bb-fileLabel {\n min-height: 36px;\n padding: 0 14px;\n font-size: 12px;\n }\n .bb-previewPlaceholderTitle {\n font-size: 22px;\n }\n .bb-previewPlaceholderButton {\n padding: 10px 18px;\n font-size: 13px;\n }\n .bb-editSpotPopup {\n min-width: 90%;\n max-width: 90%;\n padding: 20px;\n }\n .bb-modal {\n width: 95%;\n max-width: 95%;\n }\n .bb-annotationCard {\n padding: 12px;\n }\n .bb-annotationTitle {\n font-size: 14px;\n }\n .bb-annotationDescription {\n font-size: 12px;\n }\n}\n@media (max-width: 640px) {\n .bb-root {\n flex-direction: column;\n height: auto;\n min-height: 0;\n }\n .bb-sidebar--left {\n max-height: 40vh;\n width: 100% !important;\n }\n .bb-sidebar--right {\n max-height: 40vh;\n width: 100% !important;\n }\n .bb-previewShell {\n min-height: 40vh;\n padding: 10px;\n }\n .bb-preview {\n min-height: 35vh;\n border-radius: 8px;\n }\n .bb-previewHeader {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n padding: 0 0 12px;\n }\n .bb-previewTitle {\n font-size: 17px;\n }\n .bb-previewControls {\n gap: 6px;\n }\n .bb-previewMeta span {\n font-size: 10px;\n padding: 0 8px;\n min-height: 26px;\n }\n .bb-editor {\n padding: 10px 10px 16px;\n }\n .bb-editorHeader {\n padding: 12px;\n flex-direction: column;\n align-items: stretch;\n }\n .bb-editorTitle {\n font-size: 18px;\n }\n .bb-editorMeta {\n font-size: 11px;\n gap: 6px 8px;\n }\n .bb-editorBadge {\n font-size: 9px;\n padding: 4px 10px;\n align-self: flex-start;\n }\n .bb-section {\n padding: 12px;\n margin-bottom: 12px;\n }\n .bb-sectionTitle {\n font-size: 9px;\n margin-bottom: 10px;\n }\n .bb-grid {\n gap: 8px;\n }\n .bb-field--full {\n grid-column: 1 / -1;\n }\n .bb-label {\n font-size: 11px;\n }\n .bb-input,\n .bb-select,\n .bb-textarea {\n padding: 8px 10px;\n font-size: 12px;\n border-radius: 6px;\n }\n .bb-textarea {\n min-height: 70px;\n }\n .bb-button,\n .bb-fileLabel {\n min-height: 34px;\n padding: 0 12px;\n font-size: 11px;\n border-radius: 6px;\n }\n .bb-toolbar {\n padding: 12px 14px 14px;\n gap: 10px;\n }\n .bb-tabRow {\n padding: 10px 12px 0;\n gap: 4px;\n }\n .bb-tab {\n font-size: 9px;\n padding: 6px 8px;\n border-radius: 4px;\n }\n .bb-header {\n padding: 10px 12px 8px;\n }\n .bb-header--sidebar {\n min-height: 52px;\n }\n .bb-title {\n font-size: 15px;\n }\n .bb-subtitle {\n font-size: 12px;\n }\n .bb-eyebrow {\n font-size: 9px;\n padding: 4px 8px;\n margin-bottom: 8px;\n }\n .bb-statRow {\n gap: 6px;\n margin-top: 14px;\n }\n .bb-statChip {\n padding: 8px 10px;\n border-radius: 6px;\n }\n .bb-statChip strong {\n font-size: 11px;\n }\n .bb-statLabel {\n font-size: 9px;\n }\n .bb-sidebarToggle {\n width: 30px;\n height: 30px;\n font-size: 14px;\n border-radius: 5px;\n }\n .bb-nodeItems {\n padding: 4px 6px;\n }\n .bb-nodeButton {\n padding: 8px 10px;\n border-radius: 6px;\n margin-bottom: 4px;\n }\n .bb-nodeName {\n font-size: 11px;\n }\n .bb-nodeMeta {\n font-size: 10px;\n }\n .bb-search {\n padding: 8px 10px;\n }\n .bb-statusCard {\n padding: 10px 12px;\n border-radius: 7px;\n }\n .bb-status {\n font-size: 12px;\n }\n .bb-statusTitle {\n font-size: 10px;\n }\n .bb-checkboxRow {\n gap: 6px;\n }\n .bb-checkbox {\n padding: 6px 10px;\n font-size: 12px;\n border-radius: 5px;\n }\n .bb-actionCard {\n padding: 10px;\n border-radius: 7px;\n }\n .bb-actionCardTitle {\n font-size: 12px;\n }\n .bb-actionCardMeta {\n font-size: 9px;\n padding: 3px 7px;\n }\n .bb-previewPlaceholder {\n padding: 24px;\n border-radius: 8px;\n }\n .bb-previewPlaceholderTitle {\n font-size: 18px;\n }\n .bb-previewPlaceholderButton {\n padding: 8px 14px;\n font-size: 12px;\n border-radius: 999px;\n }\n .bb-editSpotPopup {\n min-width: 95%;\n max-width: 95%;\n padding: 16px;\n border-radius: 6px;\n }\n .bb-editSpotTitle {\n font-size: 16px;\n }\n .bb-editSpotActions .bb-button {\n padding: 8px 12px;\n font-size: 12px;\n }\n .bb-modal {\n width: 98%;\n max-width: 98%;\n border-radius: 5px;\n }\n .bb-modalHeader {\n padding: 12px 16px;\n }\n .bb-modalHeader h3 {\n font-size: 16px;\n }\n .bb-modalBody {\n padding: 14px;\n }\n .bb-modalFooter {\n padding: 12px 16px;\n flex-direction: column;\n gap: 8px;\n }\n .bb-modalFooter .bb-button {\n width: 100%;\n justify-content: center;\n }\n .bb-annotationCard {\n padding: 10px;\n border-left-width: 3px;\n border-radius: 6px;\n }\n .bb-annotationTitle {\n font-size: 13px;\n }\n .bb-annotationDescription {\n font-size: 11px;\n }\n .bb-annotationPosition {\n font-size: 10px;\n padding: 3px 6px;\n }\n .bb-annotationBadge {\n font-size: 9px;\n padding: 2px 8px;\n }\n .bb-emptyAnnotations {\n padding: 20px;\n font-size: 12px;\n border-radius: 7px;\n }\n .bb-removeModelButton {\n min-height: 30px;\n padding: 0 10px;\n font-size: 11px;\n }\n .bb-annotationsList {\n gap: 8px;\n }\n .bb-cameraLive,\n .bb-cameraSaved {\n padding: 10px;\n border-radius: 6px;\n }\n .bb-cameraLiveHeader,\n .bb-cameraSavedHeader {\n flex-wrap: wrap;\n }\n .bb-cameraLiveLabel,\n .bb-cameraSavedLabel {\n font-size: 11px;\n }\n .bb-cameraRow {\n font-size: 11px;\n gap: 4px;\n }\n .bb-cameraCode {\n font-size: 10px;\n padding: 2px 6px;\n }\n .bb-cameraControls {\n flex-direction: column;\n gap: 6px;\n }\n .bb-cameraControls .bb-button {\n width: 100%;\n justify-content: center;\n }\n .bb-cameraMessage {\n font-size: 11px;\n padding: 8px 12px;\n }\n .bb-readonly {\n font-size: 11px;\n padding: 6px 8px;\n }\n}\n@media (max-width: 420px) {\n .bb-sidebar--left {\n max-height: 35vh;\n }\n .bb-sidebar--right {\n max-height: 35vh;\n }\n .bb-previewShell {\n min-height: 35vh;\n padding: 6px;\n }\n .bb-preview {\n min-height: 30vh;\n border-radius: 6px;\n }\n .bb-previewTitle {\n font-size: 15px;\n }\n .bb-previewMeta span {\n font-size: 9px;\n padding: 0 6px;\n min-height: 22px;\n }\n .bb-editorTitle {\n font-size: 16px;\n }\n .bb-title {\n font-size: 13px;\n }\n .bb-tab {\n font-size: 8px;\n padding: 5px 6px;\n }\n .bb-button,\n .bb-fileLabel {\n font-size: 10px;\n min-height: 30px;\n padding: 0 10px;\n }\n .bb-input,\n .bb-select,\n .bb-textarea {\n font-size: 11px;\n padding: 6px 8px;\n }\n .bb-statChip {\n padding: 6px 8px;\n }\n .bb-statChip strong {\n font-size: 10px;\n }\n .bb-previewPlaceholderTitle {\n font-size: 15px;\n }\n .bb-previewPlaceholderButton {\n font-size: 11px;\n padding: 6px 12px;\n }\n .bb-editSpotPopup {\n padding: 14px;\n border-radius: 5px;\n }\n .bb-editSpotTitle {\n font-size: 14px;\n }\n .bb-editSpotBody .bb-input,\n .bb-editSpotBody .bb-textarea {\n font-size: 12px;\n padding: 6px 8px;\n }\n .bb-modalHeader h3 {\n font-size: 14px;\n }\n .bb-annotationTitle {\n font-size: 12px;\n }\n}\n@media (max-width: 980px) {\n .bb-sidebar--collapsed .bb-header--sidebar {\n min-height: 52px;\n }\n .bb-sidebar--collapsed .bb-title {\n font-size: 14px;\n }\n .bb-sidebar--collapsed .bb-sidebarToggle {\n width: 28px;\n height: 28px;\n font-size: 12px;\n }\n}\n@media (hover: none) and (pointer: coarse) {\n .bb-nodeButton:hover,\n .bb-button:hover,\n .bb-fileLabel:hover,\n .bb-tab:hover,\n .bb-sidebarToggle:hover,\n .bb-annotationCard:hover {\n transform: none;\n }\n .bb-nodeButton:active,\n .bb-button:active,\n .bb-fileLabel:active,\n .bb-tab:active,\n .bb-sidebarToggle:active {\n transform: scale(0.97);\n transition: transform 0.1s ease;\n }\n}\n@media print {\n .bb-root {\n height: auto;\n min-height: 0;\n background: white;\n }\n .bb-sidebar--left,\n .bb-sidebar--right {\n width: 100% !important;\n max-height: none !important;\n background: white !important;\n color: black !important;\n border: 1px solid #ddd !important;\n box-shadow: none !important;\n }\n .bb-previewShell {\n min-height: auto !important;\n padding: 10px !important;\n }\n .bb-preview {\n min-height: auto !important;\n border-radius: 4px !important;\n border: 1px solid #ddd !important;\n box-shadow: none !important;\n }\n .bb-button,\n .bb-fileLabel,\n .bb-sidebarToggle,\n .bb-tab,\n .bb-annotationAction,\n .bb-iconButton {\n display: none !important;\n }\n .bb-nodeList {\n overflow: visible !important;\n }\n .bb-previewPlaceholderButton {\n display: none !important;\n }\n}\n.bb-checkboxRow {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n align-items: center;\n padding: 4px 0;\n}\n.bb-checkbox {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n border-radius: 7px;\n font-weight: 600;\n font-size: 13px;\n color: #f3eeee;\n cursor: pointer;\n user-select: none;\n transition: all 0.2s ease;\n}\n.bb-checkbox input[type=checkbox] {\n width: 16px;\n height: 16px;\n accent-color: #f59e0b;\n cursor: pointer;\n flex-shrink: 0;\n}\n.bb-editorDivider {\n height: 1px;\n background: rgba(148, 163, 184, 0.14);\n margin: 4px 0 16px 0;\n width: 100%;\n}\n.bb-preview {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n.ri-viewer {\n width: 100% !important;\n height: 100% !important;\n position: relative !important;\n}\n.ri-buttonContainer {\n position: absolute !important;\n bottom: 20px !important;\n right: 20px !important;\n z-index: 10000 !important;\n display: flex !important;\n gap: 10px !important;\n pointer-events: auto !important;\n}\n.ri-downloadButton {\n display: flex !important;\n align-items: center !important;\n gap: 6px !important;\n padding: 10px 12px !important;\n background: #2f302f74 !important;\n color: white !important;\n border: none !important;\n border-radius: 6px !important;\n cursor: pointer !important;\n font-size: 12px !important;\n font-weight: 500 !important;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n.ri-downloadButton svg {\n width: 14px !important;\n height: 14px !important;\n}\n.ri-resetButton {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n padding: 6px !important;\n background: #2f302f74 !important;\n border: none !important;\n border-radius: 6px !important;\n cursor: pointer !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n.ri-resetButton svg {\n width: 14px !important;\n height: 14px !important;\n}\n.bb-reset-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.6);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n backdrop-filter: blur(4px);\n animation: bb-fade-in 0.2s ease;\n}\n.bb-reset-dialog {\n background: #1a1f2e;\n border-radius: 12px;\n max-width: 480px;\n width: 90%;\n border: 1px solid rgba(148, 163, 184, 0.18);\n box-shadow: 0 24px 48px rgba(0, 0, 0, 0.5);\n animation: bb-slide-up 0.25s ease;\n}\n.bb-reset-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px 16px;\n border-bottom: 1px solid rgba(148, 163, 184, 0.1);\n}\n.bb-reset-title {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0;\n font-size: 18px;\n font-weight: 700;\n color: #f8fafc;\n}\n.bb-reset-title .bb-icon-warning {\n color: #f59e0b;\n flex-shrink: 0;\n}\n.bb-reset-close {\n background: transparent;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bb-reset-close:hover {\n color: #f8fafc;\n background: rgba(255, 255, 255, 0.06);\n}\n.bb-reset-body {\n padding: 20px 24px 24px;\n}\n.bb-reset-message {\n margin: 0 0 12px 0;\n font-size: 15px;\n color: #e2e8f0;\n line-height: 1.5;\n}\n.bb-reset-message strong {\n color: #f8fafc;\n}\n.bb-reset-details {\n color: #94a3b8;\n text-align: center;\n font-size: 13px;\n line-height: 1.6;\n margin: 0 0 12px 0;\n}\n.bb-reset-warning {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #f59e0b;\n font-size: 13px;\n font-weight: 600;\n margin: 4px 0 0 0;\n padding: 10px 12px;\n background: rgba(245, 158, 11, 0.08);\n border-radius: 6px;\n border: 1px solid rgba(245, 158, 11, 0.15);\n}\n.bb-reset-footer {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n padding: 16px 24px 20px;\n border-top: 1px solid rgba(148, 163, 184, 0.1);\n}\n.bb-reset-btn {\n padding: 8px 20px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n border: 1px solid rgba(148, 163, 184, 0.18);\n background: rgba(255, 255, 255, 0.04);\n color: #e2e8f0;\n}\n.bb-reset-btn:hover {\n background: rgba(255, 255, 255, 0.08);\n transform: translateY(-1px);\n}\n.bb-reset-btn-danger {\n padding: 8px 20px;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n border: none;\n background: #dc2626;\n color: white;\n}\n.bb-reset-btn-danger:hover {\n background: #b91c1c;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(220, 38, 38, 0.3);\n}\n@keyframes bb-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes bb-slide-up {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.96);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n');
|
|
7162
7261
|
|
|
7163
7262
|
// src/hooks/useViewerCamera.ts
|
|
7164
|
-
import { useCallback as useCallback5, useRef as
|
|
7263
|
+
import { useCallback as useCallback5, useRef as useRef12, useState as useState11 } from "react";
|
|
7165
7264
|
import { Vector3 as Vector38 } from "three";
|
|
7166
7265
|
|
|
7167
7266
|
// src/utils/resolveBindingKey.ts
|
|
@@ -7213,7 +7312,7 @@ async function runSmoothCameraTransition2(controls, action, smoothTime = 0.6) {
|
|
|
7213
7312
|
}
|
|
7214
7313
|
}
|
|
7215
7314
|
function useViewerCamera() {
|
|
7216
|
-
const viewerRef =
|
|
7315
|
+
const viewerRef = useRef12(null);
|
|
7217
7316
|
const [cameraState, setCameraStateValue] = useState11(
|
|
7218
7317
|
null
|
|
7219
7318
|
);
|
|
@@ -7228,8 +7327,8 @@ function useViewerCamera() {
|
|
|
7228
7327
|
},
|
|
7229
7328
|
[updateCameraState]
|
|
7230
7329
|
);
|
|
7231
|
-
const homeCameraStateRef =
|
|
7232
|
-
const homeSceneRef =
|
|
7330
|
+
const homeCameraStateRef = useRef12(null);
|
|
7331
|
+
const homeSceneRef = useRef12(null);
|
|
7233
7332
|
const handleViewerReady = useCallback5((viewer) => {
|
|
7234
7333
|
viewerRef.current = viewer;
|
|
7235
7334
|
updateCameraState(buildCameraState(viewer.controls.camera, viewer.controls));
|
|
@@ -7399,11 +7498,11 @@ function useViewerCamera() {
|
|
|
7399
7498
|
}
|
|
7400
7499
|
|
|
7401
7500
|
// src/hooks/useViewerAnimations.ts
|
|
7402
|
-
import { useCallback as useCallback6, useEffect as useEffect15, useRef as
|
|
7501
|
+
import { useCallback as useCallback6, useEffect as useEffect15, useRef as useRef13, useState as useState12 } from "react";
|
|
7403
7502
|
function useViewerAnimations() {
|
|
7404
|
-
const controlsRef =
|
|
7503
|
+
const controlsRef = useRef13(null);
|
|
7405
7504
|
const [clips, setClips] = useState12([]);
|
|
7406
|
-
const unsubscribeRef =
|
|
7505
|
+
const unsubscribeRef = useRef13(null);
|
|
7407
7506
|
const [clipDetails, setClipDetails] = useState12([]);
|
|
7408
7507
|
const [currentClip, setCurrentClip] = useState12(null);
|
|
7409
7508
|
const [isPlaying, setIsPlaying] = useState12(false);
|
|
@@ -7685,7 +7784,7 @@ import {
|
|
|
7685
7784
|
import { HexColorInput as HexColorInput2, HexColorPicker as HexColorPicker3 } from "react-colorful";
|
|
7686
7785
|
|
|
7687
7786
|
// src/components/BindingBuilder/SceneSettings/SceneControls.tsx
|
|
7688
|
-
import { useLayoutEffect as useLayoutEffect2, useRef as
|
|
7787
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef14, useState as useState13 } from "react";
|
|
7689
7788
|
import { createPortal as createPortal2 } from "react-dom";
|
|
7690
7789
|
import { ChevronDown, Info } from "lucide-react";
|
|
7691
7790
|
import { HexColorInput, HexColorPicker as HexColorPicker2 } from "react-colorful";
|
|
@@ -7726,7 +7825,7 @@ function ColorPopover({
|
|
|
7726
7825
|
onClose,
|
|
7727
7826
|
children
|
|
7728
7827
|
}) {
|
|
7729
|
-
const popoverRef =
|
|
7828
|
+
const popoverRef = useRef14(null);
|
|
7730
7829
|
const [position, setPosition] = useState13(null);
|
|
7731
7830
|
useClickOutside([popoverRef, anchorRef], onClose, true);
|
|
7732
7831
|
useLayoutEffect2(() => {
|
|
@@ -7922,7 +8021,7 @@ function ColorRow({
|
|
|
7922
8021
|
onChange
|
|
7923
8022
|
}) {
|
|
7924
8023
|
const [open, setOpen] = useState13(false);
|
|
7925
|
-
const anchorRef =
|
|
8024
|
+
const anchorRef = useRef14(null);
|
|
7926
8025
|
return /* @__PURE__ */ jsxs16("div", { className: "se-field", children: [
|
|
7927
8026
|
/* @__PURE__ */ jsxs16("div", { className: "se-fieldInline", children: [
|
|
7928
8027
|
/* @__PURE__ */ jsx20("span", { className: "se-fieldLabel", children: label }),
|
|
@@ -8046,7 +8145,7 @@ function TierLock({
|
|
|
8046
8145
|
}
|
|
8047
8146
|
|
|
8048
8147
|
// src/components/BindingBuilder/SceneSettings/GeneralSceneSettings.tsx
|
|
8049
|
-
import { Fragment as
|
|
8148
|
+
import { Fragment as Fragment8, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
8050
8149
|
var SHADING_OPTIONS = ["lit", "unlit", "normals"];
|
|
8051
8150
|
var BACKGROUND_TYPES = ["color", "image", "environment"];
|
|
8052
8151
|
function normalizeRotation(value) {
|
|
@@ -8251,7 +8350,7 @@ function GeneralSceneSettings({ config, onChange }) {
|
|
|
8251
8350
|
),
|
|
8252
8351
|
/* @__PURE__ */ jsx22("span", { className: "se-switchTrack", children: /* @__PURE__ */ jsx22("span", { className: "se-switchThumb" }) })
|
|
8253
8352
|
] }),
|
|
8254
|
-
children: canUseStarterFeatures ? /* @__PURE__ */ jsxs18(
|
|
8353
|
+
children: canUseStarterFeatures ? /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
8255
8354
|
/* @__PURE__ */ jsx22(
|
|
8256
8355
|
SliderRow,
|
|
8257
8356
|
{
|
|
@@ -8291,7 +8390,7 @@ function GeneralSceneSettings({ config, onChange }) {
|
|
|
8291
8390
|
),
|
|
8292
8391
|
/* @__PURE__ */ jsx22("span", { className: "se-switchTrack", children: /* @__PURE__ */ jsx22("span", { className: "se-switchThumb" }) })
|
|
8293
8392
|
] }),
|
|
8294
|
-
children: background.enabled ? /* @__PURE__ */ jsxs18(
|
|
8393
|
+
children: background.enabled ? /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
8295
8394
|
/* @__PURE__ */ jsxs18("div", { className: "se-field", children: [
|
|
8296
8395
|
/* @__PURE__ */ jsx22("span", { className: "se-fieldLabel", children: "Background type" }),
|
|
8297
8396
|
/* @__PURE__ */ jsx22("div", { className: "se-segmentedControl", children: BACKGROUND_TYPES.map((type) => /* @__PURE__ */ jsx22(
|
|
@@ -8311,7 +8410,7 @@ function GeneralSceneSettings({ config, onChange }) {
|
|
|
8311
8410
|
requiredTier: "starter",
|
|
8312
8411
|
feature: "Environment backgrounds"
|
|
8313
8412
|
}
|
|
8314
|
-
) : /* @__PURE__ */ jsxs18(
|
|
8413
|
+
) : /* @__PURE__ */ jsxs18(Fragment8, { children: [
|
|
8315
8414
|
/* @__PURE__ */ jsxs18("div", { className: "se-field", children: [
|
|
8316
8415
|
/* @__PURE__ */ jsx22("span", { className: "se-fieldLabel", children: "Environment source" }),
|
|
8317
8416
|
/* @__PURE__ */ jsxs18("div", { className: "se-segmentedControl", children: [
|
|
@@ -10329,7 +10428,7 @@ function PostProcessingTab({ config, onChange }) {
|
|
|
10329
10428
|
// src/components/BindingBuilder/SceneSettings/LightingTab.tsx
|
|
10330
10429
|
import { useState as useState16 } from "react";
|
|
10331
10430
|
import { Eye, EyeOff, Plus, Trash2 } from "lucide-react";
|
|
10332
|
-
import { Fragment as
|
|
10431
|
+
import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
10333
10432
|
var SHADOW_MAP_SIZES = ["512", "1024", "2048", "4096"];
|
|
10334
10433
|
var LIGHT_TYPE_LABELS = {
|
|
10335
10434
|
none: "None",
|
|
@@ -10698,7 +10797,7 @@ function LightingTab({ config, onChange }) {
|
|
|
10698
10797
|
title: "Environment",
|
|
10699
10798
|
open: open.environment,
|
|
10700
10799
|
onToggle: () => toggleOpen("environment"),
|
|
10701
|
-
children: !canUseStarterFeatures ? /* @__PURE__ */ jsx28(TierLock, { requiredTier: "starter", feature: "Environment lighting" }) : /* @__PURE__ */ jsxs24(
|
|
10800
|
+
children: !canUseStarterFeatures ? /* @__PURE__ */ jsx28(TierLock, { requiredTier: "starter", feature: "Environment lighting" }) : /* @__PURE__ */ jsxs24(Fragment9, { children: [
|
|
10702
10801
|
/* @__PURE__ */ jsx28(
|
|
10703
10802
|
SliderRow,
|
|
10704
10803
|
{
|
|
@@ -11711,7 +11810,7 @@ function MaterialPanelGroup({
|
|
|
11711
11810
|
}
|
|
11712
11811
|
|
|
11713
11812
|
// src/components/BindingBuilder/components/MaterialFields.tsx
|
|
11714
|
-
import { useRef as
|
|
11813
|
+
import { useRef as useRef15, useState as useState20 } from "react";
|
|
11715
11814
|
import { HexColorInput as HexColorInput3, HexColorPicker as HexColorPicker4 } from "react-colorful";
|
|
11716
11815
|
import { FileUp } from "lucide-react";
|
|
11717
11816
|
import { jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
@@ -11721,7 +11820,7 @@ function MaterialTexturePathField({
|
|
|
11721
11820
|
placeholder,
|
|
11722
11821
|
onChange
|
|
11723
11822
|
}) {
|
|
11724
|
-
const inputRef =
|
|
11823
|
+
const inputRef = useRef15(null);
|
|
11725
11824
|
return /* @__PURE__ */ jsxs30("div", { className: "bb-field bb-field--full", children: [
|
|
11726
11825
|
/* @__PURE__ */ jsx35("label", { className: "bb-label", children: label }),
|
|
11727
11826
|
/* @__PURE__ */ jsxs30("div", { className: "bb-fileField", children: [
|
|
@@ -11780,7 +11879,7 @@ function MaterialColorField({
|
|
|
11780
11879
|
}) {
|
|
11781
11880
|
const [open, setOpen] = useState20(false);
|
|
11782
11881
|
const color = value || fallback;
|
|
11783
|
-
const anchorRef =
|
|
11882
|
+
const anchorRef = useRef15(null);
|
|
11784
11883
|
return /* @__PURE__ */ jsxs30("div", { className: "bb-field", children: [
|
|
11785
11884
|
/* @__PURE__ */ jsx35("span", { className: "bb-label", children: label }),
|
|
11786
11885
|
/* @__PURE__ */ jsx35("div", { className: "se-fieldInline", children: /* @__PURE__ */ jsx35("span", { ref: anchorRef, style: { display: "inline-flex" }, children: /* @__PURE__ */ jsx35(
|
|
@@ -11907,7 +12006,7 @@ function MaterialSliderField({
|
|
|
11907
12006
|
}
|
|
11908
12007
|
|
|
11909
12008
|
// src/components/BindingBuilder/components/MaterialSection.tsx
|
|
11910
|
-
import { Fragment as
|
|
12009
|
+
import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
11911
12010
|
function MaterialSection({
|
|
11912
12011
|
selectedItem,
|
|
11913
12012
|
selectedMaterial,
|
|
@@ -11936,7 +12035,7 @@ function MaterialSection({
|
|
|
11936
12035
|
const [anisotropyMode, setAnisotropyMode] = useState21(
|
|
11937
12036
|
"factor"
|
|
11938
12037
|
);
|
|
11939
|
-
return /* @__PURE__ */ jsxs31(
|
|
12038
|
+
return /* @__PURE__ */ jsxs31(Fragment10, { children: [
|
|
11940
12039
|
/* @__PURE__ */ jsx36(
|
|
11941
12040
|
MaterialPanelGroup,
|
|
11942
12041
|
{
|
|
@@ -11975,7 +12074,7 @@ function MaterialSection({
|
|
|
11975
12074
|
}))
|
|
11976
12075
|
}
|
|
11977
12076
|
),
|
|
11978
|
-
pbrWorkflow === "metalness" ? /* @__PURE__ */ jsxs31(
|
|
12077
|
+
pbrWorkflow === "metalness" ? /* @__PURE__ */ jsxs31(Fragment10, { children: [
|
|
11979
12078
|
/* @__PURE__ */ jsx36(
|
|
11980
12079
|
MaterialSliderField,
|
|
11981
12080
|
{
|
|
@@ -11999,7 +12098,7 @@ function MaterialSection({
|
|
|
11999
12098
|
onChange: (value) => setSelectedTexturePath(selectedItem, "metalnessMap", value)
|
|
12000
12099
|
}
|
|
12001
12100
|
)
|
|
12002
|
-
] }) : /* @__PURE__ */ jsxs31(
|
|
12101
|
+
] }) : /* @__PURE__ */ jsxs31(Fragment10, { children: [
|
|
12003
12102
|
/* @__PURE__ */ jsx36(
|
|
12004
12103
|
MaterialSliderField,
|
|
12005
12104
|
{
|
|
@@ -12972,7 +13071,7 @@ function MaterialPresetGallery({
|
|
|
12972
13071
|
}
|
|
12973
13072
|
|
|
12974
13073
|
// src/components/BindingBuilder/components/ToolbarExportMenu.tsx
|
|
12975
|
-
import { useEffect as useEffect18, useRef as
|
|
13074
|
+
import { useEffect as useEffect18, useRef as useRef16, useState as useState22 } from "react";
|
|
12976
13075
|
import { ChevronDown as ChevronDown5, Download as Download2, FileCode2, FileJson } from "lucide-react";
|
|
12977
13076
|
import { jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
12978
13077
|
function ToolbarExportMenu({
|
|
@@ -12982,7 +13081,7 @@ function ToolbarExportMenu({
|
|
|
12982
13081
|
onExportTs
|
|
12983
13082
|
}) {
|
|
12984
13083
|
const [open, setOpen] = useState22(false);
|
|
12985
|
-
const wrapperRef =
|
|
13084
|
+
const wrapperRef = useRef16(null);
|
|
12986
13085
|
useEffect18(() => {
|
|
12987
13086
|
if (!open) return;
|
|
12988
13087
|
const close = (event) => {
|
|
@@ -13315,7 +13414,7 @@ function ActionsPanel({
|
|
|
13315
13414
|
|
|
13316
13415
|
// src/components/BindingBuilder/components/CameraPositionPanel.tsx
|
|
13317
13416
|
import { MapPin as MapPin3, Trash2 as Trash25 } from "lucide-react";
|
|
13318
|
-
import { Fragment as
|
|
13417
|
+
import { Fragment as Fragment11, jsx as jsx42, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
13319
13418
|
function CameraPositionPanel({
|
|
13320
13419
|
selectedBinding,
|
|
13321
13420
|
open,
|
|
@@ -13334,7 +13433,7 @@ function CameraPositionPanel({
|
|
|
13334
13433
|
/* @__PURE__ */ jsx42("span", { className: "bb-cameraLiveBadge", children: "LIVE" }),
|
|
13335
13434
|
/* @__PURE__ */ jsxs37("div", { className: "se-waypointBody", children: [
|
|
13336
13435
|
/* @__PURE__ */ jsx42("div", { className: "bb-cameraWaypointLabel", children: "Current view" }),
|
|
13337
|
-
cameraState ? /* @__PURE__ */ jsxs37(
|
|
13436
|
+
cameraState ? /* @__PURE__ */ jsxs37(Fragment11, { children: [
|
|
13338
13437
|
/* @__PURE__ */ jsxs37("div", { className: "se-waypointCoords", children: [
|
|
13339
13438
|
"pos ",
|
|
13340
13439
|
formattedCameraState?.position
|
|
@@ -13538,7 +13637,7 @@ function collectModelMetadata(modelUrl) {
|
|
|
13538
13637
|
}
|
|
13539
13638
|
|
|
13540
13639
|
// src/components/BindingBuilder/components/SceneNodesPanel.tsx
|
|
13541
|
-
import { Fragment as
|
|
13640
|
+
import { Fragment as Fragment12, jsx as jsx43, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
13542
13641
|
function SceneNodesPanel({
|
|
13543
13642
|
bindings,
|
|
13544
13643
|
selectedItem,
|
|
@@ -13574,7 +13673,7 @@ function SceneNodesPanel({
|
|
|
13574
13673
|
children: "\u2190"
|
|
13575
13674
|
}
|
|
13576
13675
|
),
|
|
13577
|
-
isOpen && /* @__PURE__ */ jsxs38(
|
|
13676
|
+
isOpen && /* @__PURE__ */ jsxs38(Fragment12, { children: [
|
|
13578
13677
|
/* @__PURE__ */ jsxs38("div", { children: [
|
|
13579
13678
|
/* @__PURE__ */ jsx43("div", { className: "bb-sectionKicker", children: "Scene Nodes" }),
|
|
13580
13679
|
/* @__PURE__ */ jsxs38("div", { className: "bb-sectionHeading", children: [
|
|
@@ -13692,7 +13791,7 @@ function mergeAnimationConfig(sceneConfig, animationDetails) {
|
|
|
13692
13791
|
}
|
|
13693
13792
|
|
|
13694
13793
|
// src/components/BindingBuilder/hooks/useUndoableState.ts
|
|
13695
|
-
import { useCallback as useCallback7, useReducer, useRef as
|
|
13794
|
+
import { useCallback as useCallback7, useReducer, useRef as useRef17 } from "react";
|
|
13696
13795
|
var MAX_HISTORY = 100;
|
|
13697
13796
|
function historyReducer(state, action) {
|
|
13698
13797
|
switch (action.type) {
|
|
@@ -13736,7 +13835,7 @@ function useUndoableState(initial, coalesceWindowMs = 600) {
|
|
|
13736
13835
|
present: initial,
|
|
13737
13836
|
future: []
|
|
13738
13837
|
});
|
|
13739
|
-
const lastSetAt =
|
|
13838
|
+
const lastSetAt = useRef17(0);
|
|
13740
13839
|
const setValue = useCallback7(
|
|
13741
13840
|
(updater) => {
|
|
13742
13841
|
const now = Date.now();
|
|
@@ -13983,7 +14082,7 @@ function removeMaterialPanelFields(material, panel) {
|
|
|
13983
14082
|
}
|
|
13984
14083
|
|
|
13985
14084
|
// src/components/BindingBuilder/BindingBuilder.tsx
|
|
13986
|
-
import { Fragment as
|
|
14085
|
+
import { Fragment as Fragment13, jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
13987
14086
|
var DEMO_MODEL_URL = "/room.glb";
|
|
13988
14087
|
function isPlainObject(value) {
|
|
13989
14088
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -14000,9 +14099,9 @@ function mergeSceneConfigSection(current, incoming) {
|
|
|
14000
14099
|
return next;
|
|
14001
14100
|
}
|
|
14002
14101
|
function BindingBuilder({ licenseKey }) {
|
|
14003
|
-
const modelInputRef =
|
|
14004
|
-
const bindingsInputRef =
|
|
14005
|
-
const sceneConfigInputRef =
|
|
14102
|
+
const modelInputRef = useRef18(null);
|
|
14103
|
+
const bindingsInputRef = useRef18(null);
|
|
14104
|
+
const sceneConfigInputRef = useRef18(null);
|
|
14006
14105
|
const [modelUrl, setModelUrl] = useState24(null);
|
|
14007
14106
|
const [modelName, setModelName] = useState24("");
|
|
14008
14107
|
const [selectedItem, setSelectedItem] = useState24(null);
|
|
@@ -14054,7 +14153,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
14054
14153
|
const [activeSubTab, setActiveSubTab] = useState24("General");
|
|
14055
14154
|
const [pbrWorkflow, setPbrWorkflow] = useState24("metalness");
|
|
14056
14155
|
const [materialPanelEnabled, setMaterialPanelEnabled] = useState24(createMaterialPanelEnabledState());
|
|
14057
|
-
const materialPanelItemRef =
|
|
14156
|
+
const materialPanelItemRef = useRef18(null);
|
|
14058
14157
|
const [zoomOnSelected, setZoomOnSelected] = useState24(false);
|
|
14059
14158
|
const [highlightOnHover, setHighlightOnHover] = useState24(true);
|
|
14060
14159
|
const [resetDialogOpen, setResetDialogOpen] = useState24(false);
|
|
@@ -14077,9 +14176,9 @@ function BindingBuilder({ licenseKey }) {
|
|
|
14077
14176
|
}),
|
|
14078
14177
|
[activeEditorTab, activeSubTab, tier]
|
|
14079
14178
|
);
|
|
14080
|
-
const uploadedModelRef =
|
|
14081
|
-
const previewDragDepthRef =
|
|
14082
|
-
const loadRequestRef =
|
|
14179
|
+
const uploadedModelRef = useRef18(null);
|
|
14180
|
+
const previewDragDepthRef = useRef18(0);
|
|
14181
|
+
const loadRequestRef = useRef18(0);
|
|
14083
14182
|
const {
|
|
14084
14183
|
cameraState,
|
|
14085
14184
|
resetView,
|
|
@@ -14734,7 +14833,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
14734
14833
|
}
|
|
14735
14834
|
)
|
|
14736
14835
|
] }),
|
|
14737
|
-
!isEditorCollapsed && /* @__PURE__ */ jsxs40(
|
|
14836
|
+
!isEditorCollapsed && /* @__PURE__ */ jsxs40(Fragment13, { children: [
|
|
14738
14837
|
/* @__PURE__ */ jsxs40("div", { className: "bb-tabRow", children: [
|
|
14739
14838
|
/* @__PURE__ */ jsx45(
|
|
14740
14839
|
"button",
|
|
@@ -14755,7 +14854,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
14755
14854
|
}
|
|
14756
14855
|
)
|
|
14757
14856
|
] }),
|
|
14758
|
-
/* @__PURE__ */ jsx45("section", { className: "bb-editor", children: activeEditorTab === "scene" ? /* @__PURE__ */ jsx45(
|
|
14857
|
+
/* @__PURE__ */ jsx45("section", { className: "bb-editor", children: activeEditorTab === "scene" ? /* @__PURE__ */ jsx45(Fragment13, { children: modelUrl ? /* @__PURE__ */ jsx45(
|
|
14759
14858
|
SceneSettingsTab,
|
|
14760
14859
|
{
|
|
14761
14860
|
config: sceneConfig,
|
|
@@ -14775,7 +14874,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
14775
14874
|
animationClipDetails: viewerAnimations.clipDetails,
|
|
14776
14875
|
animationPlayback: viewerAnimations
|
|
14777
14876
|
}
|
|
14778
|
-
) : /* @__PURE__ */ jsx45("div", { className: "bb-emptyEditor", children: "Upload a model to edit its scene settings." }) }) : !selectedBinding || !selectedItem ? /* @__PURE__ */ jsx45("div", { className: "bb-emptyEditor", children: "Select a generated node binding to edit its values." }) : /* @__PURE__ */ jsxs40(
|
|
14877
|
+
) : /* @__PURE__ */ jsx45("div", { className: "bb-emptyEditor", children: "Upload a model to edit its scene settings." }) }) : !selectedBinding || !selectedItem ? /* @__PURE__ */ jsx45("div", { className: "bb-emptyEditor", children: "Select a generated node binding to edit its values." }) : /* @__PURE__ */ jsxs40(Fragment13, { children: [
|
|
14779
14878
|
/* @__PURE__ */ jsx45("div", { className: "bb-editorHeader", children: /* @__PURE__ */ jsxs40("div", { children: [
|
|
14780
14879
|
/* @__PURE__ */ jsx45("div", { className: "bb-sectionKicker", children: "Editing Binding" }),
|
|
14781
14880
|
/* @__PURE__ */ jsx45("h2", { className: "bb-editorTitle", children: selectedBinding.label || selectedItem }),
|
|
@@ -15191,7 +15290,7 @@ function BindingBuilder({ licenseKey }) {
|
|
|
15191
15290
|
|
|
15192
15291
|
// src/components/SimpleModelViewer/SimpleModelViewer.tsx
|
|
15193
15292
|
import {
|
|
15194
|
-
useRef as
|
|
15293
|
+
useRef as useRef19,
|
|
15195
15294
|
useState as useState25,
|
|
15196
15295
|
useCallback as useCallback9,
|
|
15197
15296
|
useEffect as useEffect20,
|
|
@@ -15222,7 +15321,7 @@ import {
|
|
|
15222
15321
|
Trash2 as Trash26,
|
|
15223
15322
|
Upload as Upload2
|
|
15224
15323
|
} from "lucide-react";
|
|
15225
|
-
import { Fragment as
|
|
15324
|
+
import { Fragment as Fragment14, jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
15226
15325
|
var HIGHLIGHT2 = { color: "#93c5fd", intensity: 0.05 };
|
|
15227
15326
|
var ENV_PRESETS = [
|
|
15228
15327
|
"apartment",
|
|
@@ -15328,7 +15427,7 @@ function InnerModel({
|
|
|
15328
15427
|
},
|
|
15329
15428
|
[perKeyMaterials]
|
|
15330
15429
|
);
|
|
15331
|
-
const notifiedUrl =
|
|
15430
|
+
const notifiedUrl = useRef19(null);
|
|
15332
15431
|
useEffect20(() => {
|
|
15333
15432
|
if (notifiedUrl.current === url) return;
|
|
15334
15433
|
notifiedUrl.current = url;
|
|
@@ -15425,10 +15524,10 @@ function CameraFitter({
|
|
|
15425
15524
|
refitOnResize,
|
|
15426
15525
|
onInitialFitComplete
|
|
15427
15526
|
}) {
|
|
15428
|
-
const fitted =
|
|
15527
|
+
const fitted = useRef19(false);
|
|
15429
15528
|
const invalidate = useThree11((state) => state.invalidate);
|
|
15430
15529
|
const size = useThree11((state) => state.size);
|
|
15431
|
-
const resizeTimerRef =
|
|
15530
|
+
const resizeTimerRef = useRef19(null);
|
|
15432
15531
|
useEffect20(() => {
|
|
15433
15532
|
fitted.current = false;
|
|
15434
15533
|
invalidate();
|
|
@@ -15875,11 +15974,11 @@ function SimpleModelViewer({
|
|
|
15875
15974
|
onModelLoaded,
|
|
15876
15975
|
onLoadError
|
|
15877
15976
|
}) {
|
|
15878
|
-
const cameraControlsRef =
|
|
15879
|
-
const nodeRefsOut =
|
|
15880
|
-
const fileInputRef =
|
|
15881
|
-
const uploadedModelRef =
|
|
15882
|
-
const dragDepthRef =
|
|
15977
|
+
const cameraControlsRef = useRef19(null);
|
|
15978
|
+
const nodeRefsOut = useRef19({});
|
|
15979
|
+
const fileInputRef = useRef19(null);
|
|
15980
|
+
const uploadedModelRef = useRef19(null);
|
|
15981
|
+
const dragDepthRef = useRef19(0);
|
|
15883
15982
|
const [loadedScene, setLoadedScene] = useState25(null);
|
|
15884
15983
|
const [meshKeys, setMeshKeys] = useState25({});
|
|
15885
15984
|
const [hiddenKeys, setHiddenKeys] = useState25(/* @__PURE__ */ new Set());
|
|
@@ -16091,7 +16190,7 @@ function SimpleModelViewer({
|
|
|
16091
16190
|
}
|
|
16092
16191
|
),
|
|
16093
16192
|
/* @__PURE__ */ jsxs41("div", { className: "smv-canvasArea", children: [
|
|
16094
|
-
enableModelUpload ? /* @__PURE__ */ jsxs41(
|
|
16193
|
+
enableModelUpload ? /* @__PURE__ */ jsxs41(Fragment14, { children: [
|
|
16095
16194
|
/* @__PURE__ */ jsx46(
|
|
16096
16195
|
"input",
|
|
16097
16196
|
{
|
|
@@ -16105,7 +16204,7 @@ function SimpleModelViewer({
|
|
|
16105
16204
|
}
|
|
16106
16205
|
}
|
|
16107
16206
|
),
|
|
16108
|
-
activeModelUrl ? /* @__PURE__ */ jsx46("div", { className: "smv-upload-toolbar", children: /* @__PURE__ */ jsxs41(
|
|
16207
|
+
activeModelUrl ? /* @__PURE__ */ jsx46("div", { className: "smv-upload-toolbar", children: /* @__PURE__ */ jsxs41(Fragment14, { children: [
|
|
16109
16208
|
/* @__PURE__ */ jsx46("span", { className: "smv-upload-toolbar__name", children: uploadedModelName ?? "Uploaded model" }),
|
|
16110
16209
|
/* @__PURE__ */ jsxs41(
|
|
16111
16210
|
"button",
|
|
@@ -16533,7 +16632,7 @@ function useViewerActions(objectBindings, options = {}) {
|
|
|
16533
16632
|
}
|
|
16534
16633
|
|
|
16535
16634
|
// src/hooks/useShareableViewerState.ts
|
|
16536
|
-
import { useCallback as useCallback15, useEffect as useEffect21, useRef as
|
|
16635
|
+
import { useCallback as useCallback15, useEffect as useEffect21, useRef as useRef20, useState as useState29 } from "react";
|
|
16537
16636
|
function serializeState(cameraState, objectBindings, selectedObjectBinding) {
|
|
16538
16637
|
const hidden = Object.values(objectBindings).filter((binding) => binding.visible === false).map((binding) => binding.id);
|
|
16539
16638
|
return {
|
|
@@ -16553,7 +16652,7 @@ function useShareableViewerState({
|
|
|
16553
16652
|
debounceMs = 400,
|
|
16554
16653
|
autoSync = true
|
|
16555
16654
|
}) {
|
|
16556
|
-
const lastWrittenRawRef =
|
|
16655
|
+
const lastWrittenRawRef = useRef20(null);
|
|
16557
16656
|
const buildHash = useCallback15(() => {
|
|
16558
16657
|
const state = serializeState(
|
|
16559
16658
|
cameraState,
|
|
@@ -16575,7 +16674,7 @@ function useShareableViewerState({
|
|
|
16575
16674
|
paramKey
|
|
16576
16675
|
);
|
|
16577
16676
|
}, [buildHash, paramKey]);
|
|
16578
|
-
const latestStateRef =
|
|
16677
|
+
const latestStateRef = useRef20({
|
|
16579
16678
|
cameraState,
|
|
16580
16679
|
objectBindings,
|
|
16581
16680
|
selectedObjectBinding
|
|
@@ -16586,7 +16685,7 @@ function useShareableViewerState({
|
|
|
16586
16685
|
selectedObjectBinding
|
|
16587
16686
|
};
|
|
16588
16687
|
const [restoreAttempted, setRestoreAttempted] = useState29(false);
|
|
16589
|
-
const lastSyncedHashRef =
|
|
16688
|
+
const lastSyncedHashRef = useRef20(null);
|
|
16590
16689
|
useEffect21(() => {
|
|
16591
16690
|
if (!autoSync || !restoreAttempted) return;
|
|
16592
16691
|
const tick = () => {
|
|
@@ -16609,8 +16708,8 @@ function useShareableViewerState({
|
|
|
16609
16708
|
const id = window.setInterval(tick, debounceMs);
|
|
16610
16709
|
return () => window.clearInterval(id);
|
|
16611
16710
|
}, [autoSync, restoreAttempted, debounceMs, paramKey]);
|
|
16612
|
-
const lastRestoredRawRef =
|
|
16613
|
-
const restoringRawRef =
|
|
16711
|
+
const lastRestoredRawRef = useRef20(null);
|
|
16712
|
+
const restoringRawRef = useRef20(null);
|
|
16614
16713
|
const restoreFromUrl = useCallback15(async () => {
|
|
16615
16714
|
setRestoreAttempted(true);
|
|
16616
16715
|
const rawHash = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : window.location.hash;
|