scad-gltf 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,6 +8,8 @@ The C++ source code for this custom OpenSCAD version is included directly in thi
8
8
 
9
9
  **✨ Launch Scadify:** Open the web editor and real-time 3D viewer: [https://iliagrigorevdev.github.io/scad-gltf/](https://iliagrigorevdev.github.io/scad-gltf/)
10
10
 
11
+ **🎮 Godot AI Generated Examples:** Play AI-generated Godot examples in your browser: [https://iliagrigorevdev.github.io/scad-godot/](https://iliagrigorevdev.github.io/scad-godot/)
12
+
11
13
  ![Editor Screenshot](https://raw.githubusercontent.com/iliagrigorevdev/scad-gltf/main/screenshot.png)
12
14
 
13
15
  ## Features
@@ -5,7 +5,7 @@ import{i as e,n as t,r as n,t as r}from"./assets/prompt-ui-zw7U8lsl.js";console.
5
5
  <line x1="12" y1="22.08" x2="12" y2="12"></line>
6
6
  </svg>
7
7
  <span>Preview 3D</span>
8
- `,t.onpointerdown=e=>e.stopPropagation(),t.onmousedown=e=>e.stopPropagation(),t.onclick=t=>{t.preventDefault(),t.stopPropagation();let n=e.querySelector(`code`);n&&s(n.innerText)};let n=e.querySelector(`button[aria-label*="copy" i], button[aria-label*="download" i], button[aria-label*="collapse" i], button[mattooltip*="copy" i], button[mattooltip*="download" i], button[mattooltip*="collapse" i], button[title*="Copy" i], button[title*="Download" i]`),r=n?.parentElement||e.querySelector(`.actions`)||e.querySelector(`.header-actions`)||e.querySelector(`.action-buttons`)||e.querySelector(`.buttons`)||e.querySelector(`.header`)||e.querySelector(`.code-header`);if(r)n?r.insertBefore(t,n):r.prepend(t);else{let n=e.querySelector(`pre`);n?n.parentNode.insertBefore(t,n):e.appendChild(t)}})}).observe(document.body,{childList:!0,subtree:!0});function a(){if(document.getElementById(`scad-prompt-btn`))return;let e=document.createElement(`button`);e.id=`scad-prompt-btn`,e.innerText=`✨ SCAD`,e.className=`scad-prompt-btn`,e.onclick=async e=>{e.preventDefault(),e.stopPropagation();let t=document.getElementById(`scad-prompt-modal`);if(t){let e=document.getElementById(`scad-prompt-desc`);e&&(e.value=``),t.style.display=`flex`,e&&e.focus()}},document.body.appendChild(e)}function o(){if(document.getElementById(`scad-prompt-modal`))return;let i=document.createElement(`div`);i.id=`scad-prompt-modal`,i.className=`scad-modal-overlay`,i.style.display=`none`,i.innerHTML=`
8
+ `,t.onpointerdown=e=>e.stopPropagation(),t.onmousedown=e=>e.stopPropagation(),t.onclick=t=>{t.preventDefault(),t.stopPropagation();let n=e.querySelector(`code`);n&&s(n.textContent)};let n=e.querySelector(`button[aria-label*="copy" i], button[aria-label*="download" i], button[aria-label*="collapse" i], button[mattooltip*="copy" i], button[mattooltip*="download" i], button[mattooltip*="collapse" i], button[title*="Copy" i], button[title*="Download" i]`),r=n?.parentElement||e.querySelector(`.actions`)||e.querySelector(`.header-actions`)||e.querySelector(`.action-buttons`)||e.querySelector(`.buttons`)||e.querySelector(`.header`)||e.querySelector(`.code-header`);if(r)n?r.insertBefore(t,n):r.prepend(t);else{let n=e.querySelector(`pre`);n?n.parentNode.insertBefore(t,n):e.appendChild(t)}})}).observe(document.body,{childList:!0,subtree:!0});function a(){if(document.getElementById(`scad-prompt-btn`))return;let e=document.createElement(`button`);e.id=`scad-prompt-btn`,e.innerText=`✨ SCAD`,e.className=`scad-prompt-btn`,e.onclick=async e=>{e.preventDefault(),e.stopPropagation();let t=document.getElementById(`scad-prompt-modal`);if(t){let e=document.getElementById(`scad-prompt-desc`);e&&(e.value=``),t.style.display=`flex`,e&&e.focus()}},document.body.appendChild(e)}function o(){if(document.getElementById(`scad-prompt-modal`))return;let i=document.createElement(`div`);i.id=`scad-prompt-modal`,i.className=`scad-modal-overlay`,i.style.display=`none`,i.innerHTML=`
9
9
  <div class="scad-modal-content">
10
10
  <div class="scad-modal-header">
11
11
  <h3>✨ SCAD Prompt Generator</h3>
package/editor/dist/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let e,s={};const i=(i,r)=>(i=new URL(i+".js",r).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(r,n)=>{const l=e||("document"in self?document.currentScript.src:"")||location.href;if(s[l])return;let o={};const t=e=>i(e,l),u={module:{uri:l},exports:o,require:t};s[l]=Promise.all(r.map(e=>u[e]||t(e))).then(e=>(n(...e),o))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"preview.html",revision:"16df0b9b2256a3d9f64f70190660f416"},{url:"index.html",revision:"62b35f003a048e944e6221f0778116bb"},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"content.js",revision:"97c4b6aa1c7f4dd481a03167dee94f25"},{url:"content.css",revision:"4ea93a2d03164b49c80a48138305e564"},{url:"content-loader.js",revision:"d94f1755552d49c1fe3a6da123e8a346"},{url:"aristea_wreck_puresky_2k.hdr",revision:"e764c66f871ab0987f3fac422edc841d"},{url:"assets/shared-CDFEFgsW.js",revision:null},{url:"assets/prompt-ui-zw7U8lsl.js",revision:null},{url:"assets/preview-DfaOpP2w.js",revision:null},{url:"assets/preview-Cx3FHqKG.css",revision:null},{url:"assets/openscad-DJJQxKJM.wasm",revision:null},{url:"assets/index-b4iPmEjR.js",revision:null},{url:"assets/index-D8In1wnN.css",revision:null},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"manifest.webmanifest",revision:"705049c691faa532cc20c736d56d54df"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
1
+ if(!self.define){let e,s={};const i=(i,r)=>(i=new URL(i+".js",r).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(r,n)=>{const l=e||("document"in self?document.currentScript.src:"")||location.href;if(s[l])return;let o={};const t=e=>i(e,l),u={module:{uri:l},exports:o,require:t};s[l]=Promise.all(r.map(e=>u[e]||t(e))).then(e=>(n(...e),o))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"preview.html",revision:"16df0b9b2256a3d9f64f70190660f416"},{url:"index.html",revision:"62b35f003a048e944e6221f0778116bb"},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"content.js",revision:"fb8d70942d66c5ed73f0714306a214c0"},{url:"content.css",revision:"4ea93a2d03164b49c80a48138305e564"},{url:"content-loader.js",revision:"d94f1755552d49c1fe3a6da123e8a346"},{url:"aristea_wreck_puresky_2k.hdr",revision:"e764c66f871ab0987f3fac422edc841d"},{url:"assets/shared-CDFEFgsW.js",revision:null},{url:"assets/prompt-ui-zw7U8lsl.js",revision:null},{url:"assets/preview-DfaOpP2w.js",revision:null},{url:"assets/preview-Cx3FHqKG.css",revision:null},{url:"assets/openscad-DJJQxKJM.wasm",revision:null},{url:"assets/index-b4iPmEjR.js",revision:null},{url:"assets/index-D8In1wnN.css",revision:null},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"manifest.webmanifest",revision:"705049c691faa532cc20c736d56d54df"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
@@ -2,6 +2,6 @@
2
2
 
3
3
  name="OpenSCAD GLTF Importer"
4
4
  description="Imports .scad files directly as 3D scenes using scad-gltf"
5
- author="Ilia Grigorev"
5
+ author="scad-gltf"
6
6
  version="0.1"
7
7
  script="scad_plugin.gd"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scad-gltf",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "WASM build of a custom OpenSCAD fork that compiles .scad scripts directly to glTF/GLB with PBR and animation support",
5
5
  "type": "module",
6
6
  "main": "./src/ext/openscad.js",
@@ -148,10 +148,6 @@ export function runGodotAsync(args, cwd, timeoutMs) {
148
148
  let spawnBin = godotBin;
149
149
  let spawnArgs = args;
150
150
 
151
- // ---------------------------------------------------------
152
- // CRITICAL: Do not use real display on Linux. Run inside Xvfb
153
- // to avoid popping up windows or failing in headless server environments.
154
- // ---------------------------------------------------------
155
151
  if (process.platform === "linux") {
156
152
  spawnArgs = ["-a", "-s", "-screen 0 1024x768x24", spawnBin, ...args];
157
153
  spawnBin = "xvfb-run";
@@ -159,25 +155,43 @@ export function runGodotAsync(args, cwd, timeoutMs) {
159
155
 
160
156
  const godotProcess = cp.spawn(spawnBin, spawnArgs, { cwd, env });
161
157
 
162
- godotProcess.stdout.on("data", (data) => {
163
- output += data.toString();
164
- });
165
- godotProcess.stderr.on("data", (data) => {
166
- output += data.toString();
167
- });
158
+ godotProcess.stdout.on("data", (data) => (output += data.toString()));
159
+ godotProcess.stderr.on("data", (data) => (output += data.toString()));
160
+
161
+ // 1. Add a flag to prevent resolving the promise multiple times
162
+ let isResolved = false;
168
163
 
169
164
  const timer = setTimeout(() => {
170
- godotProcess.kill();
165
+ if (isResolved) return;
166
+ isResolved = true;
167
+ try {
168
+ godotProcess.kill("SIGKILL"); // 2. Attempt a harder kill
169
+ } catch (e) {}
170
+
171
+ // 3. EXPLICITLY resolve the promise here so the MCP server doesn't hang
172
+ resolve({ code: 124, output: output + "\n--- KILLED BY TIMEOUT ---" });
171
173
  }, timeoutMs);
172
174
 
173
175
  godotProcess.on("close", (code) => {
176
+ if (isResolved) return;
177
+ isResolved = true;
174
178
  clearTimeout(timer);
175
179
  resolve({ code, output });
176
180
  });
177
181
 
178
182
  godotProcess.on("error", (err) => {
183
+ if (isResolved) return;
184
+ isResolved = true;
179
185
  clearTimeout(timer);
180
- resolve({ code: -1, output: `Process error: ${err.message}` });
186
+
187
+ let errorMsg = `Process error: ${err.message}`;
188
+
189
+ // Notify Linux users that xvfb is required
190
+ if (err.code === "ENOENT" && spawnBin === "xvfb-run") {
191
+ errorMsg = `Error: 'xvfb-run' is missing. To test Godot projects on headless Linux, you must install Xvfb.\n\nPlease run: sudo apt-get install xvfb`;
192
+ }
193
+
194
+ resolve({ code: -1, output: errorMsg });
181
195
  });
182
196
  });
183
197
  }