scad-gltf 0.2.4 → 0.3.0
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 +16 -9
- package/bin/{scad-convert.js → convert.js} +1 -1
- package/bin/gen.js +33 -0
- package/bin/{scad-mcp.js → mcp.js} +11 -11
- package/bin/{scad-play.js → play.js} +2 -4
- package/bin/scad-gltf.js +33 -0
- package/bin/{scad-serve.js → serve.js} +1 -1
- package/godot/README.md +3 -3
- package/godot/addons/scad_importer/scad_importer.gd +8 -7
- package/package.json +4 -14
- package/src/cli-utils.js +20 -31
- package/src/project-prompts.js +256 -0
- package/bin/scad-bevy.js +0 -74
- package/bin/scad-gen.js +0 -25
- package/bin/scad-godot.js +0 -140
- package/bin/scad-web.js +0 -51
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ The C++ source code for this custom OpenSCAD version is included directly in thi
|
|
|
23
23
|
- **MCP Server for AI Agents:** Bundled `scad-mcp` server enables MCP clients to iteratively design, compile, and **visually inspect** 3D models via multi-angle headless rendering and animation frame evaluation.
|
|
24
24
|
- **AI Studio Extension:** Chrome extension to natively preview, prompt, take chat snapshots, open in Scadify, and locally save AI-generated 3D models directly inside Google AI Studio.
|
|
25
25
|
- **Godot 4, Rust Bevy & Web Integration:** Native Godot 4 importer addon and Rust Bevy compile-time `build.rs` integration.
|
|
26
|
-
- **Automated AI Generation:** Pass an OpenAI-compatible base URL (and optional API key) to the `scad-
|
|
26
|
+
- **Automated AI Generation:** Pass an OpenAI-compatible base URL (and optional API key) to the `scad-gen` CLI tool to automatically spawn a local MCP server, query the LLM via standard endpoints, allow it to visually iterate, and output a ready-to-run game project or raw 3D asset script.
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -51,7 +51,7 @@ The built-in web editor (**Scadify**) provides a full-featured development envir
|
|
|
51
51
|
This package is designed to be installed directly from GitHub.
|
|
52
52
|
|
|
53
53
|
**Option 1: Global Installation (Recommended for CLI usage)**
|
|
54
|
-
If you plan to use the `scad-convert`, `scad-serve`, or `scad-mcp` command-line tools anywhere on your system:
|
|
54
|
+
If you plan to use the `scad-convert`, `scad-serve`, `scad-gen`, or `scad-mcp` command-line tools anywhere on your system:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
57
|
npm install -g scad-gltf
|
|
@@ -261,7 +261,7 @@ Instead of generating code blindly, the AI can compile its script, render the 3D
|
|
|
261
261
|
|
|
262
262
|
- `get_scad_prompt`: Injects the custom OpenSCAD syntax rules (PBR, animations, baking) into the AI's context.
|
|
263
263
|
- `render_scad_model`: Compiles the generated `.scad` code to GLB and returns base64 images from requested camera angles (front, back, left, right, top, bottom, isometric) and specific animation keyframes.
|
|
264
|
-
- `
|
|
264
|
+
- `compile_rust_project` / `test_godot_project`: Tests the generated game projects for compilation and runtime errors.
|
|
265
265
|
|
|
266
266
|
### Setup
|
|
267
267
|
|
|
@@ -295,7 +295,14 @@ The addon allows you to drag-and-drop `.scad` files directly into your Godot pro
|
|
|
295
295
|
|
|
296
296
|
### Automated AI Generation (OpenAI-Compatible API)
|
|
297
297
|
|
|
298
|
-
By default, `scad-
|
|
298
|
+
By default, the `scad-gen` utility copies a heavily engineered system prompt to your clipboard to paste into an LLM. However, if you provide a **Base URL** (and optional **API Key**), the CLI will fully automate this process. It will automatically spin up the `scad-mcp` server in the background, connect it to your LLM, and allow the AI to _visually evaluate and fix_ its code in real-time before saving the final `generate_project.js` script to your disk.
|
|
299
|
+
|
|
300
|
+
**Supported Generation Types:**
|
|
301
|
+
|
|
302
|
+
- `gen`: Generate a single raw `.scad` asset file.
|
|
303
|
+
- `godot`: Generate a fully packaged Godot 4 game project containing generated assets and GDScript logic.
|
|
304
|
+
- `bevy`: Generate a Rust Bevy game project.
|
|
305
|
+
- `web`: Generate a Vite-based Web3D app (Three.js/Babylon).
|
|
299
306
|
|
|
300
307
|
**Option 1: Using OpenAI (GPT-4o)**
|
|
301
308
|
|
|
@@ -303,7 +310,7 @@ By default, `scad-godot`, `scad-bevy`, and `scad-web` copy a heavily engineered
|
|
|
303
310
|
export OPENAI_BASE_URL="https://api.openai.com/v1"
|
|
304
311
|
export OPENAI_API_KEY="sk-..."
|
|
305
312
|
export OPENAI_MODEL="gpt-4o"
|
|
306
|
-
scad-bevy "A 3D spaceship shooter game"
|
|
313
|
+
scad-gen bevy "A 3D spaceship shooter game"
|
|
307
314
|
```
|
|
308
315
|
|
|
309
316
|
**Option 2: Using Google Gemini (via OpenAI compatibility)**
|
|
@@ -313,7 +320,7 @@ Because Gemini provides an official OpenAI-compatible endpoint, you can configur
|
|
|
313
320
|
export OPENAI_API_KEY="AIzaSy..."
|
|
314
321
|
export OPENAI_BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai/"
|
|
315
322
|
export OPENAI_MODEL="gemini-3.8-flash"
|
|
316
|
-
scad-godot "A fast-paced 3D hovercraft racing game"
|
|
323
|
+
scad-gen godot "A fast-paced 3D hovercraft racing game"
|
|
317
324
|
```
|
|
318
325
|
|
|
319
326
|
**Option 3: Using Local Server**
|
|
@@ -322,17 +329,17 @@ You can use completely local, uncensored, or fine-tuned vision models by overrid
|
|
|
322
329
|
```bash
|
|
323
330
|
export OPENAI_BASE_URL="http://127.0.0.1:8080/v1"
|
|
324
331
|
export OPENAI_MODEL="llama-3" # Or whatever model name you've loaded
|
|
325
|
-
scad-web "A 3D configurator app"
|
|
332
|
+
scad-gen web "A 3D configurator app"
|
|
326
333
|
```
|
|
327
334
|
|
|
328
335
|
**Passing Parameters via JSON**
|
|
329
336
|
You can also pass credentials inline as a JSON string argument instead of modifying environment variables:
|
|
330
337
|
|
|
331
338
|
```bash
|
|
332
|
-
scad-godot "A futuristic tank game" '{"openaiBaseUrl": "http://127.0.0.1:8080/v1", "openaiModel": "llama-3"}'
|
|
339
|
+
scad-gen godot "A futuristic tank game" '{"openaiBaseUrl": "http://127.0.0.1:8080/v1", "openaiModel": "llama-3"}'
|
|
333
340
|
```
|
|
334
341
|
|
|
335
|
-
_Once the automated process completes, simply run the generated Node.js script to assemble your complete Godot, Bevy, or Vite project structure with all assets and code!_
|
|
342
|
+
_Once the automated process completes for full game projects, simply run the generated Node.js script to assemble your complete Godot, Bevy, or Vite project structure with all assets and code!_
|
|
336
343
|
|
|
337
344
|
```bash
|
|
338
345
|
node generate_godot_project.js
|
|
@@ -62,7 +62,7 @@ async function run() {
|
|
|
62
62
|
|
|
63
63
|
if (!inputPath || !outputPath) {
|
|
64
64
|
console.error(
|
|
65
|
-
"Usage: scad-convert <input.scad | input_dir> <output.glb | output_dir> [options_json] [--cache]",
|
|
65
|
+
"Usage: scad-gltf convert <input.scad | input_dir> <output.glb | output_dir> [options_json] [--cache]",
|
|
66
66
|
);
|
|
67
67
|
process.exit(1);
|
|
68
68
|
}
|
package/bin/gen.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { runCliApp } from "../src/cli-utils.js";
|
|
4
|
+
import { getProjectPrompts } from "../src/project-prompts.js";
|
|
5
|
+
|
|
6
|
+
const VALID_TYPES = ["scad", "bevy", "web", "godot"];
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
const projectType = process.argv[2];
|
|
10
|
+
|
|
11
|
+
if (!projectType || !VALID_TYPES.includes(projectType)) {
|
|
12
|
+
console.error(`Error: Invalid or missing project type.`);
|
|
13
|
+
console.error(
|
|
14
|
+
`Usage: scad-gltf gen <${VALID_TYPES.join("|")}> "<description>" [options_json]`,
|
|
15
|
+
);
|
|
16
|
+
console.error(
|
|
17
|
+
`Example: scad-gltf gen godot "A 3D racing game" '{"openaiModel": "gpt-4o"}'`,
|
|
18
|
+
);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await runCliApp({
|
|
23
|
+
projectType,
|
|
24
|
+
...getProjectPrompts(projectType),
|
|
25
|
+
argStartIndex: 3, // Shift arg parsing right by 1 since projectType is at index 2
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Execute and handle unhandled runtime errors
|
|
30
|
+
main().catch((err) => {
|
|
31
|
+
console.error("An unexpected error occurred:", err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
@@ -229,9 +229,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
229
229
|
},
|
|
230
230
|
},
|
|
231
231
|
{
|
|
232
|
-
name: "
|
|
232
|
+
name: "compile_rust_project",
|
|
233
233
|
description:
|
|
234
|
-
"Compiles a specified Rust
|
|
234
|
+
"Compiles a specified Rust project to detect syntax errors, missing dependencies, or compilation failures. Returns the cargo console output logs.",
|
|
235
235
|
inputSchema: {
|
|
236
236
|
type: "object",
|
|
237
237
|
properties: {
|
|
@@ -243,7 +243,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
243
243
|
nodejs_script: {
|
|
244
244
|
type: "string",
|
|
245
245
|
description:
|
|
246
|
-
"The complete self-contained Node.js script that generates the
|
|
246
|
+
"The complete self-contained Node.js script that generates the Rust project. If provided, the tool will execute this script in a temporary directory to extract the project before compiling it. Use this during the generation phase to test your code before providing the final answer.",
|
|
247
247
|
},
|
|
248
248
|
},
|
|
249
249
|
},
|
|
@@ -946,9 +946,9 @@ func _ready():
|
|
|
946
946
|
}
|
|
947
947
|
|
|
948
948
|
// ------------------------------------------
|
|
949
|
-
// TOOL 4:
|
|
949
|
+
// TOOL 4: compile_rust_project
|
|
950
950
|
// ------------------------------------------
|
|
951
|
-
if (name === "
|
|
951
|
+
if (name === "compile_rust_project") {
|
|
952
952
|
let cleanupDir = null;
|
|
953
953
|
try {
|
|
954
954
|
let projectDir = null;
|
|
@@ -956,7 +956,7 @@ func _ready():
|
|
|
956
956
|
if (args.nodejs_script) {
|
|
957
957
|
// Create a unique temporary directory
|
|
958
958
|
const tempBase = fs.mkdtempSync(
|
|
959
|
-
path.join(os.tmpdir(), "scad-
|
|
959
|
+
path.join(os.tmpdir(), "scad-rust-compile-"),
|
|
960
960
|
);
|
|
961
961
|
cleanupDir = tempBase;
|
|
962
962
|
|
|
@@ -1001,7 +1001,7 @@ func _ready():
|
|
|
1001
1001
|
content: [
|
|
1002
1002
|
{
|
|
1003
1003
|
type: "text",
|
|
1004
|
-
text: `Error: The Node.js script finished running, but NO
|
|
1004
|
+
text: `Error: The Node.js script finished running, but NO Rust project was found. A valid Rust project requires a 'Cargo.toml' file. Ensure your script creates a root project directory and places 'Cargo.toml' inside it.`,
|
|
1005
1005
|
},
|
|
1006
1006
|
],
|
|
1007
1007
|
isError: true,
|
|
@@ -1026,7 +1026,7 @@ func _ready():
|
|
|
1026
1026
|
content: [
|
|
1027
1027
|
{
|
|
1028
1028
|
type: "text",
|
|
1029
|
-
text: `Error: The specified directory is not a valid Rust
|
|
1029
|
+
text: `Error: The specified directory is not a valid Rust project. 'Cargo.toml' was not found in: ${projectDir}`,
|
|
1030
1030
|
},
|
|
1031
1031
|
],
|
|
1032
1032
|
isError: true,
|
|
@@ -1055,7 +1055,7 @@ func _ready():
|
|
|
1055
1055
|
resolve({ code, output });
|
|
1056
1056
|
});
|
|
1057
1057
|
|
|
1058
|
-
// 2-minute timeout for
|
|
1058
|
+
// 2-minute timeout for Rust compilation (can be slow as dependencies download)
|
|
1059
1059
|
setTimeout(() => {
|
|
1060
1060
|
try {
|
|
1061
1061
|
child.kill();
|
|
@@ -1115,7 +1115,7 @@ func _ready():
|
|
|
1115
1115
|
content: [
|
|
1116
1116
|
{
|
|
1117
1117
|
type: "text",
|
|
1118
|
-
text: `Error compiling
|
|
1118
|
+
text: `Error compiling Rust project: ${error.message}`,
|
|
1119
1119
|
},
|
|
1120
1120
|
],
|
|
1121
1121
|
isError: true,
|
|
@@ -1138,7 +1138,7 @@ func _ready():
|
|
|
1138
1138
|
async function main() {
|
|
1139
1139
|
const transport = new StdioServerTransport();
|
|
1140
1140
|
await server.connect(transport);
|
|
1141
|
-
console.error("🚀
|
|
1141
|
+
console.error("🚀 scad-gltf mcp server running on stdio");
|
|
1142
1142
|
}
|
|
1143
1143
|
|
|
1144
1144
|
main().catch((error) => {
|
|
@@ -13,9 +13,7 @@ function main() {
|
|
|
13
13
|
console.error(
|
|
14
14
|
"❌ Error: Path to the packed Node.js generator script is required.",
|
|
15
15
|
);
|
|
16
|
-
console.error(
|
|
17
|
-
"Usage: node bin/scad-play.js <path_to_generated_project.js>",
|
|
18
|
-
);
|
|
16
|
+
console.error("Usage: scad-gltf play <path_to_generated_project.js>");
|
|
19
17
|
process.exit(1);
|
|
20
18
|
}
|
|
21
19
|
|
|
@@ -64,7 +62,7 @@ function main() {
|
|
|
64
62
|
|
|
65
63
|
// 3. Find the resulting project folder and determine its type
|
|
66
64
|
let projectDir = null;
|
|
67
|
-
let projectType = null; // 'godot' | 'web'
|
|
65
|
+
let projectType = null; // 'godot' | 'web' | 'bevy'
|
|
68
66
|
let latestTime = 0;
|
|
69
67
|
|
|
70
68
|
const items = fs.readdirSync(tempDir);
|
package/bin/scad-gltf.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
|
|
5
|
+
const commands = {
|
|
6
|
+
convert: "./convert.js",
|
|
7
|
+
serve: "./serve.js",
|
|
8
|
+
mcp: "./mcp.js",
|
|
9
|
+
gen: "./gen.js",
|
|
10
|
+
play: "./play.js",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
if (!command || !commands[command]) {
|
|
14
|
+
console.error("Usage: scad-gltf <command> [options]");
|
|
15
|
+
console.error("\nAvailable commands:");
|
|
16
|
+
console.error(" convert Convert .scad files to .glb binaries");
|
|
17
|
+
console.error(" serve Start local API server and Web Editor");
|
|
18
|
+
console.error(" mcp Start the Model Context Protocol (MCP) server");
|
|
19
|
+
console.error(
|
|
20
|
+
" gen Automated AI generation of 3D models and game projects",
|
|
21
|
+
);
|
|
22
|
+
console.error(" play Test and launch generated Node.js scripts");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Remove the subcommand from argv so the delegated scripts parse indices exactly as they did before
|
|
27
|
+
process.argv.splice(2, 1);
|
|
28
|
+
|
|
29
|
+
// Dynamically import the requested command script
|
|
30
|
+
import(commands[command]).catch((err) => {
|
|
31
|
+
console.error(`Failed to execute command '${command}':`, err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
@@ -217,7 +217,7 @@ if (fs.existsSync(editorDistDir)) {
|
|
|
217
217
|
|
|
218
218
|
// Start Server
|
|
219
219
|
app.listen(port, () => {
|
|
220
|
-
console.log(`🚀 scad-serve listening on http://localhost:${port}`);
|
|
220
|
+
console.log(`🚀 scad-gltf serve listening on http://localhost:${port}`);
|
|
221
221
|
if (fs.existsSync(editorDistDir)) {
|
|
222
222
|
console.log(`🌐 Editor available at: http://localhost:${port}/`);
|
|
223
223
|
}
|
package/godot/README.md
CHANGED
|
@@ -10,7 +10,7 @@ By leveraging the `scad-gltf` compiler under the hood, this addon allows you to
|
|
|
10
10
|
- **Advanced Materials**: Supports standard OpenSCAD plus custom extensions for roughness, metalness, transmission, emission, and more.
|
|
11
11
|
- **Hierarchical Node Animations**: Automatically parses `armature()` and `bone()` modules into Godot `Node3D` transform hierarchies animated via `AnimationPlayer` (rigid-body hierarchy animation, ideal for mechanical and articulated models).
|
|
12
12
|
- **Dependency Tracking**: Smart resolution of local `include` and `use` OpenSCAD dependencies.
|
|
13
|
-
- **Auto-Fallback Engine**: Attempts to use the high-performance CLI compiler (`scad-convert`) and seamlessly falls back to the HTTP backend (`scad-serve`) if running in a restricted environment.
|
|
13
|
+
- **Auto-Fallback Engine**: Attempts to use the high-performance CLI compiler (`scad-gltf convert`) and seamlessly falls back to the HTTP backend (`scad-gltf serve`) if running in a restricted environment.
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -42,7 +42,7 @@ When you import or reimport a `.scad` file, the plugin will attempt to compile i
|
|
|
42
42
|
|
|
43
43
|
### 1. CLI Mode (Default)
|
|
44
44
|
|
|
45
|
-
The plugin will try to execute the `scad-convert` CLI command natively through your operating system. This requires the `scad-gltf` package to be installed globally (as shown in Prerequisites). This is the fastest and recommended method for Windows, macOS, and Linux desktops.
|
|
45
|
+
The plugin will try to execute the `scad-gltf convert` CLI command natively through your operating system. This requires the `scad-gltf` package to be installed globally (as shown in Prerequisites). This is the fastest and recommended method for Windows, macOS, and Linux desktops.
|
|
46
46
|
|
|
47
47
|
### 2. Server Fallback Mode (Termux / Android / Portable)
|
|
48
48
|
|
|
@@ -53,7 +53,7 @@ It will look for a local backend server running on `127.0.0.1:3000`. To use this
|
|
|
53
53
|
1. Open your terminal in your project directory.
|
|
54
54
|
2. Run the server using `npx`:
|
|
55
55
|
```bash
|
|
56
|
-
npx
|
|
56
|
+
npx scad-gltf serve
|
|
57
57
|
```
|
|
58
58
|
3. Leave the server running in the background. Godot will now send your `.scad` code to this local server, compile it in memory, and import the resulting 3D mesh.
|
|
59
59
|
|
|
@@ -16,27 +16,28 @@ func _import_scene(path: String, flags: int, options: Dictionary) -> Object:
|
|
|
16
16
|
var temp_glb_path = ProjectSettings.globalize_path("user://scad_cache_" + unique_id + ".glb")
|
|
17
17
|
|
|
18
18
|
var args = PackedStringArray()
|
|
19
|
+
args.append("convert")
|
|
19
20
|
args.append(global_source)
|
|
20
21
|
args.append(temp_glb_path)
|
|
21
22
|
|
|
22
23
|
var output = []
|
|
23
|
-
print("Importing %s via scad-
|
|
24
|
+
print("Importing %s via scad-gltf..." % path.get_file())
|
|
24
25
|
|
|
25
26
|
var exit_code = -1
|
|
26
27
|
if OS.get_name() == "Windows":
|
|
27
|
-
var win_args = PackedStringArray(["/c", "scad-
|
|
28
|
+
var win_args = PackedStringArray(["/c", "scad-gltf"])
|
|
28
29
|
win_args.append_array(args)
|
|
29
30
|
exit_code = OS.execute("cmd.exe", win_args, output, true)
|
|
30
31
|
else:
|
|
31
|
-
exit_code = OS.execute("scad-
|
|
32
|
+
exit_code = OS.execute("scad-gltf", args, output, true)
|
|
32
33
|
|
|
33
34
|
if exit_code != 0:
|
|
34
|
-
print("scad-convert
|
|
35
|
+
print("scad-gltf convert failed for %s. Attempting fallback to local scad-gltf serve..." % path.get_file())
|
|
35
36
|
var fallback_success = _try_scad_serve_fallback(global_source, temp_glb_path)
|
|
36
37
|
|
|
37
38
|
if not fallback_success:
|
|
38
|
-
push_error("Failed to compile SCAD file: %s. Ensure Node.js is installed or scad-serve is running." % path.get_file())
|
|
39
|
-
push_error("scad-convert output: ", "\n".join(output))
|
|
39
|
+
push_error("Failed to compile SCAD file: %s. Ensure Node.js is installed or scad-gltf serve is running." % path.get_file())
|
|
40
|
+
push_error("scad-gltf convert output: ", "\n".join(output))
|
|
40
41
|
return null
|
|
41
42
|
|
|
42
43
|
var gltf_doc = GLTFDocument.new()
|
|
@@ -194,7 +195,7 @@ func _try_scad_serve_fallback(source_path: String, out_glb_path: String) -> bool
|
|
|
194
195
|
out_file.store_buffer(rb)
|
|
195
196
|
out_file.close()
|
|
196
197
|
|
|
197
|
-
print("Successfully compiled %s using scad-serve fallback." % source_path.get_file())
|
|
198
|
+
print("Successfully compiled %s using scad-gltf serve fallback." % source_path.get_file())
|
|
198
199
|
return true
|
|
199
200
|
|
|
200
201
|
return false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scad-gltf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -32,14 +32,7 @@
|
|
|
32
32
|
"editor/dist"
|
|
33
33
|
],
|
|
34
34
|
"bin": {
|
|
35
|
-
"scad-
|
|
36
|
-
"scad-serve": "./bin/scad-serve.js",
|
|
37
|
-
"scad-mcp": "./bin/scad-mcp.js",
|
|
38
|
-
"scad-godot": "./bin/scad-godot.js",
|
|
39
|
-
"scad-web": "./bin/scad-web.js",
|
|
40
|
-
"scad-bevy": "./bin/scad-bevy.js",
|
|
41
|
-
"scad-gen": "./bin/scad-gen.js",
|
|
42
|
-
"scad-play": "./bin/scad-play.js"
|
|
35
|
+
"scad-gltf": "./bin/scad-gltf.js"
|
|
43
36
|
},
|
|
44
37
|
"exports": {
|
|
45
38
|
".": "./src/ext/openscad.js",
|
|
@@ -51,10 +44,8 @@
|
|
|
51
44
|
},
|
|
52
45
|
"scripts": {
|
|
53
46
|
"format": "prettier --write .",
|
|
54
|
-
"mcp": "npx @modelcontextprotocol/inspector node ./bin/
|
|
55
|
-
"prepublishOnly": "npm install --prefix editor && npm run build --prefix editor"
|
|
56
|
-
"build:godot": "node scripts/build-godot-web.js",
|
|
57
|
-
"deploy:godot": "gh-pages -d .godot-dist --repo git@github.com:iliagrigorevdev/scad-godot.git -b gh-pages"
|
|
47
|
+
"mcp": "npx @modelcontextprotocol/inspector node ./bin/mcp.js",
|
|
48
|
+
"prepublishOnly": "npm install --prefix editor && npm run build --prefix editor"
|
|
58
49
|
},
|
|
59
50
|
"dependencies": {
|
|
60
51
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -63,7 +54,6 @@
|
|
|
63
54
|
"puppeteer": "^25.9.0"
|
|
64
55
|
},
|
|
65
56
|
"devDependencies": {
|
|
66
|
-
"gh-pages": "^6.3.0",
|
|
67
57
|
"prettier": "3.9.6"
|
|
68
58
|
}
|
|
69
59
|
}
|
package/src/cli-utils.js
CHANGED
|
@@ -19,7 +19,7 @@ export function hasStdinData() {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function parseTaskAndOptions() {
|
|
22
|
+
export function parseTaskAndOptions(startIndex = 2) {
|
|
23
23
|
let task = "";
|
|
24
24
|
let optionsStr = "{}";
|
|
25
25
|
|
|
@@ -29,10 +29,10 @@ export function parseTaskAndOptions() {
|
|
|
29
29
|
} catch (e) {
|
|
30
30
|
console.error("Error reading from STDIN:", e);
|
|
31
31
|
}
|
|
32
|
-
if (process.argv[
|
|
32
|
+
if (process.argv[startIndex]) optionsStr = process.argv[startIndex];
|
|
33
33
|
} else {
|
|
34
|
-
if (process.argv[
|
|
35
|
-
if (process.argv[
|
|
34
|
+
if (process.argv[startIndex]) task = process.argv[startIndex];
|
|
35
|
+
if (process.argv[startIndex + 1]) optionsStr = process.argv[startIndex + 1];
|
|
36
36
|
}
|
|
37
37
|
return { task, optionsStr };
|
|
38
38
|
}
|
|
@@ -145,7 +145,7 @@ export async function runAutomatedAIFlow(
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
const outputFilename = `generate_${projectType}_project.js`;
|
|
148
|
-
const isRawScad = projectType === "
|
|
148
|
+
const isRawScad = projectType === "scad";
|
|
149
149
|
const modelTag = modelName ? ` (${modelName})` : "";
|
|
150
150
|
|
|
151
151
|
console.log(`\n🚀 Starting automated AI generation${modelTag}...`);
|
|
@@ -163,7 +163,7 @@ export async function runAutomatedAIFlow(
|
|
|
163
163
|
console.log("🔌 Starting local SCAD MCP server...");
|
|
164
164
|
mcpTransport = new mcpClientStdio.StdioClientTransport({
|
|
165
165
|
command: process.execPath,
|
|
166
|
-
args: [path.resolve(__dirname, "../bin/
|
|
166
|
+
args: [path.resolve(__dirname, "../bin/mcp.js")],
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
mcpClient = new mcpClientIndex.Client(
|
|
@@ -460,7 +460,7 @@ export async function runAutomatedAIFlow(
|
|
|
460
460
|
`\n🌐 Starting local viewer to preview ${extractedFilename}...`,
|
|
461
461
|
);
|
|
462
462
|
|
|
463
|
-
const scadServePath = path.resolve(__dirname, "../bin/
|
|
463
|
+
const scadServePath = path.resolve(__dirname, "../bin/serve.js");
|
|
464
464
|
runProc = spawn(process.execPath, [scadServePath], {
|
|
465
465
|
cwd: tempDir,
|
|
466
466
|
stdio: "inherit",
|
|
@@ -645,43 +645,32 @@ export async function runCliApp({
|
|
|
645
645
|
buildSystemPrompt,
|
|
646
646
|
buildInputRequest,
|
|
647
647
|
allowedTools = ["render_scad_model"],
|
|
648
|
+
argStartIndex = 2,
|
|
648
649
|
}) {
|
|
649
650
|
if (!projectType) {
|
|
650
651
|
throw new Error("projectType is required.");
|
|
651
652
|
}
|
|
652
653
|
|
|
653
|
-
const
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
const { task, optionsStr } = parseTaskAndOptions();
|
|
654
|
+
const isRawScad = projectType === "scad";
|
|
655
|
+
const { task, optionsStr } = parseTaskAndOptions(argStartIndex);
|
|
657
656
|
|
|
658
657
|
if (!task) {
|
|
659
658
|
console.error("Error: Task parameter is required.");
|
|
659
|
+
console.error(
|
|
660
|
+
`Usage: scad-gltf gen ${projectType} "<description>" [options_json]`,
|
|
661
|
+
);
|
|
662
|
+
console.error(
|
|
663
|
+
` or: echo "<description>" | scad-gltf gen ${projectType} [options_json]`,
|
|
664
|
+
);
|
|
665
|
+
console.error("");
|
|
666
|
+
console.error("Examples with JSON options (Automated AI flow):");
|
|
660
667
|
if (isRawScad) {
|
|
661
668
|
console.error(
|
|
662
|
-
`
|
|
663
|
-
);
|
|
664
|
-
console.error(` or: echo "<description>" | ${appName} [options_json]`);
|
|
665
|
-
console.error("");
|
|
666
|
-
console.error("Examples with JSON options (Automated AI flow):");
|
|
667
|
-
console.error(
|
|
668
|
-
` ${appName} "A modular sci-fi corridor piece" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
|
|
669
|
-
);
|
|
670
|
-
console.error(
|
|
671
|
-
` ${appName} "A medieval longsword" '{"openaiBaseUrl": "http://127.0.0.1:8080/v1", "openaiModel": "llama-3"}'`,
|
|
669
|
+
` scad-gltf gen ${projectType} "A modular sci-fi corridor piece" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
|
|
672
670
|
);
|
|
673
671
|
} else {
|
|
674
672
|
console.error(
|
|
675
|
-
`
|
|
676
|
-
);
|
|
677
|
-
console.error(` or: echo "<description>" | ${appName} [options_json]`);
|
|
678
|
-
console.error("");
|
|
679
|
-
console.error("Examples with JSON options (Automated AI flow):");
|
|
680
|
-
console.error(
|
|
681
|
-
` ${appName} "A simple 3D game" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
|
|
682
|
-
);
|
|
683
|
-
console.error(
|
|
684
|
-
` ${appName} "A simple 3D game" '{"openaiBaseUrl": "http://127.0.0.1:8080/v1", "openaiModel": "llama-3"}'`,
|
|
673
|
+
` scad-gltf gen ${projectType} "A simple 3D game" '{"openaiApiKey": "sk-...", "openaiModel": "gpt-4o"}'`,
|
|
685
674
|
);
|
|
686
675
|
}
|
|
687
676
|
process.exit(1);
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import url from "node:url";
|
|
4
|
+
|
|
5
|
+
const __filename = url.fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
const DIR = path.resolve(__dirname, "..");
|
|
8
|
+
|
|
9
|
+
export function getProjectPrompts(projectType) {
|
|
10
|
+
if (projectType === "scad") {
|
|
11
|
+
return {
|
|
12
|
+
buildSystemPrompt: () =>
|
|
13
|
+
`You are an expert procedural 3D technical artist and OpenSCAD developer.
|
|
14
|
+
Your goal is to generate a single OpenSCAD (.scad) file based on the user's request.
|
|
15
|
+
|
|
16
|
+
CRITICAL WORKFLOW:
|
|
17
|
+
1. Write the OpenSCAD code using the custom syntax rules provided in the request.
|
|
18
|
+
2. Call the \`render_scad_model\` tool with your code to visually verify your design.
|
|
19
|
+
3. If the model looks incorrect, adjust your code and re-render. Iterate until perfect.
|
|
20
|
+
4. Provide your final OpenSCAD code in a standard markdown block (\`\`\`openscad).`,
|
|
21
|
+
allowedTools: ["render_scad_model"],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (projectType === "bevy") {
|
|
26
|
+
return {
|
|
27
|
+
buildSystemPrompt: (
|
|
28
|
+
promptRules,
|
|
29
|
+
) => `You are an expert Rust Bevy engine game developer and procedural 3D technical artist.
|
|
30
|
+
|
|
31
|
+
NAMING CONVENTION REQUIREMENT:
|
|
32
|
+
- 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
|
+
- NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
|
|
34
|
+
|
|
35
|
+
What to generate:
|
|
36
|
+
1. 3D Game Assets (.scad):
|
|
37
|
+
- Generate procedural 3D models for the game using OpenSCAD.
|
|
38
|
+
- 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
|
+
- 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
|
+
|
|
41
|
+
=== OPENSCAD SYNTAX RULES ===
|
|
42
|
+
${promptRules}
|
|
43
|
+
=============================
|
|
44
|
+
|
|
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
|
+
\`\`\`rust
|
|
50
|
+
use std::process::Command;
|
|
51
|
+
|
|
52
|
+
fn main() {
|
|
53
|
+
// Tell Cargo to re-run this script only if the 'scad' directory changes
|
|
54
|
+
println!("cargo::rerun-if-changed=scad");
|
|
55
|
+
|
|
56
|
+
// Ensure cross-platform compatibility for npm global binaries
|
|
57
|
+
let cmd = if cfg!(target_os = "windows") {
|
|
58
|
+
"scad-gltf.cmd"
|
|
59
|
+
} else {
|
|
60
|
+
"scad-gltf"
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
let status = Command::new(cmd)
|
|
64
|
+
.args(["convert", "./scad", "./assets/models", "--cache"])
|
|
65
|
+
.status()
|
|
66
|
+
.expect("Failed to execute scad-gltf. Is scad-gltf installed globally?");
|
|
67
|
+
|
|
68
|
+
if !status.success() {
|
|
69
|
+
panic!("scad-gltf convert failed with status: {}", status);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
\`\`\`
|
|
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.).
|
|
74
|
+
|
|
75
|
+
3. Delivery Format (Single Node.js Script):
|
|
76
|
+
- Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
|
|
77
|
+
- CRITICAL: The generated Node.js script MUST first create a root project folder (named using a slugified version of the project name) and output all files and folders inside this newly created project folder.
|
|
78
|
+
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
79
|
+
- The script must embed and write:
|
|
80
|
+
- Your generated \`.scad\` 3D assets.
|
|
81
|
+
- Your generated Rust Bevy project files (\`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
|
|
82
|
+
- Ensure all string file contents inside the Node.js script are properly escaped.`,
|
|
83
|
+
buildInputRequest: (task) =>
|
|
84
|
+
`Design and implement a Rust Bevy engine game for the following concept: "${task}"`,
|
|
85
|
+
allowedTools: ["render_scad_model", "compile_bevy_project"],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (projectType === "web") {
|
|
90
|
+
return {
|
|
91
|
+
buildSystemPrompt: (
|
|
92
|
+
promptRules,
|
|
93
|
+
) => `You are an expert Web 3D developer and procedural 3D technical artist.
|
|
94
|
+
|
|
95
|
+
What to generate:
|
|
96
|
+
1. 3D Web Assets (.scad):
|
|
97
|
+
- Generate procedural 3D models for the game using OpenSCAD.
|
|
98
|
+
- 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
|
+
- 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
|
+
|
|
101
|
+
=== OPENSCAD SYNTAX RULES ===
|
|
102
|
+
${promptRules}
|
|
103
|
+
=============================
|
|
104
|
+
|
|
105
|
+
2. Vite Web Project Files (npm based):
|
|
106
|
+
- 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.
|
|
108
|
+
- In \`package.json\`, you MUST include the scad to gltf converter tool as a dev dependency:
|
|
109
|
+
\`"scad-gltf": "^0.3.0"\`
|
|
110
|
+
- 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
|
+
For example:
|
|
112
|
+
\`"predev": "scad-gltf convert ./scad ./public/models --cache"\`
|
|
113
|
+
\`"prebuild": "scad-gltf convert ./scad ./public/models --cache"\`
|
|
114
|
+
- Write the core game logic to load and display the converted \`.glb\` files interactively.
|
|
115
|
+
|
|
116
|
+
3. Delivery Format (Single Node.js Script):
|
|
117
|
+
- Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
|
|
118
|
+
- CRITICAL: The generated Node.js script MUST first create a root project folder (named using a slugified version of the project name) and output all files and folders inside this newly created project folder.
|
|
119
|
+
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
120
|
+
- The script must embed and write:
|
|
121
|
+
- Your generated \`.scad\` 3D assets.
|
|
122
|
+
- Your generated Vite web project files.
|
|
123
|
+
- Ensure all string file contents inside the Node.js script are properly escaped.`,
|
|
124
|
+
buildInputRequest: (task) =>
|
|
125
|
+
`Design and implement a web-based 3D glTF game using Vite for the following concept: "${task}"`,
|
|
126
|
+
allowedTools: ["render_scad_model"],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (projectType === "godot") {
|
|
131
|
+
return {
|
|
132
|
+
buildSystemPrompt: (promptRules, options = {}) => {
|
|
133
|
+
const hasUserScadFiles =
|
|
134
|
+
Array.isArray(options.scadFiles) && options.scadFiles.length > 0;
|
|
135
|
+
|
|
136
|
+
const systemPrompt = `You are an expert Godot 4 game developer and procedural 3D technical artist.
|
|
137
|
+
|
|
138
|
+
NAMING CONVENTION REQUIREMENT:
|
|
139
|
+
- 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
|
+
- NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
|
|
141
|
+
|
|
142
|
+
What to generate:
|
|
143
|
+
1. 3D Game Assets (.scad):
|
|
144
|
+
- Generate procedural 3D models for the game using OpenSCAD.
|
|
145
|
+
- 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
|
+
- 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
|
+
- 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.
|
|
148
|
+
- CRITICAL Coordinate Mapping: The SCAD to glTF converter used by the Godot importer automatically converts OpenSCAD's Z-up coordinate system to Godot's Y-up coordinate system. Design your models naturally in OpenSCAD using this exact mapping:
|
|
149
|
+
* OpenSCAD +X (Right) -> Godot +X (Right)
|
|
150
|
+
* OpenSCAD -X (Left) -> Godot -X (Left)
|
|
151
|
+
* OpenSCAD +Y (Forward) -> Godot -Z (Forward)
|
|
152
|
+
* OpenSCAD -Y (Back) -> Godot +Z (Back)
|
|
153
|
+
* OpenSCAD +Z (Up) -> Godot +Y (Up)
|
|
154
|
+
DO NOT manually apply root rotations (e.g., \`rotate([90, 0, 0])\`) to compensate for Godot.
|
|
155
|
+
- 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:
|
|
156
|
+
|
|
157
|
+
=== OPENSCAD SYNTAX RULES ===
|
|
158
|
+
${promptRules}
|
|
159
|
+
=============================
|
|
160
|
+
|
|
161
|
+
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.
|
|
163
|
+
- The scenes should directly instance the generated \`.scad\` files (the provided addon will handle importing them as 3D scenes).
|
|
164
|
+
- GDScript Coordinate, Forward, and Left/Right Conventions:
|
|
165
|
+
* 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.
|
|
166
|
+
* Backward is +Z: \`Vector3.BACK\` is \`Vector3(0, 0, 1)\` (\`transform.basis.z\`).
|
|
167
|
+
* Right is +X: \`Vector3.RIGHT\` is \`Vector3(1, 0, 0)\` (\`transform.basis.x\`).
|
|
168
|
+
* Left is -X: \`Vector3.LEFT\` is \`Vector3(-1, 0, 0)\` (\`-transform.basis.x\`).
|
|
169
|
+
* Left/Right Convention in Godot Script: Maintain anatomical consistency in scripts—character Right is along +X (\`transform.basis.x\`) and character Left is along -X (\`-transform.basis.x\`).
|
|
170
|
+
* 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
|
+
- Generate a \`project.godot\` file. It must configure the project and automatically enable the \`scad_importer\` plugin.
|
|
172
|
+
- Generate a \`.gitignore\` file that ignores the \`.godot/\` folder.
|
|
173
|
+
- Generate a \`README.md\` file that documents the project, gameplay mechanics, and controls.
|
|
174
|
+
|
|
175
|
+
3. Delivery Format (Single Node.js Script):
|
|
176
|
+
- 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.
|
|
178
|
+
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
179
|
+
- The script must embed and write:
|
|
180
|
+
- Your generated \`.scad\` game assets.
|
|
181
|
+
- Your generated Godot project files.
|
|
182
|
+
- The exact source code of the provided \`addons/scad_importer/*\` files, placed in their correct respective paths.${
|
|
183
|
+
hasUserScadFiles
|
|
184
|
+
? "\n - The exact source code of the provided user `.scad` files, placed in the appropriate project folders."
|
|
185
|
+
: ""
|
|
186
|
+
}
|
|
187
|
+
- Ensure all string file contents inside the Node.js script are properly escaped.
|
|
188
|
+
- TESTING CAPABILITY: You have access to the \`test_godot_project\` tool. If you want to verify your code before outputting your final response, you can pass your complete generated Node.js script as the \`nodejs_script\` parameter. The server will execute it in a temporary folder and run the Godot tests automatically.`;
|
|
189
|
+
|
|
190
|
+
// Gather Addon Files content
|
|
191
|
+
const addonDir = path.join(DIR, "godot", "addons", "scad_importer");
|
|
192
|
+
let addonFiles = [];
|
|
193
|
+
try {
|
|
194
|
+
if (fs.existsSync(addonDir)) {
|
|
195
|
+
const files = fs.readdirSync(addonDir);
|
|
196
|
+
for (const file of files) {
|
|
197
|
+
const fullPath = path.join(addonDir, file);
|
|
198
|
+
if (
|
|
199
|
+
fs.statSync(fullPath).isFile() &&
|
|
200
|
+
(file.endsWith(".gd") || file.endsWith(".cfg"))
|
|
201
|
+
) {
|
|
202
|
+
addonFiles.push(fullPath);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.error("Warning: Could not read addon directory.", e);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let systemClipboardOutput = `${systemPrompt}\n\n`;
|
|
211
|
+
|
|
212
|
+
for (const file of addonFiles) {
|
|
213
|
+
try {
|
|
214
|
+
const content = fs
|
|
215
|
+
.readFileSync(file, "utf-8")
|
|
216
|
+
.replace(/\r\n/g, "\n");
|
|
217
|
+
const relativePath = path.relative(DIR, file).replace(/\\/g, "/");
|
|
218
|
+
const lang = file.endsWith(".gd") ? "gdscript" : "text";
|
|
219
|
+
systemClipboardOutput += `### ${relativePath}\n---\n\`\`\`${lang}\n${content}\n\`\`\`\n\n`;
|
|
220
|
+
} catch (e) {
|
|
221
|
+
console.error(
|
|
222
|
+
`Warning: Skipping '${file}'. It is not a readable file.`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (hasUserScadFiles) {
|
|
228
|
+
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`;
|
|
230
|
+
for (const file of options.scadFiles) {
|
|
231
|
+
try {
|
|
232
|
+
const content = fs
|
|
233
|
+
.readFileSync(file, "utf-8")
|
|
234
|
+
.replace(/\r\n/g, "\n");
|
|
235
|
+
const relativePath = path.isAbsolute(file)
|
|
236
|
+
? path.relative(process.cwd(), file).replace(/\\/g, "/")
|
|
237
|
+
: file.replace(/\\/g, "/");
|
|
238
|
+
systemClipboardOutput += `### ${relativePath}\n---\n\`\`\`openscad\n${content}\n\`\`\`\n\n`;
|
|
239
|
+
} catch (e) {
|
|
240
|
+
console.error(
|
|
241
|
+
`Warning: Skipping user SCAD file '${file}'. It is not a readable file.`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return systemClipboardOutput.trimEnd() + "\n";
|
|
248
|
+
},
|
|
249
|
+
buildInputRequest: (task) =>
|
|
250
|
+
`Design and implement a Godot 4 project for the following game concept: "${task}"`,
|
|
251
|
+
allowedTools: ["render_scad_model", "test_godot_project"],
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
throw new Error(`Unknown project type: ${projectType}`);
|
|
256
|
+
}
|
package/bin/scad-bevy.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { runCliApp } from "../src/cli-utils.js";
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
await runCliApp({
|
|
7
|
-
projectType: "bevy",
|
|
8
|
-
buildSystemPrompt: (
|
|
9
|
-
promptRules,
|
|
10
|
-
) => `You are an expert Rust Bevy engine game developer and procedural 3D technical artist.
|
|
11
|
-
|
|
12
|
-
NAMING CONVENTION REQUIREMENT:
|
|
13
|
-
- 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\`).
|
|
14
|
-
- NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
|
|
15
|
-
|
|
16
|
-
What to generate:
|
|
17
|
-
1. 3D Game Assets (.scad):
|
|
18
|
-
- Generate procedural 3D models for the game using OpenSCAD.
|
|
19
|
-
- 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.
|
|
20
|
-
- 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:
|
|
21
|
-
|
|
22
|
-
=== OPENSCAD SYNTAX RULES ===
|
|
23
|
-
${promptRules}
|
|
24
|
-
=============================
|
|
25
|
-
|
|
26
|
-
2. Rust Bevy Project Files:
|
|
27
|
-
- Create the necessary files for a modern Rust Bevy engine application (e.g., \`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
|
|
28
|
-
- In \`Cargo.toml\`, include \`bevy\` as a dependency.
|
|
29
|
-
- 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:
|
|
30
|
-
\`\`\`rust
|
|
31
|
-
use std::process::Command;
|
|
32
|
-
|
|
33
|
-
fn main() {
|
|
34
|
-
// Tell Cargo to re-run this script only if the 'scad' directory changes
|
|
35
|
-
println!("cargo::rerun-if-changed=scad");
|
|
36
|
-
|
|
37
|
-
// Ensure cross-platform compatibility for npm global binaries
|
|
38
|
-
let cmd = if cfg!(target_os = "windows") {
|
|
39
|
-
"scad-convert.cmd"
|
|
40
|
-
} else {
|
|
41
|
-
"scad-convert"
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
let status = Command::new(cmd)
|
|
45
|
-
.args(["./scad", "./assets/models", "--cache"])
|
|
46
|
-
.status()
|
|
47
|
-
.expect("Failed to execute scad-convert. Is scad-gltf installed globally?");
|
|
48
|
-
|
|
49
|
-
if !status.success() {
|
|
50
|
-
panic!("scad-convert failed with status: {}", status);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
\`\`\`
|
|
54
|
-
- 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.).
|
|
55
|
-
|
|
56
|
-
3. Delivery Format (Single Node.js Script):
|
|
57
|
-
- Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
|
|
58
|
-
- CRITICAL: The generated Node.js script MUST first create a root project folder (named using a slugified version of the project name) and output all files and folders inside this newly created project folder.
|
|
59
|
-
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
60
|
-
- The script must embed and write:
|
|
61
|
-
- Your generated \`.scad\` 3D assets.
|
|
62
|
-
- Your generated Rust Bevy project files (\`Cargo.toml\`, \`build.rs\`, \`src/main.rs\`).
|
|
63
|
-
- Ensure all string file contents inside the Node.js script are properly escaped.`,
|
|
64
|
-
buildInputRequest: (task) =>
|
|
65
|
-
`Design and implement a Rust Bevy engine game for the following concept: "${task}"`,
|
|
66
|
-
allowedTools: ["render_scad_model", "compile_bevy_project"],
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Execute and handle unhandled runtime errors
|
|
71
|
-
main().catch((err) => {
|
|
72
|
-
console.error("An unexpected error occurred:", err);
|
|
73
|
-
process.exit(1);
|
|
74
|
-
});
|
package/bin/scad-gen.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { runCliApp } from "../src/cli-utils.js";
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
await runCliApp({
|
|
7
|
-
projectType: "gen",
|
|
8
|
-
buildSystemPrompt: () =>
|
|
9
|
-
`You are an expert procedural 3D technical artist and OpenSCAD developer.
|
|
10
|
-
Your goal is to generate a single OpenSCAD (.scad) file based on the user's request.
|
|
11
|
-
|
|
12
|
-
CRITICAL WORKFLOW:
|
|
13
|
-
1. Write the OpenSCAD code using the custom syntax rules provided in the request.
|
|
14
|
-
2. Call the \`render_scad_model\` tool with your code to visually verify your design.
|
|
15
|
-
3. If the model looks incorrect, adjust your code and re-render. Iterate until perfect.
|
|
16
|
-
4. Provide your final OpenSCAD code in a standard markdown block (\`\`\`openscad).`,
|
|
17
|
-
allowedTools: ["render_scad_model"],
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Execute and handle unhandled runtime errors
|
|
22
|
-
main().catch((err) => {
|
|
23
|
-
console.error("An unexpected error occurred:", err);
|
|
24
|
-
process.exit(1);
|
|
25
|
-
});
|
package/bin/scad-godot.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import url from "node:url";
|
|
6
|
-
import { runCliApp } from "../src/cli-utils.js";
|
|
7
|
-
|
|
8
|
-
const __filename = url.fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
const DIR = path.resolve(__dirname, "..");
|
|
11
|
-
|
|
12
|
-
async function main() {
|
|
13
|
-
await runCliApp({
|
|
14
|
-
projectType: "godot",
|
|
15
|
-
buildSystemPrompt: (promptRules, options) => {
|
|
16
|
-
const hasUserScadFiles =
|
|
17
|
-
Array.isArray(options.scadFiles) && options.scadFiles.length > 0;
|
|
18
|
-
|
|
19
|
-
const systemPrompt = `You are an expert Godot 4 game developer and procedural 3D technical artist.
|
|
20
|
-
|
|
21
|
-
NAMING CONVENTION REQUIREMENT:
|
|
22
|
-
- 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\`).
|
|
23
|
-
- NEVER use hyphens/minus signs (\`-\`) or spaces in any file or folder names.
|
|
24
|
-
|
|
25
|
-
What to generate:
|
|
26
|
-
1. 3D Game Assets (.scad):
|
|
27
|
-
- Generate procedural 3D models for the game using OpenSCAD.
|
|
28
|
-
- 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.
|
|
29
|
-
- 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).
|
|
30
|
-
- 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.
|
|
31
|
-
- CRITICAL Coordinate Mapping: The SCAD to glTF converter used by the Godot importer automatically converts OpenSCAD's Z-up coordinate system to Godot's Y-up coordinate system. Design your models naturally in OpenSCAD using this exact mapping:
|
|
32
|
-
* OpenSCAD +X (Right) -> Godot +X (Right)
|
|
33
|
-
* OpenSCAD -X (Left) -> Godot -X (Left)
|
|
34
|
-
* OpenSCAD +Y (Forward) -> Godot -Z (Forward)
|
|
35
|
-
* OpenSCAD -Y (Back) -> Godot +Z (Back)
|
|
36
|
-
* OpenSCAD +Z (Up) -> Godot +Y (Up)
|
|
37
|
-
DO NOT manually apply root rotations (e.g., \`rotate([90, 0, 0])\`) to compensate for Godot.
|
|
38
|
-
- 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:
|
|
39
|
-
|
|
40
|
-
=== OPENSCAD SYNTAX RULES ===
|
|
41
|
-
${promptRules}
|
|
42
|
-
=============================
|
|
43
|
-
|
|
44
|
-
2. Godot 4 Project Files:
|
|
45
|
-
- Create the necessary GDScript (\`.gd\`) and scene (\`.tscn\`) files to implement the game logic, responsive player input controls, and a core gameplay loop.
|
|
46
|
-
- The scenes should directly instance the generated \`.scad\` files (the provided addon will handle importing them as 3D scenes).
|
|
47
|
-
- GDScript Coordinate, Forward, and Left/Right Conventions:
|
|
48
|
-
* 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.
|
|
49
|
-
* Backward is +Z: \`Vector3.BACK\` is \`Vector3(0, 0, 1)\` (\`transform.basis.z\`).
|
|
50
|
-
* Right is +X: \`Vector3.RIGHT\` is \`Vector3(1, 0, 0)\` (\`transform.basis.x\`).
|
|
51
|
-
* Left is -X: \`Vector3.LEFT\` is \`Vector3(-1, 0, 0)\` (\`-transform.basis.x\`).
|
|
52
|
-
* Left/Right Convention in Godot Script: Maintain anatomical consistency in scripts—character Right is along +X (\`transform.basis.x\`) and character Left is along -X (\`-transform.basis.x\`).
|
|
53
|
-
* 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.
|
|
54
|
-
- Generate a \`project.godot\` file. It must configure the project and automatically enable the \`scad_importer\` plugin.
|
|
55
|
-
- Generate a \`.gitignore\` file that ignores the \`.godot/\` folder.
|
|
56
|
-
- Generate a \`README.md\` file that documents the project, gameplay mechanics, and controls.
|
|
57
|
-
|
|
58
|
-
3. Delivery Format (Single Node.js Script):
|
|
59
|
-
- Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
|
|
60
|
-
- 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.
|
|
61
|
-
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
62
|
-
- The script must embed and write:
|
|
63
|
-
- Your generated \`.scad\` game assets.
|
|
64
|
-
- Your generated Godot project files.
|
|
65
|
-
- The exact source code of the provided \`addons/scad_importer/*\` files, placed in their correct respective paths.${
|
|
66
|
-
hasUserScadFiles
|
|
67
|
-
? "\n - The exact source code of the provided user `.scad` files, placed in the appropriate project folders."
|
|
68
|
-
: ""
|
|
69
|
-
}
|
|
70
|
-
- Ensure all string file contents inside the Node.js script are properly escaped.
|
|
71
|
-
- TESTING CAPABILITY: You have access to the \`test_godot_project\` tool. If you want to verify your code before outputting your final response, you can pass your complete generated Node.js script as the \`nodejs_script\` parameter. The server will execute it in a temporary folder and run the Godot tests automatically.`;
|
|
72
|
-
|
|
73
|
-
// Gather Addon Files content
|
|
74
|
-
const addonDir = path.join(DIR, "godot", "addons", "scad_importer");
|
|
75
|
-
let addonFiles = [];
|
|
76
|
-
try {
|
|
77
|
-
if (fs.existsSync(addonDir)) {
|
|
78
|
-
const files = fs.readdirSync(addonDir);
|
|
79
|
-
for (const file of files) {
|
|
80
|
-
const fullPath = path.join(addonDir, file);
|
|
81
|
-
if (
|
|
82
|
-
fs.statSync(fullPath).isFile() &&
|
|
83
|
-
(file.endsWith(".gd") || file.endsWith(".cfg"))
|
|
84
|
-
) {
|
|
85
|
-
addonFiles.push(fullPath);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} catch (e) {
|
|
90
|
-
console.error("Warning: Could not read addon directory.", e);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
let systemClipboardOutput = `${systemPrompt}\n\n`;
|
|
94
|
-
|
|
95
|
-
for (const file of addonFiles) {
|
|
96
|
-
try {
|
|
97
|
-
const content = fs.readFileSync(file, "utf-8").replace(/\r\n/g, "\n");
|
|
98
|
-
const relativePath = path.relative(DIR, file).replace(/\\/g, "/");
|
|
99
|
-
const lang = file.endsWith(".gd") ? "gdscript" : "text";
|
|
100
|
-
systemClipboardOutput += `### ${relativePath}\n---\n\`\`\`${lang}\n${content}\n\`\`\`\n\n`;
|
|
101
|
-
} catch (e) {
|
|
102
|
-
console.error(
|
|
103
|
-
`Warning: Skipping '${file}'. It is not a readable file.`,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (hasUserScadFiles) {
|
|
109
|
-
systemClipboardOutput += `=== USER PROVIDED OPENSCAD FILES ===\n`;
|
|
110
|
-
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`;
|
|
111
|
-
for (const file of options.scadFiles) {
|
|
112
|
-
try {
|
|
113
|
-
const content = fs
|
|
114
|
-
.readFileSync(file, "utf-8")
|
|
115
|
-
.replace(/\r\n/g, "\n");
|
|
116
|
-
const relativePath = path.isAbsolute(file)
|
|
117
|
-
? path.relative(process.cwd(), file).replace(/\\/g, "/")
|
|
118
|
-
: file.replace(/\\/g, "/");
|
|
119
|
-
systemClipboardOutput += `### ${relativePath}\n---\n\`\`\`openscad\n${content}\n\`\`\`\n\n`;
|
|
120
|
-
} catch (e) {
|
|
121
|
-
console.error(
|
|
122
|
-
`Warning: Skipping user SCAD file '${file}'. It is not a readable file.`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return systemClipboardOutput.trimEnd() + "\n";
|
|
129
|
-
},
|
|
130
|
-
buildInputRequest: (task) =>
|
|
131
|
-
`Design and implement a Godot 4 project for the following game concept: "${task}"`,
|
|
132
|
-
allowedTools: ["render_scad_model", "test_godot_project"],
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Execute and handle unhandled runtime errors
|
|
137
|
-
main().catch((err) => {
|
|
138
|
-
console.error("An unexpected error occurred:", err);
|
|
139
|
-
process.exit(1);
|
|
140
|
-
});
|
package/bin/scad-web.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { runCliApp } from "../src/cli-utils.js";
|
|
4
|
-
|
|
5
|
-
async function main() {
|
|
6
|
-
await runCliApp({
|
|
7
|
-
projectType: "web",
|
|
8
|
-
buildSystemPrompt: (
|
|
9
|
-
promptRules,
|
|
10
|
-
) => `You are an expert Web 3D developer and procedural 3D technical artist.
|
|
11
|
-
|
|
12
|
-
What to generate:
|
|
13
|
-
1. 3D Web Assets (.scad):
|
|
14
|
-
- Generate procedural 3D models for the game using OpenSCAD.
|
|
15
|
-
- 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.
|
|
16
|
-
- 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:
|
|
17
|
-
|
|
18
|
-
=== OPENSCAD SYNTAX RULES ===
|
|
19
|
-
${promptRules}
|
|
20
|
-
=============================
|
|
21
|
-
|
|
22
|
-
2. Vite Web Project Files (npm based):
|
|
23
|
-
- Create the necessary files for a modern web application (e.g., \`package.json\`, \`index.html\`, \`main.js\`).
|
|
24
|
-
- 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.
|
|
25
|
-
- In \`package.json\`, you MUST include the scad to gltf converter tool as a dev dependency:
|
|
26
|
-
\`"scad-gltf": "^0.1.0"\`
|
|
27
|
-
- 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.
|
|
28
|
-
For example:
|
|
29
|
-
\`"predev": "scad-convert ./scad ./public/models --cache"\`
|
|
30
|
-
\`"prebuild": "scad-convert ./scad ./public/models --cache"\`
|
|
31
|
-
- Write the core game logic to load and display the converted \`.glb\` files interactively.
|
|
32
|
-
|
|
33
|
-
3. Delivery Format (Single Node.js Script):
|
|
34
|
-
- Output exactly ONE self-contained Node.js script. Do not output manual setup instructions.
|
|
35
|
-
- CRITICAL: The generated Node.js script MUST first create a root project folder (named using a slugified version of the project name) and output all files and folders inside this newly created project folder.
|
|
36
|
-
- When executed, this script must programmatically create the entire project directory structure and write all the files to disk using the \`fs\` module.
|
|
37
|
-
- The script must embed and write:
|
|
38
|
-
- Your generated \`.scad\` 3D assets.
|
|
39
|
-
- Your generated Vite web project files.
|
|
40
|
-
- Ensure all string file contents inside the Node.js script are properly escaped.`,
|
|
41
|
-
buildInputRequest: (task) =>
|
|
42
|
-
`Design and implement a web-based 3D glTF game using Vite for the following concept: "${task}"`,
|
|
43
|
-
allowedTools: ["render_scad_model"],
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Execute and handle unhandled runtime errors
|
|
48
|
-
main().catch((err) => {
|
|
49
|
-
console.error("An unexpected error occurred:", err);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
});
|