@littlecarlito/blorktools 0.50.4 → 0.51.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.
Files changed (114) hide show
  1. package/bin/cli.js +69 -0
  2. package/package.json +13 -7
  3. package/src/asset_debugger/axis-indicator/axis-indicator.css +6 -0
  4. package/src/asset_debugger/axis-indicator/axis-indicator.html +20 -0
  5. package/src/asset_debugger/axis-indicator/axis-indicator.js +822 -0
  6. package/src/asset_debugger/debugger-scene/debugger-scene.css +142 -0
  7. package/src/asset_debugger/debugger-scene/debugger-scene.html +80 -0
  8. package/src/asset_debugger/debugger-scene/debugger-scene.js +791 -0
  9. package/src/asset_debugger/header/header.css +73 -0
  10. package/src/asset_debugger/header/header.html +24 -0
  11. package/src/asset_debugger/header/header.js +224 -0
  12. package/src/asset_debugger/index.html +76 -0
  13. package/src/asset_debugger/landing-page/landing-page.css +396 -0
  14. package/src/asset_debugger/landing-page/landing-page.html +81 -0
  15. package/src/asset_debugger/landing-page/landing-page.js +611 -0
  16. package/src/asset_debugger/loading-splash/loading-splash.css +195 -0
  17. package/src/asset_debugger/loading-splash/loading-splash.html +22 -0
  18. package/src/asset_debugger/loading-splash/loading-splash.js +59 -0
  19. package/src/asset_debugger/loading-splash/preview-loading-splash.js +66 -0
  20. package/src/asset_debugger/main.css +14 -0
  21. package/src/asset_debugger/modals/examples-modal/examples-modal.css +41 -0
  22. package/src/asset_debugger/modals/examples-modal/examples-modal.html +18 -0
  23. package/src/asset_debugger/modals/examples-modal/examples-modal.js +111 -0
  24. package/src/asset_debugger/modals/examples-modal/examples.js +125 -0
  25. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.css +452 -0
  26. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.html +87 -0
  27. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.js +675 -0
  28. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.css +219 -0
  29. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.html +20 -0
  30. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.js +548 -0
  31. package/src/asset_debugger/modals/settings-modal/settings-modal.css +103 -0
  32. package/src/asset_debugger/modals/settings-modal/settings-modal.html +158 -0
  33. package/src/asset_debugger/modals/settings-modal/settings-modal.js +475 -0
  34. package/src/asset_debugger/panels/asset-panel/asset-panel.css +263 -0
  35. package/src/asset_debugger/panels/asset-panel/asset-panel.html +123 -0
  36. package/src/asset_debugger/panels/asset-panel/asset-panel.js +136 -0
  37. package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.css +94 -0
  38. package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.js +312 -0
  39. package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.css +129 -0
  40. package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.js +486 -0
  41. package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.css +545 -0
  42. package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.js +538 -0
  43. package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.css +70 -0
  44. package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.js +586 -0
  45. package/src/asset_debugger/panels/world-panel/world-panel.css +364 -0
  46. package/src/asset_debugger/panels/world-panel/world-panel.html +173 -0
  47. package/src/asset_debugger/panels/world-panel/world-panel.js +1891 -0
  48. package/src/asset_debugger/router.js +190 -0
  49. package/src/asset_debugger/util/animation/playback/animation-playback-controller.js +150 -0
  50. package/src/asset_debugger/util/animation/playback/animation-preview-controller.js +316 -0
  51. package/src/asset_debugger/util/animation/playback/css3d-bounce-controller.js +400 -0
  52. package/src/asset_debugger/util/animation/playback/css3d-reversal-controller.js +821 -0
  53. package/src/asset_debugger/util/animation/render/css3d-prerender-controller.js +696 -0
  54. package/src/asset_debugger/util/animation/render/debug-texture-factory.js +0 -0
  55. package/src/asset_debugger/util/animation/render/iframe2texture-render-controller.js +199 -0
  56. package/src/asset_debugger/util/animation/render/image2texture-prerender-controller.js +461 -0
  57. package/src/asset_debugger/util/animation/render/pbr-material-factory.js +82 -0
  58. package/src/asset_debugger/util/common.css +280 -0
  59. package/src/asset_debugger/util/data/animation-classifier.js +323 -0
  60. package/src/asset_debugger/util/data/duplicate-handler.js +20 -0
  61. package/src/asset_debugger/util/data/glb-buffer-manager.js +407 -0
  62. package/src/asset_debugger/util/data/glb-classifier.js +290 -0
  63. package/src/asset_debugger/util/data/html-formatter.js +76 -0
  64. package/src/asset_debugger/util/data/html-linter.js +276 -0
  65. package/src/asset_debugger/util/data/localstorage-manager.js +265 -0
  66. package/src/asset_debugger/util/data/mesh-html-manager.js +295 -0
  67. package/src/asset_debugger/util/data/string-serder.js +303 -0
  68. package/src/asset_debugger/util/data/texture-classifier.js +663 -0
  69. package/src/asset_debugger/util/data/upload/background-file-handler.js +292 -0
  70. package/src/asset_debugger/util/data/upload/dropzone-preview-controller.js +396 -0
  71. package/src/asset_debugger/util/data/upload/file-upload-manager.js +495 -0
  72. package/src/asset_debugger/util/data/upload/glb-file-handler.js +36 -0
  73. package/src/asset_debugger/util/data/upload/glb-preview-controller.js +317 -0
  74. package/src/asset_debugger/util/data/upload/lighting-file-handler.js +194 -0
  75. package/src/asset_debugger/util/data/upload/model-file-manager.js +104 -0
  76. package/src/asset_debugger/util/data/upload/texture-file-handler.js +166 -0
  77. package/src/asset_debugger/util/data/upload/zip-handler.js +686 -0
  78. package/src/asset_debugger/util/loaders/html2canvas-loader.js +107 -0
  79. package/src/asset_debugger/util/rig/bone-kinematics.js +403 -0
  80. package/src/asset_debugger/util/rig/rig-constraint-manager.js +618 -0
  81. package/src/asset_debugger/util/rig/rig-controller.js +612 -0
  82. package/src/asset_debugger/util/rig/rig-factory.js +628 -0
  83. package/src/asset_debugger/util/rig/rig-handle-factory.js +46 -0
  84. package/src/asset_debugger/util/rig/rig-label-factory.js +441 -0
  85. package/src/asset_debugger/util/rig/rig-mouse-handler.js +377 -0
  86. package/src/asset_debugger/util/rig/rig-state-manager.js +175 -0
  87. package/src/asset_debugger/util/rig/rig-tooltip-manager.js +267 -0
  88. package/src/asset_debugger/util/rig/rig-ui-factory.js +700 -0
  89. package/src/asset_debugger/util/scene/background-manager.js +284 -0
  90. package/src/asset_debugger/util/scene/camera-controller.js +243 -0
  91. package/src/asset_debugger/util/scene/css3d-debug-controller.js +406 -0
  92. package/src/asset_debugger/util/scene/css3d-frame-factory.js +113 -0
  93. package/src/asset_debugger/util/scene/css3d-scene-manager.js +529 -0
  94. package/src/asset_debugger/util/scene/glb-controller.js +208 -0
  95. package/src/asset_debugger/util/scene/lighting-manager.js +690 -0
  96. package/src/asset_debugger/util/scene/threejs-model-manager.js +437 -0
  97. package/src/asset_debugger/util/scene/threejs-preview-manager.js +207 -0
  98. package/src/asset_debugger/util/scene/threejs-preview-setup.js +478 -0
  99. package/src/asset_debugger/util/scene/threejs-scene-controller.js +286 -0
  100. package/src/asset_debugger/util/scene/ui-manager.js +107 -0
  101. package/src/asset_debugger/util/state/animation-state.js +128 -0
  102. package/src/asset_debugger/util/state/css3d-state.js +83 -0
  103. package/src/asset_debugger/util/state/glb-preview-state.js +31 -0
  104. package/src/asset_debugger/util/state/log-util.js +197 -0
  105. package/src/asset_debugger/util/state/scene-state.js +452 -0
  106. package/src/asset_debugger/util/state/threejs-state.js +54 -0
  107. package/src/asset_debugger/util/workers/lighting-worker.js +61 -0
  108. package/src/asset_debugger/util/workers/model-worker.js +109 -0
  109. package/src/asset_debugger/util/workers/texture-worker.js +54 -0
  110. package/src/asset_debugger/util/workers/worker-manager.js +212 -0
  111. package/src/asset_debugger/widgets/mesh-info-widget.js +280 -0
  112. package/src/index.html +261 -0
  113. package/src/index.js +8 -0
  114. package/vite.config.js +66 -0
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Create or get an error log container
3
+ * @param {HTMLElement} container - Parent container for the error log
4
+ * @param {string} [logId] - Custom ID for the error log element
5
+ * @param {string} [className] - Custom class name for styling
6
+ * @returns {HTMLElement} The error log element
7
+ */
8
+ export function createErrorLog(container, logId = 'error-log', className = 'error-log') {
9
+ if (!container) throw new Error('Container element is required');
10
+
11
+ let errorLog = container.querySelector(`#${logId}`);
12
+
13
+ if (!errorLog) {
14
+ errorLog = document.createElement('div');
15
+ errorLog.id = logId;
16
+ errorLog.className = className;
17
+ errorLog.style.display = 'none';
18
+ container.appendChild(errorLog);
19
+ }
20
+
21
+ return errorLog;
22
+ }
23
+
24
+ /**
25
+ * Add an error entry to an error log
26
+ * @param {HTMLElement} errorLog - The error log container
27
+ * @param {string} message - Error message to display
28
+ * @param {Object} [options] - Additional options
29
+ * @param {boolean} [options.showTimestamp=true] - Whether to show timestamp
30
+ * @param {string} [options.entryClassName='error-entry'] - Class name for the entry
31
+ * @param {string} [options.timeClassName='error-time'] - Class name for the timestamp
32
+ */
33
+ export function addErrorEntry(errorLog, message, options = {}) {
34
+ const {
35
+ showTimestamp = true,
36
+ entryClassName = 'error-entry',
37
+ timeClassName = 'error-time'
38
+ } = options;
39
+
40
+ if (!errorLog) throw new Error('Error log element is required');
41
+
42
+ const errorEntry = document.createElement('div');
43
+ errorEntry.className = entryClassName;
44
+ errorEntry.textContent = message;
45
+
46
+ if (showTimestamp) {
47
+ const timestamp = new Date().toLocaleTimeString();
48
+ const timeSpan = document.createElement('span');
49
+ timeSpan.className = timeClassName;
50
+ timeSpan.textContent = `[${timestamp}] `;
51
+ errorEntry.prepend(timeSpan);
52
+ }
53
+
54
+ errorLog.appendChild(errorEntry);
55
+ errorLog.style.display = 'block';
56
+ }
57
+
58
+ /**
59
+ * Log an error to a container with automatic error log creation
60
+ * @param {string} message - Error message to display
61
+ * @param {HTMLElement} container - Container for the error log
62
+ * @param {Object} [options] - Configuration options
63
+ * @param {string} [options.logId] - Custom ID for error log
64
+ * @param {string} [options.logClassName] - Custom class for error log
65
+ * @param {Function} [options.statusCallback] - Function to call for status updates
66
+ * @param {boolean} [options.consoleLog=true] - Whether to also log to console
67
+ * @param {Object} [options.entryOptions] - Options passed to addErrorEntry
68
+ */
69
+ export function logError(message, container, options = {}) {
70
+ const {
71
+ logId = 'error-log',
72
+ logClassName = 'error-log',
73
+ statusCallback,
74
+ consoleLog = true,
75
+ entryOptions = {}
76
+ } = options;
77
+
78
+ if (!container) throw new Error('Container element is required');
79
+
80
+ const errorLog = createErrorLog(container, logId, logClassName);
81
+ addErrorEntry(errorLog, message, entryOptions);
82
+
83
+ if (statusCallback && typeof statusCallback === 'function') {
84
+ statusCallback(message, 'error');
85
+ }
86
+
87
+ if (consoleLog) {
88
+ console.error(message);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Clear all entries from an error log
94
+ * @param {HTMLElement} errorLog - The error log to clear
95
+ * @param {boolean} [hide=true] - Whether to hide the log after clearing
96
+ */
97
+ export function clearErrorLog(errorLog, hide = true) {
98
+ if (!errorLog) return;
99
+
100
+ errorLog.innerHTML = '';
101
+ if (hide) {
102
+ errorLog.style.display = 'none';
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Get all error entries from an error log
108
+ * @param {HTMLElement} errorLog - The error log to read from
109
+ * @returns {string[]} Array of error messages
110
+ */
111
+ export function getErrorEntries(errorLog) {
112
+ if (!errorLog) return [];
113
+
114
+ const entries = errorLog.querySelectorAll('.error-entry');
115
+ return Array.from(entries).map(entry => entry.textContent);
116
+ }
117
+
118
+ /**
119
+ * Utility function to get caller information from stack trace
120
+ * @param {number} [skipLevels=1] - Number of stack levels to skip (default skips the getCaller function itself)
121
+ * @returns {string} Caller information in format "function@file.js:line"
122
+ */
123
+ export function getCaller(skipLevels = 1) {
124
+ try {
125
+ const stack = new Error().stack;
126
+ const lines = stack.split('\n');
127
+
128
+ // Skip this function and any additional levels requested
129
+ const callerLine = lines[skipLevels + 1];
130
+ if (!callerLine) return 'no-stack';
131
+
132
+ // Quick extraction - prioritize speed over perfection
133
+ // Look for common patterns: "at function (file:line)" or "function@file:line"
134
+ if (callerLine.includes('at ')) {
135
+ const atMatch = callerLine.match(/at\s+([^(]+?)(?:\s+\(.*?([^\/\\]+):(\d+)|.*?([^\/\\]+):(\d+))/);
136
+ if (atMatch) {
137
+ const func = atMatch[1]?.trim() || 'anonymous';
138
+ const file = atMatch[2] || atMatch[4];
139
+ const line = atMatch[3] || atMatch[5];
140
+ return file && line ? `${func}@${file}:${line}` : func;
141
+ }
142
+ } else if (callerLine.includes('@')) {
143
+ const atMatch = callerLine.match(/([^@]+)@.*?([^\/\\]+):(\d+)/);
144
+ if (atMatch) return `${atMatch[1]}@${atMatch[2]}:${atMatch[3]}`;
145
+ }
146
+
147
+ // Fallback: just show a truncated version of the line
148
+ return callerLine.substring(callerLine.lastIndexOf('/') + 1, callerLine.length).trim() || 'unknown';
149
+ } catch (e) {
150
+ return 'error';
151
+ }
152
+ }
153
+
154
+ // Debug reporting function for animation analysis
155
+ export function logAnimationAnalysisReport(renderType, data) {
156
+ const {
157
+ frameCount,
158
+ duration,
159
+ isFinite,
160
+ loopDetected,
161
+ endDetected,
162
+ analysisTime,
163
+ metrics
164
+ } = data;
165
+
166
+ console.debug(
167
+ `%c Animation Analysis Report: ${renderType} %c`,
168
+ 'background: #4285f4; color: white; padding: 2px 6px; border-radius: 2px; font-weight: bold;',
169
+ 'background: transparent;'
170
+ );
171
+
172
+ console.debug({
173
+ renderType,
174
+ framesAnalyzed: frameCount,
175
+ duration: duration ? `${(duration/1000).toFixed(2)}s` : 'unknown',
176
+ isFiniteAnimation: isFinite,
177
+ loopDetected,
178
+ endDetected,
179
+ analysisTime: `${(analysisTime/1000).toFixed(2)}s`,
180
+ metrics
181
+ });
182
+ }
183
+
184
+ /**
185
+ * Log errors specifically for preview context using generic logging
186
+ */
187
+ export function logPreviewError(message, previewContent, existingErrorLog, statusCallback) {
188
+ logError(message, previewContent, {
189
+ logId: 'html-preview-error-log',
190
+ logClassName: 'preview-error-log',
191
+ statusCallback: statusCallback || showStatus,
192
+ entryOptions: {
193
+ entryClassName: 'error-entry',
194
+ timeClassName: 'error-time'
195
+ }
196
+ });
197
+ }
@@ -0,0 +1,452 @@
1
+ /**
2
+ * Texture Debugger - State Management Module
3
+ *
4
+ * This module manages the global state for the texture debugger tool.
5
+ * It provides methods to initialize, access, and update the application state.
6
+ */
7
+
8
+ import { saveCurrentSession, loadCurrentSession, clearSessionData } from '../data/localstorage-manager.js';
9
+ import { getCaller } from './log-util.js';
10
+
11
+ // Define the initial state
12
+ const initialState = {
13
+ sessionId: null,
14
+ timestamp: null,
15
+ scene: null,
16
+ camera: null,
17
+ renderer: null,
18
+ controls: null,
19
+
20
+ textureFiles: {
21
+ baseColor: null, // File object
22
+ orm: null, // File object
23
+ normal: null // File object
24
+ },
25
+ // Texture objects (THREE.Texture objects)
26
+ textureObjects: {
27
+ baseColor: null,
28
+ orm: null,
29
+ normal: null
30
+ },
31
+ modelFile: null, // File object
32
+ model: null,
33
+ cube: null,
34
+ lightingFile: null, // File object
35
+ backgroundFile: null, // File object
36
+ backgroundTexture: null,
37
+
38
+ // Animation ID for cancelAnimationFrame
39
+ animationId: null,
40
+
41
+ // Mesh management
42
+ meshes: [],
43
+ meshGroups: {},
44
+
45
+ // Atlas visualization
46
+ currentTextureType: 'baseColor',
47
+ currentUvRegion: { min: [0, 0], max: [1, 1] },
48
+
49
+ // UV data
50
+ availableUvSets: [],
51
+ uvSetNames: [],
52
+ currentUvSet: 0,
53
+ screenMeshes: [], // New: display/screen meshes
54
+ uvMappingInfo: {}, // New: detailed mapping info for UV channels
55
+
56
+ // Status flags
57
+ isDebugStarted: false,
58
+ useCustomModel: false,
59
+ useLightingTestCube: false, // Flag to indicate we should use the special lighting test cube
60
+
61
+ // Helper functions
62
+ cycleAtlasSegments: null, // New: function to cycle atlas segments
63
+ setCurrentUvRegion: null, // New: function to set current UV region
64
+ switchUvChannel: null, // New: function to switch UV channel
65
+
66
+ // Environment lighting
67
+ environmentLightingEnabled: false,
68
+ ambientLight: null,
69
+ directionalLight: null,
70
+
71
+ // Material properties
72
+ materialProperties: {
73
+ metalness: 0.5,
74
+ roughness: 0.5,
75
+ normalScale: 1.0
76
+ },
77
+
78
+ // UV unwrapping options
79
+ unwrapOptions: {
80
+ wireframe: true,
81
+ displayUVs: true,
82
+ textureDisplay: 'baseColor'
83
+ },
84
+
85
+ // Rig related properties
86
+ rigOptions: {
87
+ autoRotate: false,
88
+ showSkeleton: true,
89
+ enableIK: true,
90
+ currentAnimation: null,
91
+ playAnimation: false,
92
+ animationSpeed: 1.0
93
+ }
94
+ };
95
+
96
+ // The actual state object - singleton
97
+ let state = null;
98
+
99
+ /**
100
+ * Initialize a new draft state for the landing page
101
+ * This state won't be saved as current until startDebugging is called
102
+ * @returns {Object} The initialized state object
103
+ */
104
+ export function initDraftState() {
105
+ // Generate a new session ID and timestamp
106
+ const sessionId = Date.now().toString();
107
+ const timestamp = new Date().toISOString();
108
+
109
+ // Create a new state object with session ID and timestamp
110
+ state = { ...initialState, sessionId, timestamp };
111
+
112
+ return state;
113
+ }
114
+
115
+ /**
116
+ * Start a new debugging session with the current draft state
117
+ * This makes the current draft state the "current" session
118
+ * @returns {Object} The current state object
119
+ */
120
+ export function startDebugging() {
121
+ if (!state) {
122
+ state = initDraftState();
123
+ }
124
+
125
+ // Save to localStorage as current session
126
+ saveCurrentSession(state);
127
+
128
+ return state;
129
+ }
130
+
131
+ /**
132
+ * Update a specific part of the state
133
+ * @param {string} key - The key to update
134
+ * @param {any} value - The new value
135
+ * @returns {Object} The updated state
136
+ */
137
+ export function updateState(key, value) {
138
+ if (!state) {
139
+ initDraftState();
140
+ }
141
+
142
+ // Helper function to get file name or null
143
+ const getFileName = (file) => file ? file.name : null;
144
+
145
+ // Log the state update with caller information (throttled to avoid spam)
146
+ const now = Date.now();
147
+ if (!updateState._lastLog || now - updateState._lastLog > 100) { // Only log every 100ms
148
+ updateState._lastLog = now;
149
+ console.debug('State update:', {
150
+ caller: getCaller(1), // Skip 1 level (the updateState function itself)
151
+ key: typeof key === 'object' ? Object.keys(key) : key,
152
+ model: getFileName(state.modelFile),
153
+ lighting: getFileName(state.lightingFile),
154
+ background: getFileName(state.backgroundFile),
155
+ textures: {
156
+ baseColor: getFileName(state.textureFiles?.baseColor),
157
+ orm: getFileName(state.textureFiles?.orm),
158
+ normal: getFileName(state.textureFiles?.normal)
159
+ }
160
+ });
161
+ }
162
+
163
+ if (typeof key === 'object') {
164
+ Object.assign(state, key);
165
+ } else {
166
+ state[key] = value;
167
+ }
168
+
169
+ return state;
170
+ }
171
+
172
+ /**
173
+ * Get the current application state
174
+ * @returns {Object} The current state object
175
+ */
176
+ export function getState() {
177
+ if (!state) {
178
+ // Try to load from localStorage
179
+ const savedState = loadCurrentSession();
180
+ if (savedState) {
181
+ console.debug('Loading state from localStorage:', {
182
+ hasModelFile: !!savedState.modelFile,
183
+ hasLightingFile: !!savedState.lightingFile,
184
+ hasBackgroundFile: !!savedState.backgroundFile,
185
+ hasTextureFiles: savedState.textureFiles ? Object.values(savedState.textureFiles).some(f => f !== null) : false,
186
+ sessionId: savedState.sessionId,
187
+ timestamp: savedState.timestamp
188
+ });
189
+ state = savedState;
190
+ } else {
191
+ console.debug('No saved state found in localStorage, initializing new state');
192
+ state = initDraftState();
193
+ }
194
+ }
195
+ return state;
196
+ }
197
+
198
+ /**
199
+ * Reset the state to initial values
200
+ * @returns {Object} The reset state
201
+ */
202
+ export function resetState() {
203
+ state = initDraftState();
204
+ return state;
205
+ }
206
+
207
+ /**
208
+ * Clear all session data
209
+ */
210
+ export function clearState() {
211
+ clearSessionData();
212
+ state = null;
213
+ }
214
+
215
+ export function hasFiles() {
216
+ return hasModelFile() || hasLightingFile() || hasBackgroundFile()
217
+ || hasBaseColorFile() || hasOrmFile() || hasNormalFile();
218
+ }
219
+
220
+ export function hasModelFile() {
221
+ return state.modelFile !== null;
222
+ }
223
+
224
+ export function getModelFile() {
225
+ return state.modelFile;
226
+ }
227
+
228
+ export function hasLightingFile() {
229
+ return state.lightingFile !== null;
230
+ }
231
+
232
+ export function getLightingFile() {
233
+ return state.lightingFile;
234
+ }
235
+
236
+ export function hasBackgroundFile() {
237
+ return state.backgroundFile !== null;
238
+ }
239
+
240
+ export function getBackgroundFile() {
241
+ return state.backgroundFile;
242
+ }
243
+
244
+ export function hasBaseColorFile() {
245
+ return state.textureFiles.baseColor !== null;
246
+ }
247
+
248
+ export function getBaseColorFile() {
249
+ return state.textureFiles.baseColor;
250
+ }
251
+
252
+ export function hasOrmFile() {
253
+ return state.textureFiles.orm !== null;
254
+ }
255
+
256
+ export function getOrmFile() {
257
+ return state.textureFiles.orm;
258
+ }
259
+
260
+ export function hasNormalFile() {
261
+ return state.textureFiles.normal !== null;
262
+ }
263
+
264
+ export function getNormalFile() {
265
+ return state.textureFiles.normal;
266
+ }
267
+
268
+ /**
269
+ * Update multiple parts of the state at once
270
+ * @param {Object} updates - An object with keys and values to update
271
+ * @returns {Object} The updated state
272
+ */
273
+ export function setState(updates) {
274
+ if (!state) {
275
+ initDraftState();
276
+ }
277
+
278
+ Object.assign(state, updates);
279
+
280
+ return state;
281
+ }
282
+
283
+ /**
284
+ * Prints a formatted table report of the current state's file status
285
+ * @param {string} [caller='unknown'] - The name of the calling function/module
286
+ * @returns {void}
287
+ */
288
+ export function printStateReport(caller = 'unknown') {
289
+ console.log('\nState Report (called by ' + caller + ')\n');
290
+
291
+ const files = [
292
+ { name: 'Model', file: getModelFile(), hasFile: hasModelFile() },
293
+ { name: 'Lighting', file: getLightingFile(), hasFile: hasLightingFile() },
294
+ { name: 'Background', file: getBackgroundFile(), hasFile: hasBackgroundFile() },
295
+ { name: 'Base Color', file: getBaseColorFile(), hasFile: hasBaseColorFile() },
296
+ { name: 'ORM', file: getOrmFile(), hasFile: hasOrmFile() },
297
+ { name: 'Normal', file: getNormalFile(), hasFile: hasNormalFile() }
298
+ ];
299
+
300
+ console.table(
301
+ files.map(({ name, file, hasFile }) => ({
302
+ 'Drop Box': name,
303
+ 'File Name': file?.name || 'None',
304
+ 'Processed': hasFile
305
+ }))
306
+ );
307
+ console.log('\n');
308
+ }
309
+
310
+ /**
311
+ * NEW: Clear all file-related state
312
+ * This should be called when navigating between pages to prevent state pollution
313
+ * @param {boolean} skipLocalStorage - Whether to skip saving to localStorage (optional)
314
+ */
315
+ export function clearAllFiles(skipLocalStorage = false) {
316
+ console.log('Clearing all file state for clean navigation...');
317
+
318
+ if (!state) {
319
+ console.log('No state to clear');
320
+ return;
321
+ }
322
+
323
+ // Clear all file references
324
+ state.modelFile = null;
325
+ state.lightingFile = null;
326
+ state.backgroundFile = null;
327
+ state.backgroundTexture = null;
328
+ state.environmentTexture = null;
329
+
330
+ // Clear texture files
331
+ state.textureFiles = {
332
+ baseColor: null,
333
+ orm: null,
334
+ normal: null
335
+ };
336
+
337
+ // Clear texture objects
338
+ state.textureObjects = {
339
+ baseColor: null,
340
+ orm: null,
341
+ normal: null
342
+ };
343
+
344
+ // Don't clear scene, camera, renderer, controls as those are handled by ThreeJS cleanup
345
+ // Don't clear meshes as those are part of the scene cleanup
346
+
347
+ console.log('File state cleared successfully');
348
+
349
+ // Skip localStorage operations if requested
350
+ if (skipLocalStorage) {
351
+ console.log('Skipping localStorage operations as requested for faster navigation');
352
+ return;
353
+ }
354
+
355
+ // FIXED: Use safe save function that handles quota exceeded
356
+ import('../data/localstorage-manager.js').then(localStorageModule => {
357
+ if (localStorageModule.safeSaveCurrentSession) {
358
+ const success = localStorageModule.safeSaveCurrentSession(state);
359
+ if (!success) {
360
+ console.warn('Could not save cleared state to localStorage, continuing without persistence');
361
+ }
362
+ } else {
363
+ // Fallback to regular save
364
+ try {
365
+ saveCurrentSession(state);
366
+ } catch (error) {
367
+ console.warn('Could not save session:', error.message);
368
+ }
369
+ }
370
+ }).catch(error => {
371
+ console.warn('Could not import localStorage utility:', error);
372
+ });
373
+ }
374
+
375
+ /**
376
+ * NEW: Clear only lighting-related state
377
+ */
378
+ export function clearLightingState() {
379
+ if (!state) return;
380
+
381
+ console.log('Clearing lighting state...');
382
+ state.lightingFile = null;
383
+ state.environmentTexture = null;
384
+ state.environmentLightingEnabled = false;
385
+
386
+ // Clear scene environment if it exists
387
+ if (state.scene) {
388
+ state.scene.environment = null;
389
+ }
390
+ }
391
+
392
+ /**
393
+ * NEW: Clear only background-related state
394
+ */
395
+ export function clearBackgroundState() {
396
+ if (!state) return;
397
+
398
+ console.log('Clearing background state...');
399
+ state.backgroundFile = null;
400
+ state.backgroundTexture = null;
401
+
402
+ // Clear scene background if it exists
403
+ if (state.scene) {
404
+ state.scene.background = null;
405
+ }
406
+ }
407
+
408
+ /**
409
+ * NEW: Clear only texture-related state
410
+ */
411
+ export function clearTextureState() {
412
+ if (!state) return;
413
+
414
+ console.log('Clearing texture state...');
415
+ state.textureFiles = {
416
+ baseColor: null,
417
+ orm: null,
418
+ normal: null
419
+ };
420
+
421
+ state.textureObjects = {
422
+ baseColor: null,
423
+ orm: null,
424
+ normal: null
425
+ };
426
+ }
427
+
428
+ /**
429
+ * NEW: Reset to clean navigation state
430
+ * This preserves the session but clears all loaded content
431
+ */
432
+ export function resetToNavigationState() {
433
+ console.log('Resetting to clean navigation state...');
434
+
435
+ if (!state) {
436
+ state = initDraftState();
437
+ return state;
438
+ }
439
+
440
+ // Preserve session info
441
+ const sessionId = state.sessionId;
442
+ const timestamp = state.timestamp;
443
+
444
+ // Reset to initial state but preserve session
445
+ state = { ...initialState, sessionId, timestamp };
446
+
447
+ // Save the reset state
448
+ saveCurrentSession(state);
449
+
450
+ console.log('Reset to navigation state complete');
451
+ return state;
452
+ }
@@ -0,0 +1,54 @@
1
+ export let pendingTextureUpdate = false;
2
+ export let previewPlane;
3
+ export let animationPreviewScene, animationPreviewCamera, animationPreviewRenderer;
4
+ export let animationCss3dScene, animationCss3dRenderer, animationCss3dObject;
5
+ export let frameBuffer = [];
6
+ export let previewRenderTarget = null;
7
+
8
+ export function setAnimationCss3dScene(incomingValue) {
9
+ animationCss3dScene = incomingValue;
10
+ }
11
+
12
+ export function setAnimationCss3dRenderer(incomingValue) {
13
+ animationCss3dRenderer = incomingValue;
14
+ }
15
+
16
+ export function setAnimationCss3dObject(incomingValue) {
17
+ animationCss3dObject = incomingValue;
18
+ }
19
+
20
+ export function setAnimationPreviewScene(incomingValue) {
21
+ animationPreviewScene = incomingValue;
22
+ }
23
+
24
+ export function setAnimationPreviewRenderer(incomingValue) {
25
+ animationPreviewRenderer = incomingValue;
26
+ }
27
+
28
+ export function setPreviewPlane(incomingValue) {
29
+ previewPlane = incomingValue;
30
+ }
31
+
32
+ export function setPreviewRenderTarget(incomingValue) {
33
+ previewRenderTarget = incomingValue;
34
+ }
35
+
36
+ export function setAnimationPreviewCamera(incomingValue) {
37
+ animationPreviewCamera = incomingValue;
38
+ }
39
+
40
+ export function setPendingTextureUpdate(incomingValue) {
41
+ pendingTextureUpdate = incomingValue;
42
+ }
43
+
44
+ export function resetThreeJsState() {
45
+ previewPlane = null;
46
+ animationPreviewScene = null;
47
+ animationPreviewCamera = null;
48
+ animationPreviewRenderer = null;
49
+ animationCss3dScene = null;
50
+ animationCss3dRenderer = null;
51
+ animationCss3dObject = null;
52
+ previewRenderTarget = null;
53
+ frameBuffer = [];
54
+ }