chore: clean up code structure and remove unused code blocks

This commit is contained in:
CNCKitchen
2026-03-18 12:18:35 +01:00
parent 04afab2432
commit d09d00e5a8
6 changed files with 237 additions and 17 deletions
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

+34 -11
View File
@@ -3,8 +3,15 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>STL Texturizer</title>
<title>CNC Kitchen STL Texturizer</title>
<link rel="stylesheet" href="style.css" />
<script>
// Apply saved theme before first paint to avoid flash
(function() {
const t = localStorage.getItem('stlt-theme');
if (t === 'light') document.documentElement.setAttribute('data-theme', 'light');
})();
</script>
<script type="importmap">
{
"imports": {
@@ -22,9 +29,12 @@
<path d="M2 17L12 22L22 17" stroke="#7c6aff" stroke-width="1.5" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="#a08cff" stroke-width="1.5" stroke-linejoin="round"/>
</svg>
<span>STL Texturizer</span>
<span>CNC Kitchen STL Texturizer</span>
</div>
<div class="header-note">Units assumed to be <strong>mm</strong></div>
<button id="theme-toggle" class="theme-toggle" title="Toggle light / dark mode" aria-label="Toggle light/dark mode" style="margin-left:auto">
<span class="icon-moon">Dark</span>
<span class="icon-sun">Light</span>
</button>
</header>
<main>
@@ -153,7 +163,7 @@
<!-- Surface Mask -->
<section class="panel-section">
<h2>Surface Mask</h2>
<h2 title="0° = no masking. Surfaces within this angle of horizontal will not be textured.">Surface Mask</h2>
<div class="form-row slider-row">
<label for="bottom-angle-limit" title="Suppress texture on downward-facing surfaces within this angle of horizontal">Bottom faces</label>
<input type="range" id="bottom-angle-limit" min="0" max="90" step="1" value="5" />
@@ -164,12 +174,11 @@
<input type="range" id="top-angle-limit" min="0" max="90" step="1" value="0" />
<input type="number" class="val" id="top-angle-limit-val" value="0" min="0" max="90" step="1" />
</div>
<p class="hint">0° = no masking. Surfaces within this angle of horizontal will not be textured.</p>
</section>
<!-- Surface Exclusions -->
<section class="panel-section">
<h2 id="excl-section-heading">Surface Exclusions</h2>
<h2 id="excl-section-heading" title="Excluded surfaces appear orange and will not receive displacement during export.">Surface Exclusions</h2>
<!-- Mode toggle: Exclude / Include Only -->
<div class="excl-mode-row">
@@ -235,12 +244,11 @@
<span id="excl-count" class="excl-count">0 faces excluded</span>
<button id="excl-clear-btn" class="excl-clear-btn">Clear All</button>
</div>
<p id="excl-hint" class="hint">Excluded surfaces appear orange and will not receive displacement during export.</p>
</section>
<!-- Export -->
<section class="panel-section">
<h2>Export</h2>
<h2 title="Smaller edge length = finer displacement detail. Output is then decimated to the triangle limit.">Export</h2>
<div class="form-row slider-row">
<label for="refine-length" title="Edges longer than this value will be split during export">Max Edge Length</label>
<input type="range" id="refine-length" min="0.1" max="5" step="0.1" value="1" />
@@ -254,9 +262,7 @@
<div id="tri-limit-warning" class="tri-limit-warning hidden">
⚠ 5M-triangle safety cap hit during subdivision — result may still be coarser than requested edge length.
</div>
<p class="hint">
Smaller edge length = finer displacement detail. Output is then decimated to the triangle limit.
</p>
<div id="export-progress" class="export-progress hidden">
<div class="export-progress-track">
<div id="export-progress-bar" class="export-progress-bar"></div>
@@ -270,6 +276,23 @@
</aside>
</main>
<!-- Sponsor popup -->
<div id="sponsor-overlay" class="sponsor-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="sponsor-title">
<div class="sponsor-modal">
<h2 id="sponsor-title">Thanks for using CNC Kitchen STL Texturizer!</h2>
<p>This tool is provided <strong>completely free</strong> by CNC Kitchen.<br>
While your STL is being processed, why not check out the store that helps us keep making cool stuff for you?</p>
<a href="https://geni.us/CNCStoreTexture" target="_blank" rel="noopener noreferrer" class="sponsor-link">
🛒 Visit CNCKitchen.STORE
</a>
<label class="sponsor-no-show">
<input type="checkbox" id="sponsor-dont-show" />
Don't show this again
</label>
<button id="sponsor-close" class="sponsor-close-btn">Close &amp; Continue</button>
</div>
</div>
<script type="module" src="js/main.js"></script>
</body>
</html>
+40 -2
View File
@@ -1,7 +1,7 @@
import * as THREE from 'three';
import { initViewer, loadGeometry, setMeshMaterial, setWireframe,
getControls, getCamera, getCurrentMesh,
setExclusionOverlay, setHoverPreview } from './viewer.js';
setExclusionOverlay, setHoverPreview, setViewerTheme } from './viewer.js';
import { loadSTLFile, computeBounds, getTriangleCount } from './stlLoader.js';
import { loadPresets, loadCustomTexture } from './presetTextures.js';
import { createPreviewMaterial, updateMaterial } from './previewMaterial.js';
@@ -128,6 +128,18 @@ const posToScale = p => parseFloat(Math.exp(_LOG_MIN + (p / 1000) * (_LOG_MAX -
let PRESETS = [];
initViewer(canvas);
// Apply saved theme to 3D viewport on startup
setViewerTheme(document.documentElement.getAttribute('data-theme') === 'light');
// Theme toggle
document.getElementById('theme-toggle').addEventListener('click', () => {
const isLight = document.documentElement.getAttribute('data-theme') !== 'light';
document.documentElement.setAttribute('data-theme', isLight ? 'light' : 'dark');
localStorage.setItem('stlt-theme', isLight ? 'light' : 'dark');
setViewerTheme(isLight);
});
wireEvents();
// Sync scale number inputs with the slider's initial position
scaleUVal.value = posToScale(parseFloat(scaleUSlider.value));
@@ -136,6 +148,11 @@ scaleVVal.value = posToScale(parseFloat(scaleVSlider.value));
loadPresets().then(presets => {
PRESETS = presets;
buildPresetGrid();
// Select Noise as the default preset
const noiseIdx = PRESETS.findIndex(p => p.name === 'Noise');
const defaultIdx = noiseIdx !== -1 ? noiseIdx : 0;
const swatches = presetGrid.querySelectorAll('.preset-swatch');
if (swatches[defaultIdx]) selectPreset(defaultIdx, swatches[defaultIdx]);
}).catch(err => console.error('Failed to load preset textures:', err));
// ── Preset grid ───────────────────────────────────────────────────────────────
@@ -261,7 +278,28 @@ function wireEvents() {
linkSlider(topAngleLimitSlider, topAngleLimitVal, v => { settings.topAngleLimit = v; return v; });
// ── Export ──
exportBtn.addEventListener('click', handleExport);
exportBtn.addEventListener('click', () => {
if (localStorage.getItem('stlt-no-sponsor') === '1') {
handleExport();
return;
}
const overlay = document.getElementById('sponsor-overlay');
const closeBtn = document.getElementById('sponsor-close');
const storeLink = overlay.querySelector('.sponsor-link');
overlay.classList.remove('hidden');
const dismiss = () => {
if (document.getElementById('sponsor-dont-show').checked) {
localStorage.setItem('stlt-no-sponsor', '1');
}
overlay.classList.add('hidden');
handleExport();
};
closeBtn.onclick = dismiss;
// Also start processing when the user clicks through to the store
storeLink.onclick = () => setTimeout(dismiss, 150);
});
// ── Wireframe ──
wireframeToggle.addEventListener('change', () => setWireframe(wireframeToggle.checked));
+1
View File
@@ -24,6 +24,7 @@ const IMAGE_PRESETS = [
{ name: 'Leather 2', url: 'leather2.jpg' },
{ name: 'Weave', url: 'weave.jpg' },
{ name: 'Wood', url: 'wood.jpg' },
{ name: 'Noise', url: 'noise.jpg' },
];
function loadImagePreset({ name, url }) {
+22
View File
@@ -253,6 +253,28 @@ export function getScene() { return scene; }
export function getControls() { return controls; }
export function getCurrentMesh() { return currentMesh; }
export function setSceneBackground(hexColor) {
if (scene) scene.background = new THREE.Color(hexColor);
}
export function setViewerTheme(isLight) {
if (!scene) return;
scene.background = new THREE.Color(isLight ? 0xf0f0f5 : 0x111114);
if (grid) {
scene.remove(grid);
grid.geometry.dispose();
grid.material.dispose();
}
grid = new THREE.GridHelper(
200, 40,
isLight ? 0xb0b0c8 : 0x222228,
isLight ? 0xd0d0e0 : 0x1e1e24
);
grid.rotation.x = Math.PI / 2;
grid.position.z = 0;
scene.add(grid);
}
/**
* Replace (or clear) the flat orange exclusion overlay mesh.
* overlayGeo must be a non-indexed BufferGeometry with a 'position' attribute,
+140 -4
View File
@@ -17,6 +17,48 @@
--header-h: 48px;
}
[data-theme="light"] {
--bg: #f0f0f5;
--surface: #ffffff;
--surface2: #eaeaf2;
--border: #d0d0df;
--accent: #6355e0;
--accent-hover: #7c6aff;
--text: #1a1a2e;
--text-muted: #66667a;
--danger: #d93025;
--success: #1a7f3c;
}
/* ── Theme toggle button ─────────────────────────────────────────────── */
.theme-toggle {
display: flex;
align-items: center;
justify-content: center;
height: 28px;
padding: 0 10px;
background: var(--surface2);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-muted);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.04em;
cursor: pointer;
transition: background 0.15s, border-color 0.15s, color 0.15s;
flex-shrink: 0;
}
.theme-toggle:hover {
border-color: var(--accent);
color: var(--accent);
}
.theme-toggle .icon-moon { display: block; }
.theme-toggle .icon-sun { display: none; }
[data-theme="light"] .theme-toggle .icon-moon { display: none; }
[data-theme="light"] .theme-toggle .icon-sun { display: block; }
html, body {
height: 100%;
font-family: 'Segoe UI', system-ui, sans-serif;
@@ -153,7 +195,7 @@ main {
.viewport-controls-hint {
margin-left: auto;
font-size: 11px;
color: #555566;
color: var(--text-muted);
}
.wireframe-toggle {
@@ -198,8 +240,8 @@ main {
/* ── Preset grid ─────────────────────────────────────────────────────── */
.preset-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 4px;
grid-template-columns: repeat(6, 1fr);
gap: 3px;
margin-bottom: 10px;
}
@@ -407,6 +449,12 @@ input[type="number"].val:focus { outline: none; border-color: var(--accent); }
pointer-events: none;
}
[data-theme="light"] .export-progress-pct {
mix-blend-mode: normal;
color: #fff;
text-shadow: 0 0 4px rgba(0,0,0,0.5);
}
/* ── Export button ───────────────────────────────────────────────────── */
.export-btn {
width: 100%;
@@ -597,4 +645,92 @@ input[type="number"].val:focus { outline: none; border-color: var(--accent); }
}
/* Hide utility (used by JS to show/hide exclusion sub-rows) */
.form-row.hidden { display: none; }
.form-row.hidden { display: none; }
/* ── Sponsor / popup overlay ─────────────────────────────────────────── */
.sponsor-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
backdrop-filter: blur(3px);
}
.sponsor-overlay.hidden { display: none; }
.sponsor-modal {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 28px 32px;
max-width: 420px;
width: calc(100% - 40px);
display: flex;
flex-direction: column;
gap: 14px;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.sponsor-modal h2 {
font-size: 15px;
font-weight: 700;
color: var(--text);
text-transform: none;
letter-spacing: 0;
margin: 0;
}
.sponsor-modal p {
font-size: 13px;
color: var(--text-muted);
line-height: 1.6;
margin: 0;
}
.sponsor-link {
display: block;
text-align: center;
padding: 10px 16px;
background: var(--accent);
color: #fff;
border-radius: var(--radius);
font-size: 13px;
font-weight: 600;
text-decoration: none;
transition: background 0.15s;
}
.sponsor-link:hover { background: var(--accent-hover); }
.sponsor-no-show {
display: flex;
align-items: center;
gap: 7px;
font-size: 11px;
color: var(--text-muted);
cursor: pointer;
user-select: none;
}
.sponsor-no-show input { cursor: pointer; accent-color: var(--accent); }
.sponsor-close-btn {
padding: 8px 16px;
background: var(--surface2);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text);
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
align-self: flex-end;
}
.sponsor-close-btn:hover {
background: var(--border);
border-color: var(--accent);
}