scad-gltf 0.1.3 → 0.1.4
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 +1 -4
- package/bin/scad-godot.js +28 -2
- package/editor/dist/assets/{preview-fQfL_FJ-.css → preview-A6M04CFK.css} +1 -1
- package/editor/dist/assets/preview-CCwT_Mrn.js +1 -0
- package/editor/dist/content.css +48 -0
- package/editor/dist/content.js +19 -2
- package/editor/dist/preview.html +14 -2
- package/editor/dist/sw.js +1 -1
- package/godot/examples/kids_digit_writing.js +2532 -0
- package/godot/export_presets.cfg +1 -1
- package/package.json +1 -2
- package/editor/dist/assets/preview-CA_S_fWF.js +0 -1
package/README.md
CHANGED
|
@@ -219,6 +219,7 @@ When asking an LLM (like Gemini) to generate OpenSCAD code, the extension automa
|
|
|
219
219
|
- **Instant 3D Preview:** Injects a **"Preview 3D"** button on any OpenSCAD code block to compile and render the model in an embedded 3D viewer with grid, wireframe, and full-screen support.
|
|
220
220
|
- **Visual Chat Feedback (📷):** Click the snapshot button inside the 3D preview window to capture a PNG snapshot of the model and **automatically paste it into the AI Studio chat input**, allowing Gemini to visually evaluate and fix geometry.
|
|
221
221
|
- **Smart Prompt Injection:** Click the floating **"✨ SCAD"** button to open the configuration modal. Select your desired engine feature set (PBR, auto-smooth, animations, baking) to automatically generate and inject the prompt rules into your chat input.
|
|
222
|
+
- **Local Model Refinement:** Connect to your local `scad-serve` workspace directly from the prompt modal. Select an existing `.scad` file to automatically append its source code to your prompt as a reference, enabling seamless AI iteration and refinement of your existing local designs.
|
|
222
223
|
- **Open in Scadify:** Click **"Edit"** in the preview window to immediately transfer the current script into the full standalone Scadify editor via compressed URL hash.
|
|
223
224
|
- **Local Workspace Saving:** Directly save and overwrite models to your local directory when running `scad-serve`.
|
|
224
225
|
|
|
@@ -490,7 +491,3 @@ This repository includes a custom fork of OpenSCAD in the `openscad/` subfolder
|
|
|
490
491
|
- **Path Tracing:** The web editor utilizes [three-gpu-pathtracer](https://github.com/gkjohnson/three-gpu-pathtracer) for high-quality rendering.
|
|
491
492
|
- **Environment Map (HDR)**: [Aristea Wreck Puresky](https://polyhaven.com/a/aristea_wreck_puresky) by **Jarod Guest** via [Poly Haven](https://polyhaven.com/). Licensed under [CC0](https://polyhaven.com/license).
|
|
492
493
|
- **License:** See the `LICENSE` file (GPL-2.0 or later, inheriting from standard OpenSCAD).
|
|
493
|
-
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
```
|
package/bin/scad-godot.js
CHANGED
|
@@ -90,7 +90,7 @@ async function main() {
|
|
|
90
90
|
console.error("");
|
|
91
91
|
console.error("Example with JSON options:");
|
|
92
92
|
console.error(
|
|
93
|
-
' scad-godot "Game description" \'{"animation": false, "bakeColors": true}\'',
|
|
93
|
+
' scad-godot "Game description" \'{"animation": false, "bakeColors": true, "scadFiles": ["player.scad"]}\'',
|
|
94
94
|
);
|
|
95
95
|
process.exit(1);
|
|
96
96
|
}
|
|
@@ -102,6 +102,7 @@ async function main() {
|
|
|
102
102
|
clearcoat: false,
|
|
103
103
|
sheen: false,
|
|
104
104
|
iridescence: false,
|
|
105
|
+
scadFiles: [],
|
|
105
106
|
};
|
|
106
107
|
|
|
107
108
|
if (optionsStr) {
|
|
@@ -138,6 +139,9 @@ async function main() {
|
|
|
138
139
|
process.exit(1);
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
const hasUserScadFiles =
|
|
143
|
+
Array.isArray(options.scadFiles) && options.scadFiles.length > 0;
|
|
144
|
+
|
|
141
145
|
// 4. Construct the Main Godot Prompt System Text (System Instructions)
|
|
142
146
|
const systemPrompt = `You are an expert Godot 4 game developer and procedural 3D technical artist.
|
|
143
147
|
|
|
@@ -185,7 +189,11 @@ ${promptRules}
|
|
|
185
189
|
- The script must embed and write:
|
|
186
190
|
- Your generated \`.scad\` game assets.
|
|
187
191
|
- Your generated Godot project files.
|
|
188
|
-
- The exact source code of the provided \`addons/scad_importer/*\` files, placed in their correct respective paths
|
|
192
|
+
- The exact source code of the provided \`addons/scad_importer/*\` files, placed in their correct respective paths.${
|
|
193
|
+
hasUserScadFiles
|
|
194
|
+
? "\n - The exact source code of the provided user `.scad` files, placed in the appropriate project folders."
|
|
195
|
+
: ""
|
|
196
|
+
}
|
|
189
197
|
- Ensure all string file contents inside the Node.js script are properly escaped.`;
|
|
190
198
|
|
|
191
199
|
// 5. Gather Addon Files content
|
|
@@ -229,6 +237,24 @@ ${promptRules}
|
|
|
229
237
|
}
|
|
230
238
|
}
|
|
231
239
|
|
|
240
|
+
if (hasUserScadFiles) {
|
|
241
|
+
systemClipboardOutput += `=== USER PROVIDED OPENSCAD FILES ===\n`;
|
|
242
|
+
systemClipboardOutput += `The following .scad files are provided as reference or base assets. You MUST embed and write them into the generated project, modifying them if necessary to fit the game logic.\n\n`;
|
|
243
|
+
for (const file of options.scadFiles) {
|
|
244
|
+
try {
|
|
245
|
+
const content = fs.readFileSync(file, "utf-8").replace(/\r\n/g, "\n");
|
|
246
|
+
const relativePath = path.isAbsolute(file)
|
|
247
|
+
? path.relative(process.cwd(), file).replace(/\\/g, "/")
|
|
248
|
+
: file.replace(/\\/g, "/");
|
|
249
|
+
systemClipboardOutput += `### ${relativePath}\n---\n\`\`\`openscad\n${content}\n\`\`\`\n\n`;
|
|
250
|
+
} catch (e) {
|
|
251
|
+
console.error(
|
|
252
|
+
`Warning: Skipping user SCAD file '${file}'. It is not a readable file.`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
232
258
|
systemClipboardOutput = systemClipboardOutput.trimEnd() + "\n";
|
|
233
259
|
|
|
234
260
|
// 7. Format the input request output
|
|
@@ -1 +1 @@
|
|
|
1
|
-
body{background-color:#333;width:100vw;height:100vh;margin:0;font-family:sans-serif;display:flex;overflow:hidden}#viewer-container{background:#1e1e1e;flex-grow:1;width:100%;height:100vh;position:relative;overflow:hidden}#viewer{width:100%;height:100%}#viewer-controls{z-index:10;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0009;border-radius:6px;align-items:center;gap:8px;padding:6px;display:flex;position:absolute;top:15px;right:40px}#viewer-controls label{color:#fff;cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:4px;margin:0;font-size:13px;display:flex}#fullscreen-btn,#screenshot-btn{color:#fff;cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;height:auto;font-size:16px;display:flex}#fullscreen-btn{padding:0 4px}#screenshot-btn{padding:0 4px 6px}#fullscreen-btn:hover,#screenshot-btn:hover{color:#0af;background:0 0}#save-ui{z-index:10;background:#0009;border-radius:6px;gap:8px;padding:6px;display:flex;position:absolute;top:15px;left:15px}#filename-input{color:#fff;background:#333;border:1px solid #555;border-radius:4px;outline:none;width:160px;padding:4px 8px;font-family:monospace}#filename-input:focus{border-color:#0af}#save-btn{color:#fff;cursor:pointer;background:#0af;border:none;border-radius:4px;padding:4px 12px;font-weight:700}#save-btn:hover:not(:disabled){background:#08c}#save-btn:disabled{opacity:.7;cursor:not-allowed}#open-editor-btn{color:#fff;cursor:pointer;background:#6f42c1;border:none;border-radius:4px;padding:4px 12px;font-weight:700}#open-editor-btn:hover:not(:disabled){background:#5a32a3}#open-editor-btn:disabled{opacity:.7;cursor:not-allowed}
|
|
1
|
+
body{background-color:#333;width:100vw;height:100vh;margin:0;font-family:sans-serif;display:flex;overflow:hidden}#viewer-container{background:#1e1e1e;flex-grow:1;width:100%;height:100vh;position:relative;overflow:hidden}#viewer{width:100%;height:100%}#viewer-controls{z-index:10;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0009;border-radius:6px;align-items:center;gap:8px;padding:6px;display:flex;position:absolute;top:15px;right:40px}#viewer-controls label{color:#fff;cursor:pointer;-webkit-user-select:none;user-select:none;align-items:center;gap:4px;margin:0;font-size:13px;display:flex}#fullscreen-btn,#screenshot-btn{color:#fff;cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;height:auto;font-size:16px;display:flex}#fullscreen-btn{padding:0 4px}#screenshot-btn{padding:0 4px 6px}#fullscreen-btn:hover,#screenshot-btn:hover{color:#0af;background:0 0}#save-ui{z-index:10;background:#0009;border-radius:6px;gap:8px;padding:6px;display:flex;position:absolute;top:15px;left:15px}#filename-input{color:#fff;background:#333;border:1px solid #555;border-radius:4px;outline:none;width:160px;padding:4px 8px;font-family:monospace}#filename-input:focus{border-color:#0af}#save-btn{color:#fff;cursor:pointer;background:#0af;border:none;border-radius:4px;padding:4px 12px;font-weight:700}#save-btn:hover:not(:disabled){background:#08c}#save-btn:disabled{opacity:.7;cursor:not-allowed}#open-editor-btn{color:#fff;cursor:pointer;background:#6f42c1;border:none;border-radius:4px;padding:4px 12px;font-weight:700}#open-editor-btn:hover:not(:disabled){background:#5a32a3}#open-editor-btn:disabled{opacity:.7;cursor:not-allowed}#anim-controls{z-index:10;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#0009;border-radius:8px;align-items:center;gap:10px;width:80%;max-width:400px;padding:8px 16px;display:flex;position:absolute;bottom:20px;left:50%;transform:translate(-50%)}#anim-controls select{color:#fff;background:#333;border:1px solid #555;border-radius:4px;outline:none;padding:4px;font-size:13px}#anim-controls button{color:#fff;cursor:pointer;white-space:nowrap;background:#444;border:none;border-radius:4px;padding:4px 12px;font-size:13px}#anim-controls button:hover{background:#555}#anim-slider{cursor:pointer;-webkit-appearance:none;background:0 0;flex-grow:1;margin:0}#anim-slider:focus{outline:none}#anim-slider::-webkit-slider-runnable-track{cursor:pointer;background:#444;border-radius:3px;width:100%;height:6px}#anim-slider::-webkit-slider-thumb{cursor:pointer;-webkit-appearance:none;background:#0af;border-radius:50%;width:14px;height:14px;margin-top:-4px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as e,B as t,D as n,E as r,H as i,O as a,R as o,W as s,a as ee,d as c,et as te,f as ne,ht as re,i as ie,l,lt as u,mt as ae,n as oe,o as se,p as d,r as f,s as p,t as ce,u as le,ut as m,w as ue,y as de}from"./OutputPass-B6MrFnGE.js";var h=document.getElementById(`viewer-container`),fe=document.getElementById(`viewer`),g=document.getElementById(`filename-input`),_=document.getElementById(`save-btn`),v=document.getElementById(`open-editor-btn`),y=document.getElementById(`show-grid-cb`),b=document.getElementById(`wireframe-cb`),x=document.getElementById(`fullscreen-btn`),S=document.getElementById(`screenshot-btn`),C=document.getElementById(`anim-controls`),w=document.getElementById(`anim-play-btn`),T=document.getElementById(`anim-select`),E=document.getElementById(`anim-slider`),D=null,O=null,k=!0,A=!1,j=[],M=``,N=!1,P=null,F=null,I=!1,L=new te;L.background=new de(2236962);var R=new i(60,window.innerWidth/window.innerHeight,.1,2e3);R.position.set(50,50,-50);var z=new le({antialias:!0});z.setSize(window.innerWidth,window.innerHeight),z.setPixelRatio(Math.min(window.devicePixelRatio,2)),z.shadowMap.enabled=!0,z.shadowMap.type=2,z.toneMapping=4,z.toneMappingExposure=1,fe.appendChild(z.domElement);var B=new ie(z),pe=new f(L,R);B.addPass(pe);var me=new oe(new u(window.innerWidth,window.innerHeight),.1,.1,2);B.addPass(me);var V=new ce;B.addPass(V);var H=new p(R,z.domElement);H.enableDamping=!0,H.dampingFactor=.1,L.environment=new l(z).fromScene(new ee,.04).texture,L.environmentIntensity=.8;var U=new a;L.add(U);var he=new s(2e3,2e3),ge=new t({color:2236962,roughness:.8,metalness:.1}),W=new o(he,ge);W.rotation.x=-Math.PI/2,W.receiveShadow=!0,L.add(W);var G=new n(2e3,100,5592405,3355443);G.material.transparent=!0,G.material.opacity=.5,L.add(G);var K=new ne(100);L.add(K);var q=new ue(16777215,1.5);q.castShadow=!0,q.shadow.mapSize.width=2048,q.shadow.mapSize.height=2048,q.shadow.bias=-5e-4,U.add(q),U.add(q.target);var J=new e(16777215,4473924,.6);J.position.set(0,20,0),U.add(J),b&&b.addEventListener(`change`,()=>{let e=b.checked;D&&D.traverse(t=>{t.isMesh&&t.material&&(Array.isArray(t.material)?t.material.forEach(t=>{t.wireframe=e}):t.material.wireframe=e)})}),x&&h&&(x.addEventListener(`click`,()=>{document.fullscreenElement?document.exitFullscreen().catch(e=>{console.warn(`Error attempting to exit fullscreen: ${e.message}`)}):h.requestFullscreen().catch(e=>{console.warn(`Error attempting to enable fullscreen: ${e.message}`)})}),document.addEventListener(`fullscreenchange`,()=>{setTimeout(()=>window.dispatchEvent(new Event(`resize`)),100)})),S&&S.addEventListener(`click`,()=>{I=!0;let e=S.innerText;S.innerText=`✅`,setTimeout(()=>{S.innerText=e},1e3)});function Y(){O&&(k=!1,O.paused=!0,w&&(w.innerText=`▶ Play`))}function X(e){if(!F||!j[e])return;O&&O.stop();let t=j[e];O=F.clipAction(t),O.play(),O.time=0,F.update(0),k=!0,O.paused=!1,w&&(w.innerText=`⏸ Pause`),E&&(E.value=0)}T&&T.addEventListener(`change`,e=>{X(parseInt(e.target.value))}),w&&w.addEventListener(`click`,()=>{O&&(k=!k,O.paused=!k,w.innerText=k?`⏸ Pause`:`▶ Play`)}),E&&(E.addEventListener(`mousedown`,()=>{A=!0,Y()}),E.addEventListener(`mouseup`,()=>{A=!1}),E.addEventListener(`touchstart`,()=>{A=!0,Y()},{passive:!0}),E.addEventListener(`touchend`,()=>{A=!1},{passive:!0}),E.addEventListener(`input`,e=>{if(Y(),O){let t=O.getClip().duration;O.time=parseFloat(e.target.value)*t,F&&F.update(0)}}));var Z=performance.now();function Q(){requestAnimationFrame(Q);let e=performance.now(),t=(e-Z)/1e3;if(Z=e,F&&(F.update(t),O&&k&&!A)){let e=O.getClip().duration;if(e>0){let t=O.time%e;t<0&&(t+=e),E&&(E.value=t/e)}}H.update();let n=!y||y.checked;if(G.visible=n,K.visible=n,B.render(),I){I=!1;let e=z.domElement.toDataURL(`image/png`);window.parent.postMessage({type:`ADD_IMAGE_TO_CHAT`,dataUrl:e},`*`)}}Q(),window.addEventListener(`resize`,()=>{let e=h?h.clientWidth:window.innerWidth,t=h?h.clientHeight:window.innerHeight;R.aspect=e/t,R.updateProjectionMatrix(),z.setSize(e,t),B.setSize(e,t)});function _e(e,t){if(!e)return new d;e.updateMatrixWorld(!0);let n=new d().setFromObject(e);if(!t||t.length===0)return n;let r=new Map;e.traverse(e=>{r.set(e,{position:e.position.clone(),quaternion:e.quaternion.clone(),scale:e.scale.clone()})});let i=new c(e);for(let r of t){let t=i.clipAction(r);t.play();let a=new Set([0,r.duration]);if(r.tracks){for(let e of r.tracks)if(e.times)for(let t=0;t<e.times.length;t++)a.add(e.times[t])}if(r.duration>0)for(let e=0;e<=20;e++)a.add(e/20*r.duration);let o=Array.from(a).sort((e,t)=>e-t);if(o.length>60){let e=[],t=(o.length-1)/59;for(let n=0;n<60;n++)e.push(o[Math.round(n*t)]);o=e}for(let r of o)t.time=r,i.update(0),e.updateMatrixWorld(!0),n.expandByObject(e);t.stop()}return i.stopAllAction(),i.uncacheRoot(e),r.forEach((e,t)=>{t.position.copy(e.position),t.quaternion.copy(e.quaternion),t.scale.copy(e.scale)}),e.updateMatrixWorld(!0),n}function ve(e){return new Promise((t,n)=>{D&&=(F&&=(F.stopAllAction(),F.uncacheRoot(F.getRoot()),null),O=null,j=[],L.remove(D),D.traverse(e=>{e.isMesh&&(e.geometry.dispose(),Array.isArray(e.material)?e.material.forEach(e=>e.dispose()):e.material.dispose())}),null);let r=e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength);new se().parse(r,``,e=>{D=e.scene,j=e.animations||[];let n=b?b.checked:!1;j.length>0?(F=new c(D),C?(C.style.display=`flex`,T.innerHTML=``,j.forEach((e,t)=>{let n=document.createElement(`option`);n.value=t,n.innerText=e.name||`Animation ${t+1}`,T.appendChild(n)}),X(0)):(j.forEach(e=>{let t=F.clipAction(e);t.play(),t.time=0}),F.update(0))):(C&&(C.style.display=`none`),O=null),D.traverse(e=>{e.isMesh&&(e.castShadow=!0,e.receiveShadow=!0,e.frustumCulled=!1,e.material&&(Array.isArray(e.material)?e.material.forEach(e=>{e.wireframe=n}):e.material.wireframe=n))}),L.add(D),ye(),t()},e=>{console.error(e),n(e)})})}function ye(){if(!D)return;let e=_e(D,j);if(e.isEmpty())return;let t=e.getCenter(new m),n=e.getSize(new m),i=Math.max(n.x,n.y,n.z)||10;W.position.y=e.min.y-.01,G.position.y=W.position.y+.001,K.position.y=W.position.y+.002;let a=R.fov*(Math.PI/180),o=i/(2*Math.tan(a/2));R.aspect<1&&(o/=R.aspect),o*=1.5,R.near=Math.max(.01,i*.01),R.far=Math.max(2e3,o*10),R.updateProjectionMatrix(),H.maxDistance=R.far,R.position.set(t.x+o*.8,t.y+o*.8,t.z-o*.8),R.lookAt(t),H.target.copy(t),H.update(),q.position.set(t.x+i,t.y+i*1.5,t.z-i),q.target.position.copy(t),q.target.updateMatrixWorld();let s=i*1.5;q.shadow.camera.left=-s,q.shadow.camera.right=s,q.shadow.camera.top=s,q.shadow.camera.bottom=-s,q.shadow.camera.near=.1,q.shadow.camera.far=i*5,q.shadow.camera.updateProjectionMatrix(),L.fog=new r(2236962,o*1.5,o*5)}async function be(e){let t={},n=`http://localhost:3000`,r=[];try{let e=await fetch(`${n}/api/scads`);e.ok&&(r=(await e.json()).files||[])}catch{return t}let i=new Set;async function a(e){let o=/(?:include|use)\s*([<"])([^>"]+)([>"])/g,s;for(;(s=o.exec(e))!==null;){let e=s[2],o=e.split(/[/\\]/).pop();if(!i.has(e)&&r.includes(o)){i.add(e);try{let r=await fetch(`${n}/api/scads/${encodeURIComponent(o)}`);if(r.ok){let n=await r.json();t[e]=n.content,await a(n.content)}}catch{console.warn(`Failed to load dependency: ${e}`)}}}}return await a(e),t}async function $(e){if(N){P=e;return}N=!0;try{let t=await be(e);await ve(await ae(e,{wasmUrl:re,additionalFiles:t}))}catch(e){console.error(e)}finally{if(N=!1,P!==null){let e=P;P=null,$(e)}}}window.addEventListener(`message`,async e=>{if(e.data.type===`RENDER_SCAD`){M=e.data.code;let t=M.match(/\/\*\s*Model Name:\s*(.*?)\s*\*\//i);if(t&&t[1]){let e=t[1].trim().replace(/\s+/g,`_`).replace(/[^a-zA-Z0-9_-]/g,``);e&&(g.value=e)}await $(e.data.code)}}),_.addEventListener(`click`,async()=>{let e=g.value.trim();if(!e){alert(`Please enter a filename.`),g.focus();return}let t=`http://localhost:3000`;try{_.innerText=`Checking...`,_.disabled=!0;let n=await fetch(`${t}/api/scads`);if(!n.ok)throw Error(`Could not reach scad-serve.`);let r=await n.json(),i=e.toLowerCase().endsWith(`.scad`)?e:`${e}.scad`;if(r.files&&r.files.includes(i)&&!confirm(`File "${i}" already exists. Overwrite?`)){_.innerText=`Save`,_.disabled=!1;return}_.innerText=`Saving...`;let a=await fetch(`${t}/api/scads`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({filename:e,content:M||``})});if(!a.ok){let e=await a.json();throw Error(e.error||`Save failed.`)}_.innerText=`✅ Saved!`,setTimeout(()=>{_.innerText=`Save`,_.disabled=!1},2e3)}catch(e){console.error(e),alert(`Error saving file: `+e.message),_.innerText=`Save`,_.disabled=!1}});async function xe(e){try{if(typeof CompressionStream<`u`){let t=new Blob([e]).stream().pipeThrough(new CompressionStream(`deflate-raw`)),n=await new Response(t).arrayBuffer(),r=new Uint8Array(n),i=``;for(let e=0;e<r.length;e++)i+=String.fromCharCode(r[e]);return`c`+btoa(i).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}}catch(e){console.warn(`CompressionStream failed, falling back`,e)}return`u`+btoa(unescape(encodeURIComponent(e))).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}v.addEventListener(`click`,async()=>{if(!M){alert(`No model loaded to open.`);return}try{v.disabled=!0,v.innerText=`Preparing...`;let e=`https://iliagrigorevdev.github.io/scad-gltf/#${await xe(M)}`;window.open(e,`_blank`),window.parent.postMessage({type:`CLOSE_PREVIEW`},`*`),v.innerText=`✅ Opened!`,setTimeout(()=>{v.innerText=`Edit`,v.disabled=!1},2e3)}catch(e){console.error(`Error creating editor link`,e),alert(`Error creating editor link: `+e.message),v.innerText=`Edit`,v.disabled=!1}});
|
package/editor/dist/content.css
CHANGED
|
@@ -253,3 +253,51 @@
|
|
|
253
253
|
.scad-primary-btn:hover {
|
|
254
254
|
background: #7a1fd1;
|
|
255
255
|
}
|
|
256
|
+
|
|
257
|
+
.scad-prompt-backend-ui {
|
|
258
|
+
display: block;
|
|
259
|
+
background: #2a2a2a;
|
|
260
|
+
padding: 10px;
|
|
261
|
+
border-radius: 6px;
|
|
262
|
+
border: 1px solid #444;
|
|
263
|
+
margin-bottom: 5px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.scad-prompt-backend-ui-header {
|
|
267
|
+
display: flex;
|
|
268
|
+
justify-content: space-between;
|
|
269
|
+
align-items: center;
|
|
270
|
+
margin-bottom: 5px;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.scad-prompt-backend-ui-title {
|
|
274
|
+
font-size: 12px;
|
|
275
|
+
color: #ccc;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.scad-prompt-backend-connect-btn {
|
|
279
|
+
background: #444;
|
|
280
|
+
color: white;
|
|
281
|
+
border: none;
|
|
282
|
+
padding: 4px 10px;
|
|
283
|
+
border-radius: 4px;
|
|
284
|
+
cursor: pointer;
|
|
285
|
+
font-size: 12px;
|
|
286
|
+
transition: background 0.2s;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.scad-prompt-backend-connect-btn:hover {
|
|
290
|
+
background: #555;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
#scad-prompt-model-select {
|
|
294
|
+
width: 100%;
|
|
295
|
+
background: #1e1e1e;
|
|
296
|
+
color: #fff;
|
|
297
|
+
border: 1px solid #444;
|
|
298
|
+
border-radius: 4px;
|
|
299
|
+
padding: 6px;
|
|
300
|
+
outline: none;
|
|
301
|
+
font-family: inherit;
|
|
302
|
+
display: none;
|
|
303
|
+
}
|
package/editor/dist/content.js
CHANGED
|
@@ -5,7 +5,7 @@ import{i as e,n as t,r as n,t as r}from"./assets/prompt-ui-B9QCNLfJ.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=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.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=`
|
|
9
9
|
<div class="scad-modal-content">
|
|
10
10
|
<div class="scad-modal-header">
|
|
11
11
|
<h3>✨ SCAD Prompt Generator</h3>
|
|
@@ -13,6 +13,16 @@ import{i as e,n as t,r as n,t as r}from"./assets/prompt-ui-B9QCNLfJ.js";console.
|
|
|
13
13
|
</div>
|
|
14
14
|
<p class="scad-help-text">Describe the object you want to generate. The copied prompt will include advanced PBR and Animation rules based on your selection.</p>
|
|
15
15
|
|
|
16
|
+
<div id="scad-prompt-backend-ui" class="scad-prompt-backend-ui">
|
|
17
|
+
<div class="scad-prompt-backend-ui-header">
|
|
18
|
+
<div class="scad-prompt-backend-ui-title">Refine Local Model:</div>
|
|
19
|
+
<button id="scad-prompt-backend-connect" class="scad-prompt-backend-connect-btn">Connect</button>
|
|
20
|
+
</div>
|
|
21
|
+
<select id="scad-prompt-model-select">
|
|
22
|
+
<option value="">-- Select a local model --</option>
|
|
23
|
+
</select>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
16
26
|
<div id="scad-prompt-ui-container"></div>
|
|
17
27
|
|
|
18
28
|
<textarea id="scad-prompt-desc" rows="3" placeholder="e.g. A shiny gold ring with an embedded red gem"></textarea>
|
|
@@ -21,4 +31,11 @@ import{i as e,n as t,r as n,t as r}from"./assets/prompt-ui-B9QCNLfJ.js";console.
|
|
|
21
31
|
<button id="scad-prompt-submit" class="scad-primary-btn">📋 Generate & Paste</button>
|
|
22
32
|
</div>
|
|
23
33
|
</div>
|
|
24
|
-
`,document.body.appendChild(i);let a=document.getElementById(`scad-prompt-ui-container`);a.innerHTML=r,n(a,`scad_prompt_settings`),document.getElementById(`scad-prompt-close`).onclick=()=>i.style.display=`none`,i.onclick=e=>{e.target===i&&(i.style.display=`none`)}
|
|
34
|
+
`,document.body.appendChild(i);let a=document.getElementById(`scad-prompt-ui-container`);a.innerHTML=r,n(a,`scad_prompt_settings`),document.getElementById(`scad-prompt-close`).onclick=()=>i.style.display=`none`,i.onclick=e=>{e.target===i&&(i.style.display=`none`)};let o=document.getElementById(`scad-prompt-backend-connect`),s=document.getElementById(`scad-prompt-model-select`);o&&s&&(o.onclick=async()=>{try{o.innerText=`Connecting...`;let e=await fetch(`http://localhost:3000/api/scads`);if(e.ok){let t=await e.json();t.files&&t.files.length>0?(s.innerHTML=`<option value="">-- Select a local model --</option>`,t.files.forEach(e=>{let t=document.createElement(`option`);t.value=e,t.innerText=e,s.appendChild(t)}),s.style.display=`block`,o.style.display=`none`):(o.innerText=`No Models`,setTimeout(()=>{o.innerText=`Connect`},2e3))}else o.innerText=`Failed`,setTimeout(()=>{o.innerText=`Connect`},2e3)}catch{o.innerText=`Offline`,setTimeout(()=>{o.innerText=`Connect`},2e3)}}),document.getElementById(`scad-prompt-submit`).onclick=async()=>{let n=document.getElementById(`scad-prompt-desc`).value.trim(),r=s?s.value:``;if(!n&&!r){alert(`Please enter a description or select a model!`);return}let o=t(a),c=``;try{if(n&&(c=e(n,o)),r){let e=await fetch(`http://localhost:3000/api/scads/`+encodeURIComponent(r));if(e.ok){let t="```openscad\n"+(await e.json()).content+`
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
`;c?c+=`
|
|
38
|
+
|
|
39
|
+
Reference code:
|
|
40
|
+
`+t:c=t}else throw Error(`Failed to load local model`)}let t=document.querySelector(`ms-prompt-box textarea[formcontrolname="promptText"]`)||document.querySelector(`ms-prompt-box textarea`)||document.querySelector(`textarea`);if(t&&(t.focus(),!document.execCommand(`insertText`,!1,c))){let e=t.value,n=e?e+`
|
|
41
|
+
`+c:c;Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype,`value`).set.call(t,n),t.dispatchEvent(new Event(`input`,{bubbles:!0})),t.dispatchEvent(new Event(`change`,{bubbles:!0}))}await navigator.clipboard.writeText(c),i.style.display=`none`,s&&(s.value=``),t&&t.focus();let a=document.getElementById(`scad-prompt-btn`),l=a.innerText;a.innerText=`✅ Prompt Pasted!`,setTimeout(()=>{a.innerText=l},2e3)}catch(e){console.error(`Error generating/copying prompt:`,e),alert(`Error: `+e.message)}}}function s(e){let t=document.getElementById(`scad-preview-iframe`);if(t){t.querySelector(`iframe`).contentWindow.postMessage({type:`RENDER_SCAD`,code:e},`*`);return}let n=document.createElement(`div`);n.id=`scad-preview-iframe`;let r=document.createElement(`button`);r.innerText=`X`,r.className=`scad-close-btn`,r.onclick=()=>n.remove();let i=document.createElement(`iframe`);i.src=chrome.runtime.getURL(`preview.html`),i.allow=`fullscreen`,i.allowFullscreen=!0,i.setAttribute(`allowfullscreen`,`true`),i.setAttribute(`allow`,`fullscreen`),n.appendChild(r),n.appendChild(i),document.body.appendChild(n),i.onload=()=>{i.contentWindow.postMessage({type:`RENDER_SCAD`,code:e},`*`)}}
|
package/editor/dist/preview.html
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
|
-
<script type="module" crossorigin src="./assets/preview-
|
|
5
|
+
<script type="module" crossorigin src="./assets/preview-CCwT_Mrn.js"></script>
|
|
6
6
|
<link rel="modulepreload" crossorigin href="./assets/OutputPass-B6MrFnGE.js">
|
|
7
|
-
<link rel="stylesheet" crossorigin href="./assets/preview-
|
|
7
|
+
<link rel="stylesheet" crossorigin href="./assets/preview-A6M04CFK.css">
|
|
8
8
|
<link rel="manifest" href="./manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="./registerSW.js"></script></head>
|
|
9
9
|
<body>
|
|
10
10
|
<div id="viewer-container">
|
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
<button id="save-btn">Save</button>
|
|
22
22
|
<button id="open-editor-btn">Edit</button>
|
|
23
23
|
</div>
|
|
24
|
+
<div id="anim-controls" style="display: none">
|
|
25
|
+
<button id="anim-play-btn">⏸ Pause</button>
|
|
26
|
+
<select id="anim-select"></select>
|
|
27
|
+
<input
|
|
28
|
+
type="range"
|
|
29
|
+
id="anim-slider"
|
|
30
|
+
min="0"
|
|
31
|
+
max="1"
|
|
32
|
+
step="0.001"
|
|
33
|
+
value="0"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
24
36
|
<div id="viewer"></div>
|
|
25
37
|
</div>
|
|
26
38
|
</body>
|
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 t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let l={};const o=e=>i(e,t),c={module:{uri:t},exports:l,require:o};s[t]=Promise.all(r.map(e=>c[e]||o(e))).then(e=>(n(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"preview.html",revision:"
|
|
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 t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let l={};const o=e=>i(e,t),c={module:{uri:t},exports:l,require:o};s[t]=Promise.all(r.map(e=>c[e]||o(e))).then(e=>(n(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"402b66900e731ca748771b6fc5e7a068"},{url:"preview.html",revision:"8a9ab9ab63e023395f78103b72aa9c56"},{url:"index.html",revision:"e09c648877bb53e1fc65cfebb5a020af"},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"content.js",revision:"a0ee0962c4c041063d42d1a33eb0b294"},{url:"content.css",revision:"4ea93a2d03164b49c80a48138305e564"},{url:"content-loader.js",revision:"d94f1755552d49c1fe3a6da123e8a346"},{url:"aristea_wreck_puresky_2k.hdr",revision:"e764c66f871ab0987f3fac422edc841d"},{url:"assets/prompt-ui-B9QCNLfJ.js",revision:null},{url:"assets/preview-CCwT_Mrn.js",revision:null},{url:"assets/preview-A6M04CFK.css",revision:null},{url:"assets/openscad-CdBCY4mx.wasm",revision:null},{url:"assets/index-CgVih1C4.js",revision:null},{url:"assets/index-B1KAb97r.css",revision:null},{url:"assets/OutputPass-B6MrFnGE.js",revision:null},{url:"icon.png",revision:"a22007c1fb99682b77960b0d210e273e"},{url:"manifest.webmanifest",revision:"705049c691faa532cc20c736d56d54df"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
|