174 lines
8.5 KiB
HTML
174 lines
8.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>PCB Tools by kennycoder</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
</head>
|
|
|
|
<body>
|
|
<div class="container">
|
|
<h1>PCB Tools by kennycoder</h1>
|
|
|
|
<div class="tabs">
|
|
<button class="tab active" data-tab="stencil">Stencil</button>
|
|
<button class="tab" data-tab="enclosure">Enclosure</button>
|
|
</div>
|
|
|
|
<!-- Tab 1: Stencil -->
|
|
<div class="tab-content active" id="tab-stencil">
|
|
<form action="/upload" method="post" enctype="multipart/form-data">
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="gerber">Solder Paste Gerber File (Required)</label>
|
|
<input type="file" id="gerber" name="gerber" accept=".gbr,.gtp,.gbp" required>
|
|
<div class="tooltip">Layers to export for Gerbers
|
|
<hr>• F.Paste (front paste stencil)<br>• B.Paste (back paste stencil)
|
|
</div>
|
|
</div>
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="outline">Board Outline Gerber (Optional)</label>
|
|
<input type="file" id="outline" name="outline" accept=".gbr,.gko,.gm1">
|
|
<div class="hint">Upload this to automatically crop and generate walls.</div>
|
|
<div class="tooltip">Layers to export for Gerbers
|
|
<hr>• Edge.Cuts (board outline)
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="height">Stencil Height (mm)</label>
|
|
<input type="number" id="height" name="height" value="0.16" step="0.01">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="dpi">DPI</label>
|
|
<input type="number" id="dpi" name="dpi" value="1000" step="100">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="wallHeight">Wall Height (mm)</label>
|
|
<input type="number" id="wallHeight" name="wallHeight" value="2.0" step="0.1">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="wallThickness">Wall Thickness (mm)</label>
|
|
<input type="number" id="wallThickness" name="wallThickness" value="1.0" step="0.1">
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="submit-btn">Convert to STL</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Tab 2: Enclosure -->
|
|
<div class="tab-content" id="tab-enclosure">
|
|
<form action="/upload-enclosure" method="post" enctype="multipart/form-data">
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="enc-outline">Board Outline Gerber (Required)</label>
|
|
<input type="file" id="enc-outline" name="outline" accept=".gbr,.gko,.gm1" required>
|
|
<div class="tooltip">Layers to export for Gerbers
|
|
<hr>• Edge.Cuts (board outline)
|
|
</div>
|
|
</div>
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="enc-drill">PTH Drill File (Optional)</label>
|
|
<input type="file" id="enc-drill" name="drill" accept=".drl,.xln,.txt">
|
|
<div class="hint">Component through-holes (vias auto-filtered).</div>
|
|
<div class="tooltip">Layers to export for DRL
|
|
<hr>• Use the <b>PTH</b> file (Plated Through-Hole)<br>• Vias are automatically filtered out
|
|
</div>
|
|
</div>
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="enc-npth">NPTH Drill File (Optional)</label>
|
|
<input type="file" id="enc-npth" name="npth" accept=".drl,.xln,.txt">
|
|
<div class="hint">Mounting holes — become pegs in enclosure.</div>
|
|
<div class="tooltip">Layers to export for DRL
|
|
<hr>• Use the <b>NPTH</b> file (Non-Plated Through-Hole)<br>• These become alignment pegs
|
|
</div>
|
|
</div>
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="enc-courtyard">F.Courtyard Gerber (Optional)</label>
|
|
<input type="file" id="enc-courtyard" name="courtyard" accept=".gbr">
|
|
<div class="hint">Component outlines — used for lid cutouts.</div>
|
|
<div class="tooltip">Layers to export for Gerbers
|
|
<hr>• <b>F.Courtyard</b> (front courtyard)<br>• ☑ Exclude DNP footprints in KiCad plot
|
|
dialog<br>• Cutouts generated where components exist
|
|
</div>
|
|
</div>
|
|
<div class="form-group tooltip-wrap">
|
|
<label for="enc-mask">F.Mask Gerber (Optional)</label>
|
|
<input type="file" id="enc-mask" name="soldermask" accept=".gbr">
|
|
<div class="hint">Soldermask openings — minimum pad cutouts.</div>
|
|
<div class="tooltip">Layers to export for Gerbers
|
|
<hr>• <b>F.Mask</b> (front soldermask)<br>• Shows exact pad areas that need cutouts<br>• ☑
|
|
Exclude DNP footprints in KiCad plot dialog
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="enc-pcbThickness">PCB Thickness (mm)</label>
|
|
<input type="number" id="enc-pcbThickness" name="pcbThickness" value="1.6" step="0.1">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="enc-wallThickness">Wall Thickness (mm)</label>
|
|
<input type="number" id="enc-wallThickness" name="wallThickness" value="1.5" step="0.1">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="enc-wallHeight">Wall Height (mm)</label>
|
|
<input type="number" id="enc-wallHeight" name="wallHeight" value="10.0" step="0.5">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="enc-clearance">Clearance (mm)</label>
|
|
<input type="number" id="enc-clearance" name="clearance" value="0.3" step="0.05">
|
|
<div class="hint">Gap between PCB edge and enclosure wall.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-row">
|
|
<div class="form-group">
|
|
<label for="enc-dpi">DPI</label>
|
|
<input type="number" id="enc-dpi" name="dpi" value="500" step="100">
|
|
</div>
|
|
<div class="form-group"></div>
|
|
</div>
|
|
|
|
<button type="submit" class="submit-btn">Generate Enclosure</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="loading">
|
|
<div class="spinner"></div>
|
|
<div>Processing... This may take 10-20 seconds.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Tab switching
|
|
document.querySelectorAll('.tab').forEach(function (tab) {
|
|
tab.addEventListener('click', function () {
|
|
document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); });
|
|
document.querySelectorAll('.tab-content').forEach(function (tc) { tc.classList.remove('active'); });
|
|
tab.classList.add('active');
|
|
document.getElementById('tab-' + tab.dataset.tab).classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Loading spinner on submit
|
|
document.querySelectorAll('form').forEach(function (form) {
|
|
form.addEventListener('submit', function () {
|
|
document.getElementById('loading').style.display = 'block';
|
|
var btn = form.querySelector('.submit-btn');
|
|
btn.disabled = true;
|
|
btn.innerText = 'Processing...';
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html> |