Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Laser Cut Box Designer</title> | |
| <style> | |
| body { font-family: sans-serif; margin: 20px; } | |
| .controls { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; max-width: 600px; margin-bottom: 20px; } | |
| .controls label { display: block; margin-bottom: 5px; } | |
| .controls input { width: 100%; padding: 8px; box-sizing: border-box; } | |
| #preview-container { border: 1px solid #ccc; width: 100%; max-width: 800px; height: 500px; margin-top: 20px; overflow: auto; } | |
| #preview-svg { width: 100%; height: 100%; } | |
| button { padding: 10px 15px; margin-right: 10px; cursor: pointer; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Laser Cut Box Designer</h1> | |
| <div class="controls"> | |
| <div> | |
| <label for="width">Width (in):</label> | |
| <input type="number" id="width" value="4" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="depth">Depth (in):</label> | |
| <input type="number" id="depth" value="3" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="height">Height (in):</label> | |
| <input type="number" id="height" value="2" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="materialThickness">Material Thickness (in):</label> | |
| <input type="number" id="materialThickness" value="0.125" step="0.001"> | |
| </div> | |
| <div> | |
| <label for="kerf">Kerf (in, optional):</label> | |
| <input type="number" id="kerf" value="0.005" step="0.001"> | |
| </div> | |
| <div> | |
| <label for="boxType">Box Type:</label> | |
| <input type="radio" id="closedBox" name="boxType" value="closed" checked> <label for="closedBox">Closed Box</label><br> | |
| <input type="radio" id="openBox" name="boxType" value="open"> <label for="openBox">Open Box</label> | |
| </div> | |
| <h3>Face Spacing (0 for standard wall, >0 for gap/offset)</h3> | |
| <div> | |
| <label for="spacingTop">Top Face Spacing (in):</label> | |
| <input type="number" id="spacingTop" value="0" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="spacingBottom">Bottom Face Spacing (in):</label> | |
| <input type="number" id="spacingBottom" value="0" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="spacingFront">Front Face Spacing (in):</label> | |
| <input type="number" id="spacingFront" value="0" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="spacingBack">Back Face Spacing (in):</label> | |
| <input type="number" id="spacingBack" value="0" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="spacingLeft">Left Face Spacing (in):</label> | |
| <input type="number" id="spacingLeft" value="0" step="0.1"> | |
| </div> | |
| <div> | |
| <label for="spacingRight">Right Face Spacing (in):</label> | |
| <input type="number" id="spacingRight" value="0" step="0.1"> | |
| </div> | |
| </div> | |
| <button id="calculateBtn">Calculate & Preview Design</button> | |
| <button id="exportSvgBtn">Export as SVG</button> | |
| <button id="exportPdfBtn">Export as PDF</button> | |
| <h2>Design Preview:</h2> | |
| <div id="preview-container"> | |
| <svg id="preview-svg" viewBox="0 0 800 500"></svg> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> | |
| <script> | |
| // Placeholder for box generation logic (this is the complex part) | |
| function generateBoxSVG(width, depth, height, materialThickness, kerf, boxType, spacing) { | |
| let svgContent = ''; | |
| const fingerLength = materialThickness * 2; // Example finger length | |
| const numFingers = 5; // Example number of fingers (you'd calculate this dynamically) | |
| // For simplicity, let's just draw rectangles representing the faces | |
| // In a real application, you'd calculate precise finger joint paths | |
| // Front face (example) | |
| svgContent += `<rect x="0" y="0" width="${width}" height="${height}" fill="lightblue" stroke="black" stroke-width="0.01"/>`; | |
| // Add finger joints here based on calculations | |
| // Top face (example - adjusted for spacing if applicable) | |
| let topY = height + 1; // Some spacing for layout | |
| if (boxType === 'closed' || spacing.top === 0) { | |
| // For a closed box, draw the top. If spacingTop is 0, draw it. | |
| svgContent += `<rect x="0" y="${topY}" width="${width}" height="${depth}" fill="lightgreen" stroke="black" stroke-width="0.01"/>`; | |
| } else if (spacing.top > 0) { | |
| // If there's spacing, you might draw a visual indicator or just omit the piece | |
| // For this example, we'll just omit it if spacing is greater than 0 for "open" | |
| // In a real design, spacing might affect how joints are cut or if a face is present. | |
| } | |
| // ... repeat for other faces (back, left, right, bottom) | |
| // The "spacing" input would modify *how* each face is drawn or if it's drawn at all. | |
| // For example, if spacingTop is > 0 and it's an "open" box, you might completely omit the top face. | |
| // If it's a closed box and spacingTop is > 0, it means there's a gap between the top and the walls. | |
| // This is the most complex part of the user's request and requires careful geometric calculation for each joint. | |
| return svgContent; | |
| } | |
| function calculateAndPreview() { | |
| const width = parseFloat(document.getElementById('width').value); | |
| const depth = parseFloat(document.getElementById('depth').value); | |
| const height = parseFloat(document.getElementById('height').value); | |
| const materialThickness = parseFloat(document.getElementById('materialThickness').value); | |
| const kerf = parseFloat(document.getElementById('kerf').value); | |
| const boxType = document.querySelector('input[name="boxType"]:checked').value; | |
| const spacing = { | |
| top: parseFloat(document.getElementById('spacingTop').value), | |
| bottom: parseFloat(document.getElementById('spacingBottom').value), | |
| front: parseFloat(document.getElementById('spacingFront').value), | |
| back: parseFloat(document.getElementById('spacingBack').value), | |
| left: parseFloat(document.getElementById('spacingLeft').value), | |
| right: parseFloat(document.getElementById('spacingRight').value), | |
| }; | |
| if (isNaN(width) || isNaN(depth) || isNaN(height) || isNaN(materialThickness) || isNaN(kerf)) { | |
| alert("Please enter valid numeric dimensions."); | |
| return; | |
| } | |
| const svgElement = document.getElementById('preview-svg'); | |
| // Clear previous design | |
| svgElement.innerHTML = ''; | |
| const generatedSVG = generateBoxSVG(width, depth, height, materialThickness, kerf, boxType, spacing); | |
| svgElement.innerHTML = generatedSVG; // This is a simplified example | |
| // For a real application, you'd use a dedicated SVG library | |
| // For example, with Maker.js: | |
| /* | |
| const makerjs = require('makerjs'); // if using Node.js or a bundler | |
| // Or if directly in browser: makerjs.models.something... | |
| const boxModel = new makerjs.models.Bolt(width, depth, height, materialThickness); // (example) | |
| const svgOutput = makerjs.exporter.toSVG(boxModel); | |
| svgElement.innerHTML = svgOutput; | |
| */ | |
| } | |
| function exportSVG() { | |
| const svgElement = document.getElementById('preview-svg'); | |
| const svgData = new XMLSerializer().serializeToString(svgElement); | |
| const blob = new Blob([svgData], { type: 'image/svg+xml' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'laser_cut_box.svg'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| function exportPDF() { | |
| const width = parseFloat(document.getElementById('width').value); | |
| const depth = parseFloat(document.getElementById('depth').value); | |
| const height = parseFloat(document.getElementById('height').value); | |
| const { jsPDF } = window.jspdf; | |
| const doc = new jsPDF(); | |
| // Example: Add text and a simple rectangle to the PDF | |
| doc.text("Laser Cut Box Design", 10, 10); | |
| doc.text(`Dimensions: ${width}x${depth}x${height} inches`, 10, 20); | |
| // You would draw the actual box panels on the PDF here, | |
| // translating your SVG drawing logic to jsPDF commands. | |
| // This is more involved than just converting the SVG element directly | |
| // unless you use a library like html2pdf.js to capture the whole HTML. | |
| // A more robust solution might involve: | |
| // 1. Get the bounding box of your generated SVG content to scale it appropriately. | |
| // 2. Iterate through your calculated panel shapes and draw them using jsPDF's drawing primitives (rect, line, etc.). | |
| // Alternatively, if html2pdf.js is used: | |
| /* | |
| const element = document.getElementById('preview-container'); // Or the SVG element itself | |
| html2pdf().from(element).save('laser_cut_box.pdf'); | |
| */ | |
| // For this simple example, we'll just save a blank PDF with some text. | |
| doc.save('laser_cut_box.pdf'); | |
| } | |
| document.getElementById('calculateBtn').addEventListener('click', calculateAndPreview); | |
| document.getElementById('exportSvgBtn').addEventListener('click', exportSVG); | |
| document.getElementById('exportPdfBtn').addEventListener('click', exportPDF); | |
| // Initial preview on load | |
| calculateAndPreview(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MarkTheArtist/test1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> | |