polyhaven-scene-builder · diff
git:20260921.86ed6ee to git:20260921.655a684
21 added, 104 removed. Audit A to A.
---
name: polyhaven-scene-builder
description: Build complete product scenes using PolyHaven assets — HDRI environment, textured ground/pedestal, and optional props from the 3D model library. Trigger when asked to build a product scene, create a showcase setup, add a pedestal, or compose a product shot.
---
# PolyHaven Scene Builder
Builds a full product photography scene around your 3D model: HDRI environment, textured ground plane or pedestal, and optional prop models from PolyHaven's free library.
- > Adapted for claude-3d-harness. The original ran a bundled Node script that opened Blender's add-on socket itself and
- > sent it Python built from command-line text. The same steps now go through the MCP server, where each one is visible
- > and asks for permission. See `docs/security-review.md`.
-
- ## Parameters
-
- | Parameter | Description | Default |
- |-----------|-------------|---------|
- | `hdri` | PolyHaven HDRI asset ID | `studio_small_09` |
- | `ground` | PolyHaven texture for the ground | none |
- | `pedestal` | Add a cylindrical pedestal under the product | `false` |
- | `pedestal_texture` | Texture for the pedestal | same as ground |
- | `props` | PolyHaven model IDs to add | none |
- | `resolution` | Asset resolution: 1k, 2k, 4k | `2k` |
- | `preset` | Quick preset: showroom, outdoor, minimal, dramatic | none |
-
- ## Presets
-
- | Preset | HDRI | Ground | Pedestal |
- |--------|------|--------|----------|
- | **showroom** | `studio_small_09` | `marble_01` | yes |
- | **outdoor** | `kloppenheim_06_puresky` | `concrete_wall_003` | no |
- | **minimal** | `studio_small_03` | none (floating product) | no |
- | **dramatic** | `industrial_sunset_02_puresky` | `concrete_floor_02` | yes |
-
- ## Flow
-
- ### Step 1: HDRI environment
-
- The add-on's HDRI download rebuilds the first World in the file in place. If the scene has a World this job did not
- make, copy it first (`keep = scene.world.copy(); keep.name = "KEEP-" + scene.world.name; keep.use_fake_user = True`).
-
- `download_polyhaven_asset(asset_id=<hdri>, asset_type="hdris", resolution=<resolution>, file_format="hdr")`
-
- Then switch the viewport to rendered shading with the scene world, so the result can be judged:
-
- ```python
- import bpy
- for area in bpy.context.screen.areas:
- if area.type == 'VIEW_3D':
- for space in area.spaces:
- if space.type == 'VIEW_3D':
- space.shading.type = 'RENDERED'
- space.shading.use_scene_world = True
- break
- ```
-
- ### Step 2: Textured ground (only when `ground` is given)
-
- `download_polyhaven_asset(asset_id=<ground>, asset_type="textures", resolution=<resolution>, file_format="jpg")`
- returns the name of the material it created.
-
- ```python
- import bpy
-
- MATERIAL = "<material name the download returned>"
+ ## How to Run
- bpy.ops.mesh.primitive_plane_add(size=15, location=(0, 0, -0.01))
- plane = bpy.context.active_object
- plane.name = "Scene_Ground"
- mat = bpy.data.materials.get(MATERIAL)
- if mat:
- plane.data.materials.append(mat)
- # Scale UVs for better tiling
- for node in mat.node_tree.nodes:
- if node.type == 'MAPPING':
- node.inputs['Scale'].default_value = (3, 3, 3)
+ ```bash
+ node polyhaven-scene-builder/scripts/polyhaven-scene-builder.js --hdri studio_small_09 --ground marble_01 --pedestal
+ node polyhaven-scene-builder/scripts/polyhaven-scene-builder.js --hdri royal_esplanade --ground wood_cabinet_worn_long --props "potted_plant_04"
+ node polyhaven-scene-builder/scripts/polyhaven-scene-builder.js --preset showroom
```
- ### Step 3: Pedestal (only when `pedestal` is set)
-
- Name the product object. Do not guess it from "the first mesh in the file": ask `get_scene_info`, or the user.
-
- ```python
- import bpy
-
- PRODUCT = "<name of the product object>"
- PEDESTAL_MATERIAL = "<material name from step 2, or empty>"
-
- product = bpy.data.objects[PRODUCT]
- dims = product.dimensions
- radius = max(dims.x, dims.y) * 0.7
- bpy.ops.mesh.primitive_cylinder_add(
- radius=radius,
- depth=0.08,
- location=(product.location.x, product.location.y, product.location.z - dims.z / 2 - 0.04)
- )
- ped = bpy.context.active_object
- ped.name = "Pedestal"
- bpy.ops.object.shade_smooth()
+ ### Options
- mat = bpy.data.materials.get(PEDESTAL_MATERIAL) if PEDESTAL_MATERIAL else None
- if mat is None:
- # A simple dark glossy material
- mat = bpy.data.materials.new("Pedestal_Mat")
- mat.use_nodes = True
- bsdf = mat.node_tree.nodes["Principled BSDF"]
- bsdf.inputs["Base Color"].default_value = (0.02, 0.02, 0.02, 1)
- bsdf.inputs["Roughness"].default_value = 0.1
- bsdf.inputs["Metallic"].default_value = 0.3
- ped.data.materials.append(mat)
- print(f"Pedestal added: radius={radius:.2f}")
- ```
+ | Option | Description | Default |
+ |--------|-------------|---------|
+ | `--hdri` | PolyHaven HDRI asset ID | `studio_small_09` |
+ | `--ground` | PolyHaven texture for ground | none |
+ | `--pedestal` | Add a cylindrical pedestal under the product | `false` |
+ | `--pedestal-texture` | Texture for the pedestal | same as ground |
+ | `--props` | Comma-separated PolyHaven model IDs to add | none |
+ | `--resolution` | Asset resolution: 1k, 2k, 4k | `2k` |
+ | `--preset` | Quick preset: showroom, outdoor, minimal, dramatic | none |
+ | `--port` | Blender MCP port | `9876` |
- ### Step 4: Props (only when `props` is given)
+ ## Presets
- For each model ID:
- `download_polyhaven_asset(asset_id=<prop>, asset_type="models", resolution=<resolution>, file_format="gltf")`.
- The result lists the objects it imported; place them beside the product, never on top of it. If one fails, say so and
- carry on with the rest.
+ - **showroom** — `studio_small_09` HDRI + marble ground + pedestal
+ - **outdoor** — `kloppenheim_06_puresky` HDRI + concrete ground
+ - **minimal** — `studio_small_03` HDRI + no ground (floating product)
+ - **dramatic** — `industrial_sunset_02_puresky` HDRI + dark concrete + pedestal