Add 3D model extraction and download from embedded footprint models
- Parse embedded_files sections in KiCad footprint files - Extract and decompress (zstd) embedded STEP models - Add backend endpoint to serve 3D models - Add UI section to display and download 3D models - Include Three.js library for future interactive viewing - Provide download link for extracted STEP files - Note: Interactive 3D viewing requires STEP to STL/OBJ conversion (future enhancement) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>UM KiCad Manager</title>
|
||||
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.159.0/build/three.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.159.0/examples/js/controls/OrbitControls.js"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -486,6 +488,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3D Model Viewer -->
|
||||
<div id="modelViewerContainer" style="margin-bottom: 15px; display: none;">
|
||||
<label style="display: block; font-weight: bold; margin-bottom: 5px;">3D Model:</label>
|
||||
<div id="modelViewer" style="border: 1px solid #dee2e6; border-radius: 5px; background: #1a1a1a; width: 100%; height: 300px; position: relative;">
|
||||
<div id="modelViewerCanvas"></div>
|
||||
<div id="modelViewerMessage" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #999; text-align: center;">
|
||||
Loading 3D model...
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 5px; font-size: 12px; color: #6c757d;">
|
||||
Use mouse to rotate (left-click drag), zoom (scroll), and pan (right-click drag)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button id="createPartBtn" class="btn" disabled>Create Part</button>
|
||||
<button id="cancelCreatePartBtn" class="btn secondary" style="margin-left: 10px;">Cancel</button>
|
||||
</div>
|
||||
@@ -1261,6 +1277,7 @@
|
||||
if (!footprintName) {
|
||||
footprintPreview.innerHTML = '<span style="color: #999;">No footprint selected</span>';
|
||||
selectedFootprint = '';
|
||||
document.getElementById('modelViewerContainer').style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1269,6 +1286,12 @@
|
||||
library_path: selectedFootprintLibraryPath,
|
||||
footprint_name: footprintName
|
||||
});
|
||||
|
||||
// Request 3D model
|
||||
socket.emit('get_footprint_model', {
|
||||
library_path: selectedFootprintLibraryPath,
|
||||
footprint_name: footprintName
|
||||
});
|
||||
});
|
||||
|
||||
socket.on('footprint_render_result', (data) => {
|
||||
@@ -1278,6 +1301,22 @@
|
||||
selectedFootprint = `${libName}:${data.footprint_name}`;
|
||||
});
|
||||
|
||||
socket.on('model_result', (data) => {
|
||||
const container = document.getElementById('modelViewerContainer');
|
||||
const messageEl = document.getElementById('modelViewerMessage');
|
||||
|
||||
if (data.has_model) {
|
||||
container.style.display = 'block';
|
||||
messageEl.innerHTML = `<strong>3D Model Found:</strong> ${data.name}<br><br>` +
|
||||
`<em>Note: STEP file viewing in browser requires conversion to STL/OBJ format.<br>` +
|
||||
`This feature is under development.</em><br><br>` +
|
||||
`<a href="data:application/stp;base64,${data.data}" download="${data.name}" ` +
|
||||
`style="color: #007bff; text-decoration: underline; cursor: pointer;">Download ${data.name}</a>`;
|
||||
} else {
|
||||
container.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('missing_ipns_result', (data) => {
|
||||
createPartFormLoading.style.display = 'none';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user