scad-gltf 0.3.2 → 0.3.3

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/bin/gen.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { runCliApp } from "../src/cli-utils.js";
4
4
  import { getProjectPrompts } from "../src/project-prompts.js";
5
5
 
6
- const VALID_TYPES = ["scad", "bevy", "web", "godot"];
6
+ const VALID_TYPES = ["scad", "bevy", "wgpu", "web", "godot"];
7
7
 
8
8
  async function main() {
9
9
  const projectType = process.argv[2];
@@ -14,7 +14,7 @@ async function main() {
14
14
  `Usage: scad-gltf gen <${VALID_TYPES.join("|")}> "<description>" [options_json]`,
15
15
  );
16
16
  console.error(
17
- `Example: scad-gltf gen godot "A 3D racing game" '{"openaiModel": "gpt-4o"}'`,
17
+ `Example: scad-gltf gen godot "A 3D physics simulation" '{"openaiModel": "gpt-4o"}'`,
18
18
  );
19
19
  process.exit(1);
20
20
  }
package/bin/mcp.js CHANGED
@@ -201,7 +201,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
201
201
  {
202
202
  name: "test_godot_project",
203
203
  description:
204
- "Runs a specified Godot project for a short duration to detect script errors, missing resources, or runtime crashes. Returns the console output logs and a visual screenshot of the gameplay.",
204
+ "Runs a specified Godot project for a short duration to detect script errors, missing resources, or runtime crashes. Returns the console output logs and a visual screenshot of the running project.",
205
205
  inputSchema: {
206
206
  type: "object",
207
207
  properties: {
@@ -793,7 +793,7 @@ func _ready():
793
793
  }
794
794
  fs.writeFileSync(projectGodotPath, tempProjectGodot, "utf8");
795
795
 
796
- // 2. Play Game Step
796
+ // 2. Run Project Step
797
797
  // Always try windowed first to get the screenshot.
798
798
  // If the environment lacks a display server, we'll catch the error and fallback.
799
799
  let playArgs = [
package/bin/play.js CHANGED
@@ -62,7 +62,7 @@ function main() {
62
62
 
63
63
  // 3. Find the resulting project folder and determine its type
64
64
  let projectDir = null;
65
- let projectType = null; // 'godot' | 'web' | 'bevy'
65
+ let projectType = null; // 'godot' | 'web' | 'rust'
66
66
  let latestTime = 0;
67
67
 
68
68
  const items = fs.readdirSync(tempDir);
@@ -71,14 +71,14 @@ function main() {
71
71
  if (fs.statSync(itemPath).isDirectory()) {
72
72
  const isGodot = fs.existsSync(path.join(itemPath, "project.godot"));
73
73
  const isWeb = fs.existsSync(path.join(itemPath, "package.json"));
74
- const isBevy = fs.existsSync(path.join(itemPath, "Cargo.toml"));
74
+ const isRust = fs.existsSync(path.join(itemPath, "Cargo.toml"));
75
75
 
76
- if (isGodot || isWeb || isBevy) {
76
+ if (isGodot || isWeb || isRust) {
77
77
  const mtime = fs.statSync(itemPath).mtimeMs;
78
78
  if (mtime > latestTime) {
79
79
  latestTime = mtime;
80
80
  projectDir = itemPath;
81
- projectType = isGodot ? "godot" : isBevy ? "bevy" : "web";
81
+ projectType = isGodot ? "godot" : isRust ? "rust" : "web";
82
82
  }
83
83
  }
84
84
  }
@@ -87,7 +87,7 @@ function main() {
87
87
  if (!projectDir || !projectType) {
88
88
  console.error("\n❌ Error: Could not find a valid generated project.");
89
89
  console.error(
90
- "The script did not produce a folder containing 'project.godot' or 'package.json'.",
90
+ "The script did not produce a folder containing 'project.godot', 'package.json', or 'Cargo.toml'.",
91
91
  );
92
92
  cleanup();
93
93
  process.exit(1);
@@ -103,7 +103,7 @@ function main() {
103
103
 
104
104
  console.log(`\n⚙️ Importing Godot assets (this may take a moment)...`);
105
105
  try {
106
- // Force Godot to build the .godot/imported cache before attempting to run the game
106
+ // Force Godot to build the .godot/imported cache before attempting to run the project
107
107
  execSync(`"${godotBin}" --headless --editor --quit`, {
108
108
  cwd: projectDir,
109
109
  stdio: "inherit",
@@ -137,9 +137,9 @@ function main() {
137
137
  cwd: projectDir,
138
138
  stdio: "inherit",
139
139
  });
140
- } else if (projectType === "bevy") {
140
+ } else if (projectType === "rust") {
141
141
  console.log(
142
- `\n🦀 Compiling and starting Rust Bevy game (this may take a moment)...`,
142
+ `\n🦀 Compiling and starting Rust project (this may take a moment)...`,
143
143
  );
144
144
  const cargoCmd = process.platform === "win32" ? "cargo.exe" : "cargo";
145
145
  appProcess = spawn(cargoCmd, ["run"], {
package/bin/scad-gltf.js CHANGED
@@ -17,7 +17,7 @@ if (!command || !commands[command]) {
17
17
  console.error(" serve Start local API server and Web Editor");
18
18
  console.error(" mcp Start the Model Context Protocol (MCP) server");
19
19
  console.error(
20
- " gen Automated AI generation of 3D models and game projects",
20
+ " gen Automated AI generation of 3D models, simulations, and interactive projects",
21
21
  );
22
22
  console.error(" play Test and launch generated Node.js scripts");
23
23
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scad-gltf",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
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",
package/src/cli-utils.js CHANGED
@@ -495,8 +495,11 @@ export async function runAutomatedAIFlow(
495
495
  const isBevy =
496
496
  projectType === "bevy" &&
497
497
  fs.existsSync(path.join(itemPath, "Cargo.toml"));
498
+ const isWgpu =
499
+ projectType === "wgpu" &&
500
+ fs.existsSync(path.join(itemPath, "Cargo.toml"));
498
501
 
499
- if (isGodot || isWeb || isBevy) {
502
+ if (isGodot || isWeb || isBevy || isWgpu) {
500
503
  const mtime = fs.statSync(itemPath).mtimeMs;
501
504
  if (mtime > latestTime) {
502
505
  latestTime = mtime;
@@ -511,7 +514,7 @@ export async function runAutomatedAIFlow(
511
514
  const expectedFile =
512
515
  projectType === "godot"
513
516
  ? "project.godot"
514
- : projectType === "bevy"
517
+ : projectType === "bevy" || projectType === "wgpu"
515
518
  ? "Cargo.toml"
516
519
  : "package.json";
517
520
  messages.push({
@@ -554,9 +557,10 @@ export async function runAutomatedAIFlow(
554
557
  });
555
558
 
556
559
  await new Promise((resolve) => setTimeout(resolve, 2000));
557
- } else if (projectType === "bevy") {
560
+ } else if (projectType === "bevy" || projectType === "wgpu") {
561
+ const fwName = projectType === "bevy" ? "Bevy" : "wgpu";
558
562
  console.log(
559
- `\n🦀 Building and running Bevy project: ${path.basename(projectDir)}...`,
563
+ `\n🦀 Building and running ${fwName} project: ${path.basename(projectDir)}...`,
560
564
  );
561
565
  const cargoCmd =
562
566
  process.platform === "win32" ? "cargo.exe" : "cargo";
@@ -670,7 +674,7 @@ export async function runCliApp({
670
674
  );
671
675
  } else {
672
676
  console.error(
673
- ` scad-gltf gen ${projectType} "A simple 3D game" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
677
+ ` scad-gltf gen ${projectType} "A simple 3D simulation" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
674
678
  );
675
679
  }
676
680
  process.exit(1);
@@ -704,7 +708,7 @@ export async function runCliApp({
704
708
  try {
705
709
  const { generatePrompt } = await import("./prompt.js");
706
710
  promptRules = generatePrompt(
707
- isRawScad ? task : "the 3D assets for the game",
711
+ isRawScad ? task : "the 3D assets for the project",
708
712
  options,
709
713
  );
710
714
  } catch (e) {
@@ -22,19 +22,23 @@ CRITICAL WORKFLOW:
22
22
  };
23
23
  }
24
24
 
25
- if (projectType === "bevy") {
25
+ if (projectType === "bevy" || projectType === "wgpu") {
26
+ const isBevy = projectType === "bevy";
27
+ const frameworkName = isBevy ? "Bevy" : "wgpu";
28
+ const depName = isBevy ? "bevy" : "wgpu";
29
+
26
30
  return {
27
31
  buildSystemPrompt: (
28
32
  promptRules,
29
- ) => `You are an expert Rust Bevy engine game developer and procedural 3D technical artist.
33
+ ) => `You are an expert Rust ${frameworkName} developer and procedural 3D technical artist.
30
34
 
31
35
  NAMING CONVENTION REQUIREMENT:
32
36
  - All generated files, directories, models, scripts, and root folders MUST strictly use snake_case (lowercase with underscores, e.g. \`player_character.rs\`, \`enemy_walker.scad\`).
33
37
  - NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
34
38
 
35
39
  What to generate:
36
- 1. 3D Game Assets (.scad):
37
- - Generate procedural 3D models for the game using OpenSCAD.
40
+ 1. 3D Assets (.scad):
41
+ - Generate procedural 3D models for the project using OpenSCAD.
38
42
  - CRITICAL: The SCAD to glTF converter automatically converts OpenSCAD's Z-up coordinate system to the standard glTF Y-up coordinate system. Design your models naturally in OpenSCAD.
39
43
  - CRITICAL: You must use the custom OpenSCAD glTF extensions for PBR materials (e.g., \`roughness\`, \`metalness\`, \`emissive\`) and Hierarchical Node Animations (\`armature()\`, \`bone()\`). The rules and syntax for these features are provided below:
40
44
 
@@ -42,10 +46,10 @@ What to generate:
42
46
  ${promptRules}
43
47
  =============================
44
48
 
45
- 2. Rust Bevy Project Files:
46
- - Create the necessary files for a modern Rust Bevy engine application (e.g., \`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
47
- - In \`Cargo.toml\`, include \`bevy\` as a dependency.
48
- - You MUST include this EXACT \`build.rs\` script at the root of the project to automatically compile the \`.scad\` files into \`.glb\` format inside the \`assets/models\` folder before running the game via Cargo:
49
+ 2. Rust ${frameworkName} Project Files:
50
+ - Create the necessary files for a modern Rust ${frameworkName} application (e.g., \`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
51
+ - In \`Cargo.toml\`, include \`${depName}\` as a dependency.
52
+ - You MUST include this EXACT \`build.rs\` script at the root of the project to automatically compile the \`.scad\` files into \`.glb\` format inside the \`assets/models\` folder before running the application via Cargo:
49
53
  \`\`\`rust
50
54
  use std::process::Command;
51
55
 
@@ -70,7 +74,11 @@ ${promptRules}
70
74
  }
71
75
  }
72
76
  \`\`\`
73
- - Write the core application logic in \`src/main.rs\` to load and display the converted \`.glb\` files interactively. Provide standard Bevy game systems (camera, lights, movement, etc.).
77
+ - Write the core application logic in \`src/main.rs\` to load and display the converted \`.glb\` files interactively.${
78
+ isBevy
79
+ ? " Provide standard Bevy systems (camera, lights, movement, etc.)."
80
+ : ""
81
+ }
74
82
 
75
83
  3. Delivery Format (Single Node.js Script):
76
84
  - Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
@@ -78,10 +86,10 @@ ${promptRules}
78
86
  - When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
79
87
  - The script must embed and write:
80
88
  - Your generated \`.scad\` 3D assets.
81
- - Your generated Rust Bevy project files (\`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
89
+ - Your generated Rust ${frameworkName} project files (\`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
82
90
  - Ensure all string file contents inside the Node.js script are properly escaped.`,
83
91
  buildInputRequest: (task) =>
84
- `Design and implement a Rust Bevy engine game for the following concept: "${task}"`,
92
+ `Design and implement a Rust ${frameworkName} project for the following concept: "${task}"`,
85
93
  allowedTools: ["render_scad_model", "compile_rust_project"],
86
94
  };
87
95
  }
@@ -94,7 +102,7 @@ ${promptRules}
94
102
 
95
103
  What to generate:
96
104
  1. 3D Web Assets (.scad):
97
- - Generate procedural 3D models for the game using OpenSCAD.
105
+ - Generate procedural 3D models for the project using OpenSCAD.
98
106
  - CRITICAL: The SCAD to glTF converter automatically converts OpenSCAD's Z-up coordinate system to the standard glTF Y-up coordinate system. Design your models naturally in OpenSCAD.
99
107
  - CRITICAL: You must use the custom OpenSCAD glTF extensions for PBR materials (e.g., \`roughness\`, \`metalness\`, \`emissive\`) and Hierarchical Node Animations (\`armature()\`, \`bone()\`). The rules and syntax for these features are provided below:
100
108
 
@@ -104,14 +112,14 @@ ${promptRules}
104
112
 
105
113
  2. Vite Web Project Files (npm based):
106
114
  - Create the necessary files for a modern web application (e.g., \`package.json\`, \`index.html\`, \`main.js\`).
107
- - You can use ANY web 3D library with glTF support (e.g., Three.js, Babylon.js, @google/model-viewer, PlayCanvas, A-Frame, etc.) that fits the game's requirements.
115
+ - You can use ANY web 3D library with glTF support (e.g., Three.js, Babylon.js, @google/model-viewer, PlayCanvas, A-Frame, etc.) that fits the project's requirements.
108
116
  - In \`package.json\`, you MUST include the scad to gltf converter tool as a dev dependency:
109
117
  \`"scad-gltf": "^0.3.0"\`
110
118
  - In \`package.json\`, add npm scripts to automatically compile the \`.scad\` files into \`.glb\` format inside the \`public/\` folder before Vite runs its dev or build steps.
111
119
  For example:
112
120
  \`"predev": "scad-gltf convert ./scad ./public/models --cache"\`
113
121
  \`"prebuild": "scad-gltf convert ./scad ./public/models --cache"\`
114
- - Write the core game logic to load and display the converted \`.glb\` files interactively.
122
+ - Write the core application logic to load and display the converted \`.glb\` files interactively.
115
123
 
116
124
  3. Delivery Format (Single Node.js Script):
117
125
  - Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
@@ -122,7 +130,7 @@ ${promptRules}
122
130
  - Your generated Vite web project files.
123
131
  - Ensure all string file contents inside the Node.js script are properly escaped.`,
124
132
  buildInputRequest: (task) =>
125
- `Design and implement a web-based 3D glTF game using Vite for the following concept: "${task}"`,
133
+ `Design and implement a web-based 3D glTF project using Vite for the following concept: "${task}"`,
126
134
  allowedTools: ["render_scad_model"],
127
135
  };
128
136
  }
@@ -133,15 +141,15 @@ ${promptRules}
133
141
  const hasUserScadFiles =
134
142
  Array.isArray(options.scadFiles) && options.scadFiles.length > 0;
135
143
 
136
- const systemPrompt = `You are an expert Godot 4 game developer and procedural 3D technical artist.
144
+ const systemPrompt = `You are an expert Godot 4 developer and procedural 3D technical artist.
137
145
 
138
146
  NAMING CONVENTION REQUIREMENT:
139
147
  - All generated files, directories, models, scripts, scenes, and root folders MUST strictly use snake_case (lowercase with underscores, e.g. \`player_character.gd\`, \`main_scene.tscn\`, \`enemy_walker.scad\`).
140
148
  - NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
141
149
 
142
150
  What to generate:
143
- 1. 3D Game Assets (.scad):
144
- - Generate procedural 3D models for the game using OpenSCAD.
151
+ 1. 3D Assets (.scad):
152
+ - Generate procedural 3D models for the project using OpenSCAD.
145
153
  - Scale & Units: 1 OpenSCAD unit = 1 Godot meter. Design your models using realistic meter-based scales (e.g., a character should be ~1.8 units tall). DO NOT use millimeter-based scaling.
146
154
  - Coordinate System & Forward Convention: Write standard OpenSCAD Z-up code (+Z is UP, XY plane is ground). Build objects standing upright and facing Front (Positive Y-axis).
147
155
  - Left/Right Convention: Always name and position "left" and "right" components (e.g., LeftArm, RightEye) based on the object's anatomical point of view (facing Forward towards +Y), NOT the camera/viewer's screen perspective. Because the object faces +Y, the object's Left side is along the -X axis, and the object's Right side is along the +X axis.
@@ -159,7 +167,7 @@ ${promptRules}
159
167
  =============================
160
168
 
161
169
  2. Godot 4 Project Files:
162
- - Create the necessary GDScript (\`.gd\`) and scene (\`.tscn\`) files to implement the game logic, responsive player input controls, and a core gameplay loop.
170
+ - Create the necessary GDScript (\`.gd\`) and scene (\`.tscn\`) files to implement the project logic, responsive user input controls, and a core interaction loop.
163
171
  - The scenes should directly instance the generated \`.scad\` files (the provided addon will handle importing them as 3D scenes).
164
172
  - GDScript Coordinate, Forward, and Left/Right Conventions:
165
173
  * Forward is -Z: In Godot, \`Vector3.FORWARD\` is \`Vector3(0, 0, -1)\`. A 3D node's local forward direction is \`-transform.basis.z\` (or \`-global_transform.basis.z\`). In character movement, forward input (e.g., W or ui_up) must translate along \`-transform.basis.z\`. Never treat +Z as forward.
@@ -170,14 +178,14 @@ ${promptRules}
170
178
  * Natural Model Alignment: Because OpenSCAD models face +Y (Forward), they automatically import facing Godot's Forward direction (-Z). Built-in Godot methods like \`look_at()\` orient the node's -Z axis toward the target, which perfectly aligns with the model's front. Do NOT apply compensation rotations (e.g., \`rotate_y(PI)\`) in GDScript to compensate for model orientation.
171
179
  - Generate a \`project.godot\` file. It must configure the project and automatically enable the \`scad_importer\` plugin.
172
180
  - Generate a \`.gitignore\` file that ignores the \`.godot/\` folder.
173
- - Generate a \`README.md\` file that documents the project, gameplay mechanics, and controls.
181
+ - Generate a \`README.md\` file that documents the project, mechanics/features, and controls.
174
182
 
175
183
  3. Delivery Format (Single Node.js Script):
176
184
  - Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
177
- - CRITICAL: The generated Node.js script MUST first create a root project folder (named using snake_case with underscores, e.g., \`my_game_project\`) and output all files and folders inside this newly created project folder.
185
+ - CRITICAL: The generated Node.js script MUST first create a root project folder (named using snake_case with underscores, e.g., \`my_project\`) and output all files and folders inside this newly created project folder.
178
186
  - When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
179
187
  - The script must embed and write:
180
- - Your generated \`.scad\` game assets.
188
+ - Your generated \`.scad\` assets.
181
189
  - Your generated Godot project files.
182
190
  - The exact source code of the provided \`addons/scad_importer/*\` files, placed in their correct respective paths.${
183
191
  hasUserScadFiles
@@ -226,7 +234,7 @@ ${promptRules}
226
234
 
227
235
  if (hasUserScadFiles) {
228
236
  systemClipboardOutput += `=== USER PROVIDED OPENSCAD FILES ===\n`;
229
- 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`;
237
+ 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 project logic.\n\n`;
230
238
  for (const file of options.scadFiles) {
231
239
  try {
232
240
  const content = fs
@@ -247,7 +255,7 @@ ${promptRules}
247
255
  return systemClipboardOutput.trimEnd() + "\n";
248
256
  },
249
257
  buildInputRequest: (task) =>
250
- `Design and implement a Godot 4 project for the following game concept: "${task}"`,
258
+ `Design and implement a Godot 4 project for the following concept: "${task}"`,
251
259
  allowedTools: ["render_scad_model", "test_godot_project"],
252
260
  };
253
261
  }