storysplat-viewer 0.1.12 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +1081 -169
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/cameraManager.d.ts +1 -0
- package/dist/types/features/customScriptManager.d.ts +34 -0
- package/dist/types/features/htmlMeshManager.d.ts +23 -0
- package/dist/types/features/navigationManager.d.ts +7 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/types/dataTypes.d.ts +1 -0
- package/dist/types/ui/templateManager.d.ts +121 -0
- package/dist/types/viewer.d.ts +8 -0
- package/package.json +5 -2
package/dist/esm/index.js
CHANGED
|
@@ -41199,67 +41199,6 @@ function registerBuiltInLoaders() {
|
|
|
41199
41199
|
});
|
|
41200
41200
|
}
|
|
41201
41201
|
|
|
41202
|
-
var name$3D = "storysplat-viewer";
|
|
41203
|
-
var version = "0.1.12";
|
|
41204
|
-
var description = "A viewer component for StorySplat scenes.";
|
|
41205
|
-
var main = "dist/esm/index.js";
|
|
41206
|
-
var module = "dist/esm/index.js";
|
|
41207
|
-
var types = "dist/types/index.d.ts";
|
|
41208
|
-
var scripts = {
|
|
41209
|
-
"build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types --project tsconfig.json",
|
|
41210
|
-
build: "npm run build:types && rollup -c",
|
|
41211
|
-
"build:umd": "rollup -c rollup.config.umd.js",
|
|
41212
|
-
"build:simple": "rollup -c rollup.config.simple.js",
|
|
41213
|
-
dev: "rollup -c -w",
|
|
41214
|
-
"test:serve": "node test/server.js",
|
|
41215
|
-
"test:build-watch": "npm run build && concurrently \"npm run dev\" \"npm run test:serve\"",
|
|
41216
|
-
test: "npm run build && npm run test:serve",
|
|
41217
|
-
"test:python": "npm run build && python3 test/simple-server.py",
|
|
41218
|
-
"test:open": "npm run build && open http://localhost:8080/test/index.html && npm run test:serve"
|
|
41219
|
-
};
|
|
41220
|
-
var devDependencies = {
|
|
41221
|
-
"@babylonjs/core": "^8.4.1",
|
|
41222
|
-
"@babylonjs/loaders": "^8.4.1",
|
|
41223
|
-
"@rollup/plugin-commonjs": "^25.0.0",
|
|
41224
|
-
"@rollup/plugin-json": "^6.1.0",
|
|
41225
|
-
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
41226
|
-
"@rollup/plugin-typescript": "^11.0.0",
|
|
41227
|
-
concurrently: "^8.0.0",
|
|
41228
|
-
rollup: "^4.0.0",
|
|
41229
|
-
"rollup-plugin-postcss": "^4.0.2",
|
|
41230
|
-
tslib: "^2.6.0",
|
|
41231
|
-
typescript: "^5.0.0"
|
|
41232
|
-
};
|
|
41233
|
-
var files = [
|
|
41234
|
-
"dist/esm",
|
|
41235
|
-
"dist/types",
|
|
41236
|
-
"dist/umd"
|
|
41237
|
-
];
|
|
41238
|
-
var publishConfig = {
|
|
41239
|
-
access: "public"
|
|
41240
|
-
};
|
|
41241
|
-
var dependencies = {
|
|
41242
|
-
"@babylonjs/loaders": "^8.4.1",
|
|
41243
|
-
"gifuct-js": "^2.1.2"
|
|
41244
|
-
};
|
|
41245
|
-
var peerDependencies = {
|
|
41246
|
-
"@babylonjs/core": "^8.4.1"
|
|
41247
|
-
};
|
|
41248
|
-
var packageJson = {
|
|
41249
|
-
name: name$3D,
|
|
41250
|
-
version: version,
|
|
41251
|
-
description: description,
|
|
41252
|
-
main: main,
|
|
41253
|
-
module: module,
|
|
41254
|
-
types: types,
|
|
41255
|
-
scripts: scripts,
|
|
41256
|
-
devDependencies: devDependencies,
|
|
41257
|
-
files: files,
|
|
41258
|
-
publishConfig: publishConfig,
|
|
41259
|
-
dependencies: dependencies,
|
|
41260
|
-
peerDependencies: peerDependencies
|
|
41261
|
-
};
|
|
41262
|
-
|
|
41263
41202
|
/**
|
|
41264
41203
|
* Detect if the effect is a DrawWrapper
|
|
41265
41204
|
* @param effect defines the entity to test
|
|
@@ -75073,7 +75012,7 @@ class CameraManager {
|
|
|
75073
75012
|
}
|
|
75074
75013
|
}
|
|
75075
75014
|
setCameraMode(mode, immediate = false) {
|
|
75076
|
-
var _a, _b, _c, _d, _e, _f;
|
|
75015
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
75077
75016
|
if (!this._camera)
|
|
75078
75017
|
return;
|
|
75079
75018
|
const allowedModes = (_b = (_a = this._viewerOptions) === null || _a === void 0 ? void 0 : _a.allowedCameraModes) !== null && _b !== void 0 ? _b : ['explore', 'walk', 'tour', 'hybrid'];
|
|
@@ -75123,7 +75062,8 @@ class CameraManager {
|
|
|
75123
75062
|
// Trigger callback and update UI
|
|
75124
75063
|
if (oldMode !== mode) {
|
|
75125
75064
|
(_e = (_d = this._viewerOptions) === null || _d === void 0 ? void 0 : _d.onCameraModeChanged) === null || _e === void 0 ? void 0 : _e.call(_d, mode);
|
|
75126
|
-
(_f = this.
|
|
75065
|
+
(_f = this.onCameraModeChange) === null || _f === void 0 ? void 0 : _f.call(this, mode); // Call the new callback
|
|
75066
|
+
(_g = this._analyticsManager) === null || _g === void 0 ? void 0 : _g.trackCameraModeChange(oldMode, mode); // Track event
|
|
75127
75067
|
this._updateUIManager(); // Notify UI Manager of the change
|
|
75128
75068
|
}
|
|
75129
75069
|
}
|
|
@@ -108302,6 +108242,7 @@ class NavigationManager {
|
|
|
108302
108242
|
this.waypointInfoElement = null; // Waypoint info popup (like HTML exports)
|
|
108303
108243
|
this.prevButton = null;
|
|
108304
108244
|
this.nextButton = null;
|
|
108245
|
+
this.playPauseButton = null;
|
|
108305
108246
|
this.cameraModeToggleContainer = null; // Container for general mode toggles
|
|
108306
108247
|
this.walkExploreToggleContainer = null; // Container for Walk/Explore toggle
|
|
108307
108248
|
this.mobileJoystickContainer = null; // Container for joystick UI
|
|
@@ -108403,7 +108344,7 @@ class NavigationManager {
|
|
|
108403
108344
|
this.onProgressUpdate(scrollPercentage / 100, currentWaypointIndex);
|
|
108404
108345
|
}
|
|
108405
108346
|
// --- Tour/Hybrid Mode Logic ---
|
|
108406
|
-
if ((this.currentMode === 'hybrid'
|
|
108347
|
+
if ((this.currentMode === 'hybrid') || (this.currentMode === 'tour' && !this.userControl)) {
|
|
108407
108348
|
this.updateCameraPositionFromPath();
|
|
108408
108349
|
}
|
|
108409
108350
|
// Update UI for tour/hybrid modes
|
|
@@ -108413,8 +108354,8 @@ class NavigationManager {
|
|
|
108413
108354
|
}
|
|
108414
108355
|
// Check waypoint triggers
|
|
108415
108356
|
this.updateActiveWaypoint();
|
|
108416
|
-
// --- Explore/Walk Mode Logic ---
|
|
108417
|
-
if (this.currentMode === 'explore' || this.currentMode === 'walk') {
|
|
108357
|
+
// --- Explore/Walk/Hybrid Mode Logic ---
|
|
108358
|
+
if (this.currentMode === 'explore' || this.currentMode === 'walk' || (this.currentMode === 'hybrid' && this.userControl)) {
|
|
108418
108359
|
const deltaTime = this.scene.getEngine().getDeltaTime() / 1000.0;
|
|
108419
108360
|
this.updateExploreWalkMovement(deltaTime);
|
|
108420
108361
|
}
|
|
@@ -108487,6 +108428,15 @@ class NavigationManager {
|
|
|
108487
108428
|
const logicalDefault = this.waypoints.length > 0 ? 'tour' : 'explore';
|
|
108488
108429
|
const preferredDefault = dataInitialMode || optionsDefaultMode || logicalDefault;
|
|
108489
108430
|
this.currentMode = this.allowedModes.includes(preferredDefault) ? preferredDefault : this.allowedModes[0];
|
|
108431
|
+
console.log('DEBUG NavigationManager initial mode setting:', {
|
|
108432
|
+
dataInitialMode,
|
|
108433
|
+
optionsDefaultMode,
|
|
108434
|
+
logicalDefault,
|
|
108435
|
+
preferredDefault,
|
|
108436
|
+
allowedModes: this.allowedModes,
|
|
108437
|
+
finalCurrentMode: this.currentMode,
|
|
108438
|
+
waypointCount: this.waypoints.length
|
|
108439
|
+
});
|
|
108490
108440
|
// Set navigation parameters from options or use defaults
|
|
108491
108441
|
this.transitionSpeed = (_a = this.options.transitionSpeed) !== null && _a !== void 0 ? _a : 1.5;
|
|
108492
108442
|
this.cameraDampening = (_b = this.options.cameraDampening) !== null && _b !== void 0 ? _b : 0.1;
|
|
@@ -108525,7 +108475,14 @@ class NavigationManager {
|
|
|
108525
108475
|
this.targetRotation.copyFrom(this.camera.rotationQuaternion);
|
|
108526
108476
|
}
|
|
108527
108477
|
}
|
|
108528
|
-
|
|
108478
|
+
console.log('DEBUG NavigationManager: About to call setupUI...');
|
|
108479
|
+
try {
|
|
108480
|
+
this.setupUI(); // Setup UI based on options
|
|
108481
|
+
console.log('DEBUG NavigationManager: setupUI completed successfully');
|
|
108482
|
+
}
|
|
108483
|
+
catch (error) {
|
|
108484
|
+
console.error('DEBUG NavigationManager: Error in setupUI:', error);
|
|
108485
|
+
}
|
|
108529
108486
|
// Event handlers (scroll, keyboard, pointer) are attached/detached in setMode
|
|
108530
108487
|
// Start autoplay if enabled and applicable
|
|
108531
108488
|
if (this.autoPlayEnabled && this.waypoints.length > 0 && (this.currentMode === 'tour' || this.currentMode === 'hybrid')) {
|
|
@@ -108891,7 +108848,7 @@ class NavigationManager {
|
|
|
108891
108848
|
var _a, _b;
|
|
108892
108849
|
// Clear existing UI first
|
|
108893
108850
|
this.removeUI();
|
|
108894
|
-
console.log('NavigationManager: Setting up UI with:', {
|
|
108851
|
+
console.log('DEBUG NavigationManager: Setting up UI with:', {
|
|
108895
108852
|
waypoints: this.waypoints.length,
|
|
108896
108853
|
allowedModes: this.allowedModes,
|
|
108897
108854
|
currentMode: this.currentMode,
|
|
@@ -108900,10 +108857,11 @@ class NavigationManager {
|
|
|
108900
108857
|
showCameraModeToggle: this.options.showCameraModeToggle,
|
|
108901
108858
|
showWalkExploreToggle: this.options.showWalkExploreToggle,
|
|
108902
108859
|
uiContainer: this.uiContainer ? 'found' : 'NOT FOUND',
|
|
108903
|
-
uiType: ((_a = this.options.uiOptions) === null || _a === void 0 ? void 0 : _a.uiType) || '
|
|
108860
|
+
uiType: ((_a = this.options.uiOptions) === null || _a === void 0 ? void 0 : _a.uiType) || 'standard',
|
|
108861
|
+
fullOptions: this.options
|
|
108904
108862
|
});
|
|
108905
108863
|
// Determine template type from options
|
|
108906
|
-
const uiType = ((_b = this.options.uiOptions) === null || _b === void 0 ? void 0 : _b.uiType) || '
|
|
108864
|
+
const uiType = ((_b = this.options.uiOptions) === null || _b === void 0 ? void 0 : _b.uiType) || 'standard';
|
|
108907
108865
|
// Setup UI based on template type
|
|
108908
108866
|
switch (uiType) {
|
|
108909
108867
|
case 'pro':
|
|
@@ -108994,6 +108952,30 @@ class NavigationManager {
|
|
|
108994
108952
|
this.prevButton.style.transition = 'all 0.2s ease';
|
|
108995
108953
|
this.prevButton.addEventListener('click', this.previousWaypoint);
|
|
108996
108954
|
buttonContainer.appendChild(this.prevButton);
|
|
108955
|
+
// Play/Pause button (only if autoplay is enabled)
|
|
108956
|
+
if (this.autoPlayEnabled) {
|
|
108957
|
+
this.playPauseButton = document.createElement('button');
|
|
108958
|
+
this.playPauseButton.className = 'storysplat-nav-button storysplat-play-pause-button';
|
|
108959
|
+
this.playPauseButton.innerHTML = this.isPlaying ? '⏸️' : '▶️';
|
|
108960
|
+
this.playPauseButton.style.background = 'rgba(0, 0, 0, 0.3)';
|
|
108961
|
+
this.playPauseButton.style.border = 'none';
|
|
108962
|
+
this.playPauseButton.style.color = 'white';
|
|
108963
|
+
this.playPauseButton.style.padding = '5px 10px';
|
|
108964
|
+
this.playPauseButton.style.fontSize = '14px';
|
|
108965
|
+
this.playPauseButton.style.borderRadius = '2px';
|
|
108966
|
+
this.playPauseButton.style.cursor = 'pointer';
|
|
108967
|
+
this.playPauseButton.style.transition = 'all 0.2s ease';
|
|
108968
|
+
this.playPauseButton.addEventListener('click', () => {
|
|
108969
|
+
if (this.isPlaying) {
|
|
108970
|
+
this.pause();
|
|
108971
|
+
}
|
|
108972
|
+
else {
|
|
108973
|
+
this.play();
|
|
108974
|
+
}
|
|
108975
|
+
this.updatePlayPauseButton();
|
|
108976
|
+
});
|
|
108977
|
+
buttonContainer.appendChild(this.playPauseButton);
|
|
108978
|
+
}
|
|
108997
108979
|
this.nextButton = document.createElement('button');
|
|
108998
108980
|
this.nextButton.className = 'storysplat-nav-button storysplat-next-button';
|
|
108999
108981
|
this.nextButton.innerHTML = '→';
|
|
@@ -109017,24 +108999,8 @@ class NavigationManager {
|
|
|
109017
108999
|
this.setupCommonUI(); // Add common UI elements (walk/explore toggles, etc.)
|
|
109018
109000
|
}
|
|
109019
109001
|
setupStandardTemplateUI() {
|
|
109020
|
-
console.log('NavigationManager: Setting up STANDARD template UI');
|
|
109021
|
-
// Standard template
|
|
109022
|
-
// and supports inline/below button positioning
|
|
109023
|
-
// --- Waypoint Info (Top of screen, like HTML exports) ---
|
|
109024
|
-
this.waypointInfoElement = document.createElement('div');
|
|
109025
|
-
this.waypointInfoElement.className = 'storysplat-waypoint-info';
|
|
109026
|
-
this.waypointInfoElement.style.position = 'absolute';
|
|
109027
|
-
this.waypointInfoElement.style.top = '0';
|
|
109028
|
-
this.waypointInfoElement.style.left = '0';
|
|
109029
|
-
this.waypointInfoElement.style.right = '0';
|
|
109030
|
-
this.waypointInfoElement.style.background = 'rgba(0, 0, 0, 0.5)';
|
|
109031
|
-
this.waypointInfoElement.style.color = 'white';
|
|
109032
|
-
this.waypointInfoElement.style.textAlign = 'center';
|
|
109033
|
-
this.waypointInfoElement.style.zIndex = '1000';
|
|
109034
|
-
this.waypointInfoElement.style.pointerEvents = 'none';
|
|
109035
|
-
this.waypointInfoElement.style.display = 'none';
|
|
109036
|
-
this.waypointInfoElement.style.fontFamily = 'system-ui, -apple-system, sans-serif';
|
|
109037
|
-
this.uiContainer.appendChild(this.waypointInfoElement);
|
|
109002
|
+
console.log('DEBUG NavigationManager: Setting up STANDARD template UI');
|
|
109003
|
+
// Standard template has waypoint info integrated into the navigator (not at top of screen)
|
|
109038
109004
|
// --- Scroll Controls Container (Bottom center, like standard template) ---
|
|
109039
109005
|
if (this.waypoints.length > 1) {
|
|
109040
109006
|
this.scrollControlsContainer = document.createElement('div');
|
|
@@ -109053,6 +109019,19 @@ class NavigationManager {
|
|
|
109053
109019
|
this.scrollControlsContainer.style.zIndex = '1000';
|
|
109054
109020
|
this.scrollControlsContainer.style.background = 'rgba(0, 0, 0, 0.4)';
|
|
109055
109021
|
this.scrollControlsContainer.style.borderRadius = '8px';
|
|
109022
|
+
// --- Waypoint Info (Inside navigator for standard template) ---
|
|
109023
|
+
this.waypointInfoElement = document.createElement('div');
|
|
109024
|
+
this.waypointInfoElement.className = 'storysplat-waypoint-info';
|
|
109025
|
+
this.waypointInfoElement.style.color = 'white';
|
|
109026
|
+
this.waypointInfoElement.style.textAlign = 'center';
|
|
109027
|
+
this.waypointInfoElement.style.pointerEvents = 'none';
|
|
109028
|
+
this.waypointInfoElement.style.display = 'none';
|
|
109029
|
+
this.waypointInfoElement.style.fontFamily = 'system-ui, -apple-system, sans-serif';
|
|
109030
|
+
this.waypointInfoElement.style.fontSize = '14px';
|
|
109031
|
+
this.waypointInfoElement.style.marginBottom = '5px';
|
|
109032
|
+
this.waypointInfoElement.style.maxWidth = '500px';
|
|
109033
|
+
this.waypointInfoElement.style.lineHeight = '1.4';
|
|
109034
|
+
this.scrollControlsContainer.appendChild(this.waypointInfoElement);
|
|
109056
109035
|
// Scroll percentage display (larger for standard) - ensure no duplicates exist
|
|
109057
109036
|
if (!this.uiContainer.querySelector('.storysplat-scroll-percentage')) {
|
|
109058
109037
|
this.scrollPercentageElement = document.createElement('div');
|
|
@@ -109099,6 +109078,30 @@ class NavigationManager {
|
|
|
109099
109078
|
this.prevButton.style.transition = 'all 0.2s ease';
|
|
109100
109079
|
this.prevButton.addEventListener('click', this.previousWaypoint);
|
|
109101
109080
|
buttonContainer.appendChild(this.prevButton);
|
|
109081
|
+
// Play/Pause button (only if autoplay is enabled)
|
|
109082
|
+
if (this.autoPlayEnabled) {
|
|
109083
|
+
this.playPauseButton = document.createElement('button');
|
|
109084
|
+
this.playPauseButton.className = 'storysplat-nav-button storysplat-play-pause-button';
|
|
109085
|
+
this.playPauseButton.innerHTML = this.isPlaying ? '⏸️' : '▶️';
|
|
109086
|
+
this.playPauseButton.style.background = 'rgba(0, 0, 0, 0.5)';
|
|
109087
|
+
this.playPauseButton.style.border = '1px solid rgba(255, 255, 255, 0.3)';
|
|
109088
|
+
this.playPauseButton.style.color = 'white';
|
|
109089
|
+
this.playPauseButton.style.padding = '8px 16px';
|
|
109090
|
+
this.playPauseButton.style.fontSize = '14px';
|
|
109091
|
+
this.playPauseButton.style.borderRadius = '4px';
|
|
109092
|
+
this.playPauseButton.style.cursor = 'pointer';
|
|
109093
|
+
this.playPauseButton.style.transition = 'all 0.2s ease';
|
|
109094
|
+
this.playPauseButton.addEventListener('click', () => {
|
|
109095
|
+
if (this.isPlaying) {
|
|
109096
|
+
this.pause();
|
|
109097
|
+
}
|
|
109098
|
+
else {
|
|
109099
|
+
this.play();
|
|
109100
|
+
}
|
|
109101
|
+
this.updatePlayPauseButton();
|
|
109102
|
+
});
|
|
109103
|
+
buttonContainer.appendChild(this.playPauseButton);
|
|
109104
|
+
}
|
|
109102
109105
|
this.nextButton = document.createElement('button');
|
|
109103
109106
|
this.nextButton.className = 'storysplat-nav-button storysplat-next-button';
|
|
109104
109107
|
this.nextButton.innerHTML = 'Next <span style="margin-left: 5px;">→</span>';
|
|
@@ -109117,6 +109120,8 @@ class NavigationManager {
|
|
|
109117
109120
|
this.uiContainer.appendChild(this.scrollControlsContainer);
|
|
109118
109121
|
console.log('NavigationManager: Created standard template scroll controls');
|
|
109119
109122
|
}
|
|
109123
|
+
// Add camera mode toggles to this template
|
|
109124
|
+
this.createCameraModeToggles();
|
|
109120
109125
|
this.setupCommonUI(); // Add common UI elements
|
|
109121
109126
|
}
|
|
109122
109127
|
setupProTemplateUI() {
|
|
@@ -109208,6 +109213,31 @@ class NavigationManager {
|
|
|
109208
109213
|
this.progressIndicator.style.width = '0%';
|
|
109209
109214
|
progressBarContainer.appendChild(this.progressIndicator);
|
|
109210
109215
|
centerContent.appendChild(progressBarContainer);
|
|
109216
|
+
// Play/Pause button (only if autoplay is enabled) - centered below progress bar
|
|
109217
|
+
if (this.autoPlayEnabled) {
|
|
109218
|
+
this.playPauseButton = document.createElement('button');
|
|
109219
|
+
this.playPauseButton.className = 'storysplat-nav-button storysplat-play-pause-button';
|
|
109220
|
+
this.playPauseButton.innerHTML = this.isPlaying ? '⏸️' : '▶️';
|
|
109221
|
+
this.playPauseButton.style.background = 'rgba(0, 0, 0, 0.5)';
|
|
109222
|
+
this.playPauseButton.style.border = 'none';
|
|
109223
|
+
this.playPauseButton.style.color = 'white';
|
|
109224
|
+
this.playPauseButton.style.padding = '6px 12px';
|
|
109225
|
+
this.playPauseButton.style.fontSize = '14px';
|
|
109226
|
+
this.playPauseButton.style.borderRadius = '4px';
|
|
109227
|
+
this.playPauseButton.style.cursor = 'pointer';
|
|
109228
|
+
this.playPauseButton.style.transition = 'background 0.2s ease';
|
|
109229
|
+
this.playPauseButton.style.marginTop = '5px';
|
|
109230
|
+
this.playPauseButton.addEventListener('click', () => {
|
|
109231
|
+
if (this.isPlaying) {
|
|
109232
|
+
this.pause();
|
|
109233
|
+
}
|
|
109234
|
+
else {
|
|
109235
|
+
this.play();
|
|
109236
|
+
}
|
|
109237
|
+
this.updatePlayPauseButton();
|
|
109238
|
+
});
|
|
109239
|
+
centerContent.appendChild(this.playPauseButton);
|
|
109240
|
+
}
|
|
109211
109241
|
this.scrollControlsContainer.appendChild(centerContent);
|
|
109212
109242
|
// Next button (right side)
|
|
109213
109243
|
if (this.options.showNavButtons !== false) {
|
|
@@ -109229,33 +109259,99 @@ class NavigationManager {
|
|
|
109229
109259
|
this.uiContainer.appendChild(this.scrollControlsContainer);
|
|
109230
109260
|
console.log('NavigationManager: Created pro template scroll controls');
|
|
109231
109261
|
}
|
|
109262
|
+
// For pro template, create camera mode buttons on the left side instead
|
|
109263
|
+
this.createProTemplateCameraModeToggles();
|
|
109232
109264
|
this.setupCommonUI(); // Add common UI elements
|
|
109233
109265
|
}
|
|
109266
|
+
createProTemplateCameraModeToggles() {
|
|
109267
|
+
// Show if explicitly enabled or if not explicitly disabled and we have multiple modes
|
|
109268
|
+
const shouldShowCameraModeToggle = this.options.showCameraModeToggle === true || (this.options.showCameraModeToggle !== false && this.allowedModes.length > 1);
|
|
109269
|
+
if (shouldShowCameraModeToggle) {
|
|
109270
|
+
console.log('NavigationManager: Creating PRO template camera mode toggle container (left side)');
|
|
109271
|
+
this.cameraModeToggleContainer = document.createElement('div');
|
|
109272
|
+
this.cameraModeToggleContainer.className = 'storysplat-camera-mode-toggle storysplat-camera-mode-toggle-pro';
|
|
109273
|
+
this.cameraModeToggleContainer.id = 'modeToggleContainer';
|
|
109274
|
+
// Position on left side, vertically centered and stacked
|
|
109275
|
+
this.cameraModeToggleContainer.style.position = 'absolute';
|
|
109276
|
+
this.cameraModeToggleContainer.style.left = '20px';
|
|
109277
|
+
this.cameraModeToggleContainer.style.top = '50%';
|
|
109278
|
+
this.cameraModeToggleContainer.style.transform = 'translateY(-50%)';
|
|
109279
|
+
this.cameraModeToggleContainer.style.display = 'flex';
|
|
109280
|
+
this.cameraModeToggleContainer.style.flexDirection = 'column';
|
|
109281
|
+
this.cameraModeToggleContainer.style.gap = '8px';
|
|
109282
|
+
this.cameraModeToggleContainer.style.zIndex = '1000';
|
|
109283
|
+
// Conditional button creation like HTML exports
|
|
109284
|
+
const buttonsToCreate = [];
|
|
109285
|
+
// Walk button only if walk allowed AND explore not allowed
|
|
109286
|
+
if (this.allowedModes.includes('walk') && !this.allowedModes.includes('explore')) {
|
|
109287
|
+
buttonsToCreate.push('walk');
|
|
109288
|
+
}
|
|
109289
|
+
// Explore button if explore is allowed
|
|
109290
|
+
if (this.allowedModes.includes('explore')) {
|
|
109291
|
+
buttonsToCreate.push('explore');
|
|
109292
|
+
}
|
|
109293
|
+
// Tour button if tour is allowed
|
|
109294
|
+
if (this.allowedModes.includes('tour')) {
|
|
109295
|
+
buttonsToCreate.push('tour');
|
|
109296
|
+
}
|
|
109297
|
+
// Hybrid button if hybrid is allowed (also check for 'auto' which maps to hybrid)
|
|
109298
|
+
if (this.allowedModes.includes('hybrid') || this.allowedModes.includes('auto')) {
|
|
109299
|
+
buttonsToCreate.push('hybrid');
|
|
109300
|
+
}
|
|
109301
|
+
buttonsToCreate.forEach((mode) => {
|
|
109302
|
+
var _a;
|
|
109303
|
+
const button = document.createElement('button');
|
|
109304
|
+
button.className = `mode-button mode-button-pro`;
|
|
109305
|
+
button.id = `mode${mode.charAt(0).toUpperCase() + mode.slice(1)}`;
|
|
109306
|
+
button.textContent = mode.charAt(0).toUpperCase() + mode.slice(1);
|
|
109307
|
+
button.dataset.mode = mode;
|
|
109308
|
+
// Style for pro template - vertical stack on left side
|
|
109309
|
+
button.style.padding = '8px 12px';
|
|
109310
|
+
button.style.background = 'rgba(0, 0, 0, 0.7)';
|
|
109311
|
+
button.style.border = `1px solid ${this.options.uiColor || '#4CAF50'}`;
|
|
109312
|
+
button.style.color = 'white';
|
|
109313
|
+
button.style.cursor = 'pointer';
|
|
109314
|
+
button.style.fontSize = '14px';
|
|
109315
|
+
button.style.borderRadius = '4px';
|
|
109316
|
+
button.style.transition = 'all 0.2s ease';
|
|
109317
|
+
button.style.minWidth = '80px';
|
|
109318
|
+
button.style.textAlign = 'center';
|
|
109319
|
+
button.addEventListener('click', () => this.setMode(mode));
|
|
109320
|
+
(_a = this.cameraModeToggleContainer) === null || _a === void 0 ? void 0 : _a.appendChild(button);
|
|
109321
|
+
});
|
|
109322
|
+
// Add directly to main UI container (not scroll controls)
|
|
109323
|
+
this.uiContainer.appendChild(this.cameraModeToggleContainer);
|
|
109324
|
+
console.log('DEBUG NavigationManager: PRO template camera mode toggle container created and added to left side');
|
|
109325
|
+
}
|
|
109326
|
+
}
|
|
109234
109327
|
createCameraModeToggles() {
|
|
109235
109328
|
// Show if explicitly enabled or if not explicitly disabled and we have multiple modes
|
|
109236
109329
|
const shouldShowCameraModeToggle = this.options.showCameraModeToggle === true || (this.options.showCameraModeToggle !== false && this.allowedModes.length > 1);
|
|
109237
|
-
console.log('NavigationManager: Camera mode toggle check:', {
|
|
109330
|
+
console.log('DEBUG NavigationManager: Camera mode toggle check:', {
|
|
109238
109331
|
showCameraModeToggle: this.options.showCameraModeToggle,
|
|
109332
|
+
allowedModes: this.allowedModes,
|
|
109239
109333
|
allowedModesLength: this.allowedModes.length,
|
|
109240
|
-
shouldShow: shouldShowCameraModeToggle
|
|
109334
|
+
shouldShow: shouldShowCameraModeToggle,
|
|
109335
|
+
scrollControlsContainer: this.scrollControlsContainer ? 'exists' : 'null'
|
|
109241
109336
|
});
|
|
109242
109337
|
if (shouldShowCameraModeToggle) {
|
|
109243
109338
|
console.log('NavigationManager: Creating camera mode toggle container');
|
|
109244
109339
|
this.cameraModeToggleContainer = document.createElement('div');
|
|
109245
109340
|
this.cameraModeToggleContainer.className = 'storysplat-camera-mode-toggle';
|
|
109246
109341
|
this.cameraModeToggleContainer.id = 'modeToggleContainer';
|
|
109247
|
-
// Style the container
|
|
109248
|
-
this.cameraModeToggleContainer.style.margin = '
|
|
109342
|
+
// Style the container for minimal template - position at bottom
|
|
109343
|
+
this.cameraModeToggleContainer.style.margin = '5px 0';
|
|
109249
109344
|
this.cameraModeToggleContainer.style.display = 'flex';
|
|
109250
109345
|
this.cameraModeToggleContainer.style.justifyContent = 'center';
|
|
109251
109346
|
// Create inner toggle bar (this is the #modeToggle div in HTML exports)
|
|
109252
109347
|
const modeToggleBar = document.createElement('div');
|
|
109253
109348
|
modeToggleBar.id = 'modeToggle';
|
|
109254
109349
|
modeToggleBar.style.display = 'flex';
|
|
109255
|
-
modeToggleBar.style.border =
|
|
109256
|
-
modeToggleBar.style.borderRadius = '
|
|
109350
|
+
modeToggleBar.style.border = 'none';
|
|
109351
|
+
modeToggleBar.style.borderRadius = '3px';
|
|
109257
109352
|
modeToggleBar.style.overflow = 'hidden';
|
|
109258
|
-
modeToggleBar.style.width = '
|
|
109353
|
+
modeToggleBar.style.width = 'auto';
|
|
109354
|
+
modeToggleBar.style.gap = '4px';
|
|
109259
109355
|
// Conditional button creation like HTML exports
|
|
109260
109356
|
const buttonsToCreate = [];
|
|
109261
109357
|
// Walk button only if walk allowed AND explore not allowed
|
|
@@ -109270,8 +109366,8 @@ class NavigationManager {
|
|
|
109270
109366
|
if (this.allowedModes.includes('tour')) {
|
|
109271
109367
|
buttonsToCreate.push('tour');
|
|
109272
109368
|
}
|
|
109273
|
-
// Hybrid button if hybrid is allowed
|
|
109274
|
-
if (this.allowedModes.includes('hybrid')) {
|
|
109369
|
+
// Hybrid button if hybrid is allowed (also check for 'auto' which maps to hybrid)
|
|
109370
|
+
if (this.allowedModes.includes('hybrid') || this.allowedModes.includes('auto')) {
|
|
109275
109371
|
buttonsToCreate.push('hybrid');
|
|
109276
109372
|
}
|
|
109277
109373
|
buttonsToCreate.forEach((mode) => {
|
|
@@ -109280,27 +109376,44 @@ class NavigationManager {
|
|
|
109280
109376
|
button.id = `mode${mode.charAt(0).toUpperCase() + mode.slice(1)}`;
|
|
109281
109377
|
button.textContent = mode.charAt(0).toUpperCase() + mode.slice(1);
|
|
109282
109378
|
button.dataset.mode = mode;
|
|
109283
|
-
// Style
|
|
109379
|
+
// Style for minimal template - transparent until hover
|
|
109284
109380
|
button.style.flex = '1';
|
|
109285
|
-
button.style.padding = '10px';
|
|
109286
|
-
button.style.background =
|
|
109381
|
+
button.style.padding = '6px 10px';
|
|
109382
|
+
button.style.background = 'transparent';
|
|
109287
109383
|
button.style.border = 'none';
|
|
109288
109384
|
button.style.color = 'white';
|
|
109289
109385
|
button.style.cursor = 'pointer';
|
|
109290
|
-
button.style.fontSize = '
|
|
109291
|
-
button.style.transition = 'background-color 0.3s';
|
|
109386
|
+
button.style.fontSize = '12px';
|
|
109387
|
+
button.style.transition = 'background-color 0.3s, opacity 0.3s';
|
|
109388
|
+
button.style.borderRadius = '3px';
|
|
109389
|
+
button.style.opacity = '0.6';
|
|
109390
|
+
button.style.textAlign = 'center';
|
|
109391
|
+
button.style.margin = '0 2px';
|
|
109392
|
+
button.style.minWidth = '60px';
|
|
109292
109393
|
button.style.width = `${100 / buttonsToCreate.length}%`;
|
|
109394
|
+
// Add hover effects
|
|
109395
|
+
button.addEventListener('mouseenter', () => {
|
|
109396
|
+
button.style.background = 'rgba(0, 0, 0, 0.7)';
|
|
109397
|
+
button.style.opacity = '1';
|
|
109398
|
+
});
|
|
109399
|
+
button.addEventListener('mouseleave', () => {
|
|
109400
|
+
button.style.background = 'transparent';
|
|
109401
|
+
button.style.opacity = '0.6';
|
|
109402
|
+
});
|
|
109293
109403
|
button.addEventListener('click', () => this.setMode(mode));
|
|
109294
109404
|
modeToggleBar.appendChild(button);
|
|
109295
109405
|
});
|
|
109296
109406
|
this.cameraModeToggleContainer.appendChild(modeToggleBar);
|
|
109297
109407
|
// Add to scroll controls if they exist (like HTML exports), otherwise to main UI
|
|
109298
109408
|
if (this.scrollControlsContainer) {
|
|
109409
|
+
console.log('DEBUG NavigationManager: Adding camera mode toggle to scroll controls container');
|
|
109299
109410
|
this.scrollControlsContainer.appendChild(this.cameraModeToggleContainer);
|
|
109300
109411
|
}
|
|
109301
109412
|
else {
|
|
109413
|
+
console.log('DEBUG NavigationManager: Adding camera mode toggle to main UI container');
|
|
109302
109414
|
this.uiContainer.appendChild(this.cameraModeToggleContainer);
|
|
109303
109415
|
}
|
|
109416
|
+
console.log('DEBUG NavigationManager: Camera mode toggle container created and added to DOM');
|
|
109304
109417
|
}
|
|
109305
109418
|
}
|
|
109306
109419
|
setupCommonUI() {
|
|
@@ -109372,21 +109485,35 @@ class NavigationManager {
|
|
|
109372
109485
|
updateUI() {
|
|
109373
109486
|
// --- Navigation Progress/Buttons ---
|
|
109374
109487
|
const progress = this.getProgress();
|
|
109375
|
-
const
|
|
109488
|
+
const showNavigationControls = (this.currentMode === 'tour' || this.currentMode === 'hybrid');
|
|
109489
|
+
const hasCameraModeToggles = this.cameraModeToggleContainer !== null;
|
|
109376
109490
|
// Update progress indicator
|
|
109377
109491
|
if (this.progressIndicator) {
|
|
109378
109492
|
this.progressIndicator.style.width = `${progress * 100}%`;
|
|
109493
|
+
this.progressIndicator.style.display = showNavigationControls ? 'block' : 'none';
|
|
109379
109494
|
}
|
|
109380
|
-
// Update scroll percentage
|
|
109495
|
+
// Update scroll percentage - hide in explore/walk modes
|
|
109381
109496
|
if (this.scrollPercentageElement) {
|
|
109382
109497
|
this.scrollPercentageElement.textContent = `${Math.round(progress * 100)}%`;
|
|
109498
|
+
this.scrollPercentageElement.style.display = showNavigationControls ? 'block' : 'none';
|
|
109499
|
+
}
|
|
109500
|
+
// Show/hide prev/next buttons
|
|
109501
|
+
if (this.prevButton) {
|
|
109502
|
+
this.prevButton.style.display = showNavigationControls ? 'block' : 'none';
|
|
109383
109503
|
}
|
|
109384
|
-
|
|
109504
|
+
if (this.nextButton) {
|
|
109505
|
+
this.nextButton.style.display = showNavigationControls ? 'block' : 'none';
|
|
109506
|
+
}
|
|
109507
|
+
// Show/hide play/pause button
|
|
109508
|
+
if (this.playPauseButton) {
|
|
109509
|
+
this.playPauseButton.style.display = showNavigationControls ? 'block' : 'none';
|
|
109510
|
+
}
|
|
109511
|
+
// Keep scroll controls container visible if we have camera mode toggles OR navigation controls
|
|
109385
109512
|
if (this.scrollControlsContainer) {
|
|
109386
|
-
this.scrollControlsContainer.style.display =
|
|
109513
|
+
this.scrollControlsContainer.style.display = (showNavigationControls || hasCameraModeToggles) ? 'flex' : 'none';
|
|
109387
109514
|
}
|
|
109388
|
-
// Update button states (only when controls are visible)
|
|
109389
|
-
if (
|
|
109515
|
+
// Update button states (only when navigation controls are visible)
|
|
109516
|
+
if (showNavigationControls) {
|
|
109390
109517
|
if (this.prevButton) {
|
|
109391
109518
|
this.prevButton.disabled = progress <= 0 && !this.loopMode;
|
|
109392
109519
|
this.prevButton.style.opacity = this.prevButton.disabled ? '0.4' : '1';
|
|
@@ -109458,6 +109585,12 @@ class NavigationManager {
|
|
|
109458
109585
|
console.error("Failed to initialize virtual joysticks:", error);
|
|
109459
109586
|
}
|
|
109460
109587
|
}
|
|
109588
|
+
// Update play/pause button icon based on current state
|
|
109589
|
+
updatePlayPauseButton() {
|
|
109590
|
+
if (this.playPauseButton) {
|
|
109591
|
+
this.playPauseButton.innerHTML = this.isPlaying ? '⏸️' : '▶️';
|
|
109592
|
+
}
|
|
109593
|
+
}
|
|
109461
109594
|
// Update virtual joystick visibility based on current camera mode
|
|
109462
109595
|
updateVirtualJoystickVisibility() {
|
|
109463
109596
|
if (!this.isMobileDevice || !VirtualJoystick.Canvas)
|
|
@@ -109712,6 +109845,7 @@ class NavigationManager {
|
|
|
109712
109845
|
}
|
|
109713
109846
|
this.isPlaying = true;
|
|
109714
109847
|
this.userControl = false;
|
|
109848
|
+
this.updatePlayPauseButton(); // Update button icon
|
|
109715
109849
|
console.log("Autoplay started/resumed");
|
|
109716
109850
|
// If starting from the end (e.g., after looping manually), reset
|
|
109717
109851
|
if (this.scrollPosition >= this.path.length - 1 && this.loopMode) {
|
|
@@ -109724,6 +109858,7 @@ class NavigationManager {
|
|
|
109724
109858
|
pause() {
|
|
109725
109859
|
if (this.isPlaying) {
|
|
109726
109860
|
this.isPlaying = false;
|
|
109861
|
+
this.updatePlayPauseButton(); // Update button icon
|
|
109727
109862
|
console.log("Autoplay paused");
|
|
109728
109863
|
}
|
|
109729
109864
|
}
|
|
@@ -160898,6 +161033,13 @@ class SplatSwapManager {
|
|
|
160898
161033
|
}
|
|
160899
161034
|
}
|
|
160900
161035
|
|
|
161036
|
+
var UIType;
|
|
161037
|
+
(function (UIType) {
|
|
161038
|
+
UIType["Standard"] = "standard";
|
|
161039
|
+
UIType["Minimal"] = "minimal";
|
|
161040
|
+
UIType["Pro"] = "pro";
|
|
161041
|
+
})(UIType || (UIType = {}));
|
|
161042
|
+
|
|
160901
161043
|
/**
|
|
160902
161044
|
* Manages the preloader UI element.
|
|
160903
161045
|
*/
|
|
@@ -161466,6 +161608,775 @@ class MuteButtonUI {
|
|
|
161466
161608
|
}
|
|
161467
161609
|
}
|
|
161468
161610
|
|
|
161611
|
+
/**
|
|
161612
|
+
* Manages UI layout templates for the StorySplat viewer
|
|
161613
|
+
* Renders different UI layouts based on the uiType from scene JSON
|
|
161614
|
+
*/
|
|
161615
|
+
class TemplateManager {
|
|
161616
|
+
constructor(targetElement, options) {
|
|
161617
|
+
var _a;
|
|
161618
|
+
// UI Components
|
|
161619
|
+
this.preloaderUI = null;
|
|
161620
|
+
this.startButtonUI = null;
|
|
161621
|
+
this.watermarkUI = null;
|
|
161622
|
+
this.helpPanelUI = null;
|
|
161623
|
+
this.muteButtonUI = null;
|
|
161624
|
+
// UI Elements for templates
|
|
161625
|
+
this.controlsContainer = null;
|
|
161626
|
+
this.modeToggleContainer = null;
|
|
161627
|
+
this.progressContainer = null;
|
|
161628
|
+
this.navigationContainer = null;
|
|
161629
|
+
this.targetElement = targetElement;
|
|
161630
|
+
this.options = options;
|
|
161631
|
+
this.uiType = ((_a = options.uiOptions) === null || _a === void 0 ? void 0 : _a.uiType) || 'standard';
|
|
161632
|
+
console.log(`TemplateManager: Initializing with uiType: ${this.uiType}`);
|
|
161633
|
+
}
|
|
161634
|
+
/**
|
|
161635
|
+
* Initialize UI components based on template type
|
|
161636
|
+
*/
|
|
161637
|
+
async initializeUI(audioManager, navigationManager, cameraManager, onStartExperience) {
|
|
161638
|
+
// Create base UI components that are common to all templates
|
|
161639
|
+
this.createBaseComponents(audioManager, onStartExperience);
|
|
161640
|
+
// Apply template-specific layout
|
|
161641
|
+
switch (this.uiType) {
|
|
161642
|
+
case UIType.Minimal:
|
|
161643
|
+
case 'minimal':
|
|
161644
|
+
await this.applyMinimalTemplate(navigationManager, cameraManager);
|
|
161645
|
+
break;
|
|
161646
|
+
case UIType.Pro:
|
|
161647
|
+
case 'pro':
|
|
161648
|
+
await this.applyProTemplate(navigationManager, cameraManager);
|
|
161649
|
+
break;
|
|
161650
|
+
case UIType.Standard:
|
|
161651
|
+
case 'standard':
|
|
161652
|
+
default:
|
|
161653
|
+
await this.applyStandardTemplate(navigationManager, cameraManager);
|
|
161654
|
+
break;
|
|
161655
|
+
}
|
|
161656
|
+
}
|
|
161657
|
+
/**
|
|
161658
|
+
* Create base UI components common to all templates
|
|
161659
|
+
*/
|
|
161660
|
+
createBaseComponents(audioManager, onStartExperience) {
|
|
161661
|
+
var _a, _b, _c, _d, _e, _f;
|
|
161662
|
+
// Preloader (always created)
|
|
161663
|
+
const defaultPreloaderConfig = {
|
|
161664
|
+
enabled: true,
|
|
161665
|
+
imageUrl: 'https://firebasestorage.googleapis.com/v0/b/story-splat.firebasestorage.app/o/public%2Fimages%2FStorySplat.webp?alt=media&token=953e8ab3-1865-4ac1-a98d-b548b7066bda',
|
|
161666
|
+
lottieUrl: 'https://firebasestorage.googleapis.com/v0/b/story-splat.firebasestorage.app/o/public%2Flotties%2FstorySplatLottie.json?alt=media&token=d7edc19d-9cb8-4c20-96f3-d23b6d1272b4',
|
|
161667
|
+
uiColor: ((_a = this.options) === null || _a === void 0 ? void 0 : _a.uiColor) || '#4CAF50'
|
|
161668
|
+
};
|
|
161669
|
+
const preloaderConfig = Object.assign(Object.assign({}, defaultPreloaderConfig), (_b = this.options) === null || _b === void 0 ? void 0 : _b.preloaderConfig);
|
|
161670
|
+
this.preloaderUI = new PreloaderUI(this.targetElement, preloaderConfig);
|
|
161671
|
+
this.preloaderUI.create();
|
|
161672
|
+
// Start Button (conditional)
|
|
161673
|
+
if ((_c = this.options) === null || _c === void 0 ? void 0 : _c.showStartExperience) {
|
|
161674
|
+
this.startButtonUI = new StartButtonUI(this.targetElement, this.options, onStartExperience || (() => { }));
|
|
161675
|
+
this.startButtonUI.create();
|
|
161676
|
+
}
|
|
161677
|
+
// Watermark (conditional)
|
|
161678
|
+
this.watermarkUI = new WatermarkUI(this.targetElement, this.options);
|
|
161679
|
+
this.watermarkUI.create();
|
|
161680
|
+
// Help Panel (conditional)
|
|
161681
|
+
if ((_d = this.options) === null || _d === void 0 ? void 0 : _d.showHelpButton) {
|
|
161682
|
+
this.helpPanelUI = new HelpPanelUI(this.targetElement, this.options);
|
|
161683
|
+
this.helpPanelUI.create();
|
|
161684
|
+
}
|
|
161685
|
+
// Mute Button (conditional)
|
|
161686
|
+
if (((_f = (_e = this.options) === null || _e === void 0 ? void 0 : _e.audio) === null || _f === void 0 ? void 0 : _f.showMuteButton) && audioManager) {
|
|
161687
|
+
this.muteButtonUI = new MuteButtonUI(this.targetElement, this.options, audioManager);
|
|
161688
|
+
this.muteButtonUI.create();
|
|
161689
|
+
}
|
|
161690
|
+
}
|
|
161691
|
+
/**
|
|
161692
|
+
* Apply Minimal template layout (overlay controls)
|
|
161693
|
+
*/
|
|
161694
|
+
async applyMinimalTemplate(navigationManager, cameraManager) {
|
|
161695
|
+
console.log('TemplateManager: Applying Minimal template');
|
|
161696
|
+
// Add minimal template class
|
|
161697
|
+
this.targetElement.classList.add('template-minimal');
|
|
161698
|
+
// Create minimal controls container (overlay style)
|
|
161699
|
+
if (this.options.showProgressBar && navigationManager) {
|
|
161700
|
+
this.createMinimalControls(navigationManager);
|
|
161701
|
+
}
|
|
161702
|
+
// Create mode toggle if multiple modes allowed
|
|
161703
|
+
if (this.shouldShowModeToggle() && cameraManager) {
|
|
161704
|
+
this.createMinimalModeToggle(cameraManager);
|
|
161705
|
+
}
|
|
161706
|
+
// Apply minimal template styles
|
|
161707
|
+
this.applyMinimalStyles();
|
|
161708
|
+
}
|
|
161709
|
+
/**
|
|
161710
|
+
* Apply Standard template layout (bottom navigation)
|
|
161711
|
+
*/
|
|
161712
|
+
async applyStandardTemplate(navigationManager, cameraManager) {
|
|
161713
|
+
console.log('TemplateManager: Applying Standard template');
|
|
161714
|
+
// Add standard template class
|
|
161715
|
+
this.targetElement.classList.add('template-standard');
|
|
161716
|
+
// Create bottom navigation container
|
|
161717
|
+
if ((this.options.showProgressBar || this.options.showNavButtons) && navigationManager) {
|
|
161718
|
+
this.createStandardControls(navigationManager);
|
|
161719
|
+
}
|
|
161720
|
+
// Create mode toggle if multiple modes allowed
|
|
161721
|
+
if (this.shouldShowModeToggle() && cameraManager) {
|
|
161722
|
+
this.createStandardModeToggle(cameraManager);
|
|
161723
|
+
}
|
|
161724
|
+
// Apply standard template styles
|
|
161725
|
+
this.applyStandardStyles();
|
|
161726
|
+
}
|
|
161727
|
+
/**
|
|
161728
|
+
* Apply Pro template layout (enhanced bottom navigation)
|
|
161729
|
+
*/
|
|
161730
|
+
async applyProTemplate(navigationManager, cameraManager) {
|
|
161731
|
+
console.log('TemplateManager: Applying Pro template');
|
|
161732
|
+
// Add pro template class
|
|
161733
|
+
this.targetElement.classList.add('template-pro');
|
|
161734
|
+
// Create waypoint info display at top
|
|
161735
|
+
if (navigationManager) {
|
|
161736
|
+
this.createProWaypointInfo();
|
|
161737
|
+
}
|
|
161738
|
+
// Create enhanced bottom navigation
|
|
161739
|
+
if ((this.options.showProgressBar || this.options.showNavButtons) && navigationManager) {
|
|
161740
|
+
this.createProControls(navigationManager);
|
|
161741
|
+
}
|
|
161742
|
+
// Create mode toggle on left side
|
|
161743
|
+
if (this.shouldShowModeToggle() && cameraManager) {
|
|
161744
|
+
this.createProModeToggle(cameraManager);
|
|
161745
|
+
}
|
|
161746
|
+
// Apply pro template styles
|
|
161747
|
+
this.applyProStyles();
|
|
161748
|
+
}
|
|
161749
|
+
/**
|
|
161750
|
+
* Helper to determine if mode toggle should be shown
|
|
161751
|
+
*/
|
|
161752
|
+
shouldShowModeToggle() {
|
|
161753
|
+
const allowedModes = this.options.allowedCameraModes || [];
|
|
161754
|
+
return this.options.showCameraModeToggle !== false && allowedModes.length > 1;
|
|
161755
|
+
}
|
|
161756
|
+
/**
|
|
161757
|
+
* Create minimal overlay controls
|
|
161758
|
+
*/
|
|
161759
|
+
createMinimalControls(navigationManager) {
|
|
161760
|
+
// Create overlay container
|
|
161761
|
+
this.controlsContainer = document.createElement('div');
|
|
161762
|
+
this.controlsContainer.id = 'scrollControls';
|
|
161763
|
+
this.controlsContainer.className = 'minimal-controls';
|
|
161764
|
+
// Progress bar
|
|
161765
|
+
if (this.options.showProgressBar) {
|
|
161766
|
+
const progressContainer = document.createElement('div');
|
|
161767
|
+
progressContainer.className = 'minimal-progress-container';
|
|
161768
|
+
const progressBar = document.createElement('div');
|
|
161769
|
+
progressBar.className = 'minimal-progress-bar';
|
|
161770
|
+
const progressFill = document.createElement('div');
|
|
161771
|
+
progressFill.className = 'minimal-progress-fill';
|
|
161772
|
+
progressFill.id = 'progressBar';
|
|
161773
|
+
progressBar.appendChild(progressFill);
|
|
161774
|
+
progressContainer.appendChild(progressBar);
|
|
161775
|
+
// Add percentage display
|
|
161776
|
+
const percentageDisplay = document.createElement('div');
|
|
161777
|
+
percentageDisplay.className = 'minimal-percentage';
|
|
161778
|
+
percentageDisplay.id = 'scrollPercentage';
|
|
161779
|
+
percentageDisplay.textContent = '0%';
|
|
161780
|
+
progressContainer.appendChild(percentageDisplay);
|
|
161781
|
+
this.controlsContainer.appendChild(progressContainer);
|
|
161782
|
+
}
|
|
161783
|
+
// Navigation buttons (inline with progress)
|
|
161784
|
+
if (this.options.showNavButtons) {
|
|
161785
|
+
const navContainer = document.createElement('div');
|
|
161786
|
+
navContainer.className = 'minimal-nav-buttons';
|
|
161787
|
+
const prevButton = this.createNavButton('prev', 'minimal');
|
|
161788
|
+
const nextButton = this.createNavButton('next', 'minimal');
|
|
161789
|
+
navContainer.appendChild(prevButton);
|
|
161790
|
+
navContainer.appendChild(nextButton);
|
|
161791
|
+
this.controlsContainer.appendChild(navContainer);
|
|
161792
|
+
}
|
|
161793
|
+
this.targetElement.appendChild(this.controlsContainer);
|
|
161794
|
+
// Connect to navigation manager
|
|
161795
|
+
this.connectNavigationControls(navigationManager);
|
|
161796
|
+
}
|
|
161797
|
+
/**
|
|
161798
|
+
* Create standard bottom controls
|
|
161799
|
+
*/
|
|
161800
|
+
createStandardControls(navigationManager) {
|
|
161801
|
+
// Create bottom controls container
|
|
161802
|
+
this.controlsContainer = document.createElement('div');
|
|
161803
|
+
this.controlsContainer.id = 'scrollControls';
|
|
161804
|
+
this.controlsContainer.className = 'standard-controls';
|
|
161805
|
+
// Create controls content container
|
|
161806
|
+
const controlsContent = document.createElement('div');
|
|
161807
|
+
controlsContent.className = 'standard-controls-content';
|
|
161808
|
+
// Progress section
|
|
161809
|
+
const progressSection = document.createElement('div');
|
|
161810
|
+
progressSection.className = 'standard-progress-section';
|
|
161811
|
+
// Percentage display
|
|
161812
|
+
const percentageDisplay = document.createElement('div');
|
|
161813
|
+
percentageDisplay.id = 'scrollPercentage';
|
|
161814
|
+
percentageDisplay.className = 'standard-percentage';
|
|
161815
|
+
percentageDisplay.textContent = '0%';
|
|
161816
|
+
progressSection.appendChild(percentageDisplay);
|
|
161817
|
+
// Progress bar container
|
|
161818
|
+
const progressContainer = document.createElement('div');
|
|
161819
|
+
progressContainer.className = 'standard-progress-container';
|
|
161820
|
+
progressContainer.id = 'progressBarContainer';
|
|
161821
|
+
const progressBar = document.createElement('div');
|
|
161822
|
+
progressBar.className = 'standard-progress-bar';
|
|
161823
|
+
progressBar.id = 'progressBar';
|
|
161824
|
+
progressContainer.appendChild(progressBar);
|
|
161825
|
+
progressSection.appendChild(progressContainer);
|
|
161826
|
+
controlsContent.appendChild(progressSection);
|
|
161827
|
+
// Navigation buttons
|
|
161828
|
+
if (this.options.showNavButtons) {
|
|
161829
|
+
const buttonsContainer = document.createElement('div');
|
|
161830
|
+
buttonsContainer.className = 'standard-buttons-container';
|
|
161831
|
+
buttonsContainer.id = 'scrollButtons';
|
|
161832
|
+
const prevButton = this.createNavButton('prev', 'standard');
|
|
161833
|
+
const nextButton = this.createNavButton('next', 'standard');
|
|
161834
|
+
// Add autoplay button if enabled
|
|
161835
|
+
if (this.options.autoPlayEnabled) {
|
|
161836
|
+
const autoplayControls = document.createElement('div');
|
|
161837
|
+
autoplayControls.id = 'autoplayControls';
|
|
161838
|
+
autoplayControls.className = 'standard-autoplay';
|
|
161839
|
+
const playPauseButton = document.createElement('button');
|
|
161840
|
+
playPauseButton.id = 'playPauseButton';
|
|
161841
|
+
playPauseButton.className = 'standard-play-pause';
|
|
161842
|
+
playPauseButton.innerHTML = '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
|
|
161843
|
+
autoplayControls.appendChild(playPauseButton);
|
|
161844
|
+
buttonsContainer.appendChild(prevButton);
|
|
161845
|
+
buttonsContainer.appendChild(autoplayControls);
|
|
161846
|
+
buttonsContainer.appendChild(nextButton);
|
|
161847
|
+
}
|
|
161848
|
+
else {
|
|
161849
|
+
buttonsContainer.appendChild(prevButton);
|
|
161850
|
+
buttonsContainer.appendChild(nextButton);
|
|
161851
|
+
}
|
|
161852
|
+
controlsContent.appendChild(buttonsContainer);
|
|
161853
|
+
}
|
|
161854
|
+
this.controlsContainer.appendChild(controlsContent);
|
|
161855
|
+
this.targetElement.appendChild(this.controlsContainer);
|
|
161856
|
+
// Connect to navigation manager
|
|
161857
|
+
this.connectNavigationControls(navigationManager);
|
|
161858
|
+
}
|
|
161859
|
+
/**
|
|
161860
|
+
* Create pro enhanced controls
|
|
161861
|
+
*/
|
|
161862
|
+
createProControls(navigationManager) {
|
|
161863
|
+
// Implementation based on pro template HTML
|
|
161864
|
+
// TODO: Implement based on pro template HTML
|
|
161865
|
+
}
|
|
161866
|
+
/**
|
|
161867
|
+
* Create minimal mode toggle
|
|
161868
|
+
*/
|
|
161869
|
+
createMinimalModeToggle(cameraManager) {
|
|
161870
|
+
const allowedModes = this.options.allowedCameraModes || [];
|
|
161871
|
+
if (allowedModes.length <= 1)
|
|
161872
|
+
return;
|
|
161873
|
+
this.modeToggleContainer = document.createElement('div');
|
|
161874
|
+
this.modeToggleContainer.id = 'modeToggleContainer';
|
|
161875
|
+
this.modeToggleContainer.className = 'minimal-mode-toggle';
|
|
161876
|
+
// Create mode buttons
|
|
161877
|
+
if (allowedModes.includes('explore')) {
|
|
161878
|
+
const exploreButton = document.createElement('button');
|
|
161879
|
+
exploreButton.id = 'modeExplore';
|
|
161880
|
+
exploreButton.className = 'mode-button';
|
|
161881
|
+
exploreButton.textContent = 'Explore';
|
|
161882
|
+
exploreButton.addEventListener('click', () => cameraManager.setCameraMode('explore'));
|
|
161883
|
+
this.modeToggleContainer.appendChild(exploreButton);
|
|
161884
|
+
}
|
|
161885
|
+
if (allowedModes.includes('tour')) {
|
|
161886
|
+
const tourButton = document.createElement('button');
|
|
161887
|
+
tourButton.id = 'modeTour';
|
|
161888
|
+
tourButton.className = 'mode-button';
|
|
161889
|
+
tourButton.textContent = 'Tour';
|
|
161890
|
+
tourButton.addEventListener('click', () => cameraManager.setCameraMode('tour'));
|
|
161891
|
+
this.modeToggleContainer.appendChild(tourButton);
|
|
161892
|
+
}
|
|
161893
|
+
if (allowedModes.includes('hybrid')) {
|
|
161894
|
+
const hybridButton = document.createElement('button');
|
|
161895
|
+
hybridButton.id = 'modeHybrid';
|
|
161896
|
+
hybridButton.className = 'mode-button';
|
|
161897
|
+
hybridButton.textContent = 'Hybrid';
|
|
161898
|
+
hybridButton.addEventListener('click', () => cameraManager.setCameraMode('hybrid'));
|
|
161899
|
+
this.modeToggleContainer.appendChild(hybridButton);
|
|
161900
|
+
}
|
|
161901
|
+
if (allowedModes.includes('walk')) {
|
|
161902
|
+
const walkButton = document.createElement('button');
|
|
161903
|
+
walkButton.id = 'modeWalk';
|
|
161904
|
+
walkButton.className = 'mode-button';
|
|
161905
|
+
walkButton.textContent = 'Walk';
|
|
161906
|
+
walkButton.addEventListener('click', () => cameraManager.setCameraMode('walk'));
|
|
161907
|
+
this.modeToggleContainer.appendChild(walkButton);
|
|
161908
|
+
}
|
|
161909
|
+
this.targetElement.appendChild(this.modeToggleContainer);
|
|
161910
|
+
// Update button states based on current mode
|
|
161911
|
+
this.updateModeToggleState(cameraManager.currentMode);
|
|
161912
|
+
// Listen for mode changes
|
|
161913
|
+
cameraManager.onCameraModeChange = (mode) => {
|
|
161914
|
+
this.updateModeToggleState(mode);
|
|
161915
|
+
};
|
|
161916
|
+
}
|
|
161917
|
+
/**
|
|
161918
|
+
* Create standard mode toggle
|
|
161919
|
+
*/
|
|
161920
|
+
createStandardModeToggle(cameraManager) {
|
|
161921
|
+
const allowedModes = this.options.allowedCameraModes || [];
|
|
161922
|
+
if (allowedModes.length <= 1)
|
|
161923
|
+
return;
|
|
161924
|
+
this.modeToggleContainer = document.createElement('div');
|
|
161925
|
+
this.modeToggleContainer.id = 'modeToggleContainer';
|
|
161926
|
+
this.modeToggleContainer.className = 'standard-mode-toggle';
|
|
161927
|
+
const toggleRow = document.createElement('div');
|
|
161928
|
+
toggleRow.className = 'standard-mode-toggle-row';
|
|
161929
|
+
// Create mode buttons
|
|
161930
|
+
if (allowedModes.includes('explore')) {
|
|
161931
|
+
const exploreButton = document.createElement('button');
|
|
161932
|
+
exploreButton.id = 'modeExplore';
|
|
161933
|
+
exploreButton.className = 'mode-button';
|
|
161934
|
+
exploreButton.textContent = 'Explore';
|
|
161935
|
+
exploreButton.addEventListener('click', () => cameraManager.setCameraMode('explore'));
|
|
161936
|
+
toggleRow.appendChild(exploreButton);
|
|
161937
|
+
}
|
|
161938
|
+
if (allowedModes.includes('tour')) {
|
|
161939
|
+
const tourButton = document.createElement('button');
|
|
161940
|
+
tourButton.id = 'modeTour';
|
|
161941
|
+
tourButton.className = 'mode-button';
|
|
161942
|
+
tourButton.textContent = 'Tour';
|
|
161943
|
+
tourButton.addEventListener('click', () => cameraManager.setCameraMode('tour'));
|
|
161944
|
+
toggleRow.appendChild(tourButton);
|
|
161945
|
+
}
|
|
161946
|
+
if (allowedModes.includes('hybrid')) {
|
|
161947
|
+
const hybridButton = document.createElement('button');
|
|
161948
|
+
hybridButton.id = 'modeHybrid';
|
|
161949
|
+
hybridButton.className = 'mode-button';
|
|
161950
|
+
hybridButton.textContent = 'Hybrid';
|
|
161951
|
+
hybridButton.addEventListener('click', () => cameraManager.setCameraMode('hybrid'));
|
|
161952
|
+
toggleRow.appendChild(hybridButton);
|
|
161953
|
+
}
|
|
161954
|
+
if (allowedModes.includes('walk')) {
|
|
161955
|
+
const walkButton = document.createElement('button');
|
|
161956
|
+
walkButton.id = 'modeWalk';
|
|
161957
|
+
walkButton.className = 'mode-button';
|
|
161958
|
+
walkButton.textContent = 'Walk';
|
|
161959
|
+
walkButton.addEventListener('click', () => cameraManager.setCameraMode('walk'));
|
|
161960
|
+
toggleRow.appendChild(walkButton);
|
|
161961
|
+
}
|
|
161962
|
+
this.modeToggleContainer.appendChild(toggleRow);
|
|
161963
|
+
this.targetElement.appendChild(this.modeToggleContainer);
|
|
161964
|
+
// Update button states based on current mode
|
|
161965
|
+
this.updateModeToggleState(cameraManager.currentMode);
|
|
161966
|
+
// Listen for mode changes
|
|
161967
|
+
cameraManager.onCameraModeChange = (mode) => {
|
|
161968
|
+
this.updateModeToggleState(mode);
|
|
161969
|
+
};
|
|
161970
|
+
}
|
|
161971
|
+
/**
|
|
161972
|
+
* Create pro mode toggle (left side)
|
|
161973
|
+
*/
|
|
161974
|
+
createProModeToggle(cameraManager) {
|
|
161975
|
+
// Implementation for pro mode toggle
|
|
161976
|
+
// TODO: Implement mode toggle UI
|
|
161977
|
+
}
|
|
161978
|
+
/**
|
|
161979
|
+
* Create pro waypoint info display
|
|
161980
|
+
*/
|
|
161981
|
+
createProWaypointInfo() {
|
|
161982
|
+
const waypointInfo = document.createElement('div');
|
|
161983
|
+
waypointInfo.id = 'waypointInfo';
|
|
161984
|
+
waypointInfo.className = 'pro-waypoint-info';
|
|
161985
|
+
this.targetElement.appendChild(waypointInfo);
|
|
161986
|
+
}
|
|
161987
|
+
/**
|
|
161988
|
+
* Helper to create navigation buttons
|
|
161989
|
+
*/
|
|
161990
|
+
createNavButton(type, style) {
|
|
161991
|
+
const button = document.createElement('button');
|
|
161992
|
+
button.id = type === 'prev' ? 'prevButton' : 'nextButton';
|
|
161993
|
+
button.className = `${style}-nav-button ${type}`;
|
|
161994
|
+
button.innerHTML = type === 'prev' ? '←' : '→';
|
|
161995
|
+
button.title = type === 'prev' ? 'Previous' : 'Next';
|
|
161996
|
+
return button;
|
|
161997
|
+
}
|
|
161998
|
+
/**
|
|
161999
|
+
* Connect navigation controls to NavigationManager
|
|
162000
|
+
*/
|
|
162001
|
+
connectNavigationControls(navigationManager) {
|
|
162002
|
+
// Connect progress updates
|
|
162003
|
+
if (this.options.showProgressBar) ;
|
|
162004
|
+
// Connect button clicks
|
|
162005
|
+
if (this.options.showNavButtons) {
|
|
162006
|
+
const prevButton = document.getElementById('prevButton');
|
|
162007
|
+
const nextButton = document.getElementById('nextButton');
|
|
162008
|
+
prevButton === null || prevButton === void 0 ? void 0 : prevButton.addEventListener('click', () => navigationManager.previousWaypoint());
|
|
162009
|
+
nextButton === null || nextButton === void 0 ? void 0 : nextButton.addEventListener('click', () => navigationManager.nextWaypoint());
|
|
162010
|
+
}
|
|
162011
|
+
}
|
|
162012
|
+
/**
|
|
162013
|
+
* Apply minimal template styles
|
|
162014
|
+
*/
|
|
162015
|
+
applyMinimalStyles() {
|
|
162016
|
+
const style = document.createElement('style');
|
|
162017
|
+
style.textContent = `
|
|
162018
|
+
.template-minimal .minimal-controls {
|
|
162019
|
+
position: fixed;
|
|
162020
|
+
bottom: 20px;
|
|
162021
|
+
left: 50%;
|
|
162022
|
+
transform: translateX(-50%);
|
|
162023
|
+
display: flex;
|
|
162024
|
+
align-items: center;
|
|
162025
|
+
gap: 20px;
|
|
162026
|
+
z-index: 100;
|
|
162027
|
+
}
|
|
162028
|
+
|
|
162029
|
+
.template-minimal .minimal-progress-container {
|
|
162030
|
+
display: flex;
|
|
162031
|
+
align-items: center;
|
|
162032
|
+
gap: 10px;
|
|
162033
|
+
}
|
|
162034
|
+
|
|
162035
|
+
.template-minimal .minimal-progress-bar {
|
|
162036
|
+
width: 200px;
|
|
162037
|
+
height: 2px;
|
|
162038
|
+
background: rgba(255, 255, 255, 0.2);
|
|
162039
|
+
border-radius: 1px;
|
|
162040
|
+
overflow: hidden;
|
|
162041
|
+
}
|
|
162042
|
+
|
|
162043
|
+
.template-minimal .minimal-progress-fill {
|
|
162044
|
+
height: 100%;
|
|
162045
|
+
background: ${this.options.uiColor || '#4CAF50'};
|
|
162046
|
+
transition: width 0.3s ease;
|
|
162047
|
+
width: 0%;
|
|
162048
|
+
}
|
|
162049
|
+
|
|
162050
|
+
.template-minimal .minimal-percentage {
|
|
162051
|
+
color: white;
|
|
162052
|
+
font-size: 12px;
|
|
162053
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
162054
|
+
min-width: 35px;
|
|
162055
|
+
text-align: right;
|
|
162056
|
+
}
|
|
162057
|
+
|
|
162058
|
+
.template-minimal .minimal-nav-buttons {
|
|
162059
|
+
display: flex;
|
|
162060
|
+
gap: 10px;
|
|
162061
|
+
}
|
|
162062
|
+
|
|
162063
|
+
.template-minimal .minimal-nav-button {
|
|
162064
|
+
background: rgba(0, 0, 0, 0.5);
|
|
162065
|
+
border: none;
|
|
162066
|
+
color: white;
|
|
162067
|
+
width: 32px;
|
|
162068
|
+
height: 32px;
|
|
162069
|
+
border-radius: 50%;
|
|
162070
|
+
cursor: pointer;
|
|
162071
|
+
display: flex;
|
|
162072
|
+
align-items: center;
|
|
162073
|
+
justify-content: center;
|
|
162074
|
+
transition: background 0.2s ease;
|
|
162075
|
+
}
|
|
162076
|
+
|
|
162077
|
+
.template-minimal .minimal-nav-button:hover {
|
|
162078
|
+
background: rgba(0, 0, 0, 0.7);
|
|
162079
|
+
}
|
|
162080
|
+
|
|
162081
|
+
.template-minimal .minimal-mode-toggle {
|
|
162082
|
+
position: fixed;
|
|
162083
|
+
bottom: 70px;
|
|
162084
|
+
left: 50%;
|
|
162085
|
+
transform: translateX(-50%);
|
|
162086
|
+
display: flex;
|
|
162087
|
+
gap: 10px;
|
|
162088
|
+
z-index: 100;
|
|
162089
|
+
}
|
|
162090
|
+
|
|
162091
|
+
.template-minimal .mode-button {
|
|
162092
|
+
background: rgba(0, 0, 0, 0.5);
|
|
162093
|
+
border: none;
|
|
162094
|
+
color: white;
|
|
162095
|
+
padding: 6px 12px;
|
|
162096
|
+
border-radius: 4px;
|
|
162097
|
+
cursor: pointer;
|
|
162098
|
+
font-size: 12px;
|
|
162099
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
162100
|
+
transition: all 0.2s ease;
|
|
162101
|
+
min-width: 60px;
|
|
162102
|
+
}
|
|
162103
|
+
|
|
162104
|
+
.template-minimal .mode-button:hover {
|
|
162105
|
+
background: rgba(0, 0, 0, 0.7);
|
|
162106
|
+
}
|
|
162107
|
+
|
|
162108
|
+
.template-minimal .mode-button.selected {
|
|
162109
|
+
background: ${this.options.uiColor || '#4CAF50'};
|
|
162110
|
+
}
|
|
162111
|
+
|
|
162112
|
+
@media (max-width: 768px) {
|
|
162113
|
+
.template-minimal .minimal-controls {
|
|
162114
|
+
bottom: 10px;
|
|
162115
|
+
gap: 15px;
|
|
162116
|
+
}
|
|
162117
|
+
|
|
162118
|
+
.template-minimal .minimal-mode-toggle {
|
|
162119
|
+
bottom: 50px;
|
|
162120
|
+
}
|
|
162121
|
+
|
|
162122
|
+
.template-minimal .mode-button {
|
|
162123
|
+
padding: 5px 10px;
|
|
162124
|
+
font-size: 11px;
|
|
162125
|
+
min-width: 50px;
|
|
162126
|
+
}
|
|
162127
|
+
}
|
|
162128
|
+
`;
|
|
162129
|
+
document.head.appendChild(style);
|
|
162130
|
+
}
|
|
162131
|
+
/**
|
|
162132
|
+
* Apply standard template styles
|
|
162133
|
+
*/
|
|
162134
|
+
applyStandardStyles() {
|
|
162135
|
+
const style = document.createElement('style');
|
|
162136
|
+
style.textContent = `
|
|
162137
|
+
.template-standard .standard-controls {
|
|
162138
|
+
position: fixed;
|
|
162139
|
+
bottom: 0;
|
|
162140
|
+
left: 0;
|
|
162141
|
+
right: 0;
|
|
162142
|
+
background: rgba(0, 0, 0, 0.8);
|
|
162143
|
+
backdrop-filter: blur(10px);
|
|
162144
|
+
padding: 15px 20px;
|
|
162145
|
+
z-index: 100;
|
|
162146
|
+
display: flex;
|
|
162147
|
+
justify-content: center;
|
|
162148
|
+
}
|
|
162149
|
+
|
|
162150
|
+
.template-standard .standard-controls-content {
|
|
162151
|
+
width: 100%;
|
|
162152
|
+
max-width: 800px;
|
|
162153
|
+
display: flex;
|
|
162154
|
+
flex-direction: column;
|
|
162155
|
+
gap: 10px;
|
|
162156
|
+
}
|
|
162157
|
+
|
|
162158
|
+
.template-standard .standard-progress-section {
|
|
162159
|
+
display: flex;
|
|
162160
|
+
flex-direction: column;
|
|
162161
|
+
align-items: center;
|
|
162162
|
+
gap: 5px;
|
|
162163
|
+
}
|
|
162164
|
+
|
|
162165
|
+
.template-standard .standard-percentage {
|
|
162166
|
+
color: white;
|
|
162167
|
+
font-size: 14px;
|
|
162168
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
162169
|
+
}
|
|
162170
|
+
|
|
162171
|
+
.template-standard .standard-progress-container {
|
|
162172
|
+
width: 100%;
|
|
162173
|
+
height: 4px;
|
|
162174
|
+
background: rgba(255, 255, 255, 0.2);
|
|
162175
|
+
border-radius: 2px;
|
|
162176
|
+
overflow: hidden;
|
|
162177
|
+
}
|
|
162178
|
+
|
|
162179
|
+
.template-standard .standard-progress-bar {
|
|
162180
|
+
height: 100%;
|
|
162181
|
+
background: ${this.options.uiColor || '#4CAF50'};
|
|
162182
|
+
transition: width 0.3s ease;
|
|
162183
|
+
width: 0%;
|
|
162184
|
+
}
|
|
162185
|
+
|
|
162186
|
+
.template-standard .standard-buttons-container {
|
|
162187
|
+
display: flex;
|
|
162188
|
+
justify-content: center;
|
|
162189
|
+
align-items: center;
|
|
162190
|
+
gap: 15px;
|
|
162191
|
+
margin-top: 5px;
|
|
162192
|
+
}
|
|
162193
|
+
|
|
162194
|
+
.template-standard .standard-nav-button {
|
|
162195
|
+
background: rgba(255, 255, 255, 0.1);
|
|
162196
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
162197
|
+
color: white;
|
|
162198
|
+
padding: 8px 20px;
|
|
162199
|
+
border-radius: 20px;
|
|
162200
|
+
cursor: pointer;
|
|
162201
|
+
display: flex;
|
|
162202
|
+
align-items: center;
|
|
162203
|
+
gap: 8px;
|
|
162204
|
+
font-size: 14px;
|
|
162205
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
162206
|
+
transition: all 0.2s ease;
|
|
162207
|
+
}
|
|
162208
|
+
|
|
162209
|
+
.template-standard .standard-nav-button:hover {
|
|
162210
|
+
background: rgba(255, 255, 255, 0.2);
|
|
162211
|
+
transform: translateY(-1px);
|
|
162212
|
+
}
|
|
162213
|
+
|
|
162214
|
+
.template-standard .standard-autoplay {
|
|
162215
|
+
display: flex;
|
|
162216
|
+
align-items: center;
|
|
162217
|
+
}
|
|
162218
|
+
|
|
162219
|
+
.template-standard .standard-play-pause {
|
|
162220
|
+
background: rgba(255, 255, 255, 0.1);
|
|
162221
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
162222
|
+
color: white;
|
|
162223
|
+
width: 40px;
|
|
162224
|
+
height: 40px;
|
|
162225
|
+
border-radius: 50%;
|
|
162226
|
+
cursor: pointer;
|
|
162227
|
+
display: flex;
|
|
162228
|
+
align-items: center;
|
|
162229
|
+
justify-content: center;
|
|
162230
|
+
transition: all 0.2s ease;
|
|
162231
|
+
}
|
|
162232
|
+
|
|
162233
|
+
.template-standard .standard-play-pause:hover {
|
|
162234
|
+
background: rgba(255, 255, 255, 0.2);
|
|
162235
|
+
}
|
|
162236
|
+
|
|
162237
|
+
.template-standard .standard-play-pause svg {
|
|
162238
|
+
width: 16px;
|
|
162239
|
+
height: 16px;
|
|
162240
|
+
fill: currentColor;
|
|
162241
|
+
}
|
|
162242
|
+
|
|
162243
|
+
.template-standard .standard-mode-toggle {
|
|
162244
|
+
position: fixed;
|
|
162245
|
+
top: 20px;
|
|
162246
|
+
right: 20px;
|
|
162247
|
+
z-index: 100;
|
|
162248
|
+
}
|
|
162249
|
+
|
|
162250
|
+
.template-standard .standard-mode-toggle-row {
|
|
162251
|
+
display: flex;
|
|
162252
|
+
gap: 5px;
|
|
162253
|
+
background: rgba(0, 0, 0, 0.8);
|
|
162254
|
+
backdrop-filter: blur(10px);
|
|
162255
|
+
padding: 5px;
|
|
162256
|
+
border-radius: 8px;
|
|
162257
|
+
}
|
|
162258
|
+
|
|
162259
|
+
.template-standard .mode-button {
|
|
162260
|
+
background: rgba(255, 255, 255, 0.1);
|
|
162261
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
162262
|
+
color: white;
|
|
162263
|
+
padding: 8px 16px;
|
|
162264
|
+
border-radius: 4px;
|
|
162265
|
+
cursor: pointer;
|
|
162266
|
+
font-size: 13px;
|
|
162267
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
162268
|
+
transition: all 0.2s ease;
|
|
162269
|
+
min-width: 70px;
|
|
162270
|
+
}
|
|
162271
|
+
|
|
162272
|
+
.template-standard .mode-button:hover {
|
|
162273
|
+
background: rgba(255, 255, 255, 0.2);
|
|
162274
|
+
}
|
|
162275
|
+
|
|
162276
|
+
.template-standard .mode-button.selected {
|
|
162277
|
+
background: ${this.options.uiColor || '#4CAF50'};
|
|
162278
|
+
border-color: ${this.options.uiColor || '#4CAF50'};
|
|
162279
|
+
}
|
|
162280
|
+
|
|
162281
|
+
@media (max-width: 768px) {
|
|
162282
|
+
.template-standard .standard-controls {
|
|
162283
|
+
padding: 10px 15px;
|
|
162284
|
+
}
|
|
162285
|
+
|
|
162286
|
+
.template-standard .standard-nav-button {
|
|
162287
|
+
padding: 6px 15px;
|
|
162288
|
+
font-size: 13px;
|
|
162289
|
+
}
|
|
162290
|
+
|
|
162291
|
+
.template-standard .standard-mode-toggle {
|
|
162292
|
+
top: 10px;
|
|
162293
|
+
right: 10px;
|
|
162294
|
+
}
|
|
162295
|
+
|
|
162296
|
+
.template-standard .mode-button {
|
|
162297
|
+
padding: 6px 12px;
|
|
162298
|
+
font-size: 12px;
|
|
162299
|
+
min-width: 60px;
|
|
162300
|
+
}
|
|
162301
|
+
}
|
|
162302
|
+
`;
|
|
162303
|
+
document.head.appendChild(style);
|
|
162304
|
+
}
|
|
162305
|
+
/**
|
|
162306
|
+
* Apply pro template styles
|
|
162307
|
+
*/
|
|
162308
|
+
applyProStyles() {
|
|
162309
|
+
// TODO: Add pro template CSS
|
|
162310
|
+
}
|
|
162311
|
+
/**
|
|
162312
|
+
* Update progress display
|
|
162313
|
+
*/
|
|
162314
|
+
updateProgress(percentage) {
|
|
162315
|
+
const progressBar = document.getElementById('progressBar');
|
|
162316
|
+
const percentageDisplay = document.getElementById('scrollPercentage');
|
|
162317
|
+
if (progressBar) {
|
|
162318
|
+
progressBar.style.width = `${percentage}%`;
|
|
162319
|
+
}
|
|
162320
|
+
if (percentageDisplay) {
|
|
162321
|
+
percentageDisplay.textContent = `${Math.round(percentage)}%`;
|
|
162322
|
+
}
|
|
162323
|
+
}
|
|
162324
|
+
/**
|
|
162325
|
+
* Get preloader UI instance (for direct access if needed)
|
|
162326
|
+
*/
|
|
162327
|
+
getPreloaderUI() {
|
|
162328
|
+
return this.preloaderUI;
|
|
162329
|
+
}
|
|
162330
|
+
/**
|
|
162331
|
+
* Show/hide preloader
|
|
162332
|
+
*/
|
|
162333
|
+
showPreloader() {
|
|
162334
|
+
var _a;
|
|
162335
|
+
(_a = this.preloaderUI) === null || _a === void 0 ? void 0 : _a.show();
|
|
162336
|
+
}
|
|
162337
|
+
hidePreloader() {
|
|
162338
|
+
var _a;
|
|
162339
|
+
(_a = this.preloaderUI) === null || _a === void 0 ? void 0 : _a.hide();
|
|
162340
|
+
}
|
|
162341
|
+
/**
|
|
162342
|
+
* Update preloader progress
|
|
162343
|
+
*/
|
|
162344
|
+
updatePreloaderProgress(percentage, text) {
|
|
162345
|
+
var _a;
|
|
162346
|
+
(_a = this.preloaderUI) === null || _a === void 0 ? void 0 : _a.updateProgress(percentage, text);
|
|
162347
|
+
}
|
|
162348
|
+
/**
|
|
162349
|
+
* Update mode toggle button states
|
|
162350
|
+
*/
|
|
162351
|
+
updateModeToggleState(currentMode) {
|
|
162352
|
+
var _a;
|
|
162353
|
+
const buttons = (_a = this.modeToggleContainer) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.mode-button');
|
|
162354
|
+
buttons === null || buttons === void 0 ? void 0 : buttons.forEach(button => {
|
|
162355
|
+
const mode = button.id.replace('mode', '').toLowerCase();
|
|
162356
|
+
button.classList.toggle('selected', mode === currentMode);
|
|
162357
|
+
});
|
|
162358
|
+
}
|
|
162359
|
+
/**
|
|
162360
|
+
* Clean up and dispose
|
|
162361
|
+
*/
|
|
162362
|
+
dispose() {
|
|
162363
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
162364
|
+
// Dispose UI components
|
|
162365
|
+
(_a = this.preloaderUI) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
162366
|
+
(_b = this.startButtonUI) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
162367
|
+
(_c = this.watermarkUI) === null || _c === void 0 ? void 0 : _c.dispose();
|
|
162368
|
+
(_d = this.helpPanelUI) === null || _d === void 0 ? void 0 : _d.dispose();
|
|
162369
|
+
(_e = this.muteButtonUI) === null || _e === void 0 ? void 0 : _e.dispose();
|
|
162370
|
+
// Remove template classes
|
|
162371
|
+
this.targetElement.classList.remove('template-minimal', 'template-standard', 'template-pro');
|
|
162372
|
+
// Remove created elements
|
|
162373
|
+
(_f = this.controlsContainer) === null || _f === void 0 ? void 0 : _f.remove();
|
|
162374
|
+
(_g = this.modeToggleContainer) === null || _g === void 0 ? void 0 : _g.remove();
|
|
162375
|
+
(_h = this.progressContainer) === null || _h === void 0 ? void 0 : _h.remove();
|
|
162376
|
+
(_j = this.navigationContainer) === null || _j === void 0 ? void 0 : _j.remove();
|
|
162377
|
+
}
|
|
162378
|
+
}
|
|
162379
|
+
|
|
161469
162380
|
/******************************************************************************
|
|
161470
162381
|
Copyright (c) Microsoft Corporation.
|
|
161471
162382
|
|
|
@@ -161718,6 +162629,8 @@ class Viewer {
|
|
|
161718
162629
|
}
|
|
161719
162630
|
}
|
|
161720
162631
|
|
|
162632
|
+
// Define version constant (updated manually with each release)
|
|
162633
|
+
const VIEWER_VERSION = '0.1.21';
|
|
161721
162634
|
/**
|
|
161722
162635
|
* Initializes the StorySplat Viewer within a given HTML element.
|
|
161723
162636
|
*
|
|
@@ -161730,6 +162643,7 @@ class Viewer {
|
|
|
161730
162643
|
* Transforms raw JSON data into properly typed StorySplatData
|
|
161731
162644
|
*/
|
|
161732
162645
|
function transformSceneData(rawData) {
|
|
162646
|
+
var _a, _b;
|
|
161733
162647
|
// Handle all the data casting and transformation internally
|
|
161734
162648
|
return Object.assign({ loadedModelUrl: rawData.loadedModelUrl || rawData.modelUrl, hotspots: rawData.hotspots || [], waypoints: rawData.waypoints || [], lights: rawData.lights || [], particleSystems: rawData.particleSystems || [], customMeshes: rawData.customMeshes || [], additionalSplats: rawData.additionalSplats || [], activeSkyboxUrl: rawData.activeSkyboxUrl,
|
|
161735
162649
|
// Splat scaling properties
|
|
@@ -161737,7 +162651,7 @@ function transformSceneData(rawData) {
|
|
|
161737
162651
|
// Required top-level properties
|
|
161738
162652
|
fov: rawData.fov || 0.8, minClipPlane: rawData.minClipPlane || 0.1, maxClipPlane: rawData.maxClipPlane || 1000, cameraMovementSpeed: rawData.cameraMovementSpeed || 0.2, cameraRotationSensitivity: rawData.cameraRotationSensitivity || 4000, autoPlayEnabled: rawData.autoPlayEnabled || false, autoPlaySpeed: rawData.autoPlaySpeed || 1.0,
|
|
161739
162653
|
// Navigation properties for matching HTML export feel
|
|
161740
|
-
scrollSpeed: rawData.scrollSpeed || 0.001, transitionSpeed: rawData.transitionSpeed || 1.5, cameraDampening: rawData.cameraDampening || 0.1, initialCameraMode: rawData.defaultCameraMode || rawData.initialCameraMode || 'explore', defaultCameraMode: rawData.defaultCameraMode || 'explore', allowedCameraModes: rawData.allowedCameraModes || ['explore', 'tour', 'hybrid', 'walk'], backgroundColor: rawData.backgroundColor, backgroundAudio: rawData.backgroundAudio, sceneTitle: rawData.sceneTitle,
|
|
162654
|
+
scrollSpeed: rawData.scrollSpeed || 0.001, transitionSpeed: rawData.transitionSpeed || 1.5, cameraDampening: rawData.cameraDampening || 0.1, initialCameraMode: rawData.defaultCameraMode || rawData.initialCameraMode || (((_a = rawData.waypoints) === null || _a === void 0 ? void 0 : _a.length) > 0 ? 'tour' : 'explore'), defaultCameraMode: rawData.defaultCameraMode || (((_b = rawData.waypoints) === null || _b === void 0 ? void 0 : _b.length) > 0 ? 'tour' : 'explore'), allowedCameraModes: rawData.allowedCameraModes || ['explore', 'tour', 'hybrid', 'walk'], backgroundColor: rawData.backgroundColor, backgroundAudio: rawData.backgroundAudio, sceneTitle: rawData.sceneTitle,
|
|
161741
162655
|
// UI configuration
|
|
161742
162656
|
uiColor: rawData.uiColor || '#4CAF50', scrollButtonMode: rawData.scrollButtonMode || 'waypoint', scrollAmount: rawData.scrollAmount || 10, loopMode: rawData.loopMode || false, invertCameraRotation: rawData.invertCameraRotation || false, playerHeight: rawData.playerHeight || 1.8 }, rawData);
|
|
161743
162657
|
}
|
|
@@ -161763,7 +162677,7 @@ function createViewerOptions(rawData, userOptions) {
|
|
|
161763
162677
|
buttonPosition: ((_e = rawData.uiOptions) === null || _e === void 0 ? void 0 : _e.buttonPosition) || 'below',
|
|
161764
162678
|
showStartExperience: ((_f = rawData.uiOptions) === null || _f === void 0 ? void 0 : _f.showStartExperience) || false,
|
|
161765
162679
|
debugMode: ((_g = rawData.uiOptions) === null || _g === void 0 ? void 0 : _g.debugMode) || false,
|
|
161766
|
-
uiType: ((_h = rawData.uiOptions) === null || _h === void 0 ? void 0 : _h.uiType) || rawData.uiType || '
|
|
162680
|
+
uiType: ((_h = rawData.uiOptions) === null || _h === void 0 ? void 0 : _h.uiType) || rawData.uiType || 'standard', // Default to standard instead of minimal to match HTML
|
|
161767
162681
|
hideWatermark: ((_j = rawData.uiOptions) === null || _j === void 0 ? void 0 : _j.hideWatermark) || false,
|
|
161768
162682
|
watermarkText: (_k = rawData.uiOptions) === null || _k === void 0 ? void 0 : _k.watermarkText,
|
|
161769
162683
|
watermarkLink: (_l = rawData.uiOptions) === null || _l === void 0 ? void 0 : _l.watermarkLink
|
|
@@ -161776,7 +162690,7 @@ function createViewerOptions(rawData, userOptions) {
|
|
|
161776
162690
|
}
|
|
161777
162691
|
async function initializeViewer(targetElement, rawData, // Accept any JSON data
|
|
161778
162692
|
options) {
|
|
161779
|
-
var _a, _b;
|
|
162693
|
+
var _a, _b, _c, _d;
|
|
161780
162694
|
// Register BabylonJS loaders at runtime
|
|
161781
162695
|
try {
|
|
161782
162696
|
registerBuiltInLoaders();
|
|
@@ -161801,7 +162715,27 @@ options) {
|
|
|
161801
162715
|
}
|
|
161802
162716
|
// Create comprehensive viewer options from the data
|
|
161803
162717
|
const finalViewerOptions = createViewerOptions(rawData, options);
|
|
161804
|
-
console.log(`StorySplat Viewer v${
|
|
162718
|
+
console.log(`StorySplat Viewer v${VIEWER_VERSION}: Initializing...`);
|
|
162719
|
+
// Debug logging for camera mode configuration
|
|
162720
|
+
console.log('DEBUG: Raw data camera modes:', {
|
|
162721
|
+
defaultCameraMode: rawData.defaultCameraMode,
|
|
162722
|
+
initialCameraMode: rawData.initialCameraMode,
|
|
162723
|
+
allowedCameraModes: rawData.allowedCameraModes,
|
|
162724
|
+
waypoints: ((_a = rawData.waypoints) === null || _a === void 0 ? void 0 : _a.length) || 0
|
|
162725
|
+
});
|
|
162726
|
+
console.log('DEBUG: Transformed data camera modes:', {
|
|
162727
|
+
initialCameraMode: data.initialCameraMode,
|
|
162728
|
+
allowedCameraModes: data.allowedCameraModes,
|
|
162729
|
+
waypoints: ((_b = data.waypoints) === null || _b === void 0 ? void 0 : _b.length) || 0
|
|
162730
|
+
});
|
|
162731
|
+
console.log('DEBUG: Final viewer options camera modes:', {
|
|
162732
|
+
defaultCameraMode: finalViewerOptions.defaultCameraMode,
|
|
162733
|
+
allowedCameraModes: finalViewerOptions.allowedCameraModes,
|
|
162734
|
+
showCameraModeToggle: finalViewerOptions.showCameraModeToggle,
|
|
162735
|
+
showWalkExploreToggle: finalViewerOptions.showWalkExploreToggle,
|
|
162736
|
+
showProgressBar: finalViewerOptions.showProgressBar,
|
|
162737
|
+
showNavButtons: finalViewerOptions.showNavButtons
|
|
162738
|
+
});
|
|
161805
162739
|
// --- 1. Create Canvas ---
|
|
161806
162740
|
const canvas = document.createElement("canvas");
|
|
161807
162741
|
canvas.style.width = "100%";
|
|
@@ -161823,11 +162757,7 @@ options) {
|
|
|
161823
162757
|
let navigationManager = null;
|
|
161824
162758
|
let collisionManager = null;
|
|
161825
162759
|
// let uiManager: UIManager | null = null; // REMOVED: Old monolithic UI Manager
|
|
161826
|
-
let
|
|
161827
|
-
let startButtonUI = null;
|
|
161828
|
-
let watermarkUI = null;
|
|
161829
|
-
let helpPanelUI = null;
|
|
161830
|
-
let muteButtonUI = null; // Add reference for MuteButtonUI
|
|
162760
|
+
let templateManager = null; // NEW: Template-based UI system
|
|
161831
162761
|
let audioManager = null;
|
|
161832
162762
|
let renderLoopManager = null; // Add RenderLoopManager reference
|
|
161833
162763
|
let xrExperience = null; // Add XR experience reference
|
|
@@ -161861,13 +162791,9 @@ options) {
|
|
|
161861
162791
|
splatSwapManager = null;
|
|
161862
162792
|
audioManager === null || audioManager === void 0 ? void 0 : audioManager.dispose();
|
|
161863
162793
|
audioManager = null;
|
|
161864
|
-
// Dispose
|
|
161865
|
-
|
|
161866
|
-
|
|
161867
|
-
watermarkUI === null || watermarkUI === void 0 ? void 0 : watermarkUI.dispose();
|
|
161868
|
-
helpPanelUI === null || helpPanelUI === void 0 ? void 0 : helpPanelUI.dispose();
|
|
161869
|
-
muteButtonUI === null || muteButtonUI === void 0 ? void 0 : muteButtonUI.dispose(); // Dispose mute button UI
|
|
161870
|
-
preloaderUI = startButtonUI = watermarkUI = helpPanelUI = muteButtonUI = null;
|
|
162794
|
+
// Dispose template manager (handles all UI components)
|
|
162795
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.dispose();
|
|
162796
|
+
templateManager = null;
|
|
161871
162797
|
// NavigationManager and CameraManager disposal is handled by scene dispose or specific logic within them
|
|
161872
162798
|
// Dispose features managed outside scene graph
|
|
161873
162799
|
if (scene && finalViewerOptions) {
|
|
@@ -161970,9 +162896,17 @@ options) {
|
|
|
161970
162896
|
throw new Error("Camera not initialized before NavigationManager"); // Guard
|
|
161971
162897
|
if (!analyticsManager)
|
|
161972
162898
|
throw new Error("AnalyticsManager not initialized before NavigationManager"); // Guard
|
|
162899
|
+
// Debug logging for NavigationManager initialization
|
|
162900
|
+
console.log('DEBUG: NavigationManager initialization with camera modes:', {
|
|
162901
|
+
allowedCameraModes: data.allowedCameraModes,
|
|
162902
|
+
initialCameraMode: data.initialCameraMode,
|
|
162903
|
+
finalViewerOptions_allowedCameraModes: finalViewerOptions.allowedCameraModes,
|
|
162904
|
+
finalViewerOptions_defaultCameraMode: finalViewerOptions.defaultCameraMode,
|
|
162905
|
+
waypointCount: ((_c = data.waypoints) === null || _c === void 0 ? void 0 : _c.length) || 0
|
|
162906
|
+
});
|
|
161973
162907
|
// Pass the collisionManager and analyticsManager instances to NavigationManager
|
|
161974
162908
|
// Pass viewerOptions directly, relying on its content for allowed modes etc.
|
|
161975
|
-
navigationManager = new NavigationManager(scene, camera, Object.assign(Object.assign({}, finalViewerOptions), { allowedCameraModes: data.allowedCameraModes, initialCameraMode: data.initialCameraMode, waypoints: (
|
|
162909
|
+
navigationManager = new NavigationManager(scene, camera, Object.assign(Object.assign({}, finalViewerOptions), { allowedCameraModes: data.allowedCameraModes, initialCameraMode: data.initialCameraMode, waypoints: (_d = data.waypoints) === null || _d === void 0 ? void 0 : _d.map(wp => {
|
|
161976
162910
|
var _a;
|
|
161977
162911
|
return ({
|
|
161978
162912
|
x: wp.x,
|
|
@@ -161997,6 +162931,7 @@ options) {
|
|
|
161997
162931
|
triggerDistance: wp.triggerDistance
|
|
161998
162932
|
});
|
|
161999
162933
|
}) }), targetElement, collisionManager, analyticsManager);
|
|
162934
|
+
console.log('DEBUG: NavigationManager created. Current mode:', navigationManager.getCurrentMode());
|
|
162000
162935
|
// --- No explicit sync needed - both managers use the same initial mode logic ---
|
|
162001
162936
|
// NavigationManager determines its own initial mode in constructor based on the same data/options
|
|
162002
162937
|
// The onCameraModeChanged callback will handle future mode changes
|
|
@@ -162010,44 +162945,23 @@ options) {
|
|
|
162010
162945
|
splatSwapManager === null || splatSwapManager === void 0 ? void 0 : splatSwapManager.updateProgress(progress, waypointIndex);
|
|
162011
162946
|
};
|
|
162012
162947
|
}
|
|
162013
|
-
// --- 9. Initialize
|
|
162014
|
-
//
|
|
162015
|
-
|
|
162016
|
-
//
|
|
162017
|
-
//
|
|
162018
|
-
|
|
162019
|
-
|
|
162020
|
-
|
|
162021
|
-
|
|
162022
|
-
uiColor: (finalViewerOptions === null || finalViewerOptions === void 0 ? void 0 : finalViewerOptions.uiColor) || '#4CAF50'
|
|
162023
|
-
};
|
|
162024
|
-
const preloaderConfig = Object.assign(Object.assign({}, defaultPreloaderConfig), finalViewerOptions === null || finalViewerOptions === void 0 ? void 0 : finalViewerOptions.preloaderConfig);
|
|
162025
|
-
preloaderUI = new PreloaderUI(targetElement, preloaderConfig);
|
|
162026
|
-
preloaderUI.create();
|
|
162027
|
-
// Start Button
|
|
162028
|
-
if (finalViewerOptions === null || finalViewerOptions === void 0 ? void 0 : finalViewerOptions.showStartExperience) {
|
|
162029
|
-
startButtonUI = new StartButtonUI(targetElement, finalViewerOptions, () => {
|
|
162030
|
-
// Callback to initialize audio context on first interaction
|
|
162031
|
-
audioManager === null || audioManager === void 0 ? void 0 : audioManager.initialize(); // Use the correct initialize method
|
|
162032
|
-
});
|
|
162033
|
-
startButtonUI.create();
|
|
162034
|
-
}
|
|
162035
|
-
// Watermark
|
|
162036
|
-
watermarkUI = new WatermarkUI(targetElement, finalViewerOptions);
|
|
162037
|
-
watermarkUI.create(); // Creates conditionally based on options inside the class
|
|
162038
|
-
// Help Panel
|
|
162039
|
-
helpPanelUI = new HelpPanelUI(targetElement, finalViewerOptions);
|
|
162040
|
-
helpPanelUI.create(); // Creates conditionally based on options inside the class
|
|
162041
|
-
// Mute Button (Needs AudioManager instance)
|
|
162042
|
-
// We'll initialize this after AudioManager is created
|
|
162948
|
+
// --- 9. Initialize Template Manager ---
|
|
162949
|
+
// The template manager handles all UI components based on the uiType
|
|
162950
|
+
templateManager = new TemplateManager(targetElement, finalViewerOptions);
|
|
162951
|
+
// Initialize the template UI (but don't fully set up navigation controls yet)
|
|
162952
|
+
// We'll do that after navigation manager is created
|
|
162953
|
+
await templateManager.initializeUI(null, null, null, () => {
|
|
162954
|
+
// Callback to initialize audio context on first interaction
|
|
162955
|
+
audioManager === null || audioManager === void 0 ? void 0 : audioManager.initialize();
|
|
162956
|
+
});
|
|
162043
162957
|
// --- 10. Load Splat Data ---
|
|
162044
162958
|
console.log("StorySplat Viewer: Starting splat asset load...");
|
|
162045
162959
|
splatRootMeshes = await loadSplatAsset(scene, data, (percentage, text) => {
|
|
162046
|
-
// Update preloader UI via
|
|
162047
|
-
|
|
162960
|
+
// Update preloader UI via template manager
|
|
162961
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.updatePreloaderProgress(percentage, text);
|
|
162048
162962
|
});
|
|
162049
162963
|
console.log("StorySplat Viewer: Splat asset loaded.");
|
|
162050
|
-
|
|
162964
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.hidePreloader(); // Hide preloader after splat is loaded
|
|
162051
162965
|
// --- 11. Initialize/Setup Features ---
|
|
162052
162966
|
// Setup Particle Systems (sync)
|
|
162053
162967
|
// Ensure setupParticleSystems is correctly imported and called
|
|
@@ -162085,11 +162999,9 @@ options) {
|
|
|
162085
162999
|
if (!analyticsManager)
|
|
162086
163000
|
throw new Error("AnalyticsManager not initialized before AudioManager"); // Guard
|
|
162087
163001
|
audioManager = new AudioManager(scene, finalViewerOptions, analyticsManager);
|
|
162088
|
-
//
|
|
162089
|
-
|
|
162090
|
-
|
|
162091
|
-
muteButtonUI.create();
|
|
162092
|
-
}
|
|
163002
|
+
// Re-initialize template UI with audio manager now that it's available
|
|
163003
|
+
// This will create the mute button if needed
|
|
163004
|
+
await templateManager.initializeUI(audioManager, navigationManager, cameraManager);
|
|
162093
163005
|
// --- 12. Initialize Render Loop Manager ---
|
|
162094
163006
|
// Needs engine, scene, cameraManager, navigationManager
|
|
162095
163007
|
if (engine && scene && cameraManager) { // Ensure core components exist
|
|
@@ -162119,7 +163031,7 @@ options) {
|
|
|
162119
163031
|
}
|
|
162120
163032
|
}, 0);
|
|
162121
163033
|
}
|
|
162122
|
-
console.log(`StorySplat Viewer v${
|
|
163034
|
+
console.log(`StorySplat Viewer v${VIEWER_VERSION}: Initialized successfully.`);
|
|
162123
163035
|
// --- 16. Define API Methods ---
|
|
162124
163036
|
const setCameraMode = (mode) => cameraManager === null || cameraManager === void 0 ? void 0 : cameraManager.setCameraMode(mode);
|
|
162125
163037
|
const getCurrentCameraMode = () => { var _a; return (_a = cameraManager === null || cameraManager === void 0 ? void 0 : cameraManager.currentMode) !== null && _a !== void 0 ? _a : 'explore'; }; // Provide default
|
|
@@ -162165,8 +163077,8 @@ options) {
|
|
|
162165
163077
|
console.log(`StorySplat Viewer: Starting splat swap to ${newSplatUrl}`);
|
|
162166
163078
|
analyticsManager === null || analyticsManager === void 0 ? void 0 : analyticsManager.trackSplatSwapStarted(newSplatUrl); // Corrected method call
|
|
162167
163079
|
// Show preloader
|
|
162168
|
-
|
|
162169
|
-
|
|
163080
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.showPreloader();
|
|
163081
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.updatePreloaderProgress(0, 'Preparing to load new splat...'); // Initial message
|
|
162170
163082
|
// Dispose existing splat meshes
|
|
162171
163083
|
console.log("StorySplat Viewer: Disposing current splat meshes...");
|
|
162172
163084
|
splatRootMeshes.forEach(mesh => {
|
|
@@ -162189,7 +163101,7 @@ options) {
|
|
|
162189
163101
|
// Ensure other potentially relevant fields from data are present if needed
|
|
162190
163102
|
waypoints: data.waypoints, hotspots: data.hotspots });
|
|
162191
163103
|
splatRootMeshes = await loadSplatAsset(scene, tempData, (percentage, text) => {
|
|
162192
|
-
|
|
163104
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.updatePreloaderProgress(percentage, text);
|
|
162193
163105
|
});
|
|
162194
163106
|
currentSplatUrl = newSplatUrl; // Update the tracked URL
|
|
162195
163107
|
console.log("StorySplat Viewer: New splat asset loaded successfully.");
|
|
@@ -162211,12 +163123,12 @@ options) {
|
|
|
162211
163123
|
console.error(`StorySplat Viewer: Failed to load new splat asset from ${newSplatUrl}:`, error);
|
|
162212
163124
|
analyticsManager === null || analyticsManager === void 0 ? void 0 : analyticsManager.trackSplatSwapFailed(error, newSplatUrl); // Corrected method call
|
|
162213
163125
|
// Hide preloader even on error
|
|
162214
|
-
|
|
163126
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.hidePreloader();
|
|
162215
163127
|
// Re-throw error to signal failure to the caller
|
|
162216
163128
|
throw error;
|
|
162217
163129
|
}
|
|
162218
163130
|
// Hide preloader on success
|
|
162219
|
-
|
|
163131
|
+
templateManager === null || templateManager === void 0 ? void 0 : templateManager.hidePreloader();
|
|
162220
163132
|
console.log("StorySplat Viewer: Splat swap complete.");
|
|
162221
163133
|
};
|
|
162222
163134
|
/**
|