Minimal template for building Blender extensions with Python wheel dependencies, cross-platform builds, and GitHub Actions CI/CD.
Generate a fully configured project interactively — no need to clone this repo:
bash <(curl -s https://raw.githubusercontent.com/josemarinfarina/blender_addon_template/main/create_addon.sh)The script asks for addon name, author, description, Blender version, etc. and writes all files with your data already in place.
Or locally, if you have the repo:
./create_addon.sh
.
├── create_addon.sh # Interactive scaffolding script (like create-next-app)
├── blender_manifest.toml # Blender extension manifest (metadata + wheels)
├── build_extension.sh # Assembles build_temp/ and runs blender extension build
├── my_addon/ # Addon source code (rename to your addon name)
│ └── __init__.py
├── constraints/ # Pinned dependency lists per platform
│ ├── base.txt # flexible ranges (documentation / pip install)
│ ├── linux-x64.txt # pinned versions for reproducible wheel downloads
│ ├── windows-x64.txt
│ ├── macos-x64.txt
│ └── macos-arm64.txt
├── scripts/
│ └── fetch_wheels.sh # Downloads wheels for all 4 platforms into wheels/
├── wheels/ # Created by fetch_wheels.sh (gitignored .whl files)
├── dist/ # Build output (gitignored)
├── build_temp/ # Temporary build dir (gitignored)
├── .github/
│ └── workflows/
│ └── build-extension.yml # CI: fetch wheels → download Blender → build → upload artifacts
├── .gitignore
├── LICENSE
└── README.md
If you prefer to clone this repo instead of using create_addon.sh:
Replace my_addon everywhere:
- Rename the
my_addon/directory. - Update
ADDON_DIRdefault inbuild_extension.sh. - Update paths in
.github/workflows/build-extension.yml. - Update
id,name, and other fields inblender_manifest.toml. - Update
bl_infoin__init__.py.
If your addon needs third-party Python packages:
- Add the package with flexible version ranges to
constraints/base.txt. - Pin exact versions in each platform file (
constraints/linux-x64.txt, etc.). - Run
scripts/fetch_wheels.shto download all wheels intowheels/. - List the downloaded
.whlfilenames in thewheelsarray ofblender_manifest.toml.
Tip: Blender already ships
numpy. Do not include it in your constraints.
# 1. Download wheels (only needed once, or when deps change)
chmod +x scripts/fetch_wheels.sh
./scripts/fetch_wheels.sh
# 2. Build the extension (requires `blender` on PATH or BLENDER_BIN set)
chmod +x build_extension.sh
./build_extension.shPer-platform .zip files are written to dist/.
The included workflow (.github/workflows/build-extension.yml) runs on every push to main/master or on tags matching v*. It:
- Checks out the repo.
- Fetches wheels for all platforms via
scripts/fetch_wheels.sh. - Downloads a Blender release.
- Builds the extension with
--split-platforms. - Uploads per-platform
.zipartifacts.
Update the BLENDER_VERSION variable in the workflow to match your target.
Each platform file lists pinned dependency versions. fetch_wheels.sh reads these and uses pip download --only-binary=:all: --platform=<tag> to fetch the correct wheels without installing anything locally.
The extension manifest tells Blender about your addon. The wheels array lists every .whl that must be shipped — both universal (py3-none-any) and platform-specific (cp311-cp311-<platform>).
Copies only the necessary files (manifest, addon source, wheels) into a temporary build_temp/ directory, then invokes blender --command extension build --split-platforms. This keeps the repository clean — test files, scripts, docs, etc. are never included in the built extension.
Downloaded .whl files live here but are gitignored. They are fetched fresh at build time (locally or in CI). Only the wheels/ directory itself is committed (empty).
This template is released under the GPL-3.0-or-later license.