Experiments in automating Blender with Python.
brew install poetry
poetry completions fish > ~/.config/fish/completions/poetry.fish
# run this once to create venv and install poe
poetry install
# run to (re)install everything--this is the main install command
poe install# run with UI to work visually
blender -P headless_mode.py # `poe blend`
# run without UI to debug (fast)
blender -P headless_mode.py -b # `poe bblend`butils abstracts common Blender scripting code and provides CLI commands.
# General help
python -m butils --help
# Install dependencies into Blender's Python environment and symlink `butils`
# Run this when new dependencies are added to `butils`.
python -m butils install
# (Alias: poe install-butils)
# Create a new Blender starter script
python -m butils create -i my_new_script.py
# (Alias: poe create)
# The -i/--input-file flag specifies the name for the new script.
# Compress output images and videos
# Supported image formats: .png, .jpg, .jpeg
# Supported video formats: .mkv, .mp4
python -m butils compress -i path/to/your/file.png
python -m butils compress -i path/to/your/file.mkv --crf 23
# (Alias: poe compress)
# Options for 'compress':
# -i, --input-file: (Required) Path to the image or video file to compress.
# --analyze: (For images only) Get image attrs and metadata. Skips compression.
# --crf: Constant Rate Factor. Sets bitrate (e.g., 18-28). Lower is better.
# profile GPU performance
pipx run nvitop
# module structure
butils/
├── animation/
│ ├── fcurve.py # Utilities for F-Curves
│ └── keyframe.py # Utilities for keyframes
├── blend_file.py # Work with .blend files
├── btyping/
│ ├── animation.py # Type hints for animation module
│ └── render.py # Type hints for render module
├── commands/ # CLI commands
│ ├── compress/
│ │ ├── image.py # Image compression commands
│ │ └── video.py # Video compression commands
│ ├── install/
│ │ ├── pythonpath.py # Command to set up Python path for Blender
│ │ └── requirements.py # Command to install deps in Blender's Python
│ └── starter/
│ ├── create.py # Command to create a new starter script
│ └── starter_script.py # Boilerplate for scripting a Blender scene
├── mesh.py # Simplify working with meshes
├── render/
│ ├── config.py # Rendering configuration utilities
│ ├── optimize.py # Utilities for optimizing render performance
│ ├── render.py # Core rendering utilities
│ └── update_mask.py # Utilities for updating render masks
├── scene.py # Clean scenes, work with collections
└── ui.py # Work with the Blender UI: get contexts, control viewportThis project uses the pre-commit python module to ensure code quality and
consistency. These hooks are automatically installed when you run poe install,
and can be run on demand withnormal maps and texture painting poe pre-commit.
- lint and format using
ruff,shfmt,shellcheck, andmarkdownlint,yamllint,actionlint. - check spelling, trim trailing spaces, add final newline to files.
- validate links, scan for large files, warn about any added secrets.
- validate json, yaml and toml files.
This project uses Python's built-in unittest module for testing. Tests are
executed within a Docker container that includes Blender, ensuring a consistent
testing environment. This setup is defined in the GitHub Actions workflow file
(.github/workflows/blender_tests.yml).
There are several ways to run the tests:
-
Locally with
act: You can simulate the GitHub Actions environment locally usingact. Thepyproject.tomldefines apoetask for this:poe act poe act --input="testcase=tests.test_module.TestCase.test_function"Refer to the
tool.poe.tasks.actsection inpyproject.tomland theworkflow_dispatchinputs in.github/workflows/blender_tests.ymlfor more details on available parameters. -
GitHub Actions: Tests are automatically executed in GitHub Actions on every
pushandpull_requestto themainbranch. You can also manually trigger the "Blender Tests" workflow from the Actions tab in your GitHub repository, providing inputs for specific test cases, verbosity, etc.gh workflow run "Blender Tests" --input testcase=your_test_case --input verbosity=2
![]() |
|---|
| Geometry nodes aftereffects like effect |
![]() |
|---|
| Geometry nodes glass metaball exercise - Blender 5.0 beta |
![]() |
|---|
| Particle system using turbulence force field |
![]() |
|---|
| Learning about particle emitters |
![]() |
|---|
| Cloth pinning tests using hook mod and vertex weight mix mod |
![]() |
|---|
| Testing subdiv -> cloth -> solidify -> subdiv mod stack |
![]() |
|---|
| Cloth sim preset testing |
![]() |
|---|
| Cloth sim + Hair particle system |
![]() |
|---|
| Experiments with Distribute Points in Volume |
![]() |
|---|
| LED matrix using ray casting to calc text collisions |
![]() |
|---|
| Proximity based geo nodes exercise |
![]() |
|---|
| Metaball effect using geometry nodes |
![]() |
|---|
| Learning product design motion graphics |
![]() |
![]() |
|---|---|
| Shuttle Radar Topography Mission data | Open Street Map data via BlenderGIS |
![]() |
|---|
| Proximity plus fracture modifier |
![]() |
|---|
| Geometry proximity node |
![]() |
|---|
| Emissive image textures for screen and keyboard backlight |
![]() |
|---|
| Started product design exercise - Laptop |
![]() |
|---|
| Sourcing low res/poly textures from ebay photos. |
![]() |
|---|
| Finished animation with pixelate compositor node. |
![]() |
|---|
| Learning more about displacement maps and vertex painting. |
![]() |
|---|
| Learning more about procedural texture creation. |
![]() |
|---|
| Learning more about normal maps and texture painting. |
![]() |
|---|
| Exploring alternative photogrammetry workflow with Metashape. |
![]() |
|---|
| Improving Meshroom results: low ISO, small aperature, tripod, remote. |
![]() |
|---|
| Rendering Earth using NASA satellite imagery. |
![]() |
|---|
| Photogrammetry experiment in Meshroom. |
![]() |
|---|
| Hyperspace effect w/ HDRI scaling. |
![]() |
|---|
| Animating instance scale with a noise texture. |
![]() |
|---|
| Exploring basic lighting concepts. |
![]() |
|---|
| Using a driver to control a value with a named attribute. |
![]() |
|---|
| Getting collection instances by random index with geometry nodes. |
![]() |
|---|
| Reading variables with geometry nodes. |
![]() |
|---|
| meshes from scratch using geometry nodes. |
![]() |
|---|
| Finished chair modeling series. |
![]() |
|---|
| Profiling GPU performance to identify bottlenecks in render pipeline. |
![]() |
|---|
| UV unwrap to prepare for texturing. |
![]() |
|---|
| Chair model complete. |
![]() |
|---|
brew install gifski && gifski -ogeo_nodes_proximity2 file.gif img0*.png |
![]() |
|---|
| Manipulating the UI with Python |
![]() |
|---|
| Tradition |
![]() |
|---|
| Practicing rendering and combining images in the compositor |
![]() |
|---|
| Composing an interior scene with 3rd party models |
![]() |
|---|
| Animating geometry nodes |
![]() |
|---|
| Exploring modifiers |
![]() |
|---|
| Learning to create clean, precise topology |
![]() |
|---|
| Learning to model with reference images |
![]() |
|---|
| Creating rock textures from procedural shaders |
![]() |
|---|
| Writing Shaders in Open Shader Language (OSL) |
![]() |
|---|
| Parametric Modeling with Geometry Nodes |
![]() |
|---|
| Learning Hard Surface Modeling |
![]() |
|---|
| Working with node based geometry modifiers |
![]() |
|---|
| Iterative Material Experiments |
iew |
| | :-----------------------------------------------------------------------: |
| Exploring Fresnel node and adding bloom with the compositor |
![]() |
|---|
| Wave Texture -> Voronoi Texture -> Displacement |
![]() |
![]() |
|---|---|
| Experimenting with iteration | Iterating using trigonometric functions |
![]() |
|---|
| Defining Materials with Python |
![]() |
|---|
| Node Based Material Experiments |
![]() |
|---|
| Using graph editor and camera view to proof an animation |
![]() |
|---|
| Mesh from scratch, composing and repetition |
![]() |
|---|
| Procedural Animation Example |





























































