feat: add STL file upload button and implement flat-bottom clamp logic in export

This commit is contained in:
CNCKitchen
2026-03-17 17:47:26 +01:00
parent 1d3e756245
commit cbe7e7ffef
2 changed files with 22 additions and 0 deletions
+8
View File
@@ -55,6 +55,14 @@
<!-- ─── Settings Panel ───────────────────────────────────────── --> <!-- ─── Settings Panel ───────────────────────────────────────── -->
<aside id="settings-panel"> <aside id="settings-panel">
<!-- Load STL -->
<section class="panel-section">
<label class="upload-btn" for="stl-file-input" style="width:100%;box-sizing:border-box;justify-content:center;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M12 2L2 7l10 5 10-5-10-5Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><path d="M2 17l10 5 10-5M2 12l10 5 10-5" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/></svg>
Load STL…
</label>
</section>
<!-- Displacement Map --> <!-- Displacement Map -->
<section class="panel-section"> <section class="panel-section">
<h2>Displacement Map</h2> <h2>Displacement Map</h2>
+14
View File
@@ -19,6 +19,7 @@ let currentBounds = null; // bounds of the original geometry
let activeMapEntry = null; // { name, texture, imageData, width, height } let activeMapEntry = null; // { name, texture, imageData, width, height }
let previewMaterial = null; let previewMaterial = null;
let isExporting = false; let isExporting = false;
let previewDebounce = null;
// ── Exclusion state ─────────────────────────────────────────────────────────── // ── Exclusion state ───────────────────────────────────────────────────────────
let excludedFaces = new Set(); // triangle indices in currentGeometry let excludedFaces = new Set(); // triangle indices in currentGeometry
@@ -636,6 +637,19 @@ async function handleExport() {
); );
} }
// Flat-bottom clamp: when bottom faces are masked (bottomAngleLimit > 0),
// any vertex that ended up below the original model's bottom layer gets
// snapped back up to that Z. Only the Z-value is changed.
if (settings.bottomAngleLimit > 0) {
const bottomZ = currentBounds.min.z;
const posArr = finalGeometry.attributes.position.array;
for (let i = 2; i < posArr.length; i += 3) {
if (posArr[i] < bottomZ) posArr[i] = bottomZ;
}
finalGeometry.attributes.position.needsUpdate = true;
finalGeometry.computeVertexNormals();
}
setProgress(0.97, 'Writing STL…'); setProgress(0.97, 'Writing STL…');
await yieldFrame(); await yieldFrame();