cyclecad 0.9.7 → 1.0.1
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/app/explodeview-test-agent.html +1003 -0
- package/app/index.html +304 -39
- package/app/test-agent-v2.html +2 -2
- package/app/tutorials/advanced-runner.html +959 -0
- package/app/tutorials/assembly-explodeview.html +1108 -0
- package/app/tutorials/basic-runner.html +800 -0
- package/app/tutorials/explodeview-integration.html +1 -1
- package/app/tutorials/explodeview-runner.html +1407 -0
- package/app/tutorials/intermediate-runner.html +1306 -0
- package/app/tutorials/tutorial-runner.html +1421 -0
- package/package.json +1 -1
- package/test-report.html +1 -1
|
@@ -0,0 +1,1407 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ExplodeView Integration Runner</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
10
|
+
<style>
|
|
11
|
+
* {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body {
|
|
18
|
+
font-family: 'Inter', sans-serif;
|
|
19
|
+
background-color: #f0f2f5;
|
|
20
|
+
color: #1a1a2e;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Header */
|
|
28
|
+
header {
|
|
29
|
+
background-color: #ffffff;
|
|
30
|
+
border-bottom: 1px solid #d0d7de;
|
|
31
|
+
padding: 16px 20px;
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
position: sticky;
|
|
34
|
+
top: 0;
|
|
35
|
+
z-index: 100;
|
|
36
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.header-content {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: space-between;
|
|
43
|
+
gap: 20px;
|
|
44
|
+
max-width: 2000px;
|
|
45
|
+
margin: 0 auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.header-left {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: 12px;
|
|
52
|
+
flex: 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.header-title {
|
|
56
|
+
font-size: 18px;
|
|
57
|
+
font-weight: 700;
|
|
58
|
+
color: #0969da;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.progress-section {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: 12px;
|
|
65
|
+
flex: 1;
|
|
66
|
+
min-width: 300px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.progress-bar-container {
|
|
70
|
+
flex: 1;
|
|
71
|
+
height: 8px;
|
|
72
|
+
background-color: #d0d7de;
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.progress-bar {
|
|
78
|
+
height: 100%;
|
|
79
|
+
background: linear-gradient(90deg, #0969da, #54aeff);
|
|
80
|
+
width: 0%;
|
|
81
|
+
transition: width 0.3s ease;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.step-counter {
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
color: #57606a;
|
|
87
|
+
white-space: nowrap;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.header-controls {
|
|
91
|
+
display: flex;
|
|
92
|
+
gap: 8px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
button {
|
|
96
|
+
padding: 8px 16px;
|
|
97
|
+
border-radius: 6px;
|
|
98
|
+
border: 1px solid #d0d7de;
|
|
99
|
+
background-color: #ffffff;
|
|
100
|
+
color: #1a1a2e;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
font-size: 13px;
|
|
103
|
+
font-weight: 500;
|
|
104
|
+
transition: all 0.2s ease;
|
|
105
|
+
font-family: 'Inter', sans-serif;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
button:hover:not(:disabled) {
|
|
109
|
+
background-color: #f0f2f5;
|
|
110
|
+
border-color: #0969da;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.btn-primary {
|
|
114
|
+
background-color: #0969da;
|
|
115
|
+
border-color: #0969da;
|
|
116
|
+
color: #fff;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.btn-primary:hover:not(:disabled) {
|
|
120
|
+
background-color: #0860ca;
|
|
121
|
+
border-color: #0860ca;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.btn-danger {
|
|
125
|
+
background-color: #cf222e;
|
|
126
|
+
border-color: #cf222e;
|
|
127
|
+
color: #fff;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.btn-danger:hover:not(:disabled) {
|
|
131
|
+
background-color: #a40e26;
|
|
132
|
+
border-color: #a40e26;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
button:disabled {
|
|
136
|
+
opacity: 0.5;
|
|
137
|
+
cursor: not-allowed;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Main Container */
|
|
141
|
+
.container {
|
|
142
|
+
display: flex;
|
|
143
|
+
flex: 1;
|
|
144
|
+
overflow: hidden;
|
|
145
|
+
gap: 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Left Panel - Tutorial Steps */
|
|
149
|
+
.tutorial-panel {
|
|
150
|
+
width: 35%;
|
|
151
|
+
background-color: #ffffff;
|
|
152
|
+
border-right: 1px solid #d0d7de;
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.steps-container {
|
|
159
|
+
flex: 1;
|
|
160
|
+
overflow-y: auto;
|
|
161
|
+
padding: 16px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.steps-container::-webkit-scrollbar {
|
|
165
|
+
width: 8px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.steps-container::-webkit-scrollbar-track {
|
|
169
|
+
background: transparent;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.steps-container::-webkit-scrollbar-thumb {
|
|
173
|
+
background-color: #c1c8cf;
|
|
174
|
+
border-radius: 4px;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.steps-container::-webkit-scrollbar-thumb:hover {
|
|
178
|
+
background-color: #57606a;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Step Card */
|
|
182
|
+
.step-card {
|
|
183
|
+
background-color: #f6f8fa;
|
|
184
|
+
border: 1px solid #d0d7de;
|
|
185
|
+
border-radius: 8px;
|
|
186
|
+
padding: 12px;
|
|
187
|
+
margin-bottom: 12px;
|
|
188
|
+
transition: all 0.2s ease;
|
|
189
|
+
cursor: pointer;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.step-card:hover {
|
|
193
|
+
border-color: #0969da;
|
|
194
|
+
background-color: #eaf5ff;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.step-card.active {
|
|
198
|
+
background-color: #ddf4ff;
|
|
199
|
+
border-color: #0969da;
|
|
200
|
+
animation: pulse 1s infinite;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.step-card.active .step-badge {
|
|
204
|
+
background-color: #0969da;
|
|
205
|
+
color: #fff;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.step-card.completed {
|
|
209
|
+
border-color: #1a7f37;
|
|
210
|
+
background-color: #dafbe1;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.step-card.completed .step-badge {
|
|
214
|
+
background-color: #1a7f37;
|
|
215
|
+
color: #fff;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.step-card.completed::after {
|
|
219
|
+
content: " ✓";
|
|
220
|
+
color: #1a7f37;
|
|
221
|
+
font-weight: 700;
|
|
222
|
+
margin-left: 4px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@keyframes pulse {
|
|
226
|
+
0%, 100% {
|
|
227
|
+
box-shadow: 0 0 0 0 rgba(9, 105, 218, 0.4);
|
|
228
|
+
}
|
|
229
|
+
50% {
|
|
230
|
+
box-shadow: 0 0 0 10px rgba(9, 105, 218, 0);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.step-header {
|
|
235
|
+
display: flex;
|
|
236
|
+
align-items: center;
|
|
237
|
+
gap: 12px;
|
|
238
|
+
margin-bottom: 8px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.step-badge {
|
|
242
|
+
background-color: #0969da;
|
|
243
|
+
color: #ffffff;
|
|
244
|
+
width: 28px;
|
|
245
|
+
height: 28px;
|
|
246
|
+
border-radius: 50%;
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
font-size: 12px;
|
|
251
|
+
font-weight: 700;
|
|
252
|
+
flex-shrink: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.step-title {
|
|
256
|
+
font-size: 14px;
|
|
257
|
+
font-weight: 600;
|
|
258
|
+
color: #1a1a2e;
|
|
259
|
+
flex: 1;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.step-status {
|
|
263
|
+
font-size: 11px;
|
|
264
|
+
color: #57606a;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.step-description {
|
|
268
|
+
font-size: 13px;
|
|
269
|
+
color: #57606a;
|
|
270
|
+
margin-bottom: 8px;
|
|
271
|
+
line-height: 1.4;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.step-details {
|
|
275
|
+
display: none;
|
|
276
|
+
background-color: #eaf5ff;
|
|
277
|
+
border-left: 2px solid #0969da;
|
|
278
|
+
padding: 8px 12px;
|
|
279
|
+
border-radius: 4px;
|
|
280
|
+
margin-bottom: 8px;
|
|
281
|
+
font-size: 12px;
|
|
282
|
+
color: #1a1a2e;
|
|
283
|
+
line-height: 1.5;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.step-details.expanded {
|
|
287
|
+
display: block;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.step-code {
|
|
291
|
+
background-color: #f6f8fa;
|
|
292
|
+
border: 1px solid #d0d7de;
|
|
293
|
+
border-radius: 4px;
|
|
294
|
+
padding: 8px;
|
|
295
|
+
margin-top: 4px;
|
|
296
|
+
font-family: 'Monaco', monospace;
|
|
297
|
+
font-size: 11px;
|
|
298
|
+
color: #79c0ff;
|
|
299
|
+
overflow-x: auto;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.step-actions {
|
|
303
|
+
display: flex;
|
|
304
|
+
gap: 8px;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.step-run-btn {
|
|
308
|
+
flex: 1;
|
|
309
|
+
padding: 8px 12px;
|
|
310
|
+
font-size: 12px;
|
|
311
|
+
background-color: #0969da;
|
|
312
|
+
border-color: #0969da;
|
|
313
|
+
color: #ffffff;
|
|
314
|
+
font-weight: 600;
|
|
315
|
+
border-radius: 4px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.step-run-btn:hover:not(:disabled) {
|
|
319
|
+
background-color: #79c0ff;
|
|
320
|
+
border-color: #79c0ff;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.step-run-btn:disabled {
|
|
324
|
+
background-color: #d0d7de;
|
|
325
|
+
border-color: #d0d7de;
|
|
326
|
+
color: #57606a;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.step-details-toggle {
|
|
330
|
+
padding: 6px 10px;
|
|
331
|
+
font-size: 11px;
|
|
332
|
+
background-color: transparent;
|
|
333
|
+
border: 1px solid #d0d7de;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* Right Panel - App Preview */
|
|
337
|
+
.app-panel {
|
|
338
|
+
flex: 1;
|
|
339
|
+
display: flex;
|
|
340
|
+
flex-direction: column;
|
|
341
|
+
background-color: #ffffff;
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.app-header {
|
|
346
|
+
background-color: #f6f8fa;
|
|
347
|
+
border-bottom: 1px solid #d0d7de;
|
|
348
|
+
padding: 12px 16px;
|
|
349
|
+
display: flex;
|
|
350
|
+
align-items: center;
|
|
351
|
+
justify-content: space-between;
|
|
352
|
+
flex-shrink: 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.app-header-left {
|
|
356
|
+
display: flex;
|
|
357
|
+
align-items: center;
|
|
358
|
+
gap: 8px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.app-indicator {
|
|
362
|
+
width: 10px;
|
|
363
|
+
height: 10px;
|
|
364
|
+
border-radius: 50%;
|
|
365
|
+
background-color: #238636;
|
|
366
|
+
animation: blink 1s infinite;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
@keyframes blink {
|
|
370
|
+
0%, 49%, 100% { opacity: 1; }
|
|
371
|
+
50%, 99% { opacity: 0.5; }
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.app-url {
|
|
375
|
+
font-size: 12px;
|
|
376
|
+
color: #57606a;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.app-actions {
|
|
380
|
+
display: flex;
|
|
381
|
+
gap: 8px;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.app-actions button {
|
|
385
|
+
padding: 6px 12px;
|
|
386
|
+
font-size: 12px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
#app-frame {
|
|
390
|
+
flex: 1;
|
|
391
|
+
border: none;
|
|
392
|
+
background-color: #fff;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* Floating Shortcuts Panel */
|
|
396
|
+
.shortcuts-panel {
|
|
397
|
+
position: fixed;
|
|
398
|
+
bottom: 20px;
|
|
399
|
+
right: 20px;
|
|
400
|
+
width: 320px;
|
|
401
|
+
max-height: 500px;
|
|
402
|
+
background-color: #f6f8fa;
|
|
403
|
+
border: 1px solid #d0d7de;
|
|
404
|
+
border-radius: 8px;
|
|
405
|
+
display: none;
|
|
406
|
+
flex-direction: column;
|
|
407
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
|
408
|
+
z-index: 200;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.shortcuts-panel.visible {
|
|
412
|
+
display: flex;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.shortcuts-header {
|
|
416
|
+
padding: 12px 16px;
|
|
417
|
+
border-bottom: 1px solid #d0d7de;
|
|
418
|
+
display: flex;
|
|
419
|
+
justify-content: space-between;
|
|
420
|
+
align-items: center;
|
|
421
|
+
flex-shrink: 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.shortcuts-header h3 {
|
|
425
|
+
font-size: 14px;
|
|
426
|
+
font-weight: 600;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.shortcuts-close {
|
|
430
|
+
background: none;
|
|
431
|
+
border: none;
|
|
432
|
+
color: #57606a;
|
|
433
|
+
cursor: pointer;
|
|
434
|
+
padding: 0;
|
|
435
|
+
font-size: 16px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.shortcuts-content {
|
|
439
|
+
flex: 1;
|
|
440
|
+
overflow-y: auto;
|
|
441
|
+
padding: 12px 16px;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.shortcuts-content::-webkit-scrollbar {
|
|
445
|
+
width: 6px;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.shortcuts-content::-webkit-scrollbar-thumb {
|
|
449
|
+
background-color: #d0d7de;
|
|
450
|
+
border-radius: 3px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.shortcut-item {
|
|
454
|
+
display: flex;
|
|
455
|
+
justify-content: space-between;
|
|
456
|
+
gap: 12px;
|
|
457
|
+
margin-bottom: 8px;
|
|
458
|
+
font-size: 12px;
|
|
459
|
+
padding-bottom: 8px;
|
|
460
|
+
border-bottom: 1px solid #d0d7de;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.shortcut-item:last-child {
|
|
464
|
+
border-bottom: none;
|
|
465
|
+
margin-bottom: 0;
|
|
466
|
+
padding-bottom: 0;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.shortcut-key {
|
|
470
|
+
background-color: #ffffff;
|
|
471
|
+
border: 1px solid #d0d7de;
|
|
472
|
+
border-radius: 4px;
|
|
473
|
+
padding: 2px 6px;
|
|
474
|
+
font-family: 'Monaco', monospace;
|
|
475
|
+
font-weight: 600;
|
|
476
|
+
color: #0969da;
|
|
477
|
+
white-space: nowrap;
|
|
478
|
+
flex-shrink: 0;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.shortcut-desc {
|
|
482
|
+
color: #57606a;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.shortcuts-toggle {
|
|
486
|
+
position: fixed;
|
|
487
|
+
bottom: 20px;
|
|
488
|
+
right: 20px;
|
|
489
|
+
width: 48px;
|
|
490
|
+
height: 48px;
|
|
491
|
+
border-radius: 50%;
|
|
492
|
+
background-color: #0969da;
|
|
493
|
+
border: none;
|
|
494
|
+
color: #ffffff;
|
|
495
|
+
font-size: 20px;
|
|
496
|
+
font-weight: 700;
|
|
497
|
+
cursor: pointer;
|
|
498
|
+
display: flex;
|
|
499
|
+
align-items: center;
|
|
500
|
+
justify-content: center;
|
|
501
|
+
transition: all 0.2s ease;
|
|
502
|
+
z-index: 150;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.shortcuts-toggle:hover {
|
|
506
|
+
background-color: #79c0ff;
|
|
507
|
+
transform: scale(1.1);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.shortcuts-toggle.hidden {
|
|
511
|
+
display: none;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* Footer */
|
|
515
|
+
footer {
|
|
516
|
+
background-color: #f6f8fa;
|
|
517
|
+
border-top: 1px solid #d0d7de;
|
|
518
|
+
padding: 12px 20px;
|
|
519
|
+
flex-shrink: 0;
|
|
520
|
+
font-size: 12px;
|
|
521
|
+
color: #57606a;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/* Loading Spinner */
|
|
525
|
+
.spinner {
|
|
526
|
+
display: inline-block;
|
|
527
|
+
width: 14px;
|
|
528
|
+
height: 14px;
|
|
529
|
+
border: 2px solid rgba(88, 166, 255, 0.3);
|
|
530
|
+
border-top-color: #0969da;
|
|
531
|
+
border-radius: 50%;
|
|
532
|
+
animation: spin 0.8s linear infinite;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
@keyframes spin {
|
|
536
|
+
to { transform: rotate(360deg); }
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* Responsive */
|
|
540
|
+
@media (max-width: 1200px) {
|
|
541
|
+
.container {
|
|
542
|
+
flex-direction: column;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
.tutorial-panel {
|
|
546
|
+
width: 100%;
|
|
547
|
+
height: 40%;
|
|
548
|
+
border-right: none;
|
|
549
|
+
border-bottom: 1px solid #d0d7de;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.app-panel {
|
|
553
|
+
height: 60%;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/* Tooltip */
|
|
558
|
+
.tooltip {
|
|
559
|
+
position: absolute;
|
|
560
|
+
background-color: #eaeef2;
|
|
561
|
+
color: #1a1a2e;
|
|
562
|
+
padding: 8px 12px;
|
|
563
|
+
border-radius: 4px;
|
|
564
|
+
border: 1px solid #d0d7de;
|
|
565
|
+
font-size: 12px;
|
|
566
|
+
white-space: nowrap;
|
|
567
|
+
z-index: 1000;
|
|
568
|
+
pointer-events: none;
|
|
569
|
+
opacity: 0;
|
|
570
|
+
transition: opacity 0.2s ease;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.tooltip.visible {
|
|
574
|
+
opacity: 1;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* Message Box */
|
|
578
|
+
.message-box {
|
|
579
|
+
background-color: #eaeef2;
|
|
580
|
+
border: 1px solid #d0d7de;
|
|
581
|
+
border-radius: 6px;
|
|
582
|
+
padding: 12px;
|
|
583
|
+
margin-bottom: 12px;
|
|
584
|
+
font-size: 12px;
|
|
585
|
+
color: #57606a;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.message-box.warning {
|
|
589
|
+
border-color: #d29922;
|
|
590
|
+
background-color: rgba(210, 153, 34, 0.1);
|
|
591
|
+
color: #d0883c;
|
|
592
|
+
}
|
|
593
|
+
</style>
|
|
594
|
+
</head>
|
|
595
|
+
<body>
|
|
596
|
+
<!-- Header -->
|
|
597
|
+
<header>
|
|
598
|
+
<div class="header-content">
|
|
599
|
+
<div class="header-left">
|
|
600
|
+
<div class="header-title">ExplodeView Integration Runner</div>
|
|
601
|
+
</div>
|
|
602
|
+
<div class="progress-section">
|
|
603
|
+
<div class="progress-bar-container">
|
|
604
|
+
<div class="progress-bar" id="progressBar"></div>
|
|
605
|
+
</div>
|
|
606
|
+
<div class="step-counter" id="stepCounter">Step 0 of 57</div>
|
|
607
|
+
</div>
|
|
608
|
+
<div class="header-controls">
|
|
609
|
+
<button class="btn-primary" id="runAllBtn">▶ Run All</button>
|
|
610
|
+
<button class="btn-danger" id="stopBtn" disabled>⏹ Stop</button>
|
|
611
|
+
</div>
|
|
612
|
+
</div>
|
|
613
|
+
</header>
|
|
614
|
+
|
|
615
|
+
<!-- Main Container -->
|
|
616
|
+
<div class="container">
|
|
617
|
+
<!-- Left Panel - Tutorial Steps -->
|
|
618
|
+
<div class="tutorial-panel">
|
|
619
|
+
<div class="steps-container" id="stepsContainer"></div>
|
|
620
|
+
<footer>
|
|
621
|
+
<div id="footerText">Select a step to begin</div>
|
|
622
|
+
</footer>
|
|
623
|
+
</div>
|
|
624
|
+
|
|
625
|
+
<!-- Right Panel - App Preview -->
|
|
626
|
+
<div class="app-panel">
|
|
627
|
+
<div class="app-header">
|
|
628
|
+
<div class="app-header-left">
|
|
629
|
+
<div class="app-indicator" id="appIndicator"></div>
|
|
630
|
+
<div class="app-url">cyclecad.com/app/ (Viewer Mode)</div>
|
|
631
|
+
</div>
|
|
632
|
+
<div class="app-actions">
|
|
633
|
+
<button id="openTabBtn">↗ Open in Tab</button>
|
|
634
|
+
<button id="reloadAppBtn">⟳ Reload</button>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
<iframe id="app-frame" src="../"></iframe>
|
|
638
|
+
<div class="message-box warning" style="margin: 12px; display: none;" id="crossOriginMsg">
|
|
639
|
+
<strong>Note:</strong> If steps don't auto-execute, ensure cycleCAD is loaded. Open in a separate tab and follow along manually.
|
|
640
|
+
</div>
|
|
641
|
+
</div>
|
|
642
|
+
</div>
|
|
643
|
+
|
|
644
|
+
<!-- Floating Shortcuts Panel -->
|
|
645
|
+
<button class="shortcuts-toggle" id="shortcutsToggle" title="Keyboard Shortcuts (?)">?</button>
|
|
646
|
+
<div class="shortcuts-panel" id="shortcutsPanel">
|
|
647
|
+
<div class="shortcuts-header">
|
|
648
|
+
<h3>Keyboard Shortcuts</h3>
|
|
649
|
+
<button class="shortcuts-close" id="shortcutsClose">✕</button>
|
|
650
|
+
</div>
|
|
651
|
+
<div class="shortcuts-content" id="shortcutsContent"></div>
|
|
652
|
+
</div>
|
|
653
|
+
|
|
654
|
+
<script>
|
|
655
|
+
// Tutorial Steps Data - ExplodeView Integration Features
|
|
656
|
+
const TUTORIAL_STEPS = [
|
|
657
|
+
// Part 1: Viewer Mode Basics (Steps 1-10)
|
|
658
|
+
{
|
|
659
|
+
number: 1,
|
|
660
|
+
title: "Toggle Viewer Mode",
|
|
661
|
+
description: "Switch to ExplodeView visualization",
|
|
662
|
+
detail: "Press 'V' to toggle between modeling and viewing modes. This enables the ExplodeView toolbar with 57+ analysis and visualization tools.",
|
|
663
|
+
key: "v",
|
|
664
|
+
type: "key",
|
|
665
|
+
category: "Viewer Mode Basics"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
number: 2,
|
|
669
|
+
title: "Fit to All",
|
|
670
|
+
description: "Auto-zoom to fit entire assembly",
|
|
671
|
+
detail: "Press 'F' to zoom and pan the view to show all components with proper framing.",
|
|
672
|
+
key: "f",
|
|
673
|
+
type: "key",
|
|
674
|
+
category: "Viewer Mode Basics"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
number: 3,
|
|
678
|
+
title: "Rotate 3D View",
|
|
679
|
+
description: "Rotate the model using mouse",
|
|
680
|
+
detail: "Click and drag with left mouse button to rotate the 3D view. Right-drag to pan.",
|
|
681
|
+
mouse: "left-drag",
|
|
682
|
+
type: "mouse",
|
|
683
|
+
category: "Viewer Mode Basics"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
number: 4,
|
|
687
|
+
title: "Zoom with Scroll",
|
|
688
|
+
description: "Zoom in and out using mouse wheel",
|
|
689
|
+
detail: "Use mouse wheel to zoom. Hold Shift + scroll for faster zoom.",
|
|
690
|
+
mouse: "scroll",
|
|
691
|
+
type: "mouse",
|
|
692
|
+
category: "Viewer Mode Basics"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
number: 5,
|
|
696
|
+
title: "Select a Part",
|
|
697
|
+
description: "Click on any part to select it",
|
|
698
|
+
detail: "Click on a component in the 3D view. The part will be highlighted and info shown in the right panel.",
|
|
699
|
+
mouse: "click",
|
|
700
|
+
type: "mouse",
|
|
701
|
+
category: "Viewer Mode Basics"
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
number: 6,
|
|
705
|
+
title: "View Assembly Tree",
|
|
706
|
+
description: "Expand the assembly hierarchy",
|
|
707
|
+
detail: "The left panel shows the full component tree. Click items to select parts and expand assemblies.",
|
|
708
|
+
panel: "tree",
|
|
709
|
+
type: "panel",
|
|
710
|
+
category: "Viewer Mode Basics"
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
number: 7,
|
|
714
|
+
title: "Part Info Card",
|
|
715
|
+
description: "View detailed part information",
|
|
716
|
+
detail: "Selected parts show dimensions, material, volume, weight, and part number in the right panel.",
|
|
717
|
+
panel: "info",
|
|
718
|
+
type: "panel",
|
|
719
|
+
category: "Viewer Mode Basics"
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
number: 8,
|
|
723
|
+
title: "Context Menu",
|
|
724
|
+
description: "Right-click on a part",
|
|
725
|
+
detail: "Right-click any component to access actions: hide, isolate, move, export STL, info, etc.",
|
|
726
|
+
mouse: "right-click",
|
|
727
|
+
type: "mouse",
|
|
728
|
+
category: "Viewer Mode Basics"
|
|
729
|
+
},
|
|
730
|
+
{
|
|
731
|
+
number: 9,
|
|
732
|
+
title: "Wireframe Toggle",
|
|
733
|
+
description: "Switch to wireframe rendering",
|
|
734
|
+
detail: "Press 'W' to see the model as wireframe for better understanding of edges and structure.",
|
|
735
|
+
key: "w",
|
|
736
|
+
type: "key",
|
|
737
|
+
category: "Viewer Mode Basics"
|
|
738
|
+
},
|
|
739
|
+
{
|
|
740
|
+
number: 10,
|
|
741
|
+
title: "Grid Floor",
|
|
742
|
+
description: "Display reference grid",
|
|
743
|
+
detail: "Press 'G' to show/hide the ground plane grid for spatial reference and scale.",
|
|
744
|
+
key: "g",
|
|
745
|
+
type: "key",
|
|
746
|
+
category: "Viewer Mode Basics"
|
|
747
|
+
},
|
|
748
|
+
|
|
749
|
+
// Part 2: Explode & Assembly (Steps 11-20)
|
|
750
|
+
{
|
|
751
|
+
number: 11,
|
|
752
|
+
title: "Explode Assembly",
|
|
753
|
+
description: "Expand all assembly components",
|
|
754
|
+
detail: "Press 'E' to explode the assembly. Components separate spatially to show how they fit together.",
|
|
755
|
+
key: "e",
|
|
756
|
+
type: "key",
|
|
757
|
+
category: "Explode & Assembly"
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
number: 12,
|
|
761
|
+
title: "Collapse Assembly",
|
|
762
|
+
description: "Return to assembled view",
|
|
763
|
+
detail: "Press 'E' again to collapse back to the original assembled configuration.",
|
|
764
|
+
key: "e",
|
|
765
|
+
type: "key",
|
|
766
|
+
category: "Explode & Assembly"
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
number: 13,
|
|
770
|
+
title: "Explode Slider",
|
|
771
|
+
description: "Fine-tune explosion distance",
|
|
772
|
+
detail: "Use the explosion slider in the View toolbar to adjust how far apart components move during explosion.",
|
|
773
|
+
control: "slider",
|
|
774
|
+
type: "control",
|
|
775
|
+
category: "Explode & Assembly"
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
number: 14,
|
|
779
|
+
title: "Animation Sequence",
|
|
780
|
+
description: "Auto-animate assembly/disassembly",
|
|
781
|
+
detail: "Click the play button in the toolbar to animate the explosion and assembly in sequence.",
|
|
782
|
+
button: "play",
|
|
783
|
+
type: "button",
|
|
784
|
+
category: "Explode & Assembly"
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
number: 15,
|
|
788
|
+
title: "Previous Step",
|
|
789
|
+
description: "Go to previous animation frame",
|
|
790
|
+
detail: "Click the previous arrow button to step backwards through the animation sequence.",
|
|
791
|
+
button: "prev",
|
|
792
|
+
type: "button",
|
|
793
|
+
category: "Explode & Assembly"
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
number: 16,
|
|
797
|
+
title: "Next Step",
|
|
798
|
+
description: "Go to next animation frame",
|
|
799
|
+
detail: "Click the next arrow button to step forwards through the animation sequence.",
|
|
800
|
+
button: "next",
|
|
801
|
+
type: "button",
|
|
802
|
+
category: "Explode & Assembly"
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
number: 17,
|
|
806
|
+
title: "Save Animation",
|
|
807
|
+
description: "Save current animation sequence",
|
|
808
|
+
detail: "Save the current explosion/assembly animation for later playback or presentation.",
|
|
809
|
+
button: "save-anim",
|
|
810
|
+
type: "button",
|
|
811
|
+
category: "Explode & Assembly"
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
number: 18,
|
|
815
|
+
title: "Load Animation",
|
|
816
|
+
description: "Load a saved animation sequence",
|
|
817
|
+
detail: "Restore a previously saved animation sequence from the dropdown menu.",
|
|
818
|
+
button: "load-anim",
|
|
819
|
+
type: "button",
|
|
820
|
+
category: "Explode & Assembly"
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
number: 19,
|
|
824
|
+
title: "Toggle Direction",
|
|
825
|
+
description: "Swap explosion/assembly direction",
|
|
826
|
+
detail: "Toggle between assembly (parts → together) and explosion (together → parts) views.",
|
|
827
|
+
button: "toggle-dir",
|
|
828
|
+
type: "button",
|
|
829
|
+
category: "Explode & Assembly"
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
number: 20,
|
|
833
|
+
title: "Assembly Tree",
|
|
834
|
+
description: "View assembly hierarchy",
|
|
835
|
+
detail: "Left panel shows nested assemblies with expansion controls. Collapse/expand at any level.",
|
|
836
|
+
panel: "tree",
|
|
837
|
+
type: "panel",
|
|
838
|
+
category: "Explode & Assembly"
|
|
839
|
+
},
|
|
840
|
+
|
|
841
|
+
// Part 3: Section Cut & Clipping (Steps 21-30)
|
|
842
|
+
{
|
|
843
|
+
number: 21,
|
|
844
|
+
title: "Section Cut",
|
|
845
|
+
description: "Create a cross-section view",
|
|
846
|
+
detail: "Press 'C' to slice through the model. See internal structure with real-time clipping planes.",
|
|
847
|
+
key: "c",
|
|
848
|
+
type: "key",
|
|
849
|
+
category: "Section Cut & Clipping"
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
number: 22,
|
|
853
|
+
title: "X-Axis Clipping",
|
|
854
|
+
description: "Slice perpendicular to X axis",
|
|
855
|
+
detail: "Click the X button in the section cut toolbar to align clipping plane to the X axis.",
|
|
856
|
+
button: "section-x",
|
|
857
|
+
type: "button",
|
|
858
|
+
category: "Section Cut & Clipping"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
number: 23,
|
|
862
|
+
title: "Y-Axis Clipping",
|
|
863
|
+
description: "Slice perpendicular to Y axis",
|
|
864
|
+
detail: "Click the Y button to align clipping plane to the Y axis.",
|
|
865
|
+
button: "section-y",
|
|
866
|
+
type: "button",
|
|
867
|
+
category: "Section Cut & Clipping"
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
number: 24,
|
|
871
|
+
title: "Z-Axis Clipping",
|
|
872
|
+
description: "Slice perpendicular to Z axis",
|
|
873
|
+
detail: "Click the Z button to align clipping plane to the Z axis.",
|
|
874
|
+
button: "section-z",
|
|
875
|
+
type: "button",
|
|
876
|
+
category: "Section Cut & Clipping"
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
number: 25,
|
|
880
|
+
title: "Flip Clipping",
|
|
881
|
+
description: "Reverse clipping plane direction",
|
|
882
|
+
detail: "Click the flip arrow button to reverse which side of the plane is visible.",
|
|
883
|
+
button: "section-flip",
|
|
884
|
+
type: "button",
|
|
885
|
+
category: "Section Cut & Clipping"
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
number: 26,
|
|
889
|
+
title: "Section Slider",
|
|
890
|
+
description: "Adjust clipping plane position",
|
|
891
|
+
detail: "Use the slider to move the clipping plane along the selected axis (0-100%).",
|
|
892
|
+
control: "slider",
|
|
893
|
+
type: "control",
|
|
894
|
+
category: "Section Cut & Clipping"
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
number: 27,
|
|
898
|
+
title: "Per-Material Clipping",
|
|
899
|
+
description: "Apply clipping per material type",
|
|
900
|
+
detail: "Toggle per-material clipping to clip each material group independently.",
|
|
901
|
+
control: "toggle",
|
|
902
|
+
type: "control",
|
|
903
|
+
category: "Section Cut & Clipping"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
number: 28,
|
|
907
|
+
title: "DoubleSide Rendering",
|
|
908
|
+
description: "See both sides of cut surface",
|
|
909
|
+
detail: "Enable DoubleSide rendering to see interior surfaces clearly in cross-sections.",
|
|
910
|
+
control: "toggle",
|
|
911
|
+
type: "control",
|
|
912
|
+
category: "Section Cut & Clipping"
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
number: 29,
|
|
916
|
+
title: "Hide Clipping Plane",
|
|
917
|
+
description: "Temporarily disable clipping",
|
|
918
|
+
detail: "Turn off the clipping plane to see the solid model again without closing the tool.",
|
|
919
|
+
button: "section-hide",
|
|
920
|
+
type: "button",
|
|
921
|
+
category: "Section Cut & Clipping"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
number: 30,
|
|
925
|
+
title: "Close Section Cut",
|
|
926
|
+
description: "Exit section cut tool",
|
|
927
|
+
detail: "Press 'C' again or click the close button to exit the section cut tool.",
|
|
928
|
+
key: "c",
|
|
929
|
+
type: "key",
|
|
930
|
+
category: "Section Cut & Clipping"
|
|
931
|
+
},
|
|
932
|
+
|
|
933
|
+
// Part 4: Analysis & Measurements (Steps 31-40)
|
|
934
|
+
{
|
|
935
|
+
number: 31,
|
|
936
|
+
title: "Measurement Tool",
|
|
937
|
+
description: "Measure distances and angles",
|
|
938
|
+
detail: "Press 'M' to activate. Click 2 points for distance, 3 points for angle. Result shown in real-time.",
|
|
939
|
+
key: "m",
|
|
940
|
+
type: "key",
|
|
941
|
+
category: "Analysis & Measurements"
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
number: 32,
|
|
945
|
+
title: "Part Comparison",
|
|
946
|
+
description: "Compare 2 selected parts",
|
|
947
|
+
detail: "Select 2 parts then use Part Comparison to see side-by-side dimensions, volume, and weight.",
|
|
948
|
+
button: "compare",
|
|
949
|
+
type: "button",
|
|
950
|
+
category: "Analysis & Measurements"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
number: 33,
|
|
954
|
+
title: "Weight Estimator",
|
|
955
|
+
description: "Calculate part and assembly weight",
|
|
956
|
+
detail: "View estimated weight based on material density and part geometry. Material selector available.",
|
|
957
|
+
button: "weight",
|
|
958
|
+
type: "button",
|
|
959
|
+
category: "Analysis & Measurements"
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
number: 34,
|
|
963
|
+
title: "Clearance Checker",
|
|
964
|
+
description: "Check spacing between parts",
|
|
965
|
+
detail: "Analyze minimum clearances between selected parts. Highlights collision/spacing issues.",
|
|
966
|
+
button: "clearance",
|
|
967
|
+
type: "button",
|
|
968
|
+
category: "Analysis & Measurements"
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
number: 35,
|
|
972
|
+
title: "Assembly Validator",
|
|
973
|
+
description: "Score assembly quality (A-F)",
|
|
974
|
+
detail: "Validates assembly: checks for hidden parts, empty groups, unassigned components, duplicates.",
|
|
975
|
+
button: "validate",
|
|
976
|
+
type: "button",
|
|
977
|
+
category: "Analysis & Measurements"
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
number: 36,
|
|
981
|
+
title: "BOM Export",
|
|
982
|
+
description: "Export bill of materials to CSV",
|
|
983
|
+
detail: "Generate and download a complete BOM with part numbers, quantities, materials, and weights.",
|
|
984
|
+
button: "bom",
|
|
985
|
+
type: "button",
|
|
986
|
+
category: "Analysis & Measurements"
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
number: 37,
|
|
990
|
+
title: "AI Part Identifier",
|
|
991
|
+
description: "Identify parts using AI vision",
|
|
992
|
+
detail: "Uses Gemini Vision to analyze geometry and suggest McMaster-Carr sourcing with estimated costs.",
|
|
993
|
+
button: "ai-identify",
|
|
994
|
+
type: "button",
|
|
995
|
+
category: "Analysis & Measurements"
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
number: 38,
|
|
999
|
+
title: "Performance Monitor",
|
|
1000
|
+
description: "Show FPS and memory usage",
|
|
1001
|
+
detail: "Press Ctrl+Shift+F to display frame rate, memory consumption, and part count statistics.",
|
|
1002
|
+
key: "ctrl+shift+f",
|
|
1003
|
+
type: "key",
|
|
1004
|
+
category: "Analysis & Measurements"
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
number: 39,
|
|
1008
|
+
title: "Part Search",
|
|
1009
|
+
description: "Live search in assembly tree",
|
|
1010
|
+
detail: "Type in the search box to filter parts by name. Results highlight in real-time.",
|
|
1011
|
+
control: "search",
|
|
1012
|
+
type: "control",
|
|
1013
|
+
category: "Analysis & Measurements"
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
number: 40,
|
|
1017
|
+
title: "Batch AI Scan",
|
|
1018
|
+
description: "Scan all parts at once",
|
|
1019
|
+
detail: "Automatically identify all components using AI with progress tracking and CSV export.",
|
|
1020
|
+
button: "batch-scan",
|
|
1021
|
+
type: "button",
|
|
1022
|
+
category: "Analysis & Measurements"
|
|
1023
|
+
},
|
|
1024
|
+
|
|
1025
|
+
// Part 5: Advanced Features (Steps 41-57)
|
|
1026
|
+
{
|
|
1027
|
+
number: 41,
|
|
1028
|
+
title: "QR Code Generator",
|
|
1029
|
+
description: "Create QR codes per part",
|
|
1030
|
+
detail: "Generate QR codes that link to part info. Useful for physical labeling and documentation.",
|
|
1031
|
+
button: "qr",
|
|
1032
|
+
type: "button",
|
|
1033
|
+
category: "Advanced Features"
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
number: 42,
|
|
1037
|
+
title: "Annotation Pins",
|
|
1038
|
+
description: "Add labeled pins to parts",
|
|
1039
|
+
detail: "Click to place pins with custom labels. Draggable pins for documentation and collaboration.",
|
|
1040
|
+
button: "annotate",
|
|
1041
|
+
type: "button",
|
|
1042
|
+
category: "Advanced Features"
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
number: 43,
|
|
1046
|
+
title: "Screenshot Export",
|
|
1047
|
+
description: "Capture high-resolution view",
|
|
1048
|
+
detail: "Press 'S' to save a high-res PNG screenshot (2x retina) of the current 3D view.",
|
|
1049
|
+
key: "s",
|
|
1050
|
+
type: "key",
|
|
1051
|
+
category: "Advanced Features"
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
number: 44,
|
|
1055
|
+
title: "STL Export",
|
|
1056
|
+
description: "Export individual parts to STL",
|
|
1057
|
+
detail: "Right-click a part → Export STL to download for 3D printing or CAM software.",
|
|
1058
|
+
button: "export-stl",
|
|
1059
|
+
type: "button",
|
|
1060
|
+
category: "Advanced Features"
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
number: 45,
|
|
1064
|
+
title: "Transparency Control",
|
|
1065
|
+
description: "Adjust part opacity",
|
|
1066
|
+
detail: "Use opacity slider to make parts semi-transparent for viewing internal components.",
|
|
1067
|
+
control: "slider",
|
|
1068
|
+
type: "control",
|
|
1069
|
+
category: "Advanced Features"
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
number: 46,
|
|
1073
|
+
title: "Part Visibility",
|
|
1074
|
+
description: "Show/hide individual parts",
|
|
1075
|
+
detail: "Click the eye icon in the tree or press Delete to toggle part visibility.",
|
|
1076
|
+
control: "toggle",
|
|
1077
|
+
type: "control",
|
|
1078
|
+
category: "Advanced Features"
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
number: 47,
|
|
1082
|
+
title: "Show All Parts",
|
|
1083
|
+
description: "Restore all hidden parts",
|
|
1084
|
+
detail: "One-click button to unhide all previously hidden components and reset visibility state.",
|
|
1085
|
+
button: "show-all",
|
|
1086
|
+
type: "button",
|
|
1087
|
+
category: "Advanced Features"
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
number: 48,
|
|
1091
|
+
title: "Blueprint Theme",
|
|
1092
|
+
description: "Toggle blueprint color scheme",
|
|
1093
|
+
detail: "Applies technical blueprint visual theme with white background and blue wireframe edges.",
|
|
1094
|
+
button: "blueprint",
|
|
1095
|
+
type: "button",
|
|
1096
|
+
category: "Advanced Features"
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
number: 49,
|
|
1100
|
+
title: "DIN/ISO Standards",
|
|
1101
|
+
description: "Identify standard parts",
|
|
1102
|
+
detail: "Analyze parts against DIN/ISO standards with automatic McMaster-Carr part lookup.",
|
|
1103
|
+
button: "standards",
|
|
1104
|
+
type: "button",
|
|
1105
|
+
category: "Advanced Features"
|
|
1106
|
+
},
|
|
1107
|
+
{
|
|
1108
|
+
number: 50,
|
|
1109
|
+
title: "Maintenance Heatmap",
|
|
1110
|
+
description: "Color parts by maintenance urgency",
|
|
1111
|
+
detail: "Parts colored red/yellow/green by service interval. Export maintenance schedule.",
|
|
1112
|
+
button: "heatmap",
|
|
1113
|
+
type: "button",
|
|
1114
|
+
category: "Advanced Features"
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
number: 51,
|
|
1118
|
+
title: "Assembly Instructions",
|
|
1119
|
+
description: "Auto-generate disassembly manual",
|
|
1120
|
+
detail: "Creates step-by-step instructions from AI analysis. HTML export for documentation.",
|
|
1121
|
+
button: "instructions",
|
|
1122
|
+
type: "button",
|
|
1123
|
+
category: "Advanced Features"
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
number: 52,
|
|
1127
|
+
title: "Part Wear Timeline",
|
|
1128
|
+
description: "5-year replacement schedule",
|
|
1129
|
+
detail: "Gantt-style timeline showing when each component needs replacement. Export as CSV.",
|
|
1130
|
+
button: "timeline",
|
|
1131
|
+
type: "button",
|
|
1132
|
+
category: "Advanced Features"
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
number: 53,
|
|
1136
|
+
title: "Smart NL Search",
|
|
1137
|
+
description: "Natural language part search",
|
|
1138
|
+
detail: "Type plain English like 'bearing' or 'spring' with synonym support. Show/highlight/order.",
|
|
1139
|
+
control: "search",
|
|
1140
|
+
type: "control",
|
|
1141
|
+
category: "Advanced Features"
|
|
1142
|
+
},
|
|
1143
|
+
{
|
|
1144
|
+
number: 54,
|
|
1145
|
+
title: "Service Mode",
|
|
1146
|
+
description: "Field technician workflow",
|
|
1147
|
+
detail: "Checklist-based service mode with urgency coloring and technician notes. Export report.",
|
|
1148
|
+
button: "service",
|
|
1149
|
+
type: "button",
|
|
1150
|
+
category: "Advanced Features"
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
number: 55,
|
|
1154
|
+
title: "Technical Report",
|
|
1155
|
+
description: "Generate complete PDF report",
|
|
1156
|
+
detail: "Full HTML report with overview, BOM, parts, maintenance, timeline, and assemblies.",
|
|
1157
|
+
button: "report",
|
|
1158
|
+
type: "button",
|
|
1159
|
+
category: "Advanced Features"
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
number: 56,
|
|
1163
|
+
title: "Model Library",
|
|
1164
|
+
description: "Import/manage multiple models",
|
|
1165
|
+
detail: "Load and switch between multiple STEP/GLB files in the same session.",
|
|
1166
|
+
button: "library",
|
|
1167
|
+
type: "button",
|
|
1168
|
+
category: "Advanced Features"
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
number: 57,
|
|
1172
|
+
title: "Keyboard Shortcuts Panel",
|
|
1173
|
+
description: "View all available shortcuts",
|
|
1174
|
+
detail: "Press '?' to open the full keyboard shortcuts reference (25+ shortcuts available).",
|
|
1175
|
+
key: "?",
|
|
1176
|
+
type: "key",
|
|
1177
|
+
category: "Advanced Features"
|
|
1178
|
+
}
|
|
1179
|
+
];
|
|
1180
|
+
|
|
1181
|
+
// Keyboard shortcuts reference
|
|
1182
|
+
const SHORTCUTS_REFERENCE = {
|
|
1183
|
+
'V': 'Toggle Viewer Mode',
|
|
1184
|
+
'E': 'Explode/Collapse Assembly',
|
|
1185
|
+
'C': 'Section Cut (Cross-Section)',
|
|
1186
|
+
'W': 'Wireframe Toggle',
|
|
1187
|
+
'G': 'Grid Floor Toggle',
|
|
1188
|
+
'F': 'Fit to All',
|
|
1189
|
+
'S': 'Screenshot Export',
|
|
1190
|
+
'M': 'Measurement Tool',
|
|
1191
|
+
'A': 'Annotations',
|
|
1192
|
+
'?': 'Help / Shortcuts Panel',
|
|
1193
|
+
'Ctrl+Shift+F': 'Performance Monitor',
|
|
1194
|
+
'Delete': 'Hide Selected Part'
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
// UI State
|
|
1198
|
+
let currentStep = 0;
|
|
1199
|
+
let isRunning = false;
|
|
1200
|
+
let completedSteps = new Set();
|
|
1201
|
+
|
|
1202
|
+
// Initialize
|
|
1203
|
+
function init() {
|
|
1204
|
+
renderSteps();
|
|
1205
|
+
setupEventListeners();
|
|
1206
|
+
populateShortcuts();
|
|
1207
|
+
updateProgress();
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// Render all step cards
|
|
1211
|
+
function renderSteps() {
|
|
1212
|
+
const container = document.getElementById('stepsContainer');
|
|
1213
|
+
container.innerHTML = '';
|
|
1214
|
+
|
|
1215
|
+
TUTORIAL_STEPS.forEach((step, idx) => {
|
|
1216
|
+
const card = document.createElement('div');
|
|
1217
|
+
card.className = 'step-card';
|
|
1218
|
+
card.id = `step-${idx}`;
|
|
1219
|
+
if (completedSteps.has(idx)) card.classList.add('completed');
|
|
1220
|
+
|
|
1221
|
+
card.innerHTML = `
|
|
1222
|
+
<div class="step-header">
|
|
1223
|
+
<div class="step-badge">${step.number}</div>
|
|
1224
|
+
<div class="step-title">${step.title}</div>
|
|
1225
|
+
<div class="step-status">${step.category}</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
<div class="step-description">${step.description}</div>
|
|
1228
|
+
<div class="step-details" id="details-${idx}">${step.detail}</div>
|
|
1229
|
+
<div class="step-actions">
|
|
1230
|
+
<button class="step-run-btn" onclick="runStep(${idx})">▶ Run</button>
|
|
1231
|
+
<button class="step-details-toggle" onclick="toggleDetails(${idx})">Details</button>
|
|
1232
|
+
</div>
|
|
1233
|
+
`;
|
|
1234
|
+
|
|
1235
|
+
card.addEventListener('click', (e) => {
|
|
1236
|
+
if (e.target.tagName !== 'BUTTON') {
|
|
1237
|
+
selectStep(idx);
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
container.appendChild(card);
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// Select step
|
|
1246
|
+
function selectStep(idx) {
|
|
1247
|
+
document.querySelectorAll('.step-card.active').forEach(el => el.classList.remove('active'));
|
|
1248
|
+
document.getElementById(`step-${idx}`).classList.add('active');
|
|
1249
|
+
currentStep = idx;
|
|
1250
|
+
updateFooter();
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// Toggle details
|
|
1254
|
+
function toggleDetails(idx) {
|
|
1255
|
+
const details = document.getElementById(`details-${idx}`);
|
|
1256
|
+
details.classList.toggle('expanded');
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// Run single step
|
|
1260
|
+
function runStep(idx) {
|
|
1261
|
+
const step = TUTORIAL_STEPS[idx];
|
|
1262
|
+
selectStep(idx);
|
|
1263
|
+
executeStep(step);
|
|
1264
|
+
completedSteps.add(idx);
|
|
1265
|
+
document.getElementById(`step-${idx}`).classList.add('completed');
|
|
1266
|
+
updateProgress();
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// Execute step action
|
|
1270
|
+
function executeStep(step) {
|
|
1271
|
+
const iframe = document.getElementById('app-frame');
|
|
1272
|
+
try {
|
|
1273
|
+
if (step.type === 'key') {
|
|
1274
|
+
sendKeyPress(iframe, step.key);
|
|
1275
|
+
} else if (step.type === 'mouse') {
|
|
1276
|
+
// Mouse actions are simulated
|
|
1277
|
+
console.log(`Simulated ${step.mouse} on app`);
|
|
1278
|
+
} else if (step.type === 'button') {
|
|
1279
|
+
sendButtonClick(iframe, step.button);
|
|
1280
|
+
} else if (step.type === 'control') {
|
|
1281
|
+
console.log(`Interact with ${step.control} control`);
|
|
1282
|
+
} else if (step.type === 'panel') {
|
|
1283
|
+
console.log(`Check ${step.panel} panel`);
|
|
1284
|
+
}
|
|
1285
|
+
} catch (e) {
|
|
1286
|
+
console.log('Note: Some actions may require manual execution due to cross-origin restrictions');
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// Send key press to iframe
|
|
1291
|
+
function sendKeyPress(iframe, key) {
|
|
1292
|
+
try {
|
|
1293
|
+
const keyMap = {
|
|
1294
|
+
'v': 'KeyV',
|
|
1295
|
+
'e': 'KeyE',
|
|
1296
|
+
'c': 'KeyC',
|
|
1297
|
+
'w': 'KeyW',
|
|
1298
|
+
'g': 'KeyG',
|
|
1299
|
+
'f': 'KeyF',
|
|
1300
|
+
's': 'KeyS',
|
|
1301
|
+
'm': 'KeyM',
|
|
1302
|
+
'a': 'KeyA',
|
|
1303
|
+
'?': 'Slash'
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
const code = keyMap[key.toLowerCase()] || key;
|
|
1307
|
+
const event = new KeyboardEvent('keydown', {
|
|
1308
|
+
key: key,
|
|
1309
|
+
code: code,
|
|
1310
|
+
bubbles: true
|
|
1311
|
+
});
|
|
1312
|
+
iframe.contentDocument?.dispatchEvent(event);
|
|
1313
|
+
} catch (e) {
|
|
1314
|
+
console.log('Cannot send keypress to iframe (cross-origin)');
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
// Send button click to iframe
|
|
1319
|
+
function sendButtonClick(iframe, buttonId) {
|
|
1320
|
+
try {
|
|
1321
|
+
const btn = iframe.contentDocument?.querySelector(`[data-button="${buttonId}"]`);
|
|
1322
|
+
if (btn) btn.click();
|
|
1323
|
+
} catch (e) {
|
|
1324
|
+
console.log('Cannot click button in iframe (cross-origin)');
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Run all steps
|
|
1329
|
+
function runAll() {
|
|
1330
|
+
isRunning = true;
|
|
1331
|
+
document.getElementById('runAllBtn').disabled = true;
|
|
1332
|
+
document.getElementById('stopBtn').disabled = false;
|
|
1333
|
+
|
|
1334
|
+
let idx = 0;
|
|
1335
|
+
const interval = setInterval(() => {
|
|
1336
|
+
if (!isRunning || idx >= TUTORIAL_STEPS.length) {
|
|
1337
|
+
isRunning = false;
|
|
1338
|
+
document.getElementById('runAllBtn').disabled = false;
|
|
1339
|
+
document.getElementById('stopBtn').disabled = true;
|
|
1340
|
+
clearInterval(interval);
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
runStep(idx++);
|
|
1344
|
+
}, 1000);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Stop running
|
|
1348
|
+
function stopRunning() {
|
|
1349
|
+
isRunning = false;
|
|
1350
|
+
document.getElementById('runAllBtn').disabled = false;
|
|
1351
|
+
document.getElementById('stopBtn').disabled = true;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// Update progress
|
|
1355
|
+
function updateProgress() {
|
|
1356
|
+
const completed = completedSteps.size;
|
|
1357
|
+
const total = TUTORIAL_STEPS.length;
|
|
1358
|
+
const percent = (completed / total) * 100;
|
|
1359
|
+
|
|
1360
|
+
document.getElementById('progressBar').style.width = percent + '%';
|
|
1361
|
+
document.getElementById('stepCounter').textContent = `Step ${completed} of ${total}`;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// Update footer
|
|
1365
|
+
function updateFooter() {
|
|
1366
|
+
const step = TUTORIAL_STEPS[currentStep];
|
|
1367
|
+
document.getElementById('footerText').textContent = `${step.number}. ${step.title}`;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Populate shortcuts panel
|
|
1371
|
+
function populateShortcuts() {
|
|
1372
|
+
const content = document.getElementById('shortcutsContent');
|
|
1373
|
+
Object.entries(SHORTCUTS_REFERENCE).forEach(([key, desc]) => {
|
|
1374
|
+
const item = document.createElement('div');
|
|
1375
|
+
item.className = 'shortcut-item';
|
|
1376
|
+
item.innerHTML = `
|
|
1377
|
+
<span class="shortcut-desc">${desc}</span>
|
|
1378
|
+
<span class="shortcut-key">${key}</span>
|
|
1379
|
+
`;
|
|
1380
|
+
content.appendChild(item);
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// Setup event listeners
|
|
1385
|
+
function setupEventListeners() {
|
|
1386
|
+
document.getElementById('runAllBtn').addEventListener('click', runAll);
|
|
1387
|
+
document.getElementById('stopBtn').addEventListener('click', stopRunning);
|
|
1388
|
+
document.getElementById('shortcutsToggle').addEventListener('click', () => {
|
|
1389
|
+
const panel = document.getElementById('shortcutsPanel');
|
|
1390
|
+
panel.classList.toggle('visible');
|
|
1391
|
+
});
|
|
1392
|
+
document.getElementById('shortcutsClose').addEventListener('click', () => {
|
|
1393
|
+
document.getElementById('shortcutsPanel').classList.remove('visible');
|
|
1394
|
+
});
|
|
1395
|
+
document.getElementById('openTabBtn').addEventListener('click', () => {
|
|
1396
|
+
window.open('../', '_blank');
|
|
1397
|
+
});
|
|
1398
|
+
document.getElementById('reloadAppBtn').addEventListener('click', () => {
|
|
1399
|
+
document.getElementById('app-frame').src += '?t=' + Date.now();
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// Start
|
|
1404
|
+
init();
|
|
1405
|
+
</script>
|
|
1406
|
+
</body>
|
|
1407
|
+
</html>
|