@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.
- package/bin/cli.js +69 -0
- package/package.json +13 -7
- package/src/asset_debugger/axis-indicator/axis-indicator.css +6 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.html +20 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.js +822 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.css +142 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.html +80 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.js +791 -0
- package/src/asset_debugger/header/header.css +73 -0
- package/src/asset_debugger/header/header.html +24 -0
- package/src/asset_debugger/header/header.js +224 -0
- package/src/asset_debugger/index.html +76 -0
- package/src/asset_debugger/landing-page/landing-page.css +396 -0
- package/src/asset_debugger/landing-page/landing-page.html +81 -0
- package/src/asset_debugger/landing-page/landing-page.js +611 -0
- package/src/asset_debugger/loading-splash/loading-splash.css +195 -0
- package/src/asset_debugger/loading-splash/loading-splash.html +22 -0
- package/src/asset_debugger/loading-splash/loading-splash.js +59 -0
- package/src/asset_debugger/loading-splash/preview-loading-splash.js +66 -0
- package/src/asset_debugger/main.css +14 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.css +41 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.html +18 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.js +111 -0
- package/src/asset_debugger/modals/examples-modal/examples.js +125 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.css +452 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.html +87 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.js +675 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.css +219 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.html +20 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.js +548 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.css +103 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.html +158 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.js +475 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.css +263 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.html +123 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.js +136 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.css +94 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.js +312 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.css +129 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.js +486 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.css +545 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.js +538 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.css +70 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.js +586 -0
- package/src/asset_debugger/panels/world-panel/world-panel.css +364 -0
- package/src/asset_debugger/panels/world-panel/world-panel.html +173 -0
- package/src/asset_debugger/panels/world-panel/world-panel.js +1891 -0
- package/src/asset_debugger/router.js +190 -0
- package/src/asset_debugger/util/animation/playback/animation-playback-controller.js +150 -0
- package/src/asset_debugger/util/animation/playback/animation-preview-controller.js +316 -0
- package/src/asset_debugger/util/animation/playback/css3d-bounce-controller.js +400 -0
- package/src/asset_debugger/util/animation/playback/css3d-reversal-controller.js +821 -0
- package/src/asset_debugger/util/animation/render/css3d-prerender-controller.js +696 -0
- package/src/asset_debugger/util/animation/render/debug-texture-factory.js +0 -0
- package/src/asset_debugger/util/animation/render/iframe2texture-render-controller.js +199 -0
- package/src/asset_debugger/util/animation/render/image2texture-prerender-controller.js +461 -0
- package/src/asset_debugger/util/animation/render/pbr-material-factory.js +82 -0
- package/src/asset_debugger/util/common.css +280 -0
- package/src/asset_debugger/util/data/animation-classifier.js +323 -0
- package/src/asset_debugger/util/data/duplicate-handler.js +20 -0
- package/src/asset_debugger/util/data/glb-buffer-manager.js +407 -0
- package/src/asset_debugger/util/data/glb-classifier.js +290 -0
- package/src/asset_debugger/util/data/html-formatter.js +76 -0
- package/src/asset_debugger/util/data/html-linter.js +276 -0
- package/src/asset_debugger/util/data/localstorage-manager.js +265 -0
- package/src/asset_debugger/util/data/mesh-html-manager.js +295 -0
- package/src/asset_debugger/util/data/string-serder.js +303 -0
- package/src/asset_debugger/util/data/texture-classifier.js +663 -0
- package/src/asset_debugger/util/data/upload/background-file-handler.js +292 -0
- package/src/asset_debugger/util/data/upload/dropzone-preview-controller.js +396 -0
- package/src/asset_debugger/util/data/upload/file-upload-manager.js +495 -0
- package/src/asset_debugger/util/data/upload/glb-file-handler.js +36 -0
- package/src/asset_debugger/util/data/upload/glb-preview-controller.js +317 -0
- package/src/asset_debugger/util/data/upload/lighting-file-handler.js +194 -0
- package/src/asset_debugger/util/data/upload/model-file-manager.js +104 -0
- package/src/asset_debugger/util/data/upload/texture-file-handler.js +166 -0
- package/src/asset_debugger/util/data/upload/zip-handler.js +686 -0
- package/src/asset_debugger/util/loaders/html2canvas-loader.js +107 -0
- package/src/asset_debugger/util/rig/bone-kinematics.js +403 -0
- package/src/asset_debugger/util/rig/rig-constraint-manager.js +618 -0
- package/src/asset_debugger/util/rig/rig-controller.js +612 -0
- package/src/asset_debugger/util/rig/rig-factory.js +628 -0
- package/src/asset_debugger/util/rig/rig-handle-factory.js +46 -0
- package/src/asset_debugger/util/rig/rig-label-factory.js +441 -0
- package/src/asset_debugger/util/rig/rig-mouse-handler.js +377 -0
- package/src/asset_debugger/util/rig/rig-state-manager.js +175 -0
- package/src/asset_debugger/util/rig/rig-tooltip-manager.js +267 -0
- package/src/asset_debugger/util/rig/rig-ui-factory.js +700 -0
- package/src/asset_debugger/util/scene/background-manager.js +284 -0
- package/src/asset_debugger/util/scene/camera-controller.js +243 -0
- package/src/asset_debugger/util/scene/css3d-debug-controller.js +406 -0
- package/src/asset_debugger/util/scene/css3d-frame-factory.js +113 -0
- package/src/asset_debugger/util/scene/css3d-scene-manager.js +529 -0
- package/src/asset_debugger/util/scene/glb-controller.js +208 -0
- package/src/asset_debugger/util/scene/lighting-manager.js +690 -0
- package/src/asset_debugger/util/scene/threejs-model-manager.js +437 -0
- package/src/asset_debugger/util/scene/threejs-preview-manager.js +207 -0
- package/src/asset_debugger/util/scene/threejs-preview-setup.js +478 -0
- package/src/asset_debugger/util/scene/threejs-scene-controller.js +286 -0
- package/src/asset_debugger/util/scene/ui-manager.js +107 -0
- package/src/asset_debugger/util/state/animation-state.js +128 -0
- package/src/asset_debugger/util/state/css3d-state.js +83 -0
- package/src/asset_debugger/util/state/glb-preview-state.js +31 -0
- package/src/asset_debugger/util/state/log-util.js +197 -0
- package/src/asset_debugger/util/state/scene-state.js +452 -0
- package/src/asset_debugger/util/state/threejs-state.js +54 -0
- package/src/asset_debugger/util/workers/lighting-worker.js +61 -0
- package/src/asset_debugger/util/workers/model-worker.js +109 -0
- package/src/asset_debugger/util/workers/texture-worker.js +54 -0
- package/src/asset_debugger/util/workers/worker-manager.js +212 -0
- package/src/asset_debugger/widgets/mesh-info-widget.js +280 -0
- package/src/index.html +261 -0
- package/src/index.js +8 -0
- package/vite.config.js +66 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import {
|
|
3
|
+
isReversingAnimations,
|
|
4
|
+
pushAnimationStack,
|
|
5
|
+
setCapturingAnimations,
|
|
6
|
+
setReversingAnimation,
|
|
7
|
+
resetCurrentAniamtionBatch,
|
|
8
|
+
currentAnimationBatch,
|
|
9
|
+
lastBatchTime,
|
|
10
|
+
resetReverseAnimationFrameId,
|
|
11
|
+
reverseAnimationFrameId,
|
|
12
|
+
animationStack,
|
|
13
|
+
resetAnimationState
|
|
14
|
+
} from '../state/css3d-state';
|
|
15
|
+
import { createMeshInfoPanel } from '../../widgets/mesh-info-widget';
|
|
16
|
+
import {
|
|
17
|
+
setAnimationCss3dRenderer,
|
|
18
|
+
setAnimationCss3dScene,
|
|
19
|
+
setAnimationCss3dObject,
|
|
20
|
+
setAnimationPreviewCamera,
|
|
21
|
+
setPreviewRenderTarget,
|
|
22
|
+
animationPreviewCamera
|
|
23
|
+
} from '../state/threejs-state';
|
|
24
|
+
import { showStatus } from '../../modals/html-editor-modal/html-editor-modal';
|
|
25
|
+
import { playNextReverseAnimation } from '../animation/playback/css3d-reversal-controller';
|
|
26
|
+
import { setupBounceAnimationTracking } from '../animation/playback/css3d-bounce-controller';
|
|
27
|
+
import { isPreviewActive } from '../state/animation-state';
|
|
28
|
+
import { calculateMeshTransform } from './css3d-frame-factory';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Setup the CSS3D scene
|
|
32
|
+
* @param {HTMLElement} container - The container element for the renderers
|
|
33
|
+
* @param {HTMLIFrameElement} iframe - The iframe containing the HTML content
|
|
34
|
+
* @param {number} currentMeshId - The ID of the current mesh
|
|
35
|
+
* @param {boolean} createInfoPanel - Whether to create the info panel
|
|
36
|
+
*/
|
|
37
|
+
export function setupCSS3DScene(container, iframe, CSS3DRenderer, CSS3DObject, currentMeshId, createInfoPanel = true) {
|
|
38
|
+
try {
|
|
39
|
+
console.log('Setting up CSS3D scene with container:', container);
|
|
40
|
+
|
|
41
|
+
resetAnimationState();
|
|
42
|
+
|
|
43
|
+
// Clear any existing content
|
|
44
|
+
container.innerHTML = '';
|
|
45
|
+
|
|
46
|
+
// Basic variables
|
|
47
|
+
const userHtml = document.getElementById('html-editor-textarea').value || '';
|
|
48
|
+
|
|
49
|
+
// Panel size - use a single panel instead of a cube
|
|
50
|
+
const panelWidth = 500;
|
|
51
|
+
const panelHeight = 400;
|
|
52
|
+
|
|
53
|
+
// Setup camera with proper distance to see the panel
|
|
54
|
+
const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientHeight, 1, 10000);
|
|
55
|
+
camera.position.set(0, 0, 700); // Position to see panel straight on
|
|
56
|
+
|
|
57
|
+
// Create CSS3D scene
|
|
58
|
+
const scene = new THREE.Scene();
|
|
59
|
+
scene.background = new THREE.Color(0x303030); // Dark gray background like Unreal Editor
|
|
60
|
+
|
|
61
|
+
// Create CSS3D renderer
|
|
62
|
+
const renderer = new CSS3DRenderer();
|
|
63
|
+
renderer.setSize(container.clientWidth, container.clientHeight);
|
|
64
|
+
renderer.domElement.style.position = 'absolute';
|
|
65
|
+
renderer.domElement.style.top = '0';
|
|
66
|
+
container.appendChild(renderer.domElement);
|
|
67
|
+
// Create info panel if requested
|
|
68
|
+
if (createInfoPanel) {
|
|
69
|
+
createMeshInfoPanel(container, currentMeshId);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Get settings for this mesh
|
|
73
|
+
const settings = getHtmlSettingsForMesh(currentMeshId);
|
|
74
|
+
const playbackSpeed = settings.playbackSpeed || 1.0;
|
|
75
|
+
|
|
76
|
+
// Function to create HTML content - simplified to avoid layout warnings
|
|
77
|
+
const wrapContent = (content) => {
|
|
78
|
+
// Generate a unique ID for this iframe instance
|
|
79
|
+
const uniqueFrameId = 'frame_' + Date.now() + '_' + Math.floor(Math.random() * 1000000);
|
|
80
|
+
|
|
81
|
+
// Process content to handle typical variable declarations
|
|
82
|
+
// Find script tags and wrap their contents in a function to avoid global variable redeclarations
|
|
83
|
+
let processedContent = content;
|
|
84
|
+
|
|
85
|
+
// Find all script tags and wrap their contents in a closure to avoid redeclaration issues
|
|
86
|
+
processedContent = processedContent.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, (match, scriptContent) => {
|
|
87
|
+
// Wrap script content in an IIFE to create a new scope each time
|
|
88
|
+
return `<script>
|
|
89
|
+
(function() {
|
|
90
|
+
// Create a new scope for variables
|
|
91
|
+
${scriptContent}
|
|
92
|
+
})();
|
|
93
|
+
</script>`;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return `<!DOCTYPE html>
|
|
97
|
+
<html>
|
|
98
|
+
<head>
|
|
99
|
+
<style>
|
|
100
|
+
html, body {
|
|
101
|
+
margin: 0;
|
|
102
|
+
padding: 0;
|
|
103
|
+
width: 100%;
|
|
104
|
+
height: 100%;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
box-sizing: border-box;
|
|
107
|
+
}
|
|
108
|
+
body {
|
|
109
|
+
background-color: white;
|
|
110
|
+
color: #333;
|
|
111
|
+
font-family: Arial, sans-serif;
|
|
112
|
+
padding: 10px;
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
}
|
|
116
|
+
.content {
|
|
117
|
+
flex: 1;
|
|
118
|
+
overflow: hidden;
|
|
119
|
+
padding: 5px;
|
|
120
|
+
position: relative;
|
|
121
|
+
width: calc(100% - 10px);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Add a border if enabled */
|
|
125
|
+
${window.showPreviewBorders ?
|
|
126
|
+
`body { border: 5px solid #3498db; }` :
|
|
127
|
+
''}
|
|
128
|
+
|
|
129
|
+
/* Control animation speed - apply to all animations */
|
|
130
|
+
* {
|
|
131
|
+
animation-duration: ${1.0 / playbackSpeed}s !important;
|
|
132
|
+
transition-duration: ${1.0 / playbackSpeed}s !important;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Ensure content doesn't overflow */
|
|
136
|
+
.content > * {
|
|
137
|
+
max-width: 100%;
|
|
138
|
+
box-sizing: border-box;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Override any styles that might cause horizontal scrollbars */
|
|
142
|
+
.content div, .content p, .content span, .content img {
|
|
143
|
+
max-width: 100%;
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
146
|
+
</head>
|
|
147
|
+
<body>
|
|
148
|
+
<div class="content">${processedContent}</div>
|
|
149
|
+
</body>
|
|
150
|
+
</html>`;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Store the wrapContent function at the global file scope to make it available to other functions
|
|
154
|
+
setupCSS3DScene.wrapContent = wrapContent;
|
|
155
|
+
|
|
156
|
+
// Create a DOM container to hold the iframe temporarily
|
|
157
|
+
const tempContainer = document.createElement('div');
|
|
158
|
+
tempContainer.style.position = 'absolute';
|
|
159
|
+
tempContainer.style.left = '-9999px'; // Off-screen
|
|
160
|
+
tempContainer.style.top = '0';
|
|
161
|
+
tempContainer.style.zIndex = '-1'; // Behind everything
|
|
162
|
+
tempContainer.style.opacity = '0.01'; // Almost invisible, but still rendered
|
|
163
|
+
tempContainer.style.pointerEvents = 'none'; // Don't interact with user input
|
|
164
|
+
document.body.appendChild(tempContainer);
|
|
165
|
+
|
|
166
|
+
// Create a single iframe for the panel
|
|
167
|
+
let element = document.createElement('iframe');
|
|
168
|
+
element.id = 'css3d-panel-iframe';
|
|
169
|
+
element.style.width = `${panelWidth}px`;
|
|
170
|
+
element.style.height = `${panelHeight}px`;
|
|
171
|
+
element.style.border = 'none'; // Remove border - we'll add it in the content if needed
|
|
172
|
+
element.style.borderRadius = '5px';
|
|
173
|
+
element.style.backgroundColor = 'white';
|
|
174
|
+
element.style.overflow = 'hidden'; // Prevent scrollbars
|
|
175
|
+
element.style.boxSizing = 'border-box';
|
|
176
|
+
|
|
177
|
+
// Add the iframe to DOM first
|
|
178
|
+
tempContainer.appendChild(element);
|
|
179
|
+
|
|
180
|
+
// Create a CSS3D object with the iframe
|
|
181
|
+
const object = new CSS3DObject(element);
|
|
182
|
+
|
|
183
|
+
// Add to scene
|
|
184
|
+
scene.add(object);
|
|
185
|
+
|
|
186
|
+
// Store references for cleanup
|
|
187
|
+
setAnimationCss3dScene(scene);
|
|
188
|
+
setAnimationCss3dRenderer(renderer);
|
|
189
|
+
setAnimationPreviewCamera(camera);
|
|
190
|
+
|
|
191
|
+
// Store for replay
|
|
192
|
+
setPreviewRenderTarget(element);
|
|
193
|
+
setAnimationCss3dObject(object);
|
|
194
|
+
|
|
195
|
+
// Write content to the iframe after a brief delay
|
|
196
|
+
setTimeout(() => {
|
|
197
|
+
try {
|
|
198
|
+
if (element.contentDocument) {
|
|
199
|
+
element.contentDocument.open();
|
|
200
|
+
element.contentDocument.write(wrapContent(userHtml));
|
|
201
|
+
element.contentDocument.close();
|
|
202
|
+
|
|
203
|
+
// Get detected animation duration from pre-render (animationDuration is in milliseconds)
|
|
204
|
+
import('../state/animation-state').then(module => {
|
|
205
|
+
const { animationDuration, isAnimationFinite } = module;
|
|
206
|
+
|
|
207
|
+
// Get animation type from dropdown
|
|
208
|
+
const animationTypeSelect = document.getElementById('html-animation-type');
|
|
209
|
+
const animationType = animationTypeSelect ? animationTypeSelect.value : 'play';
|
|
210
|
+
|
|
211
|
+
// Only set up restart timer if:
|
|
212
|
+
// 1. Animation is finite and has a duration
|
|
213
|
+
// 2. Animation type is set to "loop" or "bounce"
|
|
214
|
+
if (isAnimationFinite && animationDuration > 0 && (animationType === 'loop' || animationType === 'bounce')) {
|
|
215
|
+
console.log(`Setting up CSS3D iframe restart timer for ${animationDuration}ms animation with animation type: ${animationType}`);
|
|
216
|
+
|
|
217
|
+
// Calculate actual duration based on playback speed
|
|
218
|
+
const actualDuration = animationDuration / playbackSpeed;
|
|
219
|
+
|
|
220
|
+
// For bounce, we need to track animations
|
|
221
|
+
const isBounceMode = animationType === 'bounce';
|
|
222
|
+
|
|
223
|
+
// Create repeating timer to reload the iframe content
|
|
224
|
+
const restartTimer = setInterval(() => {
|
|
225
|
+
if (!isPreviewActive) {
|
|
226
|
+
// Clean up timer if preview is no longer active
|
|
227
|
+
clearInterval(restartTimer);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Handle bounce animation differently
|
|
232
|
+
if (isBounceMode) {
|
|
233
|
+
if (!isReversingAnimations) {
|
|
234
|
+
// We've reached the end of the forward animation
|
|
235
|
+
console.debug('Bounce end reached popping animation stack');
|
|
236
|
+
setReversingAnimation(true);
|
|
237
|
+
setCapturingAnimations(false);
|
|
238
|
+
|
|
239
|
+
// If we have animations in the stack, play them in reverse
|
|
240
|
+
if (animationStack.length > 0) {
|
|
241
|
+
console.debug(`Animation stack contains ${animationStack.length} items to reverse`);
|
|
242
|
+
try {
|
|
243
|
+
if (element.contentDocument) {
|
|
244
|
+
// First, ensure any pending animation batch is committed to the stack
|
|
245
|
+
if (currentAnimationBatch.length > 0) {
|
|
246
|
+
console.debug(`Committing final batch of ${currentAnimationBatch.length} animations to stack before reversal`);
|
|
247
|
+
pushAnimationStack({
|
|
248
|
+
type: 'batch',
|
|
249
|
+
animations: [...currentAnimationBatch],
|
|
250
|
+
time: lastBatchTime || Date.now()
|
|
251
|
+
});
|
|
252
|
+
resetCurrentAniamtionBatch();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Set all animations to pause at end point
|
|
256
|
+
const animElements = element.contentDocument.querySelectorAll('[style*="animation"]');
|
|
257
|
+
animElements.forEach(el => {
|
|
258
|
+
el.style.animationPlayState = 'paused';
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Set all transitions to pause too
|
|
262
|
+
const transElements = element.contentDocument.querySelectorAll('[style*="transition"]');
|
|
263
|
+
transElements.forEach(el => {
|
|
264
|
+
el.style.transitionProperty = 'none';
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Start the first reverse animation
|
|
268
|
+
playNextReverseAnimation(element);
|
|
269
|
+
}
|
|
270
|
+
} catch (err) {
|
|
271
|
+
console.error('Error preparing for reverse animations:', err);
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
// Stack is empty, odd case
|
|
275
|
+
console.debug('Animation stack is empty, restarting cycle');
|
|
276
|
+
setReversingAnimation(false);
|
|
277
|
+
setCapturingAnimations(true);
|
|
278
|
+
resetAndRestartAnimationCycle(element, userHtml);
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// We've completed one animation in reverse, continue with the next
|
|
282
|
+
if (animationStack.length > 0) {
|
|
283
|
+
// Play the next animation in reverse
|
|
284
|
+
playNextReverseAnimation(element);
|
|
285
|
+
} else {
|
|
286
|
+
// No more animations to reverse, cycle complete
|
|
287
|
+
console.debug('Animation rewind successful');
|
|
288
|
+
setReversingAnimation(false);
|
|
289
|
+
setCapturingAnimations(true);
|
|
290
|
+
resetAndRestartAnimationCycle(element, userHtml);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
// Normal loop behavior - just restart the content
|
|
295
|
+
console.log('Restarting CSS3D preview iframe content');
|
|
296
|
+
|
|
297
|
+
// Reload the iframe content to restart all animations from the beginning
|
|
298
|
+
try {
|
|
299
|
+
if (element.contentDocument) {
|
|
300
|
+
// Simply rewrite the content in the existing iframe
|
|
301
|
+
element.contentDocument.open();
|
|
302
|
+
element.contentDocument.write(wrapContent(userHtml));
|
|
303
|
+
element.contentDocument.close();
|
|
304
|
+
}
|
|
305
|
+
} catch (err) {
|
|
306
|
+
console.error('Error reloading iframe content:', err);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}, actualDuration);
|
|
310
|
+
|
|
311
|
+
// Store timer reference for cleanup
|
|
312
|
+
element.restartTimer = restartTimer;
|
|
313
|
+
|
|
314
|
+
// For bounce mode, set up initial animation tracking
|
|
315
|
+
if (isBounceMode) {
|
|
316
|
+
setTimeout(() => {
|
|
317
|
+
setupBounceAnimationTracking(element);
|
|
318
|
+
}, 50);
|
|
319
|
+
}
|
|
320
|
+
} else {
|
|
321
|
+
console.log('No finite animation duration detected or using Play animation mode, not setting up restart timer');
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error('Error writing content to iframe:', err);
|
|
327
|
+
}
|
|
328
|
+
}, 50);
|
|
329
|
+
|
|
330
|
+
// Set up OrbitControls
|
|
331
|
+
import('three/examples/jsm/controls/OrbitControls.js').then(module => {
|
|
332
|
+
const { OrbitControls } = module;
|
|
333
|
+
|
|
334
|
+
// Create controls
|
|
335
|
+
const controls = new OrbitControls(camera, renderer.domElement);
|
|
336
|
+
controls.enableDamping = true;
|
|
337
|
+
controls.dampingFactor = 0.2;
|
|
338
|
+
controls.rotateSpeed = 0.5;
|
|
339
|
+
controls.minDistance = 100; // CSS3D needs larger distances
|
|
340
|
+
controls.maxDistance = 2000;
|
|
341
|
+
controls.zoomSpeed = 1.2;
|
|
342
|
+
|
|
343
|
+
// Initial look at origin
|
|
344
|
+
camera.lookAt(0, 0, 0);
|
|
345
|
+
|
|
346
|
+
// Animation loop
|
|
347
|
+
function animate() {
|
|
348
|
+
if (!isPreviewActive) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
requestAnimationFrame(animate);
|
|
353
|
+
|
|
354
|
+
// Update controls
|
|
355
|
+
controls.update();
|
|
356
|
+
|
|
357
|
+
// Render scene
|
|
358
|
+
renderer.render(scene, camera);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Start animation loop
|
|
362
|
+
animate();
|
|
363
|
+
|
|
364
|
+
// Show success status
|
|
365
|
+
showStatus('CSS3D preview ready. Use +/- keys to zoom in/out', 'success');
|
|
366
|
+
|
|
367
|
+
// Add keyboard shortcuts for zooming
|
|
368
|
+
const handleKeydown = (event) => {
|
|
369
|
+
if (!isPreviewActive) return;
|
|
370
|
+
|
|
371
|
+
// Get current controls - they should be attached to the camera by this point
|
|
372
|
+
const controls = animationPreviewCamera.userData.controls;
|
|
373
|
+
if (!controls) return;
|
|
374
|
+
|
|
375
|
+
const zoomSpeed = 0.2; // How fast to zoom with keyboard
|
|
376
|
+
|
|
377
|
+
switch (event.key) {
|
|
378
|
+
case '+':
|
|
379
|
+
case '=': // Common + key without shift
|
|
380
|
+
// Zoom in - decrease distance to target
|
|
381
|
+
controls.dollyIn(1 + zoomSpeed);
|
|
382
|
+
controls.update();
|
|
383
|
+
break;
|
|
384
|
+
case '-':
|
|
385
|
+
case '_': // Common - key with shift
|
|
386
|
+
// Zoom out - increase distance to target
|
|
387
|
+
controls.dollyOut(1 + zoomSpeed);
|
|
388
|
+
controls.update();
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// Register keyboard handler
|
|
394
|
+
document.addEventListener('keydown', handleKeydown);
|
|
395
|
+
|
|
396
|
+
// Store for cleanup
|
|
397
|
+
animationPreviewCamera.userData.keyHandler = handleKeydown;
|
|
398
|
+
}).catch(error => {
|
|
399
|
+
console.error('Error loading OrbitControls:', error);
|
|
400
|
+
showStatus('Error loading 3D controls: ' + error.message, 'error');
|
|
401
|
+
return false;
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// Success
|
|
405
|
+
return true;
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error('Error in setupCSS3DScene:', error);
|
|
408
|
+
showStatus('Error creating 3D view: ' + error.message, 'error');
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Reset and restart the animation cycle with fresh content
|
|
415
|
+
* @param {HTMLIFrameElement} iframe - The iframe to reset
|
|
416
|
+
* @param {string} html - The HTML content to reload
|
|
417
|
+
*/
|
|
418
|
+
function resetAndRestartAnimationCycle(iframe, html) {
|
|
419
|
+
console.debug('Restarting CSS3D bounce animation cycle');
|
|
420
|
+
try {
|
|
421
|
+
// Access the wrapContent function from the global scope
|
|
422
|
+
const wrapContentFunc = setupCSS3DScene.wrapContent;
|
|
423
|
+
|
|
424
|
+
if (!wrapContentFunc) {
|
|
425
|
+
console.error('wrapContent function not available, cannot restart animation cycle');
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (iframe.contentDocument) {
|
|
430
|
+
// Cancel any pending animation operations
|
|
431
|
+
if (reverseAnimationFrameId) {
|
|
432
|
+
cancelAnimationFrame(reverseAnimationFrameId);
|
|
433
|
+
resetReverseAnimationFrameId();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Clean up the mutation observer if it exists
|
|
437
|
+
if (iframe.mutationObserver) {
|
|
438
|
+
iframe.mutationObserver.disconnect();
|
|
439
|
+
iframe.mutationObserver = null;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// First, clear all content to a blank slate
|
|
443
|
+
iframe.contentDocument.open();
|
|
444
|
+
iframe.contentDocument.write(`
|
|
445
|
+
<!DOCTYPE html>
|
|
446
|
+
<html>
|
|
447
|
+
<head>
|
|
448
|
+
<style>
|
|
449
|
+
html, body {
|
|
450
|
+
margin: 0;
|
|
451
|
+
padding: 0;
|
|
452
|
+
width: 100%;
|
|
453
|
+
height: 100%;
|
|
454
|
+
overflow: hidden;
|
|
455
|
+
background-color: white;
|
|
456
|
+
}
|
|
457
|
+
</style>
|
|
458
|
+
</head>
|
|
459
|
+
<body></body>
|
|
460
|
+
</html>
|
|
461
|
+
`);
|
|
462
|
+
iframe.contentDocument.close();
|
|
463
|
+
|
|
464
|
+
// Give a brief moment to ensure cleanup
|
|
465
|
+
setTimeout(() => {
|
|
466
|
+
resetAnimationState();
|
|
467
|
+
|
|
468
|
+
// Now reload the real content
|
|
469
|
+
iframe.contentDocument.open();
|
|
470
|
+
iframe.contentDocument.write(wrapContentFunc(html));
|
|
471
|
+
iframe.contentDocument.close();
|
|
472
|
+
|
|
473
|
+
// Set up animation tracking for the new cycle
|
|
474
|
+
setTimeout(() => {
|
|
475
|
+
setupBounceAnimationTracking(iframe);
|
|
476
|
+
}, 50);
|
|
477
|
+
}, 100); // Longer timeout for better cleanup
|
|
478
|
+
}
|
|
479
|
+
} catch (err) {
|
|
480
|
+
console.error('Error restarting animation cycle:', err);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export function cleanupCSS3D(targetElement = null) {
|
|
485
|
+
resetAnimationState();
|
|
486
|
+
|
|
487
|
+
if (reverseAnimationFrameId) {
|
|
488
|
+
cancelAnimationFrame(reverseAnimationFrameId);
|
|
489
|
+
resetReverseAnimationFrameId();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const iframe = targetElement || document.getElementById('css3d-panel-iframe');
|
|
493
|
+
if (iframe) {
|
|
494
|
+
if (iframe.restartTimer) {
|
|
495
|
+
clearInterval(iframe.restartTimer);
|
|
496
|
+
iframe.restartTimer = null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (iframe._animationStartHandler && iframe.contentDocument) {
|
|
500
|
+
iframe.contentDocument.removeEventListener('animationstart', iframe._animationStartHandler);
|
|
501
|
+
iframe._animationStartHandler = null;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (iframe._transitionStartHandler && iframe.contentDocument) {
|
|
505
|
+
iframe.contentDocument.removeEventListener('transitionstart', iframe._transitionStartHandler);
|
|
506
|
+
iframe._transitionStartHandler = null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (iframe.mutationObserver) {
|
|
510
|
+
iframe.mutationObserver.disconnect();
|
|
511
|
+
iframe.mutationObserver = null;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
export function addFrameToScene(frame, scene, mesh, frameConfig) {
|
|
517
|
+
const { realWidth, realHeight, frameWidth, frameHeight, offsetDistance = 0.001 } = frameConfig;
|
|
518
|
+
|
|
519
|
+
const transform = calculateMeshTransform(mesh, offsetDistance);
|
|
520
|
+
frame.position.copy(transform.position);
|
|
521
|
+
frame.rotation.copy(transform.rotation);
|
|
522
|
+
frame.quaternion.copy(transform.quaternion);
|
|
523
|
+
|
|
524
|
+
const scaleX = realWidth / frameWidth;
|
|
525
|
+
const scaleY = realHeight / frameHeight;
|
|
526
|
+
frame.scale.set(scaleX, scaleY, 1);
|
|
527
|
+
|
|
528
|
+
scene.add(frame);
|
|
529
|
+
}
|