blender-cli 0.1.0__tar.gz

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.
Files changed (104) hide show
  1. blender_cli-0.1.0/PKG-INFO +281 -0
  2. blender_cli-0.1.0/README.md +251 -0
  3. blender_cli-0.1.0/pyproject.toml +57 -0
  4. blender_cli-0.1.0/src/blender_cli/__init__.py +151 -0
  5. blender_cli-0.1.0/src/blender_cli/__init__.pyi +55 -0
  6. blender_cli-0.1.0/src/blender_cli/alignment/__init__.py +37 -0
  7. blender_cli-0.1.0/src/blender_cli/alignment/_fal.py +74 -0
  8. blender_cli-0.1.0/src/blender_cli/alignment/depth.py +250 -0
  9. blender_cli-0.1.0/src/blender_cli/alignment/generation.py +248 -0
  10. blender_cli-0.1.0/src/blender_cli/alignment/integration.py +80 -0
  11. blender_cli-0.1.0/src/blender_cli/alignment/pipeline.py +200 -0
  12. blender_cli-0.1.0/src/blender_cli/alignment/pose.py +1453 -0
  13. blender_cli-0.1.0/src/blender_cli/alignment/types.py +165 -0
  14. blender_cli-0.1.0/src/blender_cli/alignment/viz.py +62 -0
  15. blender_cli-0.1.0/src/blender_cli/animation/__init__.py +15 -0
  16. blender_cli-0.1.0/src/blender_cli/animation/codegen.py +134 -0
  17. blender_cli-0.1.0/src/blender_cli/animation/keyframes.py +211 -0
  18. blender_cli-0.1.0/src/blender_cli/assets/__init__.py +14 -0
  19. blender_cli-0.1.0/src/blender_cli/assets/image.py +36 -0
  20. blender_cli-0.1.0/src/blender_cli/assets/material.py +578 -0
  21. blender_cli-0.1.0/src/blender_cli/assets/prefab.py +72 -0
  22. blender_cli-0.1.0/src/blender_cli/assets/registry.py +189 -0
  23. blender_cli-0.1.0/src/blender_cli/blenvy.py +214 -0
  24. blender_cli-0.1.0/src/blender_cli/blenvy_registry.py +237 -0
  25. blender_cli-0.1.0/src/blender_cli/build/__init__.py +18 -0
  26. blender_cli-0.1.0/src/blender_cli/build/build_types.py +9 -0
  27. blender_cli-0.1.0/src/blender_cli/build/context.py +179 -0
  28. blender_cli-0.1.0/src/blender_cli/build/generation_step.py +97 -0
  29. blender_cli-0.1.0/src/blender_cli/build/runner.py +74 -0
  30. blender_cli-0.1.0/src/blender_cli/cli/__init__.py +5 -0
  31. blender_cli-0.1.0/src/blender_cli/cli/__main__.py +5 -0
  32. blender_cli-0.1.0/src/blender_cli/cli/commands/__init__.py +65 -0
  33. blender_cli-0.1.0/src/blender_cli/cli/commands/align.py +524 -0
  34. blender_cli-0.1.0/src/blender_cli/cli/commands/anchor_cmd.py +47 -0
  35. blender_cli-0.1.0/src/blender_cli/cli/commands/animation_cmd.py +187 -0
  36. blender_cli-0.1.0/src/blender_cli/cli/commands/assets.py +94 -0
  37. blender_cli-0.1.0/src/blender_cli/cli/commands/blenvy_cmd.py +228 -0
  38. blender_cli-0.1.0/src/blender_cli/cli/commands/camera_cmd.py +120 -0
  39. blender_cli-0.1.0/src/blender_cli/cli/commands/candidates.py +289 -0
  40. blender_cli-0.1.0/src/blender_cli/cli/commands/inspect.py +124 -0
  41. blender_cli-0.1.0/src/blender_cli/cli/commands/instance_cmd.py +72 -0
  42. blender_cli-0.1.0/src/blender_cli/cli/commands/manifest.py +90 -0
  43. blender_cli-0.1.0/src/blender_cli/cli/commands/material_cmd.py +65 -0
  44. blender_cli-0.1.0/src/blender_cli/cli/commands/measure.py +58 -0
  45. blender_cli-0.1.0/src/blender_cli/cli/commands/modifier_cmd.py +179 -0
  46. blender_cli-0.1.0/src/blender_cli/cli/commands/object_cmd.py +80 -0
  47. blender_cli-0.1.0/src/blender_cli/cli/commands/op.py +2353 -0
  48. blender_cli-0.1.0/src/blender_cli/cli/commands/project.py +343 -0
  49. blender_cli-0.1.0/src/blender_cli/cli/commands/raycast.py +85 -0
  50. blender_cli-0.1.0/src/blender_cli/cli/commands/render.py +503 -0
  51. blender_cli-0.1.0/src/blender_cli/cli/commands/render_settings_cmd.py +114 -0
  52. blender_cli-0.1.0/src/blender_cli/cli/commands/repl_cmd.py +25 -0
  53. blender_cli-0.1.0/src/blender_cli/cli/commands/run.py +34 -0
  54. blender_cli-0.1.0/src/blender_cli/cli/commands/select.py +22 -0
  55. blender_cli-0.1.0/src/blender_cli/cli/commands/session_cmd.py +90 -0
  56. blender_cli-0.1.0/src/blender_cli/cli/commands/stats.py +20 -0
  57. blender_cli-0.1.0/src/blender_cli/cli/commands/terrain_cmd.py +116 -0
  58. blender_cli-0.1.0/src/blender_cli/cli/commands/world_cmd.py +91 -0
  59. blender_cli-0.1.0/src/blender_cli/cli/common.py +339 -0
  60. blender_cli-0.1.0/src/blender_cli/cli/main.py +74 -0
  61. blender_cli-0.1.0/src/blender_cli/cli/repl.py +121 -0
  62. blender_cli-0.1.0/src/blender_cli/constants.py +6 -0
  63. blender_cli-0.1.0/src/blender_cli/core/__init__.py +39 -0
  64. blender_cli-0.1.0/src/blender_cli/core/diagnostics.py +9 -0
  65. blender_cli-0.1.0/src/blender_cli/core/metadata.py +70 -0
  66. blender_cli-0.1.0/src/blender_cli/geometry/__init__.py +34 -0
  67. blender_cli-0.1.0/src/blender_cli/geometry/_erosion.py +114 -0
  68. blender_cli-0.1.0/src/blender_cli/geometry/field2d.py +306 -0
  69. blender_cli-0.1.0/src/blender_cli/geometry/heightfield.py +586 -0
  70. blender_cli-0.1.0/src/blender_cli/geometry/mask.py +232 -0
  71. blender_cli-0.1.0/src/blender_cli/geometry/pointset.py +603 -0
  72. blender_cli-0.1.0/src/blender_cli/geometry/spline.py +279 -0
  73. blender_cli-0.1.0/src/blender_cli/geometry/spline_ops.py +320 -0
  74. blender_cli-0.1.0/src/blender_cli/modifiers/__init__.py +15 -0
  75. blender_cli-0.1.0/src/blender_cli/modifiers/codegen.py +94 -0
  76. blender_cli-0.1.0/src/blender_cli/modifiers/modifier.py +185 -0
  77. blender_cli-0.1.0/src/blender_cli/modifiers/registry.py +346 -0
  78. blender_cli-0.1.0/src/blender_cli/project/__init__.py +6 -0
  79. blender_cli-0.1.0/src/blender_cli/project/project_file.py +2207 -0
  80. blender_cli-0.1.0/src/blender_cli/project/session.py +124 -0
  81. blender_cli-0.1.0/src/blender_cli/py.typed +0 -0
  82. blender_cli-0.1.0/src/blender_cli/render/__init__.py +46 -0
  83. blender_cli-0.1.0/src/blender_cli/render/camera.py +397 -0
  84. blender_cli-0.1.0/src/blender_cli/render/camera_path.py +321 -0
  85. blender_cli-0.1.0/src/blender_cli/render/context.py +1897 -0
  86. blender_cli-0.1.0/src/blender_cli/render/settings.py +286 -0
  87. blender_cli-0.1.0/src/blender_cli/render/world.py +170 -0
  88. blender_cli-0.1.0/src/blender_cli/scene/__init__.py +27 -0
  89. blender_cli-0.1.0/src/blender_cli/scene/anchor.py +65 -0
  90. blender_cli-0.1.0/src/blender_cli/scene/entity.py +542 -0
  91. blender_cli-0.1.0/src/blender_cli/scene/instances.py +524 -0
  92. blender_cli-0.1.0/src/blender_cli/scene/primitives.py +574 -0
  93. blender_cli-0.1.0/src/blender_cli/scene/scene.py +1613 -0
  94. blender_cli-0.1.0/src/blender_cli/scene/selection.py +273 -0
  95. blender_cli-0.1.0/src/blender_cli/snap/__init__.py +26 -0
  96. blender_cli-0.1.0/src/blender_cli/snap/axis.py +80 -0
  97. blender_cli-0.1.0/src/blender_cli/snap/objects.py +628 -0
  98. blender_cli-0.1.0/src/blender_cli/snap/results.py +190 -0
  99. blender_cli-0.1.0/src/blender_cli/types.py +292 -0
  100. blender_cli-0.1.0/src/blender_cli/utils/__init__.py +29 -0
  101. blender_cli-0.1.0/src/blender_cli/utils/placement.py +511 -0
  102. blender_cli-0.1.0/src/blender_cli/utils/spline_strip.py +233 -0
  103. blender_cli-0.1.0/src/blender_cli/utils/strings.py +30 -0
  104. blender_cli-0.1.0/src/blender_cli/utils/sweep.py +154 -0
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.3
2
+ Name: blender-cli
3
+ Version: 0.1.0
4
+ Summary: Agent-friendly procedural map generation SDK built on Blender's Python API
5
+ Keywords: blender,procedural,map,3d,terrain,generation
6
+ Author: Julien Blanchon
7
+ Author-email: Julien Blanchon <julien@blanchon.cc>
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
14
+ Classifier: Topic :: Games/Entertainment
15
+ Requires-Dist: bpy>=5.1.0
16
+ Requires-Dist: cma>=3.3
17
+ Requires-Dist: click>=8.0
18
+ Requires-Dist: fal-client>=0.7
19
+ Requires-Dist: matplotlib>=3.8
20
+ Requires-Dist: numpy>=1.24
21
+ Requires-Dist: opencv-python-headless>=4.8
22
+ Requires-Dist: pillow>=10.0
23
+ Requires-Dist: prompt-toolkit>=3.0
24
+ Requires-Dist: pyrender>=0.1.45
25
+ Requires-Dist: rtree>=1.2
26
+ Requires-Dist: scipy>=1.11
27
+ Requires-Dist: trimesh>=4.0
28
+ Requires-Python: >=3.13
29
+ Description-Content-Type: text/markdown
30
+
31
+ # blender-cli
32
+
33
+ Agent-friendly procedural map generation SDK built on Blender's Python API.
34
+
35
+ `blender-cli` provides a **Python SDK** and a **CLI** for building 3D scenes declaratively through a `project.json` file — procedural terrain, PBR materials, object placement with snap/raycast, GPU-instanced scatter, cameras, lights, and Bevy/Blenvy ECS component embedding — then exports to GLB.
36
+
37
+ ## Installation
38
+
39
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
40
+
41
+ ```bash
42
+ # Install from source
43
+ uv pip install .
44
+
45
+ # Or run directly with uvx (no install needed)
46
+ uvx --from . blender-cli
47
+
48
+ # From a git repo
49
+ uvx --from git+https://github.com/julien-blanchon/blender_cli blender-cli
50
+ ```
51
+
52
+ ## Quick start
53
+
54
+ ### CLI
55
+
56
+ ```bash
57
+ # Create a project
58
+ blender-cli project new --name "Alpine" --profile hd1080p -o project.json
59
+
60
+ # Add materials
61
+ blender-cli material add --project project.json grass --pbr-folder ./textures/grass/ --tiling 4 4
62
+
63
+ # Build terrain
64
+ blender-cli terrain init --project project.json --width 512 --height 512 --seed 42
65
+ blender-cli terrain op --project project.json noise type=fbm amp=15 freq=0.008 octaves=6
66
+ blender-cli terrain op --project project.json smooth radius=3 iters=1
67
+ blender-cli terrain material --project project.json grass
68
+
69
+ # Place objects (snapped to terrain)
70
+ blender-cli project add-object --project project.json Wall \
71
+ --primitive box --primitive-params '{"size":[10,0.3,3]}' \
72
+ --at 50 50 0 --material rock --snap -Z --tags building
73
+
74
+ # Add camera and light
75
+ blender-cli project add-camera --project project.json Main --at 0 -50 30 --lens 35
76
+ blender-cli project add-light --project project.json Sun --type SUN --energy 5.0
77
+
78
+ # Export to GLB
79
+ blender-cli project export --project project.json --out scene.glb
80
+
81
+ # Render a preview
82
+ blender-cli render still --glb scene.glb --project project.json --preset iso --out preview.png
83
+ ```
84
+
85
+ ### Python SDK
86
+
87
+ ```python
88
+ from blender_cli import ProjectFile
89
+
90
+ pf = ProjectFile.new("Alpine", profile="hd1080p")
91
+
92
+ # Materials
93
+ pf.add_material("grass", pbr_folder="./textures/grass/", tiling=[4, 4])
94
+ pf.add_material("rock", pbr_folder="./textures/rock/", tiling=[2, 2])
95
+
96
+ # Terrain
97
+ pf.set_terrain(512, 512, seed=42)
98
+ pf.terrain_op("noise", type="fbm", amp=12.0, freq=0.008, octaves=6)
99
+ pf.terrain_op("smooth", radius=3, iters=1)
100
+ pf.terrain_op("erode", type="hydraulic", iterations=40)
101
+ pf.set_terrain_material("grass")
102
+
103
+ # Anchors (named spatial references)
104
+ pf.add_anchor("village", [256, 256, 0], annotation="center")
105
+
106
+ # Objects (snapped to terrain at export)
107
+ pf.add_object("Cottage", asset_path="./assets/cottage.glb",
108
+ location=pf.anchor_pos("village"), tags=["building"], snap=True)
109
+
110
+ # Camera, light
111
+ pf.add_camera("Main", location=[0, -50, 30], look_at=[256, 256, 0], lens=35)
112
+ pf.add_light("Sun", "SUN", energy=5.0, rotation=[0.5, 0.0, 0.0])
113
+
114
+ # Export
115
+ pf.save("project.json")
116
+ pf.export_glb("scene.glb")
117
+ ```
118
+
119
+ ## Architecture
120
+
121
+ ```
122
+ project.json ──[export_glb]──► scene.glb
123
+ ▲ │
124
+ │ │
125
+ └────────[import_glb]──────────┘
126
+ ```
127
+
128
+ Everything goes through **`project.json`** as the single source of truth. Edit it via the Python SDK (`ProjectFile`) or the CLI (`blender-cli`), then export to GLB. You can also import an existing GLB back into a project file.
129
+
130
+ ## Features
131
+
132
+ ### Terrain
133
+
134
+ Procedural heightfield terrain built from a chain of operations:
135
+
136
+ | Operation | Effect |
137
+ | ---------------- | ------------------------- |
138
+ | `flat` | Start flat at elevation z |
139
+ | `noise` | Add fbm/ridged noise |
140
+ | `smooth` | Gaussian blur |
141
+ | `terrace` | Plateau effect |
142
+ | `clamp` | Clamp height range |
143
+ | `stamp` | Local circular/ring edit |
144
+ | `erode` | Hydraulic/thermal erosion |
145
+ | `radial_falloff` | Island/crater falloff |
146
+ | `remap_curve` | Height remapping curve |
147
+
148
+ ### Materials
149
+
150
+ PBR texture folders (auto-detects diffuse, normal, roughness, AO, displacement) or flat colors with metallic/roughness control.
151
+
152
+ ### Objects & Primitives
153
+
154
+ Primitives: `box`, `plane`, `cylinder`, `sphere`, `cone`, `torus`. Also supports prefab GLB assets and empties.
155
+
156
+ **Snap system** — raycast objects onto geometry at export time:
157
+
158
+ | Axis | Use case | Policy | Effect |
159
+ | ---- | ------------- | --------- | ------------------------ |
160
+ | `-Z` | Floor/terrain | `FIRST` | Sit on first surface hit |
161
+ | `+Z` | Ceiling mount | `ORIENT` | Align to surface normal |
162
+ | `+X` | Wall mount | `HIGHEST` | Highest hit Z |
163
+
164
+ Filter snapping with `target_tags` and `exclude_tags`.
165
+
166
+ ### Anchors
167
+
168
+ Named spatial reference points. Place objects, cameras, and lights relative to anchors instead of hardcoded coordinates:
169
+
170
+ ```python
171
+ pf.add_anchor("gate", [100, 100, 0])
172
+ pf.add_object("Tower", location=pf.anchor_pos("gate", [5, 0, 0]), snap=True)
173
+ ```
174
+
175
+ ### Instances
176
+
177
+ GPU-instanced scatter groups for vegetation, rocks, and props with per-point rotation and scale.
178
+
179
+ ### Cameras
180
+
181
+ Static cameras or animated paths (orbit, dolly, flyover). Ghost cameras are excluded from GLB export and used only for debug renders.
182
+
183
+ ### Lights
184
+
185
+ SUN, POINT, SPOT, AREA light types. Ghost lights for debug previews.
186
+
187
+ ### Bevy / Blenvy Integration
188
+
189
+ Embed Bevy ECS components directly in the GLB. The SDK validates component names against a Bevy `registry.json`:
190
+
191
+ ```bash
192
+ blender-cli blenvy set-registry --project project.json assets/registry.json
193
+ blender-cli blenvy add-component --project project.json Ground RigidBody Static
194
+ blender-cli blenvy validate --registry assets/registry.json --project project.json
195
+ ```
196
+
197
+ ### Render & Debug
198
+
199
+ Render stills from named cameras or presets (`top`, `iso`). Supports:
200
+
201
+ - Tag-based show/hide (`--hide-tag ceiling` for dollhouse views)
202
+ - Wireframe mode
203
+ - Highlight + ghost mode
204
+ - Decomposition render (flat colors per object/tag)
205
+ - Multi-pass (beauty, depth, normal)
206
+
207
+ ### Session
208
+
209
+ Undo/redo with named snapshots.
210
+
211
+ ### REPL
212
+
213
+ Interactive prompt for exploring scenes:
214
+
215
+ ```bash
216
+ blender-cli repl --project project.json
217
+ ```
218
+
219
+ ## Render profiles
220
+
221
+ | Profile | Engine | Resolution | Samples | Use case |
222
+ | ------------------- | ------ | ---------- | ------- | ------------------- |
223
+ | `default` | EEVEE | 1920x1080 | 64 | General development |
224
+ | `preview` | EEVEE | 960x540 | 16 | Quick iteration |
225
+ | `hd1080p` | CYCLES | 1920x1080 | 128 | High quality |
226
+ | `4k` | CYCLES | 3840x2160 | 256 | Ultra quality |
227
+ | `product_render` | CYCLES | 2048x2048 | 512 | Transparent bg |
228
+ | `animation_preview` | EEVEE | 1280x720 | 16 | Animation testing |
229
+
230
+ ## CLI reference
231
+
232
+ ```
233
+ blender-cli [--project FILE] [--json] COMMAND
234
+ ```
235
+
236
+ | Command | Description |
237
+ | ------------ | ----------------------------------------- |
238
+ | `project` | Create, info, export, import projects |
239
+ | `terrain` | Init, add ops, set mesh/material |
240
+ | `material` | Add/list PBR or flat-color materials |
241
+ | `anchor` | Add/list/remove spatial anchors |
242
+ | `object` | Add/remove/manage objects |
243
+ | `instance` | Add/list/remove GPU-instanced groups |
244
+ | `camera` | Add cameras and animated paths |
245
+ | `render` | Render stills, focus shots, decomposition |
246
+ | `world` | Set background color or HDRI |
247
+ | `blenvy` | Bevy component validation and embedding |
248
+ | `session` | Undo/redo/history |
249
+ | `select` | Query objects with DSL |
250
+ | `inspect` | Inspect GLB scene contents |
251
+ | `stats` | Scene statistics |
252
+ | `repl` | Interactive REPL |
253
+ | `align` | Image-to-3D alignment pipeline |
254
+ | `animation` | Keyframe animation |
255
+ | `modifier` | Geometry modifiers |
256
+ | `op` | Low-level Blender operations |
257
+ | `run` | Execute build scripts |
258
+ | `measure` | Measure distances and dimensions |
259
+ | `raycast` | Raycast queries |
260
+ | `candidates` | Placement candidate generation |
261
+ | `assets` | Asset management |
262
+ | `manifest` | Scene manifest operations |
263
+
264
+ Pass `--json` for machine-readable JSON output on all commands.
265
+
266
+ ## Development
267
+
268
+ ```bash
269
+ # Install dev dependencies
270
+ uv sync --group dev
271
+
272
+ # Run tests
273
+ uv run pytest
274
+
275
+ # Type check
276
+ uv run pyright
277
+ ```
278
+
279
+ ## License
280
+
281
+ MIT
@@ -0,0 +1,251 @@
1
+ # blender-cli
2
+
3
+ Agent-friendly procedural map generation SDK built on Blender's Python API.
4
+
5
+ `blender-cli` provides a **Python SDK** and a **CLI** for building 3D scenes declaratively through a `project.json` file — procedural terrain, PBR materials, object placement with snap/raycast, GPU-instanced scatter, cameras, lights, and Bevy/Blenvy ECS component embedding — then exports to GLB.
6
+
7
+ ## Installation
8
+
9
+ Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
10
+
11
+ ```bash
12
+ # Install from source
13
+ uv pip install .
14
+
15
+ # Or run directly with uvx (no install needed)
16
+ uvx --from . blender-cli
17
+
18
+ # From a git repo
19
+ uvx --from git+https://github.com/julien-blanchon/blender_cli blender-cli
20
+ ```
21
+
22
+ ## Quick start
23
+
24
+ ### CLI
25
+
26
+ ```bash
27
+ # Create a project
28
+ blender-cli project new --name "Alpine" --profile hd1080p -o project.json
29
+
30
+ # Add materials
31
+ blender-cli material add --project project.json grass --pbr-folder ./textures/grass/ --tiling 4 4
32
+
33
+ # Build terrain
34
+ blender-cli terrain init --project project.json --width 512 --height 512 --seed 42
35
+ blender-cli terrain op --project project.json noise type=fbm amp=15 freq=0.008 octaves=6
36
+ blender-cli terrain op --project project.json smooth radius=3 iters=1
37
+ blender-cli terrain material --project project.json grass
38
+
39
+ # Place objects (snapped to terrain)
40
+ blender-cli project add-object --project project.json Wall \
41
+ --primitive box --primitive-params '{"size":[10,0.3,3]}' \
42
+ --at 50 50 0 --material rock --snap -Z --tags building
43
+
44
+ # Add camera and light
45
+ blender-cli project add-camera --project project.json Main --at 0 -50 30 --lens 35
46
+ blender-cli project add-light --project project.json Sun --type SUN --energy 5.0
47
+
48
+ # Export to GLB
49
+ blender-cli project export --project project.json --out scene.glb
50
+
51
+ # Render a preview
52
+ blender-cli render still --glb scene.glb --project project.json --preset iso --out preview.png
53
+ ```
54
+
55
+ ### Python SDK
56
+
57
+ ```python
58
+ from blender_cli import ProjectFile
59
+
60
+ pf = ProjectFile.new("Alpine", profile="hd1080p")
61
+
62
+ # Materials
63
+ pf.add_material("grass", pbr_folder="./textures/grass/", tiling=[4, 4])
64
+ pf.add_material("rock", pbr_folder="./textures/rock/", tiling=[2, 2])
65
+
66
+ # Terrain
67
+ pf.set_terrain(512, 512, seed=42)
68
+ pf.terrain_op("noise", type="fbm", amp=12.0, freq=0.008, octaves=6)
69
+ pf.terrain_op("smooth", radius=3, iters=1)
70
+ pf.terrain_op("erode", type="hydraulic", iterations=40)
71
+ pf.set_terrain_material("grass")
72
+
73
+ # Anchors (named spatial references)
74
+ pf.add_anchor("village", [256, 256, 0], annotation="center")
75
+
76
+ # Objects (snapped to terrain at export)
77
+ pf.add_object("Cottage", asset_path="./assets/cottage.glb",
78
+ location=pf.anchor_pos("village"), tags=["building"], snap=True)
79
+
80
+ # Camera, light
81
+ pf.add_camera("Main", location=[0, -50, 30], look_at=[256, 256, 0], lens=35)
82
+ pf.add_light("Sun", "SUN", energy=5.0, rotation=[0.5, 0.0, 0.0])
83
+
84
+ # Export
85
+ pf.save("project.json")
86
+ pf.export_glb("scene.glb")
87
+ ```
88
+
89
+ ## Architecture
90
+
91
+ ```
92
+ project.json ──[export_glb]──► scene.glb
93
+ ▲ │
94
+ │ │
95
+ └────────[import_glb]──────────┘
96
+ ```
97
+
98
+ Everything goes through **`project.json`** as the single source of truth. Edit it via the Python SDK (`ProjectFile`) or the CLI (`blender-cli`), then export to GLB. You can also import an existing GLB back into a project file.
99
+
100
+ ## Features
101
+
102
+ ### Terrain
103
+
104
+ Procedural heightfield terrain built from a chain of operations:
105
+
106
+ | Operation | Effect |
107
+ | ---------------- | ------------------------- |
108
+ | `flat` | Start flat at elevation z |
109
+ | `noise` | Add fbm/ridged noise |
110
+ | `smooth` | Gaussian blur |
111
+ | `terrace` | Plateau effect |
112
+ | `clamp` | Clamp height range |
113
+ | `stamp` | Local circular/ring edit |
114
+ | `erode` | Hydraulic/thermal erosion |
115
+ | `radial_falloff` | Island/crater falloff |
116
+ | `remap_curve` | Height remapping curve |
117
+
118
+ ### Materials
119
+
120
+ PBR texture folders (auto-detects diffuse, normal, roughness, AO, displacement) or flat colors with metallic/roughness control.
121
+
122
+ ### Objects & Primitives
123
+
124
+ Primitives: `box`, `plane`, `cylinder`, `sphere`, `cone`, `torus`. Also supports prefab GLB assets and empties.
125
+
126
+ **Snap system** — raycast objects onto geometry at export time:
127
+
128
+ | Axis | Use case | Policy | Effect |
129
+ | ---- | ------------- | --------- | ------------------------ |
130
+ | `-Z` | Floor/terrain | `FIRST` | Sit on first surface hit |
131
+ | `+Z` | Ceiling mount | `ORIENT` | Align to surface normal |
132
+ | `+X` | Wall mount | `HIGHEST` | Highest hit Z |
133
+
134
+ Filter snapping with `target_tags` and `exclude_tags`.
135
+
136
+ ### Anchors
137
+
138
+ Named spatial reference points. Place objects, cameras, and lights relative to anchors instead of hardcoded coordinates:
139
+
140
+ ```python
141
+ pf.add_anchor("gate", [100, 100, 0])
142
+ pf.add_object("Tower", location=pf.anchor_pos("gate", [5, 0, 0]), snap=True)
143
+ ```
144
+
145
+ ### Instances
146
+
147
+ GPU-instanced scatter groups for vegetation, rocks, and props with per-point rotation and scale.
148
+
149
+ ### Cameras
150
+
151
+ Static cameras or animated paths (orbit, dolly, flyover). Ghost cameras are excluded from GLB export and used only for debug renders.
152
+
153
+ ### Lights
154
+
155
+ SUN, POINT, SPOT, AREA light types. Ghost lights for debug previews.
156
+
157
+ ### Bevy / Blenvy Integration
158
+
159
+ Embed Bevy ECS components directly in the GLB. The SDK validates component names against a Bevy `registry.json`:
160
+
161
+ ```bash
162
+ blender-cli blenvy set-registry --project project.json assets/registry.json
163
+ blender-cli blenvy add-component --project project.json Ground RigidBody Static
164
+ blender-cli blenvy validate --registry assets/registry.json --project project.json
165
+ ```
166
+
167
+ ### Render & Debug
168
+
169
+ Render stills from named cameras or presets (`top`, `iso`). Supports:
170
+
171
+ - Tag-based show/hide (`--hide-tag ceiling` for dollhouse views)
172
+ - Wireframe mode
173
+ - Highlight + ghost mode
174
+ - Decomposition render (flat colors per object/tag)
175
+ - Multi-pass (beauty, depth, normal)
176
+
177
+ ### Session
178
+
179
+ Undo/redo with named snapshots.
180
+
181
+ ### REPL
182
+
183
+ Interactive prompt for exploring scenes:
184
+
185
+ ```bash
186
+ blender-cli repl --project project.json
187
+ ```
188
+
189
+ ## Render profiles
190
+
191
+ | Profile | Engine | Resolution | Samples | Use case |
192
+ | ------------------- | ------ | ---------- | ------- | ------------------- |
193
+ | `default` | EEVEE | 1920x1080 | 64 | General development |
194
+ | `preview` | EEVEE | 960x540 | 16 | Quick iteration |
195
+ | `hd1080p` | CYCLES | 1920x1080 | 128 | High quality |
196
+ | `4k` | CYCLES | 3840x2160 | 256 | Ultra quality |
197
+ | `product_render` | CYCLES | 2048x2048 | 512 | Transparent bg |
198
+ | `animation_preview` | EEVEE | 1280x720 | 16 | Animation testing |
199
+
200
+ ## CLI reference
201
+
202
+ ```
203
+ blender-cli [--project FILE] [--json] COMMAND
204
+ ```
205
+
206
+ | Command | Description |
207
+ | ------------ | ----------------------------------------- |
208
+ | `project` | Create, info, export, import projects |
209
+ | `terrain` | Init, add ops, set mesh/material |
210
+ | `material` | Add/list PBR or flat-color materials |
211
+ | `anchor` | Add/list/remove spatial anchors |
212
+ | `object` | Add/remove/manage objects |
213
+ | `instance` | Add/list/remove GPU-instanced groups |
214
+ | `camera` | Add cameras and animated paths |
215
+ | `render` | Render stills, focus shots, decomposition |
216
+ | `world` | Set background color or HDRI |
217
+ | `blenvy` | Bevy component validation and embedding |
218
+ | `session` | Undo/redo/history |
219
+ | `select` | Query objects with DSL |
220
+ | `inspect` | Inspect GLB scene contents |
221
+ | `stats` | Scene statistics |
222
+ | `repl` | Interactive REPL |
223
+ | `align` | Image-to-3D alignment pipeline |
224
+ | `animation` | Keyframe animation |
225
+ | `modifier` | Geometry modifiers |
226
+ | `op` | Low-level Blender operations |
227
+ | `run` | Execute build scripts |
228
+ | `measure` | Measure distances and dimensions |
229
+ | `raycast` | Raycast queries |
230
+ | `candidates` | Placement candidate generation |
231
+ | `assets` | Asset management |
232
+ | `manifest` | Scene manifest operations |
233
+
234
+ Pass `--json` for machine-readable JSON output on all commands.
235
+
236
+ ## Development
237
+
238
+ ```bash
239
+ # Install dev dependencies
240
+ uv sync --group dev
241
+
242
+ # Run tests
243
+ uv run pytest
244
+
245
+ # Type check
246
+ uv run pyright
247
+ ```
248
+
249
+ ## License
250
+
251
+ MIT
@@ -0,0 +1,57 @@
1
+ [project]
2
+ name = "blender-cli"
3
+ version = "0.1.0"
4
+ description = "Agent-friendly procedural map generation SDK built on Blender's Python API"
5
+ keywords = ["blender", "procedural", "map", "3d", "terrain", "generation"]
6
+ classifiers = [
7
+ "Development Status :: 3 - Alpha",
8
+ "Intended Audience :: Developers",
9
+ "Programming Language :: Python :: 3",
10
+ "Programming Language :: Python :: 3.11",
11
+ "Programming Language :: Python :: 3.12",
12
+ "Topic :: Multimedia :: Graphics :: 3D Modeling",
13
+ "Topic :: Games/Entertainment",
14
+ ]
15
+ readme = "README.md"
16
+ authors = [{ name = "Julien Blanchon", email = "julien@blanchon.cc" }]
17
+ requires-python = ">=3.13"
18
+ dependencies = [
19
+ "bpy>=5.1.0",
20
+ "cma>=3.3",
21
+ "click>=8.0",
22
+ "fal-client>=0.7",
23
+ "matplotlib>=3.8",
24
+ "numpy>=1.24",
25
+ "opencv-python-headless>=4.8",
26
+ "Pillow>=10.0",
27
+ "prompt-toolkit>=3.0",
28
+ "pyrender>=0.1.45",
29
+ "rtree>=1.2",
30
+ "scipy>=1.11",
31
+ "trimesh>=4.0",
32
+ ]
33
+
34
+ [project.scripts]
35
+ blender_cli = "blender_cli.cli:main"
36
+
37
+ [dependency-groups]
38
+ dev = [
39
+ "pytest>=8.0",
40
+ "pyright>=1.1",
41
+ "trimesh>=4.0",
42
+ "numpy>=1.24",
43
+ "rtree>=1.4.1",
44
+ "fake-bpy-module>=20260220",
45
+ ]
46
+
47
+ [tool.pytest.ini_options]
48
+ markers = ["slow: tests taking >30s (deselect with -m 'not slow')"]
49
+ testpaths = ["tests"]
50
+
51
+ [tool.pyright]
52
+ # bpy stubs are incomplete — data/types/ops/context are not recognized.
53
+ reportAttributeAccessIssue = "warning"
54
+
55
+ [build-system]
56
+ requires = ["uv_build>=0.10.5,<0.11.0"]
57
+ build-backend = "uv_build"