[READ-ONLY] Mirror of https://github.com/flo-bit/room. tiny 3d rooms saved locally or in your bluesky account, svelte/threlte flo-bit.dev/room/
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1 from Aebel-Shajan/main

Add "export as stl" button in the preview ui.

authored by

Florian and committed by
GitHub
(Mar 9, 2025, 2:22 PM +0100) b700dc81 07277be6

+68 -16
+1
src/lib/Room.svelte
··· 97 97 gridSize={[roomState.size.z * 2, roomState.size.x * 2]} 98 98 scale={0.5} 99 99 sectionThickness={0} 100 + name="grid" 100 101 /> 101 102 {/if} 102 103
+40 -1
src/lib/Scene.svelte
··· 6 6 7 7 import Room from './Room.svelte'; 8 8 import Outline from './Outline.svelte'; 9 - import { roomState } from './state.svelte'; 9 + import { applyTransformOfSelected, editorState, roomState } from './state.svelte'; 10 10 import { onMount } from 'svelte'; 11 11 import { ACESFilmicToneMapping } from 'three'; 12 12 import { base } from '$app/paths'; 13 + import { STLExporter } from 'three/examples/jsm/Addons.js'; 13 14 14 15 const { renderer, scene } = useThrelte(); 15 16 ··· 36 37 scene.environmentIntensity = e.matches ? darkModeEnvIntensity : lightModeEnvIntensity; 37 38 lightIntensity = e.matches ? darkModeLightIntensity : lightModeLightIntensity; 38 39 }); 40 + 41 + // Listen for export event 42 + document.addEventListener("exportSTL", exportSTL); 39 43 }); 44 + 45 + async function exportSTL() { 46 + const exporter = new STLExporter(); 47 + 48 + // apply transform 49 + applyTransformOfSelected(); 50 + 51 + editorState.selectedObject = null; 52 + editorState.placingObject = null; 53 + 54 + // wait 1 frame 55 + await new Promise((resolve) => setTimeout(resolve, 1)); 56 + 57 + // Clone the scene to avoid modifying the original 58 + const sceneCopy = scene.clone(); 59 + 60 + // Rotate the entire scene copy (convert from Y-up to Z-up) 61 + sceneCopy.rotation.x = Math.PI / 2; 62 + sceneCopy.updateMatrixWorld(true); // Apply the transformation 63 + 64 + // Remove the grid from the scene 65 + const grid = sceneCopy.getObjectByName('grid'); 66 + if(grid) { 67 + grid.removeFromParent(); 68 + } 69 + 70 + // Export the modified copy 71 + const stlString = exporter.parse(sceneCopy); 72 + const blob = new Blob([stlString], { type: "application/sla" }); 73 + const link = document.createElement("a"); 74 + link.href = URL.createObjectURL(blob); 75 + link.download = "room.stl"; 76 + link.click(); 77 + } 78 + 40 79 </script> 41 80 42 81 <T.PerspectiveCamera
+27 -15
src/routes/EditorUI.svelte
··· 423 423 onchange={() => saveRoomToLocalStorage()} 424 424 /> 425 425 </div> 426 + <Subheading>Export</Subheading> 426 427 427 - <Button 428 - class="mt-6" 429 - variant="secondary" 430 - onclick={async () => { 431 - const json = JSON.stringify(roomState, null, 2); 432 - const blob = new Blob([json], { type: 'application/json' }); 433 - const url = URL.createObjectURL(blob); 434 - const a = document.createElement('a'); 435 - a.href = url; 436 - a.download = 'room.json'; 437 - a.click(); 438 - }} 439 - > 440 - Export as json 441 - </Button> 428 + <div class="flex flex-wrap gap-2"> 429 + <Button 430 + variant="secondary" 431 + onclick={async () => { 432 + const json = JSON.stringify(roomState, null, 2); 433 + const blob = new Blob([json], { type: 'application/json' }); 434 + const url = URL.createObjectURL(blob); 435 + const a = document.createElement('a'); 436 + a.href = url; 437 + a.download = 'room.json'; 438 + a.click(); 439 + }} 440 + > 441 + Export as json 442 + </Button> 443 + 444 + <Button 445 + variant="secondary" 446 + onclick={async () => { 447 + document.dispatchEvent(new Event('exportSTL')); 448 + }} 449 + > 450 + Export as stl 451 + </Button> 452 + </div> 453 + 442 454 <Subheading class="mt-2">Danger zone</Subheading> 443 455 <div class="mt-4 flex flex-wrap gap-2"> 444 456 <Button