refactor(assets): move sprite renderer to standalone project at renderer/

Separates the 3D-to-2D render pipeline from the game client into its
own minimal Godot project. No autoloads, no plugins, no game code —
just the render scene, models, textures, and export script. Eliminates
SimBridge parse errors and gdUnit4 scanning during renders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 23:26:16 +01:00
co-authored by Claude Opus 4.6
parent 8a1b10786f
commit 921d2aef0d
11 changed files with 38 additions and 20 deletions
+7 -8
View File
@@ -6,8 +6,7 @@ description: >
east, south, west) with outline applied at working resolution. Use when the east, south, west) with outline applied at working resolution. Use when the
user says "render sprite", "render model", "run the render pipeline", user says "render sprite", "render model", "run the render pipeline",
"test the pipeline", "/render-sprite", or asks to render a specific model "test the pipeline", "/render-sprite", or asks to render a specific model
(e.g., "render wall_structural"). Output: 12 PNG files in (e.g., "render wall_structural"). Output: 12 PNG files in renderer/output/.
client/tooling/sprite_renderer/output/.
--- ---
## Render Pipeline ## Render Pipeline
@@ -20,15 +19,15 @@ Run the render script with the model name:
### Available Models ### Available Models
Models live at `client/tooling/sprite_renderer/models/<name>.tscn`. List them: Models live at `renderer/models/<name>.tscn`. List them:
```bash ```bash
ls client/tooling/sprite_renderer/models/*.tscn | xargs -I{} basename {} .tscn ls renderer/models/*.tscn | xargs -I{} basename {} .tscn
``` ```
### Output ### Output
12 files per model in `client/tooling/sprite_renderer/output/`: 12 files per model in `renderer/output/`:
``` ```
<model>_north_1024.png <model>_north_256.png <model>_north_64.png <model>_north_1024.png <model>_north_256.png <model>_north_64.png
@@ -46,11 +45,11 @@ ls client/tooling/sprite_renderer/models/*.tscn | xargs -I{} basename {} .tscn
### Troubleshooting ### Troubleshooting
- **No output files**: Godot needs a display. If running headless, prefix with `xvfb-run`. - **No output files**: Godot needs a display. If running headless, prefix with `xvfb-run`.
- **Model not found**: Check the model .tscn exists in `models/` directory. - **Model not found**: Check the model .tscn exists in `renderer/models/`.
- **Godot not found**: Pass path as second arg: `render.sh wall_structural /path/to/godot` - **Godot not found**: Pass path as second arg: `render.sh wall_structural /path/to/godot`
### Adding New Models ### Adding New Models
1. Create model scene at `client/tooling/sprite_renderer/models/<name>.tscn` 1. Create model scene at `renderer/models/<name>.tscn`
2. Apply texture from `textures/` via StandardMaterial3D 2. Apply texture from `renderer/textures/` via StandardMaterial3D
3. Run: `.claude/skills/render-sprite/scripts/render.sh <name>` 3. Run: `.claude/skills/render-sprite/scripts/render.sh <name>`
@@ -7,16 +7,16 @@ set -euo pipefail
MODEL_NAME="${1:?Usage: render.sh <model_name> [godot_path]}" MODEL_NAME="${1:?Usage: render.sh <model_name> [godot_path]}"
GODOT="${2:-$HOME/bin/godot}" GODOT="${2:-$HOME/bin/godot}"
REPO_ROOT="$(cd "$(dirname "$0")" && git rev-parse --show-toplevel)" REPO_ROOT="$(cd "$(dirname "$0")" && git rev-parse --show-toplevel)"
PROJECT="$REPO_ROOT/client" PROJECT="$REPO_ROOT/renderer"
SCENE="res://tooling/sprite_renderer/render_scene.tscn" SCENE="res://render_scene.tscn"
OUTPUT="$PROJECT/tooling/sprite_renderer/output" OUTPUT="$PROJECT/output"
# Verify model exists # Verify model exists
MODEL_FILE="$PROJECT/tooling/sprite_renderer/models/${MODEL_NAME}.tscn" MODEL_FILE="$PROJECT/models/${MODEL_NAME}.tscn"
if [ ! -f "$MODEL_FILE" ]; then if [ ! -f "$MODEL_FILE" ]; then
echo "ERROR: Model not found: $MODEL_FILE" echo "ERROR: Model not found: $MODEL_FILE"
echo "Available models:" echo "Available models:"
ls "$PROJECT/tooling/sprite_renderer/models/"*.tscn 2>/dev/null | xargs -I{} basename {} .tscn ls "$PROJECT/models/"*.tscn 2>/dev/null | xargs -I{} basename {} .tscn
exit 1 exit 1
fi fi
+6 -1
View File
@@ -8,7 +8,12 @@ client/export/
client/reports/ client/reports/
client/**/*.import client/**/*.import
client/**/*.uid client/**/*.uid
client/tooling/sprite_renderer/output/*.png
# Renderer (separate Godot project for sprite pipeline)
renderer/.godot/
renderer/**/*.import
renderer/**/*.uid
renderer/output/*.png
# Database (shared across worktrees at ../settledreach.db, not tracked) # Database (shared across worktrees at ../settledreach.db, not tracked)
db/commonwealth.db* db/commonwealth.db*
@@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3] [gd_scene load_steps=3 format=3]
[ext_resource type="Texture2D" path="res://tooling/sprite_renderer/textures/wall_bar_green_panels.png" id="1_wall_texture"] [ext_resource type="Texture2D" path="res://textures/wall_bar_green_panels.png" id="1_wall_texture"]
[sub_resource type="BoxMesh" id="BoxMesh_wall"] [sub_resource type="BoxMesh" id="BoxMesh_wall"]
size = Vector3(1.0, 0.8, 0.2) size = Vector3(1.0, 0.8, 0.2)
@@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://cyh0xf1nv2j3e"] [gd_scene load_steps=3 format=3 uid="uid://cyh0xf1nv2j3e"]
[ext_resource type="Texture2D" uid="uid://bgn5kvwjdqrx0" path="res://tooling/sprite_renderer/textures/wall_institutional_era1.png" id="1_wall_texture"] [ext_resource type="Texture2D" path="res://textures/wall_institutional_era1.png" id="1_wall_texture"]
[sub_resource type="BoxMesh" id="BoxMesh_wall"] [sub_resource type="BoxMesh" id="BoxMesh_wall"]
size = Vector3(1.0, 0.8, 0.2) size = Vector3(1.0, 0.8, 0.2)
+14
View File
@@ -0,0 +1,14 @@
; Sprite Renderer — standalone Godot project for 3D-to-2D sprite pipeline.
; No game logic, no autoloads, no plugins. Just rendering.
config_version=5
[application]
config/name="Settled Reach Sprite Renderer"
config/features=PackedStringArray("4.6", "GL Compatibility")
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
@@ -24,12 +24,12 @@ const ROTATIONS: PackedFloat64Array = [0.0, 90.0, 180.0, 270.0]
func _ready() -> void: func _ready() -> void:
if Engine.is_editor_hint(): if Engine.is_editor_hint():
return return
# CLI mode: godot --path client/ res://tooling/sprite_renderer/render_scene.tscn -- wall_structural # CLI mode: godot --path client/ res://render_scene.tscn -- wall_structural
var args := OS.get_cmdline_user_args() var args := OS.get_cmdline_user_args()
if args.size() == 0: if args.size() == 0:
return return
var model_name := args[0] var model_name := args[0]
var model_path := "res://tooling/sprite_renderer/models/%s.tscn" % model_name var model_path := "res://models/%s.tscn" % model_name
if not ResourceLoader.exists(model_path): if not ResourceLoader.exists(model_path):
push_error("Model not found: %s" % model_path) push_error("Model not found: %s" % model_path)
get_tree().quit(1) get_tree().quit(1)
@@ -59,7 +59,7 @@ func _execute_render() -> void:
model_root.add_child(model_instance) model_root.add_child(model_instance)
# Ensure output directory exists # Ensure output directory exists
var output_dir := "res://tooling/sprite_renderer/output" var output_dir := "res://output"
if not DirAccess.dir_exists_absolute(output_dir): if not DirAccess.dir_exists_absolute(output_dir):
DirAccess.make_dir_recursive_absolute(output_dir) DirAccess.make_dir_recursive_absolute(output_dir)
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cqvfv4uhbgq6h"] [gd_scene load_steps=2 format=3 uid="uid://cqvfv4uhbgq6h"]
[ext_resource type="Script" path="res://tooling/sprite_renderer/render_export.gd" id="1_render_script"] [ext_resource type="Script" path="res://render_export.gd" id="1_render_script"]
[node name="RenderScene" type="Node3D"] [node name="RenderScene" type="Node3D"]
script = ExtResource("1_render_script") script = ExtResource("1_render_script")

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before

Width:  |  Height:  |  Size: 991 KiB

After

Width:  |  Height:  |  Size: 991 KiB