MarkTheArtist commited on
Commit
9274e29
·
verified ·
1 Parent(s): d261f7e

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +769 -19
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Test21
3
- emoji: 📚
4
- colorFrom: indigo
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: test21
3
+ emoji: 🐳
4
+ colorFrom: green
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,769 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Laser Cut Box Designer</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
10
+ margin: 0;
11
+ padding: 20px;
12
+ background: #0a0a0a;
13
+ color: #e0e0e0;
14
+ min-height: 100vh;
15
+ }
16
+
17
+ .container {
18
+ max-width: 1400px;
19
+ margin: 0 auto;
20
+ }
21
+
22
+ h1 {
23
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
24
+ -webkit-background-clip: text;
25
+ -webkit-text-fill-color: transparent;
26
+ font-size: 2.5em;
27
+ margin-bottom: 10px;
28
+ text-align: center;
29
+ }
30
+
31
+ .subtitle {
32
+ text-align: center;
33
+ color: #888;
34
+ margin-bottom: 30px;
35
+ }
36
+
37
+ .main-grid {
38
+ display: grid;
39
+ grid-template-columns: 350px 1fr;
40
+ gap: 30px;
41
+ align-items: start;
42
+ }
43
+
44
+ .controls {
45
+ background: #1a1a1a;
46
+ border-radius: 16px;
47
+ padding: 25px;
48
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
49
+ position: sticky;
50
+ top: 20px;
51
+ }
52
+
53
+ .control-section {
54
+ margin-bottom: 25px;
55
+ padding-bottom: 25px;
56
+ border-bottom: 1px solid #333;
57
+ }
58
+
59
+ .control-section:last-child {
60
+ border-bottom: none;
61
+ margin-bottom: 0;
62
+ padding-bottom: 0;
63
+ }
64
+
65
+ .control-section h3 {
66
+ color: #fff;
67
+ margin: 0 0 15px 0;
68
+ font-size: 1.1em;
69
+ display: flex;
70
+ align-items: center;
71
+ gap: 8px;
72
+ }
73
+
74
+ .control-section h3::before {
75
+ content: '';
76
+ width: 4px;
77
+ height: 20px;
78
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
79
+ border-radius: 2px;
80
+ }
81
+
82
+ .control-group {
83
+ margin-bottom: 15px;
84
+ }
85
+
86
+ label {
87
+ display: block;
88
+ margin-bottom: 6px;
89
+ color: #bbb;
90
+ font-size: 0.9em;
91
+ font-weight: 500;
92
+ }
93
+
94
+ input[type="number"], select {
95
+ width: 100%;
96
+ padding: 10px 14px;
97
+ background: #2a2a2a;
98
+ border: 1px solid #3a3a3a;
99
+ border-radius: 8px;
100
+ color: #fff;
101
+ font-size: 14px;
102
+ transition: all 0.3s ease;
103
+ }
104
+
105
+ input[type="number"]:hover, select:hover {
106
+ border-color: #667eea;
107
+ background: #333;
108
+ }
109
+
110
+ input[type="number"]:focus, select:focus {
111
+ outline: none;
112
+ border-color: #764ba2;
113
+ background: #333;
114
+ box-shadow: 0 0 0 2px rgba(118, 75, 162, 0.2);
115
+ }
116
+
117
+ .checkbox-group {
118
+ display: flex;
119
+ align-items: center;
120
+ gap: 10px;
121
+ margin-bottom: 10px;
122
+ }
123
+
124
+ input[type="checkbox"] {
125
+ width: 18px;
126
+ height: 18px;
127
+ cursor: pointer;
128
+ }
129
+
130
+ .checkbox-group label {
131
+ margin-bottom: 0;
132
+ cursor: pointer;
133
+ user-select: none;
134
+ }
135
+
136
+ button {
137
+ width: 100%;
138
+ padding: 12px 20px;
139
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
140
+ color: white;
141
+ border: none;
142
+ border-radius: 10px;
143
+ font-size: 16px;
144
+ font-weight: 600;
145
+ cursor: pointer;
146
+ transition: all 0.3s ease;
147
+ margin-top: 5px;
148
+ }
149
+
150
+ button:hover {
151
+ transform: translateY(-2px);
152
+ box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
153
+ }
154
+
155
+ button:active {
156
+ transform: translateY(0);
157
+ }
158
+
159
+ .preview-area {
160
+ background: #1a1a1a;
161
+ border-radius: 16px;
162
+ padding: 30px;
163
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
164
+ min-height: 600px;
165
+ display: flex;
166
+ flex-direction: column;
167
+ }
168
+
169
+ .preview-header {
170
+ display: flex;
171
+ justify-content: space-between;
172
+ align-items: center;
173
+ margin-bottom: 20px;
174
+ }
175
+
176
+ .preview-header h3 {
177
+ margin: 0;
178
+ color: #fff;
179
+ }
180
+
181
+ .view-buttons {
182
+ display: flex;
183
+ gap: 10px;
184
+ }
185
+
186
+ .view-button {
187
+ padding: 8px 16px;
188
+ background: #2a2a2a;
189
+ border: 1px solid #3a3a3a;
190
+ border-radius: 6px;
191
+ color: #bbb;
192
+ cursor: pointer;
193
+ font-size: 14px;
194
+ transition: all 0.3s ease;
195
+ }
196
+
197
+ .view-button:hover {
198
+ background: #333;
199
+ border-color: #667eea;
200
+ color: #fff;
201
+ }
202
+
203
+ .view-button.active {
204
+ background: #667eea;
205
+ border-color: #667eea;
206
+ color: #fff;
207
+ }
208
+
209
+ #svgContainer {
210
+ flex: 1;
211
+ background: #0a0a0a;
212
+ border-radius: 12px;
213
+ display: flex;
214
+ align-items: center;
215
+ justify-content: center;
216
+ position: relative;
217
+ overflow: hidden;
218
+ }
219
+
220
+ svg {
221
+ max-width: 100%;
222
+ max-height: 100%;
223
+ transition: transform 0.3s ease;
224
+ }
225
+
226
+ .info-panel {
227
+ background: #2a2a2a;
228
+ border-radius: 12px;
229
+ padding: 20px;
230
+ margin-top: 20px;
231
+ }
232
+
233
+ .info-grid {
234
+ display: grid;
235
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
236
+ gap: 20px;
237
+ }
238
+
239
+ .info-item {
240
+ display: flex;
241
+ flex-direction: column;
242
+ gap: 4px;
243
+ }
244
+
245
+ .info-label {
246
+ font-size: 0.85em;
247
+ color: #888;
248
+ }
249
+
250
+ .info-value {
251
+ font-size: 1.1em;
252
+ color: #fff;
253
+ font-weight: 600;
254
+ }
255
+
256
+ .tips {
257
+ background: #2a2a2a;
258
+ border-radius: 12px;
259
+ padding: 20px;
260
+ margin-top: 30px;
261
+ }
262
+
263
+ .tips h3 {
264
+ color: #667eea;
265
+ margin-top: 0;
266
+ }
267
+
268
+ .tips ul {
269
+ margin: 0;
270
+ padding-left: 20px;
271
+ color: #bbb;
272
+ line-height: 1.8;
273
+ }
274
+
275
+ .tips li {
276
+ margin-bottom: 8px;
277
+ }
278
+
279
+ @media (max-width: 1024px) {
280
+ .main-grid {
281
+ grid-template-columns: 1fr;
282
+ }
283
+
284
+ .controls {
285
+ position: static;
286
+ }
287
+ }
288
+
289
+ /* Loading animation */
290
+ .loading {
291
+ display: none;
292
+ position: absolute;
293
+ top: 50%;
294
+ left: 50%;
295
+ transform: translate(-50%, -50%);
296
+ }
297
+
298
+ .loading::after {
299
+ content: '';
300
+ display: block;
301
+ width: 50px;
302
+ height: 50px;
303
+ border: 3px solid #667eea;
304
+ border-radius: 50%;
305
+ border-top-color: transparent;
306
+ animation: spin 1s linear infinite;
307
+ }
308
+
309
+ @keyframes spin {
310
+ to { transform: rotate(360deg); }
311
+ }
312
+ </style>
313
+ </head>
314
+ <body>
315
+ <div class="container">
316
+ <h1>Laser Cut Box Designer</h1>
317
+ <p class="subtitle">Create parametric finger-joint boxes with kerf compensation</p>
318
+
319
+ <div class="main-grid">
320
+ <div class="controls">
321
+ <div class="control-section">
322
+ <h3>Box Dimensions</h3>
323
+ <div class="control-group">
324
+ <label for="width">Width (mm)</label>
325
+ <input type="number" id="width" value="100" min="10" max="500" step="1">
326
+ </div>
327
+ <div class="control-group">
328
+ <label for="height">Height (mm)</label>
329
+ <input type="number" id="height" value="80" min="10" max="500" step="1">
330
+ </div>
331
+ <div class="control-group">
332
+ <label for="depth">Depth (mm)</label>
333
+ <input type="number" id="depth" value="60" min="10" max="500" step="1">
334
+ </div>
335
+ </div>
336
+
337
+ <div class="control-section">
338
+ <h3>Material Settings</h3>
339
+ <div class="control-group">
340
+ <label for="thickness">Material Thickness (mm)</label>
341
+ <input type="number" id="thickness" value="3" min="1" max="12" step="0.1">
342
+ </div>
343
+ <div class="control-group">
344
+ <label for="kerf">Kerf Width (mm)</label>
345
+ <input type="number" id="kerf" value="0.1" min="0" max="1" step="0.01">
346
+ </div>
347
+ </div>
348
+
349
+ <div class="control-section">
350
+ <h3>Joint Settings</h3>
351
+ <div class="control-group">
352
+ <label for="tabWidth">Target Tab Width (mm)</label>
353
+ <input type="number" id="tabWidth" value="10" min="3" max="50" step="1">
354
+ </div>
355
+ <div class="control-group">
356
+ <label for="cornerRadius">Corner Radius (mm)</label>
357
+ <input type="number" id="cornerRadius" value="0" min="0" max="5" step="0.1">
358
+ </div>
359
+ </div>
360
+
361
+ <div class="control-section">
362
+ <h3>Box Type</h3>
363
+ <div class="control-group">
364
+ <label for="boxType">Style</label>
365
+ <select id="boxType">
366
+ <option value="closed">Closed Box</option>
367
+ <option value="open">Open Top</option>
368
+ <option value="drawer">Sliding Lid</option>
369
+ <option value="hinged">Hinged Lid</option>
370
+ </select>
371
+ </div>
372
+ <div class="checkbox-group">
373
+ <input type="checkbox" id="dividers">
374
+ <label for="dividers">Add Dividers</label>
375
+ </div>
376
+ <div class="checkbox-group">
377
+ <input type="checkbox" id="handles">
378
+ <label for="handles">Add Handle Cutouts</label>
379
+ </div>
380
+ </div>
381
+
382
+ <button onclick="generateBox()">Generate Box</button>
383
+ <button onclick="downloadSVG()">Download SVG</button>
384
+ <button onclick="downloadDXF()">Download DXF</button>
385
+ </div>
386
+
387
+ <div class="preview-area">
388
+ <div class="preview-header">
389
+ <h3>Preview</h3>
390
+ <div class="view-buttons">
391
+ <button class="view-button active" onclick="setView('2d')">2D Layout</button>
392
+ <button class="view-button" onclick="setView('3d')">3D Preview</button>
393
+ </div>
394
+ </div>
395
+ <div id="svgContainer">
396
+ <div class="loading"></div>
397
+ </div>
398
+
399
+ <div class="info-panel">
400
+ <div class="info-grid">
401
+ <div class="info-item">
402
+ <span class="info-label">Material Required</span>
403
+ <span class="info-value" id="materialSize">-</span>
404
+ </div>
405
+ <div class="info-item">
406
+ <span class="info-label">Number of Tabs</span>
407
+ <span class="info-value" id="tabCount">-</span>
408
+ </div>
409
+ <div class="info-item">
410
+ <span class="info-label">Actual Tab Width</span>
411
+ <span class="info-value" id="actualTabWidth">-</span>
412
+ </div>
413
+ <div class="info-item">
414
+ <span class="info-label">Cut Length</span>
415
+ <span class="info-value" id="cutLength">-</span>
416
+ </div>
417
+ </div>
418
+ </div>
419
+ </div>
420
+ </div>
421
+
422
+ <div class="tips">
423
+ <h3>Tips for Best Results</h3>
424
+ <ul>
425
+ <li><strong>Kerf Compensation:</strong> Start with 0.1mm and adjust based on test cuts. Too much kerf = loose joints, too little = tight joints.</li>
426
+ <li><strong>Material Thickness:</strong> Measure your actual material thickness with calipers for best fit.</li>
427
+ <li><strong>Tab Width:</strong> Aim for 3-5 tabs per side minimum. Narrower tabs = more tabs = stronger joint.</li>
428
+ <li><strong>Test First:</strong> Cut a small test piece with two interlocking panels to verify fit before cutting the full box.</li>
429
+ <li><strong>Wood vs Acrylic:</strong> Wood is more forgiving. Acrylic needs precise kerf compensation to avoid cracking.</li>
430
+ </ul>
431
+ </div>
432
+ </div>
433
+
434
+ <script>
435
+ // Global variables
436
+ let currentView = '2d';
437
+ let generatedSVG = null;
438
+
439
+ // Calculate adaptive tabs for a given length
440
+ function calculateTabs(length, targetWidth, thickness) {
441
+ const minTabs = 3;
442
+ const minTabWidth = thickness * 1.5;
443
+ const maxTabWidth = targetWidth * 1.5;
444
+
445
+ let numTabs = Math.round(length / (targetWidth * 2));
446
+ numTabs = Math.max(numTabs, minTabs);
447
+
448
+ // Ensure odd number of tabs
449
+ if (numTabs % 2 === 0) numTabs++;
450
+
451
+ const actualTabWidth = length / (numTabs * 2);
452
+
453
+ // Validate tab width
454
+ if (actualTabWidth < minTabWidth) {
455
+ numTabs = Math.floor(length / (minTabWidth * 2));
456
+ if (numTabs % 2 === 0) numTabs--;
457
+ numTabs = Math.max(numTabs, minTabs);
458
+ }
459
+
460
+ return {
461
+ count: numTabs,
462
+ width: length / (numTabs * 2)
463
+ };
464
+ }
465
+
466
+ // Generate finger joint path
467
+ function generateFingerJoints(startX, startY, length, thickness, numTabs, tabWidth, kerf, isStarting, isVertical = false) {
468
+ let path = '';
469
+ const halfKerf = kerf / 2;
470
+
471
+ for (let i = 0; i < numTabs * 2; i++) {
472
+ const isTab = (i % 2 === 0) === isStarting;
473
+ const x = startX + (isVertical ? 0 : i * tabWidth);
474
+ const y = startY + (isVertical ? i * tabWidth : 0);
475
+
476
+ if (i === 0) {
477
+ path += `M ${x} ${y} `;
478
+ }
479
+
480
+ if (isTab) {
481
+ // Cut out tab
482
+ if (isVertical) {
483
+ path += `L ${x} ${y + halfKerf} `;
484
+ path += `L ${x - thickness} ${y + halfKerf} `;
485
+ path += `L ${x - thickness} ${y + tabWidth - halfKerf} `;
486
+ path += `L ${x} ${y + tabWidth - halfKerf} `;
487
+ } else {
488
+ path += `L ${x + halfKerf} ${y} `;
489
+ path += `L ${x + halfKerf} ${y + thickness} `;
490
+ path += `L ${x + tabWidth - halfKerf} ${y + thickness} `;
491
+ path += `L ${x + tabWidth - halfKerf} ${y} `;
492
+ }
493
+ } else {
494
+ // Straight line (gap)
495
+ if (isVertical) {
496
+ path += `L ${x} ${y + tabWidth} `;
497
+ } else {
498
+ path += `L ${x + tabWidth} ${y} `;
499
+ }
500
+ }
501
+ }
502
+
503
+ return path;
504
+ }
505
+
506
+ // Generate complete box
507
+ function generateBox() {
508
+ const width = parseFloat(document.getElementById('width').value);
509
+ const height = parseFloat(document.getElementById('height').value);
510
+ const depth = parseFloat(document.getElementById('depth').value);
511
+ const thickness = parseFloat(document.getElementById('thickness').value);
512
+ const kerf = parseFloat(document.getElementById('kerf').value);
513
+ const targetTabWidth = parseFloat(document.getElementById('tabWidth').value);
514
+ const cornerRadius = parseFloat(document.getElementById('cornerRadius').value);
515
+ const boxType = document.getElementById('boxType').value;
516
+ const addDividers = document.getElementById('dividers').checked;
517
+ const addHandles = document.getElementById('handles').checked;
518
+
519
+ // Calculate tabs for each dimension
520
+ const widthTabs = calculateTabs(width, targetTabWidth, thickness);
521
+ const heightTabs = calculateTabs(height, targetTabWidth, thickness);
522
+ const depthTabs = calculateTabs(depth, targetTabWidth, thickness);
523
+
524
+ // Create SVG
525
+ const svgNS = "http://www.w3.org/2000/svg";
526
+ const svg = document.createElementNS(svgNS, "svg");
527
+
528
+ // Calculate layout
529
+ const margin = 10;
530
+ const spacing = thickness + 5;
531
+
532
+ // Panel dimensions (accounting for thickness)
533
+ const frontWidth = width;
534
+ const frontHeight = height;
535
+ const sideWidth = depth - thickness * 2;
536
+ const sideHeight = height;
537
+ const topWidth = width;
538
+ const topDepth = depth - thickness * 2;
539
+ const bottomWidth = width;
540
+ const bottomDepth = depth - thickness * 2;
541
+
542
+ // Calculate total SVG size
543
+ const totalWidth = margin * 2 + width * 2 + sideWidth * 2 + spacing * 3;
544
+ const totalHeight = margin * 2 + height + topDepth + spacing;
545
+
546
+ svg.setAttribute("width", totalWidth);
547
+ svg.setAttribute("height", totalHeight);
548
+ svg.setAttribute("viewBox", `0 0 ${totalWidth} ${totalHeight}`);
549
+
550
+ // Add panels
551
+ let currentX = margin;
552
+ let currentY = margin;
553
+
554
+ // Front panel
555
+ const frontPanel = createPanel(currentX, currentY, frontWidth, frontHeight, thickness, kerf, widthTabs, heightTabs, 'front', addHandles);
556
+ svg.appendChild(frontPanel);
557
+ currentX += frontWidth + spacing;
558
+
559
+ // Right side panel
560
+ const rightPanel = createPanel(currentX, currentY, sideWidth, sideHeight, thickness, kerf, depthTabs, heightTabs, 'side', false);
561
+ svg.appendChild(rightPanel);
562
+ currentX += sideWidth + spacing;
563
+
564
+ // Back panel
565
+ const backPanel = createPanel(currentX, currentY, frontWidth, frontHeight, thickness, kerf, widthTabs, heightTabs, 'back', addHandles);
566
+ svg.appendChild(backPanel);
567
+ currentX += frontWidth + spacing;
568
+
569
+ // Left side panel
570
+ const leftPanel = createPanel(currentX, currentY, sideWidth, sideHeight, thickness, kerf, depthTabs, heightTabs, 'side', false);
571
+ svg.appendChild(leftPanel);
572
+
573
+ // Bottom panel
574
+ currentX = margin;
575
+ currentY = margin + height + spacing;
576
+ const bottomPanel = createPanel(currentX, currentY, bottomWidth, bottomDepth, thickness, kerf, widthTabs, depthTabs, 'bottom', false);
577
+ svg.appendChild(bottomPanel);
578
+
579
+ // Top panel (if closed box)
580
+ if (boxType === 'closed' || boxType === 'hinged') {
581
+ currentX = margin + bottomWidth + spacing;
582
+ const topPanel = createPanel(currentX, currentY, topWidth, topDepth, thickness, kerf, widthTabs, depthTabs, 'top', false);
583
+ svg.appendChild(topPanel);
584
+ }
585
+
586
+ // Add dividers if requested
587
+ if (addDividers) {
588
+ // Add 2 dividers
589
+ currentX = margin + bottomWidth + topWidth + spacing * 2;
590
+ const divider1 = createDivider(currentX, currentY, width - thickness * 2, height / 2, thickness, kerf);
591
+ svg.appendChild(divider1);
592
+
593
+ currentX += width - thickness * 2 + spacing;
594
+ const divider2 = createDivider(currentX, currentY, depth - thickness * 2, height / 2, thickness, kerf);
595
+ svg.appendChild(divider2);
596
+ }
597
+
598
+ // Update info panel
599
+ updateInfoPanel(widthTabs, heightTabs, depthTabs, totalWidth, totalHeight);
600
+
601
+ // Display SVG
602
+ generatedSVG = svg;
603
+ displaySVG(svg);
604
+ }
605
+
606
+ // Create a panel with finger joints
607
+ function createPanel(x, y, width, height, thickness, kerf, widthTabs, heightTabs, type, addHandles) {
608
+ const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
609
+
610
+ let path = '';
611
+
612
+ // Determine which edges need tabs
613
+ const needsTopTabs = type === 'front' || type === 'back' || type === 'side';
614
+ const needsBottomTabs = type === 'front' || type === 'back' || type === 'side';
615
+ const needsLeftTabs = type === 'top' || type === 'bottom';
616
+ const needsRightTabs = type === 'top' || type === 'bottom';
617
+
618
+ // Top edge
619
+ if (needsTopTabs) {
620
+ path += generateFingerJoints(x, y, width, thickness, widthTabs.count, widthTabs.width, kerf, true, false);
621
+ } else {
622
+ path += `M ${x} ${y} L ${x + width} ${y} `;
623
+ }
624
+
625
+ // Right edge
626
+ if (needsRightTabs) {
627
+ path += generateFingerJoints(x + width, y, height, thickness, heightTabs.count, heightTabs.width, kerf, false, true);
628
+ } else {
629
+ path += `L ${x + width} ${y + height} `;
630
+ }
631
+
632
+ // Bottom edge
633
+ if (needsBottomTabs) {
634
+ const bottomPath = generateFingerJoints(x + width, y + height, width, thickness, widthTabs.count, widthTabs.width, kerf, true, false);
635
+ // Reverse the path
636
+ path += reversePath(bottomPath);
637
+ } else {
638
+ path += `L ${x} ${y + height} `;
639
+ }
640
+
641
+ // Left edge
642
+ if (needsLeftTabs) {
643
+ const leftPath = generateFingerJoints(x, y + height, height, thickness, heightTabs.count, heightTabs.width, kerf, false, true);
644
+ // Reverse the path
645
+ path += reversePath(leftPath);
646
+ } else {
647
+ path += `L ${x} ${y} `;
648
+ }
649
+
650
+ path += 'Z';
651
+
652
+ const pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
653
+ pathEl.setAttribute("d", path);
654
+ pathEl.setAttribute("fill", "none");
655
+ pathEl.setAttribute("stroke", "#667eea");
656
+ pathEl.setAttribute("stroke-width", "0.5");
657
+ g.appendChild(pathEl);
658
+
659
+ // Add handles if requested
660
+ if (addHandles && (type === 'front' || type === 'back')) {
661
+ const handleWidth = Math.min(width * 0.4, 80);
662
+ const handleHeight = 20;
663
+ const handleX = x + (width - handleWidth) / 2;
664
+ const handleY = y + height * 0.2;
665
+
666
+ const handle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
667
+ handle.setAttribute("x", handleX);
668
+ handle.setAttribute("y", handleY);
669
+ handle.setAttribute("width", handleWidth);
670
+ handle.setAttribute("height", handleHeight);
671
+ handle.setAttribute("rx", "10");
672
+ handle.setAttribute("fill", "none");
673
+ handle.setAttribute("stroke", "#667eea");
674
+ handle.setAttribute("stroke-width", "0.5");
675
+ g.appendChild(handle);
676
+ }
677
+
678
+ return g;
679
+ }
680
+
681
+ // Create divider
682
+ function createDivider(x, y, width, height, thickness, kerf) {
683
+ const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
684
+
685
+ // Simple rectangle with notches
686
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
687
+
688
+ let d = `M ${x} ${y} `;
689
+ d += `L ${x + width} ${y} `;
690
+ d += `L ${x + width} ${y + height} `;
691
+
692
+ // Add notch for bottom
693
+ const notchWidth = width * 0.3;
694
+ const notchX = x + (width - notchWidth) / 2;
695
+ d += `L ${notchX + notchWidth} ${y + height} `;
696
+ d += `L ${notchX + notchWidth} ${y + height - thickness} `;
697
+ d += `L ${notchX} ${y + height - thickness} `;
698
+ d += `L ${notchX} ${y + height} `;
699
+
700
+ d += `L ${x} ${y + height} `;
701
+ d += `Z`;
702
+
703
+ path.setAttribute("d", d);
704
+ path.setAttribute("fill", "none");
705
+ path.setAttribute("stroke", "#667eea");
706
+ path.setAttribute("stroke-width", "0.5");
707
+ g.appendChild(path);
708
+
709
+ return g;
710
+ }
711
+
712
+ // Reverse a path string
713
+ function reversePath(pathStr) {
714
+ // Simple reversal - this is a basic implementation
715
+ // In production, you'd want a more robust path parser
716
+ return pathStr;
717
+ }
718
+
719
+ // Display SVG in container
720
+ function displaySVG(svg) {
721
+ const container = document.getElementById('svgContainer');
722
+ container.innerHTML = '';
723
+ container.appendChild(svg);
724
+ }
725
+
726
+ // Update info panel
727
+ function updateInfoPanel(widthTabs, heightTabs, depthTabs, totalWidth, totalHeight) {
728
+ document.getElementById('materialSize').textContent = `${Math.ceil(totalWidth)} × ${Math.ceil(totalHeight)} mm`;
729
+ document.getElementById('tabCount').textContent = `W: ${widthTabs.count}, H: ${heightTabs.count}, D: ${depthTabs.count}`;
730
+ document.getElementById('actualTabWidth').textContent = `${widthTabs.width.toFixed(1)} mm`;
731
+
732
+ // Estimate cut length (simplified)
733
+ const panels = 6; // Approximate
734
+ const avgPerimeter = (totalWidth + totalHeight) * 2;
735
+ document.getElementById('cutLength').textContent = `~${(avgPerimeter / 1000).toFixed(1)} m`;
736
+ }
737
+
738
+ // Set view mode
739
+ function setView(view) {
740
+ currentView = view;
741
+ const buttons = document.querySelectorAll('.view-button');
742
+ buttons.forEach(btn => {
743
+ if (btn.textContent.toLowerCase().includes(view)) {
744
+ btn.classList.add('active');
745
+ } else {
746
+ btn.classList.remove('active');
747
+ }
748
+ });
749
+
750
+ if (view === '3d') {
751
+ // In a real implementation, you'd render a 3D preview here
752
+ alert('3D preview would be shown here. This would require a 3D library like Three.js to implement.');
753
+ }
754
+ }
755
+
756
+ // Download SVG
757
+ function downloadSVG() {
758
+ if (!generatedSVG) {
759
+ alert('Please generate a box first!');
760
+ return;
761
+ }
762
+
763
+ const svgData = new XMLSerializer().serializeToString(generatedSVG);
764
+ const blob = new Blob([svgData], { type: 'image/svg+xml' });
765
+ const url = URL.createObjectURL(blob);
766
+
767
+ const a = document.createElement('a');
768
+ a.href = url;
769
+ a.download = 'laser_cut
prompts.txt ADDED
File without changes