@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,82 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { getState, updateState } from '../../state/scene-state.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a PBR material with the loaded textures
|
|
6
|
+
* @returns {THREE.MeshStandardMaterial} The created material
|
|
7
|
+
*/
|
|
8
|
+
export function createMaterial() {
|
|
9
|
+
const state = getState();
|
|
10
|
+
|
|
11
|
+
// Set proper texture parameters for all textures
|
|
12
|
+
setupTextureParameters();
|
|
13
|
+
|
|
14
|
+
// Create a material configuration with available textures
|
|
15
|
+
const materialConfig = {
|
|
16
|
+
side: THREE.DoubleSide // Make material double-sided
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Apply baseColor texture if available
|
|
20
|
+
if (state.textureObjects.baseColor) {
|
|
21
|
+
materialConfig.map = state.textureObjects.baseColor;
|
|
22
|
+
materialConfig.color = 0xffffff; // White color to let the texture show properly
|
|
23
|
+
} else {
|
|
24
|
+
// If no base color texture, use a light gray color
|
|
25
|
+
materialConfig.color = 0xcccccc;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Apply normal map if available
|
|
29
|
+
if (state.textureObjects.normal) {
|
|
30
|
+
materialConfig.normalMap = state.textureObjects.normal;
|
|
31
|
+
materialConfig.normalScale = new THREE.Vector2(1, 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Apply ORM texture if available
|
|
35
|
+
if (state.textureObjects.orm) {
|
|
36
|
+
// If we have the ORM texture, apply all its channels
|
|
37
|
+
materialConfig.aoMap = state.textureObjects.orm;
|
|
38
|
+
materialConfig.roughnessMap = state.textureObjects.orm;
|
|
39
|
+
materialConfig.metalnessMap = state.textureObjects.orm;
|
|
40
|
+
// When ORM is available, use its full range
|
|
41
|
+
materialConfig.roughness = 1.0;
|
|
42
|
+
materialConfig.metalness = 1.0;
|
|
43
|
+
} else {
|
|
44
|
+
// If we don't have ORM, use reasonable defaults
|
|
45
|
+
materialConfig.roughness = 0.7;
|
|
46
|
+
materialConfig.metalness = 0.2;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create material with properly configured textures
|
|
50
|
+
// Explicitly ensure transparency is disabled
|
|
51
|
+
materialConfig.transparent = false;
|
|
52
|
+
materialConfig.alphaTest = 0;
|
|
53
|
+
|
|
54
|
+
return new THREE.MeshStandardMaterial(materialConfig);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Setup texture parameters for all loaded textures
|
|
59
|
+
*/
|
|
60
|
+
function setupTextureParameters() {
|
|
61
|
+
const state = getState();
|
|
62
|
+
|
|
63
|
+
if (state.textureObjects.baseColor) {
|
|
64
|
+
state.textureObjects.baseColor.encoding = THREE.sRGBEncoding;
|
|
65
|
+
state.textureObjects.baseColor.wrapS = THREE.RepeatWrapping;
|
|
66
|
+
state.textureObjects.baseColor.wrapT = THREE.RepeatWrapping;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (state.textureObjects.normal) {
|
|
70
|
+
state.textureObjects.normal.encoding = THREE.LinearEncoding;
|
|
71
|
+
state.textureObjects.normal.wrapS = THREE.RepeatWrapping;
|
|
72
|
+
state.textureObjects.normal.wrapT = THREE.RepeatWrapping;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (state.textureObjects.orm) {
|
|
76
|
+
state.textureObjects.orm.encoding = THREE.LinearEncoding;
|
|
77
|
+
state.textureObjects.orm.wrapS = THREE.RepeatWrapping;
|
|
78
|
+
state.textureObjects.orm.wrapT = THREE.RepeatWrapping;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/* Blorkvisor-inspired theme */
|
|
2
|
+
:root {
|
|
3
|
+
--primary-color: #4CAF50; /* Terminal green */
|
|
4
|
+
--tool-color: #F1C40F; /* Blorkvisor tool color (yellow) for borders */
|
|
5
|
+
--fallout-yellow: #f8d73e; /* Adjusted to be more yellow and less orange */
|
|
6
|
+
--button-color: #1E88E5; /* Blorkvisor button color (blue) */
|
|
7
|
+
--secondary-color: #1a1a1a; /* Dark background but not pure black */
|
|
8
|
+
--bg-color: #121212; /* Dark background */
|
|
9
|
+
--panel-bg: #1e1e1e; /* Panel background */
|
|
10
|
+
--panel-bg-lighter: #252525; /* Lighter panel background */
|
|
11
|
+
--panel-border: #333; /* Panel border */
|
|
12
|
+
--text-color: #b8b8b8; /* Light gray for regular text */
|
|
13
|
+
--card-border: #333; /* Card border color */
|
|
14
|
+
--input-bg: #252525; /* Input background */
|
|
15
|
+
--input-text: #dadada; /* Input text */
|
|
16
|
+
--label-text: #959595; /* Label text */
|
|
17
|
+
--hover-glow: 0 0 5px rgba(241, 196, 15, 0.7); /* Yellow glow for hover */
|
|
18
|
+
--success-glow: 0 0 5px rgba(76, 175, 80, 0.7); /* Green glow for success */
|
|
19
|
+
--tooltip-bg: rgba(40, 40, 40, 0.95); /* Tooltip background */
|
|
20
|
+
--tooltip-border: #555; /* Tooltip border */
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
html, body {
|
|
24
|
+
margin: 0;
|
|
25
|
+
padding: 0;
|
|
26
|
+
height: 100%;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
font-family: monospace;
|
|
32
|
+
background-color: var(--bg-color);
|
|
33
|
+
color: var(--text-color);
|
|
34
|
+
transition: background-color 0.3s ease, color 0.3s ease;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
header {
|
|
38
|
+
display: flex;
|
|
39
|
+
justify-content: space-between;
|
|
40
|
+
align-items: center;
|
|
41
|
+
padding: 5px 20px;
|
|
42
|
+
background-color: rgba(26, 26, 26, 0.85);
|
|
43
|
+
color: var(--primary-color);
|
|
44
|
+
border-bottom: 1px solid var(--panel-border);
|
|
45
|
+
position: fixed;
|
|
46
|
+
top: 0;
|
|
47
|
+
left: 0;
|
|
48
|
+
width: 100%;
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
z-index: 1000;
|
|
51
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
52
|
+
height: 50px;
|
|
53
|
+
backdrop-filter: blur(5px);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
h1 {
|
|
57
|
+
margin: 0;
|
|
58
|
+
font-size: 24px;
|
|
59
|
+
color: var(--primary-color);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
h2 {
|
|
63
|
+
font-size: 18px;
|
|
64
|
+
margin: 5px 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
h3 {
|
|
68
|
+
margin: 0;
|
|
69
|
+
font-size: 16px;
|
|
70
|
+
color: var(--primary-color);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
h2, h3 {
|
|
74
|
+
margin: 5px 0;
|
|
75
|
+
color: var(--primary-color);
|
|
76
|
+
font-weight: normal;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/* Shared toggle theme */
|
|
81
|
+
.theme-toggle {
|
|
82
|
+
background-color: transparent;
|
|
83
|
+
border: 1px solid var(--button-color);
|
|
84
|
+
color: var(--button-color);
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
padding: 8px 12px;
|
|
88
|
+
font-family: monospace;
|
|
89
|
+
transition: all 0.3s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.theme-toggle:hover {
|
|
93
|
+
background-color: rgba(30, 136, 229, 0.2);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.theme-toggle.active {
|
|
97
|
+
background-color: rgba(30, 136, 229, 0.3);
|
|
98
|
+
color: white;
|
|
99
|
+
border-color: var(--button-color);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
/* Shared modal styling */
|
|
104
|
+
.modal-overlay {
|
|
105
|
+
position: fixed;
|
|
106
|
+
top: 0;
|
|
107
|
+
left: 0;
|
|
108
|
+
right: 0;
|
|
109
|
+
bottom: 0;
|
|
110
|
+
background-color: rgba(0, 0, 0, 0.7);
|
|
111
|
+
backdrop-filter: blur(3px);
|
|
112
|
+
display: none;
|
|
113
|
+
justify-content: center;
|
|
114
|
+
align-items: center;
|
|
115
|
+
z-index: 2000;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.modal-container {
|
|
119
|
+
background-color: var(--panel-bg);
|
|
120
|
+
width: 400px;
|
|
121
|
+
max-width: 90%;
|
|
122
|
+
border: 1px solid var(--panel-border);
|
|
123
|
+
overflow: hidden;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.modal-header {
|
|
127
|
+
display: flex;
|
|
128
|
+
justify-content: space-between;
|
|
129
|
+
align-items: center;
|
|
130
|
+
padding: 15px 20px;
|
|
131
|
+
border-bottom: 1px solid var(--panel-border);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.modal-title {
|
|
135
|
+
font-weight: bold;
|
|
136
|
+
font-size: 18px;
|
|
137
|
+
margin: 0;
|
|
138
|
+
color: var(--primary-color);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.modal-close {
|
|
142
|
+
background: none;
|
|
143
|
+
border: none;
|
|
144
|
+
font-size: 24px;
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
color: var(--text-color);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.modal-body {
|
|
150
|
+
padding: 20px;
|
|
151
|
+
max-height: 70vh;
|
|
152
|
+
overflow-y: auto;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.modal-footer {
|
|
156
|
+
padding: 15px 20px;
|
|
157
|
+
border-top: 1px solid var(--panel-border);
|
|
158
|
+
display: flex;
|
|
159
|
+
justify-content: flex-end;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.modal-btn {
|
|
163
|
+
padding: 8px 16px;
|
|
164
|
+
border: none;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
margin-left: 10px;
|
|
167
|
+
font-family: monospace;
|
|
168
|
+
transition: all 0.3s ease;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.modal-btn-primary {
|
|
172
|
+
background-color: var(--button-color);
|
|
173
|
+
color: white;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.modal-btn-secondary {
|
|
177
|
+
background-color: #555;
|
|
178
|
+
color: white;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.modal-btn:hover {
|
|
182
|
+
opacity: 0.9;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
/* Shared settings styles */
|
|
187
|
+
.settings-group {
|
|
188
|
+
margin-bottom: 20px;
|
|
189
|
+
border: 1px solid var(--panel-border);
|
|
190
|
+
padding: 15px;
|
|
191
|
+
background-color: rgba(0,0,0,0.1);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.settings-option {
|
|
195
|
+
flex: 0 0 48%;
|
|
196
|
+
margin-bottom: 12px;
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
justify-content: flex-start;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.settings-option label {
|
|
203
|
+
width: 120px;
|
|
204
|
+
margin-left: 10px;
|
|
205
|
+
color: var(--label-text);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.settings-select {
|
|
209
|
+
width: 100%;
|
|
210
|
+
padding: 8px;
|
|
211
|
+
border: 1px solid var(--panel-border);
|
|
212
|
+
background-color: var(--input-bg);
|
|
213
|
+
color: var(--input-text);
|
|
214
|
+
font-family: monospace;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.settings-slider {
|
|
218
|
+
width: 80%;
|
|
219
|
+
margin-right: 10px;
|
|
220
|
+
background-color: var(--secondary-color);
|
|
221
|
+
border: 1px solid var(--panel-border);
|
|
222
|
+
height: 5px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.slider-container {
|
|
226
|
+
display: flex;
|
|
227
|
+
align-items: center;
|
|
228
|
+
margin-top: 5px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
/* Shared collapsible styles */
|
|
233
|
+
.collapsible-header {
|
|
234
|
+
display: flex;
|
|
235
|
+
justify-content: space-between;
|
|
236
|
+
align-items: center;
|
|
237
|
+
cursor: pointer;
|
|
238
|
+
padding: 4px 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.collapsible-header .settings-subheading {
|
|
242
|
+
margin-bottom: 0;
|
|
243
|
+
flex: 1;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.collapse-indicator {
|
|
247
|
+
font-size: 14px;
|
|
248
|
+
color: #777;
|
|
249
|
+
margin-right: 4px;
|
|
250
|
+
transition: none;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.collapsible-header.expanded .collapse-indicator {
|
|
254
|
+
transform: none;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Shared no image container*/
|
|
258
|
+
.no-image-message-container {
|
|
259
|
+
position: absolute;
|
|
260
|
+
top: 50%;
|
|
261
|
+
left: 50%;
|
|
262
|
+
transform: translate(-50%, -50%);
|
|
263
|
+
text-align: center;
|
|
264
|
+
color: #777;
|
|
265
|
+
font-size: 0.9em;
|
|
266
|
+
font-style: italic;
|
|
267
|
+
padding: 20px;
|
|
268
|
+
background-color: rgba(30, 30, 30, 0.7);
|
|
269
|
+
border-radius: 4px;
|
|
270
|
+
width: 80%;
|
|
271
|
+
display: block;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.no-image-message-container.visible {
|
|
275
|
+
display: block;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.no-image-message-container.hidden {
|
|
279
|
+
display: none;
|
|
280
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify the type of animation based on name and initial style
|
|
3
|
+
* @param {string} animationName - The animation name
|
|
4
|
+
* @param {Object} initialStyle - Initial computed style
|
|
5
|
+
* @returns {Object} Classification information
|
|
6
|
+
*/
|
|
7
|
+
export function classifyAnimation(animationName, initialStyle) {
|
|
8
|
+
const name = animationName.toLowerCase();
|
|
9
|
+
|
|
10
|
+
// Build a classification object
|
|
11
|
+
const classification = {
|
|
12
|
+
isFadeIn: name.includes('fadein') || (name.includes('fade') && name.includes('in')),
|
|
13
|
+
isFadeOut: name.includes('fadeout') || (name.includes('fade') && name.includes('out')),
|
|
14
|
+
isSlideIn: name.includes('slidein') || (name.includes('slide') && name.includes('in')),
|
|
15
|
+
isSlideOut: name.includes('slideout') || (name.includes('slide') && name.includes('out')),
|
|
16
|
+
isZoomIn: name.includes('zoomin') || (name.includes('zoom') && name.includes('in')),
|
|
17
|
+
isZoomOut: name.includes('zoomout') || (name.includes('zoom') && name.includes('out')),
|
|
18
|
+
isBounce: name.includes('bounce'),
|
|
19
|
+
isRotate: name.includes('rotate'),
|
|
20
|
+
isPulse: name.includes('pulse'),
|
|
21
|
+
isFlash: name.includes('flash'),
|
|
22
|
+
isShake: name.includes('shake'),
|
|
23
|
+
isWobble: name.includes('wobble'),
|
|
24
|
+
isJello: name.includes('jello'),
|
|
25
|
+
isFlip: name.includes('flip'),
|
|
26
|
+
isHeartBeat: name.includes('heartbeat') || name.includes('heart-beat'),
|
|
27
|
+
isHinge: name.includes('hinge'),
|
|
28
|
+
isBlink: name.includes('blink')
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Determine animation category
|
|
32
|
+
if (classification.isFadeIn || classification.isFadeOut) {
|
|
33
|
+
classification.category = 'fade';
|
|
34
|
+
} else if (classification.isSlideIn || classification.isSlideOut) {
|
|
35
|
+
classification.category = 'slide';
|
|
36
|
+
} else if (classification.isZoomIn || classification.isZoomOut) {
|
|
37
|
+
classification.category = 'zoom';
|
|
38
|
+
} else if (classification.isRotate) {
|
|
39
|
+
classification.category = 'rotate';
|
|
40
|
+
} else if (classification.isBounce || classification.isPulse || classification.isFlash ||
|
|
41
|
+
classification.isShake || classification.isWobble || classification.isJello ||
|
|
42
|
+
classification.isFlip || classification.isHeartBeat || classification.isHinge ||
|
|
43
|
+
classification.isBlink) {
|
|
44
|
+
classification.category = 'attention';
|
|
45
|
+
} else {
|
|
46
|
+
classification.category = 'other';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return classification;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Classify the type of transition
|
|
54
|
+
* @param {string} property - The CSS property being transitioned
|
|
55
|
+
* @param {string} initialValue - Starting value
|
|
56
|
+
* @param {string} currentValue - Current value during transition
|
|
57
|
+
* @returns {Object} Classification information
|
|
58
|
+
*/
|
|
59
|
+
export function classifyTransition(property, initialValue, currentValue) {
|
|
60
|
+
const classification = {
|
|
61
|
+
property: property
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Determine transition type based on property
|
|
65
|
+
switch (property) {
|
|
66
|
+
case 'opacity':
|
|
67
|
+
const initialOpacity = parseFloat(initialValue) || 0;
|
|
68
|
+
const currentOpacity = parseFloat(currentValue) || 0;
|
|
69
|
+
classification.isFadeIn = initialOpacity < currentOpacity;
|
|
70
|
+
classification.isFadeOut = initialOpacity > currentOpacity;
|
|
71
|
+
classification.category = 'fade';
|
|
72
|
+
break;
|
|
73
|
+
|
|
74
|
+
case 'transform':
|
|
75
|
+
if (initialValue.includes('scale')) {
|
|
76
|
+
const initialScale = extractScaleValue(initialValue);
|
|
77
|
+
const currentScale = extractScaleValue(currentValue);
|
|
78
|
+
classification.isZoomIn = initialScale < currentScale;
|
|
79
|
+
classification.isZoomOut = initialScale > currentScale;
|
|
80
|
+
classification.category = 'zoom';
|
|
81
|
+
} else if (initialValue.includes('rotate')) {
|
|
82
|
+
classification.isRotate = true;
|
|
83
|
+
classification.category = 'rotate';
|
|
84
|
+
} else if (initialValue.includes('translate')) {
|
|
85
|
+
classification.isMove = true;
|
|
86
|
+
classification.category = 'move';
|
|
87
|
+
} else {
|
|
88
|
+
classification.category = 'transform';
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
|
|
92
|
+
case 'left':
|
|
93
|
+
case 'right':
|
|
94
|
+
case 'top':
|
|
95
|
+
case 'bottom':
|
|
96
|
+
classification.isMove = true;
|
|
97
|
+
classification.category = 'move';
|
|
98
|
+
break;
|
|
99
|
+
|
|
100
|
+
case 'width':
|
|
101
|
+
case 'height':
|
|
102
|
+
const initialSize = parseFloat(initialValue) || 0;
|
|
103
|
+
const currentSize = parseFloat(currentValue) || 0;
|
|
104
|
+
classification.isExpand = initialSize < currentSize;
|
|
105
|
+
classification.isShrink = initialSize > currentSize;
|
|
106
|
+
classification.category = 'size';
|
|
107
|
+
break;
|
|
108
|
+
|
|
109
|
+
default:
|
|
110
|
+
classification.category = 'other';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return classification;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Extract scale value from a transform string
|
|
118
|
+
* @param {string} transform - CSS transform value
|
|
119
|
+
* @returns {number} Extracted scale or 1 if not found
|
|
120
|
+
*/
|
|
121
|
+
function extractScaleValue(transform) {
|
|
122
|
+
try {
|
|
123
|
+
const scaleMatch = transform.match(/scale\(([^)]+)\)/);
|
|
124
|
+
if (scaleMatch && scaleMatch[1]) {
|
|
125
|
+
return parseFloat(scaleMatch[1]) || 1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const scale3dMatch = transform.match(/scale3d\(([^,]+),/);
|
|
129
|
+
if (scale3dMatch && scale3dMatch[1]) {
|
|
130
|
+
return parseFloat(scale3dMatch[1]) || 1;
|
|
131
|
+
}
|
|
132
|
+
} catch (e) {}
|
|
133
|
+
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Unified animation detection script for both CSS3D and Image2Texture modes
|
|
138
|
+
export function injectUnifiedAnimationDetectionScript(iframe, mode = 'auto') {
|
|
139
|
+
if (!iframe || !iframe.contentDocument) return;
|
|
140
|
+
|
|
141
|
+
const script = iframe.contentDocument.createElement('script');
|
|
142
|
+
script.textContent = `
|
|
143
|
+
// Unified animation detection system
|
|
144
|
+
window.__animationDetection = {
|
|
145
|
+
// Basic counters
|
|
146
|
+
setTimeout: 0,
|
|
147
|
+
setInterval: 0,
|
|
148
|
+
rAF: 0,
|
|
149
|
+
activeTimeouts: 0,
|
|
150
|
+
activeIntervals: 0,
|
|
151
|
+
animationFrameIds: new Set(),
|
|
152
|
+
|
|
153
|
+
// CSS animation tracking
|
|
154
|
+
cssAnimations: new Set(),
|
|
155
|
+
cssTransitions: new Set(),
|
|
156
|
+
|
|
157
|
+
// DOM change tracking
|
|
158
|
+
domChanges: 0,
|
|
159
|
+
lastDomChange: 0,
|
|
160
|
+
styleChanges: false,
|
|
161
|
+
|
|
162
|
+
// Mode configuration
|
|
163
|
+
mode: '${mode}', // 'css3d', 'image2texture', or 'auto'
|
|
164
|
+
|
|
165
|
+
// Advanced detection
|
|
166
|
+
isAnimationLoop: false,
|
|
167
|
+
loopDetectionThreshold: 5
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const detection = window.__animationDetection;
|
|
171
|
+
|
|
172
|
+
// Override setTimeout
|
|
173
|
+
const originalSetTimeout = window.setTimeout;
|
|
174
|
+
window.setTimeout = function(callback, delay) {
|
|
175
|
+
detection.setTimeout++;
|
|
176
|
+
detection.activeTimeouts++;
|
|
177
|
+
const id = originalSetTimeout.call(this, function() {
|
|
178
|
+
detection.activeTimeouts--;
|
|
179
|
+
if (typeof callback === 'function') callback();
|
|
180
|
+
}, delay);
|
|
181
|
+
return id;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Override setInterval
|
|
185
|
+
const originalSetInterval = window.setInterval;
|
|
186
|
+
window.setInterval = function(callback, delay) {
|
|
187
|
+
detection.setInterval++;
|
|
188
|
+
detection.activeIntervals++;
|
|
189
|
+
return originalSetInterval.call(this, callback, delay);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Override requestAnimationFrame
|
|
193
|
+
const originalRAF = window.requestAnimationFrame;
|
|
194
|
+
window.requestAnimationFrame = function(callback) {
|
|
195
|
+
detection.rAF++;
|
|
196
|
+
const id = originalRAF.call(this, function(timestamp) {
|
|
197
|
+
detection.animationFrameIds.add(id);
|
|
198
|
+
if (typeof callback === 'function') callback(timestamp);
|
|
199
|
+
|
|
200
|
+
// Animation loop detection for image2texture mode
|
|
201
|
+
if (detection.mode === 'image2texture' || detection.mode === 'auto') {
|
|
202
|
+
if (detection.animationFrameIds.size > detection.loopDetectionThreshold) {
|
|
203
|
+
detection.isAnimationLoop = true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
return id;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// CSS Animation and Transition Event Listeners (for CSS3D mode or auto)
|
|
211
|
+
if (detection.mode === 'css3d' || detection.mode === 'auto') {
|
|
212
|
+
// CSS animation events
|
|
213
|
+
document.addEventListener('animationstart', (event) => {
|
|
214
|
+
detection.cssAnimations.add(event.animationName);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
document.addEventListener('animationend', (event) => {
|
|
218
|
+
detection.cssAnimations.delete(event.animationName);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
document.addEventListener('animationiteration', (event) => {
|
|
222
|
+
detection.lastDomChange = Date.now();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// CSS transition events
|
|
226
|
+
document.addEventListener('transitionstart', (event) => {
|
|
227
|
+
detection.cssTransitions.add(event.propertyName);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
document.addEventListener('transitionend', (event) => {
|
|
231
|
+
detection.cssTransitions.delete(event.propertyName);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
document.addEventListener('transitionrun', (event) => {
|
|
235
|
+
detection.lastDomChange = Date.now();
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// DOM Mutation Observer (enhanced for both modes)
|
|
240
|
+
try {
|
|
241
|
+
const observer = new MutationObserver(mutations => {
|
|
242
|
+
detection.domChanges += mutations.length;
|
|
243
|
+
detection.lastDomChange = Date.now();
|
|
244
|
+
|
|
245
|
+
for (const mutation of mutations) {
|
|
246
|
+
// Check for style or class changes
|
|
247
|
+
if (mutation.type === 'attributes' &&
|
|
248
|
+
(mutation.attributeName === 'style' || mutation.attributeName === 'class')) {
|
|
249
|
+
detection.styleChanges = true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Check for added/removed nodes (image2texture specific)
|
|
253
|
+
if (detection.mode === 'image2texture' || detection.mode === 'auto') {
|
|
254
|
+
if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
|
|
255
|
+
detection.domChanges++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Configure observer based on mode
|
|
262
|
+
const observerConfig = {
|
|
263
|
+
attributes: true,
|
|
264
|
+
childList: true,
|
|
265
|
+
subtree: true
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Add attribute filter for CSS3D mode for better performance
|
|
269
|
+
if (detection.mode === 'css3d') {
|
|
270
|
+
observerConfig.attributeFilter = ['style', 'class'];
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
observer.observe(document.documentElement, observerConfig);
|
|
274
|
+
|
|
275
|
+
} catch (e) {
|
|
276
|
+
console.debug('MutationObserver not available:', e);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Utility methods for external access
|
|
280
|
+
window.__animationDetection.getStatus = function() {
|
|
281
|
+
const now = Date.now();
|
|
282
|
+
return {
|
|
283
|
+
hasActiveTimeouts: detection.activeTimeouts > 0,
|
|
284
|
+
hasActiveIntervals: detection.activeIntervals > 0,
|
|
285
|
+
hasActiveRAF: detection.rAF > 0 && detection.animationFrameIds.size > 0,
|
|
286
|
+
hasCssAnimations: detection.cssAnimations.size > 0,
|
|
287
|
+
hasCssTransitions: detection.cssTransitions.size > 0,
|
|
288
|
+
hasRecentDomChanges: (now - detection.lastDomChange) < 500,
|
|
289
|
+
timeSinceLastChange: now - detection.lastDomChange,
|
|
290
|
+
totalChanges: detection.domChanges,
|
|
291
|
+
isAnimationLoop: detection.isAnimationLoop,
|
|
292
|
+
mode: detection.mode
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
window.__animationDetection.isAnimating = function() {
|
|
297
|
+
const status = this.getStatus();
|
|
298
|
+
return status.hasActiveTimeouts ||
|
|
299
|
+
status.hasActiveIntervals ||
|
|
300
|
+
status.hasActiveRAF ||
|
|
301
|
+
status.hasCssAnimations ||
|
|
302
|
+
status.hasCssTransitions ||
|
|
303
|
+
status.hasRecentDomChanges;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
window.__animationDetection.reset = function() {
|
|
307
|
+
detection.setTimeout = 0;
|
|
308
|
+
detection.setInterval = 0;
|
|
309
|
+
detection.rAF = 0;
|
|
310
|
+
detection.activeTimeouts = 0;
|
|
311
|
+
detection.activeIntervals = 0;
|
|
312
|
+
detection.animationFrameIds.clear();
|
|
313
|
+
detection.cssAnimations.clear();
|
|
314
|
+
detection.cssTransitions.clear();
|
|
315
|
+
detection.domChanges = 0;
|
|
316
|
+
detection.lastDomChange = 0;
|
|
317
|
+
detection.styleChanges = false;
|
|
318
|
+
detection.isAnimationLoop = false;
|
|
319
|
+
};
|
|
320
|
+
`;
|
|
321
|
+
|
|
322
|
+
iframe.contentDocument.head.appendChild(script);
|
|
323
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deduplicate items by name, counting duplicates
|
|
3
|
+
* @param {Array} items - Array of items to deduplicate
|
|
4
|
+
* @returns {Array} Deduplicated items with count property
|
|
5
|
+
*/
|
|
6
|
+
export function deduplicateItemsByName(items) {
|
|
7
|
+
const uniqueItems = new Map();
|
|
8
|
+
|
|
9
|
+
items.forEach(item => {
|
|
10
|
+
const key = item.name;
|
|
11
|
+
if (uniqueItems.has(key)) {
|
|
12
|
+
const existingItem = uniqueItems.get(key);
|
|
13
|
+
existingItem.count = (existingItem.count || 1) + 1;
|
|
14
|
+
} else {
|
|
15
|
+
uniqueItems.set(key, {...item, count: 1});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return Array.from(uniqueItems.values());
|
|
20
|
+
}
|