Purge orphan data in one shot
After deleting meshes, materials, or images, Blender can still keep unused datablocks around. This is the quick cleanup pass.
bpy.ops.outliner.orphans_purge(do_recursive=True)
The best Blender scripts are not always giant add-ons. Sometimes the biggest productivity gains come from a tiny line of Python that deletes junk, renames a hundred objects, fixes pivots, or exports everything in one pass. This guide focuses on short, practical snippets you can paste into Blender’s scripting workspace and adapt in seconds.
Most of these examples are intentionally tiny. That is the point. They solve repetitive tasks without the overhead of building a full tool first.
Short scripts are powerful because they touch lots of data quickly. Before running anything destructive, save a versioned copy of the project or duplicate the affected collection.
After deleting meshes, materials, or images, Blender can still keep unused datablocks around. This is the quick cleanup pass.
bpy.ops.outliner.orphans_purge(do_recursive=True)
Imported scenes often accumulate helper empties you no longer need. This removes them across the file.
for obj in [o for o in bpy.data.objects if o.type == 'EMPTY']:
bpy.data.objects.remove(obj, do_unlink=True)
Imported assets often contain bloated slot stacks. This trims only the selected objects.
for obj in bpy.context.selected_objects:
bpy.context.view_layer.objects.active = obj
while obj.material_slots:
bpy.ops.object.material_slot_remove_unused()
This is a fast way to isolate the part of the scene you are actively editing.
sel = set(bpy.context.selected_objects)
[o.hide_set(o not in sel) for o in bpy.context.scene.objects]
When a scene is full of Cube.001-style noise, a short loop gives you readable object names instantly.
for i, obj in enumerate(bpy.context.selected_objects, 1):
obj.name = f"Asset_{i:03d}"
Asset for Tree, Bolt, Window, or any project prefix.Sometimes you need to target only real geometry, skipping lights, cameras, armatures, and helpers.
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.context.scene.objects:
obj.select_set(obj.type == 'MESH')
Create a target collection if needed, then link every selected object into it for quick scene cleanup.
col = bpy.data.collections.get("Exports") or bpy.data.collections.new("Exports")
if col.name not in bpy.context.scene.collection.children:
bpy.context.scene.collection.children.link(col)
for obj in bpy.context.selected_objects:
col.objects.link(obj)
A tiny debugging helper when you want a quick report before doing something destructive.
print([obj.name for obj in bpy.context.selected_objects])
Many downstream problems come from unapplied scale. This makes the current selection safe for modifiers, physics, and export.
for obj in bpy.context.selected_objects:
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
Imported assets often arrive with awful pivots. This snaps the origin to each object’s geometry center.
for obj in bpy.context.selected_objects:
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
Quickly reset object locations without touching their mesh data or hierarchy.
for obj in bpy.context.selected_objects:
obj.location = (0, 0, 0)
This creates a clean control object for grouped transforms without joining geometry.
empty = bpy.data.objects.new("CTRL_Master", None)
bpy.context.collection.objects.link(empty)
for obj in bpy.context.selected_objects:
obj.parent = empty
One of the fastest ways to improve hard-surface readability is to bevel everything consistently.
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
mod = obj.modifiers.new(name="Bevel", type='BEVEL')
mod.width = 0.01
mod.segments = 2
For imported hard-surface assets, this is often a faster fix than manually correcting normals object by object.
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
bpy.context.view_layer.objects.active = obj
bpy.ops.object.shade_auto_smooth()
Solid viewport colors can make scene organization much easier before materials are finalized.
for obj in bpy.context.selected_objects:
obj.color = (0.2, 0.7, 1.0, 1.0)
When linked duplicates are getting in the way, this separates object and data ownership for the selection.
bpy.ops.object.make_single_user(object=True, obdata=True)
Before running test renders or animation batches, lock in the output destination with one tiny snippet.
scene = bpy.context.scene
scene.render.filepath = "//renders/shot01_"
scene.render.image_settings.file_format = 'PNG'
// prefix makes the path relative to the current .blend file.This is one of those scripts that pays for itself immediately in game-art or asset-store workflows.
import os
folder = bpy.path.abspath("//exports/")
os.makedirs(folder, exist_ok=True)
for obj in bpy.context.selected_objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.export_scene.fbx(filepath=os.path.join(folder, f"{obj.name}.fbx"), use_selection=True)
Great for test loops, look-dev automation, or button-driven mini tools.
bpy.ops.render.render(write_still=True)
Versioned saves are one of the safest habits in Blender, and this shortcut makes them painless.
bpy.ops.wm.save_as_mainfile(filepath=bpy.data.filepath.replace(".blend", "_v002.blend"))