About blockbench-substance
An advanced skill for using Adobe Substance 3D assets and tools in Blockbench texturing workflows. It covers procedural materials, baking, Painter exports, map preparation, and importing texture sets.
Key features
- 01Renders procedural Substance materials
- 02Bakes model masks such as AO and curvature
- 03Runs Painter workflows through HTTP
- 04Converts and packs texture maps
- 05Imports maps into Blockbench
Use cases
- 01Creating procedural textures for a Blockbench model
- 02Baking masks from model geometry
- 03Preparing Painter exports for Blockbench
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ jasonjgardner/ blockbench-mcp-project --skill blockbench-substanceAfter installing, type/blockbench-substancein Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/baker.mdpainter.mdsat-cli.mdscripts/painter_bedrock_export.pypainter_new_project.pypainter_remote.pyprep_maps.pysat_locate.pysat_render.pyDetails
From the project READMEBlockbench + Adobe Substance 3D
Optional and advanced. Most Blockbench work never needs this: paint with blockbench-texturing, generate with blockbench-gpt-image-textures, derive normal/MER with blockbench-albedo-to-pbr. Use this skill only when the user asks for Substance or already has .sbsar/.sbs/Painter assets. It needs a licensed Adobe Substance 3D install. Load blockbench-use first and blockbench-pbr-materials to assign results.
Substance produces image files. Blockbench stays the source of geometry and UVs. Every path ends with files imported through create_texture (data, pbr_channel) or import_texture_set.
0. Locate the tools
python scripts/sat_locate.py
Designer bundles sbsrender, sbscooker, sbsupdater and substance3d_baker, off PATH, in C:\Program Files\Adobe\Adobe Substance 3D Designer\. sbsmutator and the pysbs Python API come only with the standalone Substance Automation Toolkit. Painter is a GUI app driven over HTTP. If nothing is found, stop and tell the user; do not install Adobe software.
Pick the path
| Goal | Tool | Reference |
|---|---|---|
| Procedural material (bricks, rust, leaves) as Blockbench textures | sat_render.py → sbsrender | sat-cli.md |
Have a .sbs graph, need an .sbsar | sbscooker (sbsupdater first if old) | sat-cli.md |
Edit/specialise a .sbs headlessly | sbsmutator (SAT only) | sat-cli.md |
| AO / curvature / ID / position masks from the model | substance3d_baker | baker.md |
| Hand-paint the model with smart materials | Painter + painter_remote.py | painter.md |
| Pack Bedrock MER, convert bit depth, flip normal green, shrink | prep_maps.py | below |
Workflow A: procedural material → Blockbench
python scripts/sat_render.py material.sbsar --out out --size 16 --seed 7 \
--set Season=0.8 --normal-format directx
--sizeis pixels; the script converts to log2$outputsize(rawsbsrenderneeds'$outputsize@4,4'for 16 px). It creates--out; rawsbsrenderexits 47 if the folder is missing.- Read
inputsfrom the JSON report, then set parameters by identifier. Unknown identifiers come back aswarnings, becausesbsrenderignores them silently. - Match outputs to channels by
usages:baseColor/diffuse→ color;normal;height;metallic+roughness(orglossiness, inverted) +emissive→ MER. - Output is 8-bit by default. Tiling block textures render straight at 16/32 px. For atlases, render at the atlas size or larger and shrink.
Workflow B: bake masks from the Blockbench model
- Fix UVs: every face needs its own UV rectangle. Default per-face Auto UV on block formats stacks faces on top of each other and ruins the bake. See baker.md § Prepare.
export_model→codec_id: "gltf",options: {"encoding": "binary"},path: <abs>.glb(orobj).- Bake at 8–16× density with underscore flags (the online docs show hyphens, which fail):
substance3d_baker AmbientOcclusion.Raytraced model.glb --use_lowdef_as_highdef true --output_size 512,512 --output_path bake python scripts/prep_maps.py convert bake/*.png --out bake/64 --size 64(16-bit → 8-bit, box downsample).- Use the maps as masks: multiply AO into the colour texture, or feed them to
sbsrender --set-entry/ Painter.
Workflow C: paint in Painter, bring maps back
- Fix UVs, then
export_modelwithcodec_id: "obj". Painter cannot import glTF. - Start Painter with
--enable-remote-scripting(never--help: it opens the app), then:python scripts/painter_remote.py --ping --wait 240 python scripts/painter_remote.py --python-file scripts/painter_new_project.py --result \ --set MESH=C:/work/model.obj --set NORMAL=DirectX --set RESOLUTION=1024 --set BAKE=1 - The user paints in Painter (or you script layers after reading the local API docs).
- Export and shrink:
python scripts/painter_remote.py --python-file scripts/painter_bedrock_export.py --result \ --set OUT=C:/work/painter_out --set NAME=model --set PRESET=bedrock --set SIZE_LOG2=9 python scripts/prep_maps.py convert C:/work/painter_out/model*.png --out final --size 64bedrockgivesNAME.png,NAME_mer.png,NAME_normal.png(DirectX).gltfgives ORM + OpenGL normal. Painter never exports below 128 px, and skips maps whose channel is absent. Trust thefileslist in the result.
Pack and import
python scripts/prep_maps.py pack-mer --metallic out/m_metallic.png --emissive 0 --roughness out/m_roughness.png --out final/model_mer.png
python scripts/prep_maps.py texture-set --color model --mer model_mer --normal model_normal --out final/model.texture_set.json
Constants are 0–255; --glossiness replaces --roughness and is inverted. Then import_texture_set with the JSON path, or create_texture per file (pbr_channel: color/normal/height/mer) + create_pbr_material. Normal or height, never both.
Conventions and verification
- Normals: Bedrock → DirectX (green-down), glTF/Java labPBR → OpenGL. Baker default is
directx. A graph's$normalformatis graph-defined (one tested graph flipped red, not green), so compare renders or useprep_maps.py convert --flip-green. After import, raised features must read as raised in the Blockbench preview. - 16-bit trap: AO/curvature/height PNGs are often 16-bit;
PIL.Image.convert("L")clips them to white. Useprep_maps.py convertor--output-bit-depth 8. - Paths: pass
C:/...paths to the executables;/c/...from Git Bash breaks--alias. Quote'$outputsize@...'. - Blockbench project safety: note the project UUID before export and import, and confirm it before writing textures back.
- Check each imported map with
list_textures/get_textureand acapture_screenshot. A blank-white or uniformly gray map means the bit depth, UV overlap or parameter was wrong. It is not a stylistic result.