
Extensions on GitHub
These slides and accompanying blog post were created for my talk at the 2025 Blender conference.
See the slides below of click directly on this link.
Who am I?
I’m Brady!
Molecular Nodes
This hasn’t been the first attempt at bringing molecular data sets into Blender, but I blieve it has so far been the most successful. In a very short summary, we can think of atoms and molecules as a collection of vertices and edges. Blender knows how to handle vertices and edges. Once we have the data inside of Blender (along with a large number of ‘molecular’ attributes for points and edges) then the full power of Geometry Nodes is at our fingertips for molecular visualisation.
Install as a python package?
It’s less likely than you’d think!
Creating an add-on for Blender that can also be built and shipping as a python package was quite the task. It leads to a variety of problems and strange engineering issues that come with writing code for Blender that a ‘regular’ python package wouldn’t have to deal with.
Covering that topic with all of our learnings would be a massive blog post itself. The short version is that you can install molecularnodes from pypi
and use if for molecular rendering in python scripts of jupyter notebooks like this one.

databpy
- ‘numpy-like’ interfaces to attributes on objects
# set the x component for the first 10 verts to 1.0
obj["position"][:10, 0] = 1.0
# add 1 to x, 2 to y, 3 to z component of position
obj["position"] += np.array([1, 2, 3])
# infers data types for storage and retrieval
obj["att_name"] = np.zeros(len(obj), dypte=int)
obj["att_name"]
# get and set attributes on non-point domains
obj.store_named_attribute(
data=np.zeros((len(bob), 4, 4), dtype=float),
name="a_matrix",
domain=db.AttributeDomains.FACE
)
obj.named_attribute()
Building on GitHub
Why build on GitHub?
Building & Distributing MN
Building & Distributing MN
- Run tests against different versions of Blender (including daily builds)
- Run tests against
bpy
installed viapip
for automated pipelines - Download and bundle
.whl
files with extension - Upload extension to GitHub & Extensions platform
Testing your Add-ons
Checko out Spencer’s talk on testing add-ons here.
Anatomy of a GitHub Action
- Runs on hardware managed by GitHub
- Free for public projects
- Mac / Windows / Linux
- Mid-power machines, no GPU
- Can use your own hardware as a GHA runner
- My PC with an RTX 3090 runs any GPU worklods back in Australia
Running Tests
name: tests
on:
push:
branches: ["main"]
pull_request:
branches: ["*"]
jobs:
blender:
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 4
fail-fast: false
matrix:
version: ["4.5", "daily"]
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: BradyAJohnston/setup-blender@v4
with:
version: ${{ matrix.version }}
- name: Install in Blender
run: |
blender -b -P tests/python.py -- -m pip install ".[test]"
- name: Run Tests
run: |
blender -b -P tests/run.py -- -vv tests --cov --cov-report=xml
- name: Expose coverage as a CI download
uses: actions/upload-artifact@v4
if: matrix.os == 'ubuntu-latest' && matrix.version == '4.2.5'
with:
name: coverage.xml
path: coverage.xml
- name: Upload coverage reports to Codecov
if: matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v3
Breaking 5.0 Changes
Tests are run daily on MacOS, Windows & Linux against the latest alpha builds from Blender.
BLENDER_EEVEE_NEXT
renamed toBLENDER_EEVEE
#855
- Compositor no longer has
use_nodes
#971
Set Curve Resolution
not updating datablock #141721
bpy.data.materials.new()
starts with empty node tree (not BSDF + Output) #980
These were some of the recent changes that were breaking the add-on but automated testing alterted us and we were able to fix it quickly. When 5.0 is released as long as we keep fixing the problems as they appear we can be confident that it will work day-of.
Fixing individual errors as they appear is also much easier to debug than testing once the beta releases happen (or worse the final release) where multiple failures might pile up on top of each other.
Distributing on GitHub
‘Old School’
- have your add-on be ‘top-level’ on GitHub - users just download the
.zip
of the repo and install
- Never clear when updates are out or what version is ‘released’
- package up
.zip
and create a GitHub release - users download from release page and check back for updates
- Clearer which version is currently released, requires users to manually update
Hip & New and Cool and Fresh with ‘Extensions’
- Host an
index.json
somewhere accessible on the network which points to files, allows automatic updates
- Host an
index.json
and files all on GitHub- Simple index for single add-on on a single repo
- A repo that indexes and builds multiple add-ons from multiple sources
A live example
This is a minimal example of an add-on we can subscribe to.
Your Personal Extensions Repo
- Build and release add-ons on GitHub (through automations!) in their own repos
- Compile multiple add-ons in a single subscribeable repo
- Users add ‘your personal repo’ - they get updates just like they would from the official Extensions platform
How is it Built?
We can use GitHub actions (or another similar service) to compile ‘released’ add-ons from multiple different services into a single extenion repo.
Importantly we need Blender to run checksum on the actual files that your users will download before publishing the index.json
. We don’t host or serve the actual files ourselves, those remain on at the original publishing locations (the release pages of the individual repos). We just generate an index that points to those locations.
name: Download Release Files
on:
push:
branches: ["main"]
schedule:
- cron: '0 0 * * *'
jobs:
build-website:
runs-on: macos-latest
permissions: write-all
steps:
- uses: actions/checkout@v4
- uses: quarto-dev/quarto-actions/setup@v2
- uses: bradyajohnston/setup-blender@v4
with:
version: latest
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Get Release Assets
run: |
uv run --with requests scripts/download.py
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Generate index.json
run: |
blender --command extension server-generate --repo-dir=repo
- name: Quarto Render
run: |
uv run --with pyyaml quarto render
- name: Publish to GitHub Pages (and render)
uses: quarto-dev/quarto-actions/publish@v2
with:
target: gh-pages
path: .
render: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Distributing your own Extensions
Details and built: https://bradyajohnston.github.io/extensions/ Subscribe with:
https://bradyajohnston.github.io/extensions/index.json
Blext
Package for building, maintaining and releasing extensions
Thanks!
@bradyajohnston
everywhere- slides: bradyajohnston.githbub.io/talks/bcon2025