Discovered “clamp overlap” which seemingly has no documentation on Blender’s site? but essentially prevents beveling from happening in some scenarios so the newly created edges do not overlap. Disabling the clamp overlap allowed the bevel to … do something.
Blender Scripting Lesson of the Week: Beveling
We were playing around with bevels this week – it’s pretty straight forward, the API lets you set the parameters you set through the GUI in a bevel modifier.
import bpy
# Clear all existing objects
for obj in list(bpy.data.objects):
bpy.data.objects.remove(obj, do_unlink=True)
# Set Units
scene = bpy.context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.001 # 1 BU = 1 mm
# Create rectangular cube
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))
block = bpy.context.active_object
block.name = "Block"
# cube default size is 2x2x2, so set absolute dimensions
block.dimensions = (2.0, 20.0, 0.25)
bpy.context.view_layer.objects.active = block
block.select_set(True)
# Apply scale so booleans/bevel behave predictably
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
# Create cylinder cutter
hole_diameter = 1.0
hole_radius = hole_diameter / 2.0
# Make it longer than the block thickness so it fully cuts through
cutter_depth = 5.0
bpy.ops.mesh.primitive_cylinder_add(
vertices=64,
radius=hole_radius,
depth=cutter_depth,
location=(0.0, 0.0, 0.0), # center of the block
rotation=(0.0, 0.0, 0.0)
)
cutter = bpy.context.active_object
cutter.name = "HoleCutter"
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
# Boolean: cut hole
bpy.context.view_layer.objects.active = block
bool_mod = block.modifiers.new(name="Hole", type='BOOLEAN')
bool_mod.operation = 'DIFFERENCE'
bool_mod.solver = 'EXACT'
bool_mod.object = cutter
# Apply boolean
bpy.ops.object.modifier_apply(modifier=bool_mod.name)
# Hide cutter in viewport + renders
cutter.hide_set(True)
cutter.hide_render = True
# Bevel the block
bevel_width = 0.08
bevel_segments = 5
bevel_mod = block.modifiers.new(name="Bevel", type='BEVEL')
bevel_mod.width = bevel_width
bevel_mod.segments = bevel_segments
bevel_mod.limit_method = 'ANGLE'
bevel_mod.angle_limit = 0.523599 # 30 degrees in radians
# Apply bevel
bpy.ops.object.modifier_apply(modifier=bevel_mod.name)
Gluten Free Buttermilk Pancakes
Ingredients
- 2 cups gluten free flour (King Arthur Flour’s “Measure-for-measure”)
- 1 Tbsp baking powder
- 1 tsp salt
- 1/2 cup buttermillk powder + 2 cups water (or 2 cups of buttermilk!)
- 2 eggs
- 1 tsp psyllium husk fiber (finely ground powder)
Method:
Combine all dry ingredients. Mix in wet ingredients. Allow batter to sit for about ten minutes and add more water as needed – the gluten free flour absorbs a LOT of water. Then cook pancakes.
2026 Maple Season: Firewood!
Blender Scripting – T-Post Sign Holder
We spent a lot of the day trying to modify 3D models that we found online to work as a sign holder. Something like the bent metal plates you can buy at the tractor store. Since these are simple polygons, I thought it might be easier to script the build (plus making changes to the dimensions would just require tweaking variables).
Voila – hopefully it’s a T-post sign holder! It at least looks like one.

import bpy
import bmesh
import math
from mathutils import Vector
# Clear all existing objects
for obj in list(bpy.data.objects):
bpy.data.objects.remove(obj, do_unlink=True)
# -----------------------------
# Scene units (mm)
# -----------------------------
scene = bpy.context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.001 # 1 Blender unit = 1 mm
INCH = 25.4
def inch(x): return x * INCH
# -----------------------------
# PARAMETERS (mm)
# -----------------------------
bracket_thickness = inch(0.25) # sheet thickness
bracket_width = inch(3) # bracket width (across the post)
# Leg lengths (side profile)
bracket_top_length = inch(1) # bracket segment 1 length
bracket_middle_length = inch(2) # bracket segment 2 length
bracket_bottom_length = inch(4.5) # bracket segment 3 length
# Bend included angles
bend1_angle_included = 105.0 # top flange
bend2_angle_included = 255.0 # web -> long leg
# If the long leg goes the wrong direction, flip this
flip_second_bend = True
# -----------------------------
# Punch hole
# -----------------------------
do_punch = True
# T-post size references
tpost_horizontal_hole_height = inch(0.25)
tpost_horizontal_hole_width = inch(1.5)
tpost_vertical_hole_height = inch(2)
tpost_vertical_hole_width = inch(0.25)
punch_clearance = 1.0 # clearance added around each rectangle (mm)
# Position of t-post before rotation (Z from p0 end, and X across width)
punch_center_z = inch(1)
punch_center_x = bracket_width / 2
# Vertical placement on top flange (Y=0 plane)
punch_center_y = -inch(0.5)
# -----------------------------
# Optional bevel to make edges25ook more formed
# -----------------------------
do_bevel = True
bevel_width = inch(0.05)
bevel_segments = 25
# -----------------------------
# Cleanup
# -----------------------------
#for n in ["BracketShape", "PunchBar", "PunchStem", "HoleRight1", "HoleRight2", "HoleRight3", "HoleRight4", "HoleLeft1", "HoleRLeft2", "HoleLeft3", "HoleLeft4"]:
# o = bpy.data.objects.get(n)
# if o:
# bpy.data.objects.remove(o, do_unlink=True)
# -----------------------------
# Helpers (YZ plane directions)
# Define 0° as +Z. +90° is +Y. -90° is -Y.
# -----------------------------
def unit_from_angle(deg_from_posZ):
a = math.radians(deg_from_posZ)
return Vector((0.0, math.sin(a), math.cos(a)))
def boolean_diff(target, cutter):
mod = target.modifiers.new(name=f"BOOL_{cutter.name}", type="BOOLEAN")
mod.operation = 'DIFFERENCE'
mod.solver = 'EXACT'
mod.object = cutter
bpy.context.view_layer.objects.active = target
bpy.ops.object.modifier_apply(modifier=mod.name)
cutter.hide_set(True)
def add_cube(name, size_xyz, location_xyz, rotation_xyz):
bpy.ops.mesh.primitive_cube_add(size=1, location=location_xyz, rotation=rotation_xyz)
obj = bpy.context.active_object
obj.name = name
obj.scale = (size_xyz[0], size_xyz[1], size_xyz[2])
bpy.ops.object.transform_apply()
return obj
def add_cylinder(name, radius, length, location_xyz, rotation_xyz):
bpy.ops.mesh.primitive_cylinder_add(radius=radius, depth=length, location=location_xyz, rotation=rotation_xyz)
obj = bpy.context.active_object
obj.name = name
bpy.ops.object.transform_apply()
return obj
# Convert included bend angles to turn angles
angle_top = 180.0 - bend1_angle_included
angle_bottom = 180.0 - bend2_angle_included
# Start along +Z (top flange)
theta0 = 0.0
d0 = unit_from_angle(theta0)
# After bend1, go "down" (toward -Y) by turning negative
theta1 = theta0 - angle_top
d1 = unit_from_angle(theta1)
# After bend2, go toward +Z again (or flip if needed)
theta2 = theta1 + (angle_bottom if not flip_second_bend else - angle_bottom)
d2 = unit_from_angle(theta2)
# Profile points (center surface)
p0 = Vector((0.0, 0.0, 0.0)) # free end of top flange
p1 = p0 + d0 * bracket_top_length # bend1 line
p2 = p1 + d1 * bracket_middle_length # bend2 line
p3 = p2 + d2 * bracket_bottom_length # end of long leg
# -----------------------------
# Build a single connected sheet surface:
# Create two polylines separated in X, then make quads between them.
# -----------------------------
mesh = bpy.data.meshes.new("BracketShapeMesh")
bracket = bpy.data.objects.new("BracketShape", mesh)
bpy.context.collection.objects.link(bracket)
bpy.context.view_layer.objects.active = bracket
bracket.select_set(True)
bm = bmesh.new()
x0, x1 = 0.0, bracket_width
# Left side (x0)
v0a = bm.verts.new((x0, p0.y, p0.z))
v1a = bm.verts.new((x0, p1.y, p1.z))
v2a = bm.verts.new((x0, p2.y, p2.z))
v3a = bm.verts.new((x0, p3.y, p3.z))
# Right side (x1)
v0b = bm.verts.new((x1, p0.y, p0.z))
v1b = bm.verts.new((x1, p1.y, p1.z))
v2b = bm.verts.new((x1, p2.y, p2.z))
v3b = bm.verts.new((x1, p3.y, p3.z))
# Faces (one per segment)
bm.faces.new((v0a, v0b, v1b, v1a)) # top flange
bm.faces.new((v1a, v1b, v2b, v2a)) # web
bm.faces.new((v2a, v2b, v3b, v3a)) # long leg
bm.normal_update()
bm.to_mesh(mesh)
bm.free()
# -----------------------------
# Solidify to thickness (sheet metal look)
# -----------------------------
solid = bracket.modifiers.new("Solidify", type="SOLIDIFY")
solid.thickness = bracket_thickness
solid.offset = 0.0
bpy.ops.object.modifier_apply(modifier=solid.name)
# -----------------------------
# Punch the lowercase "t" on the top flange
# (Top flange is flat at Y=0; punch straight through Y)
# -----------------------------
if do_punch:
tpost_length_y = bracket_thickness * 5 # ensure it fully cuts through
# Crossbar rectangle
horizontal_hole = add_cube(
"PunchBar",
size_xyz=(tpost_horizontal_hole_width + 2 * punch_clearance, tpost_length_y, tpost_horizontal_hole_height + 2 * punch_clearance),
location_xyz=(punch_center_x, 13 + punch_center_y, punch_center_z),
rotation_xyz=(math.radians(90 - bend1_angle_included / 2), math.radians(0), math.radians(0))
)
# Stem rectangle (placed under the bar like a lowercase "t")
vertical_hole = add_cube(
"PunchStem",
size_xyz=(tpost_vertical_hole_width + 2 * punch_clearance, tpost_length_y, tpost_vertical_hole_height + 2 * punch_clearance),
location_xyz=(punch_center_x, punch_center_y, punch_center_z),
rotation_xyz=(math.radians(90), math.radians(0), math.radians(0))
#rotation_xyz=(math.radians(90 - bend1_angle_included / 2), math.radians(0), math.radians(0))
)
boolean_diff(bracket, vertical_hole)
boolean_diff(bracket, horizontal_hole)
for hole in range(4):
right_hole = add_cylinder(
"HoleRight{}".format(hole),
radius=inch(0.125),
length=100,
location_xyz=(inch(0.5), -inch(2), inch(2) + inch(1.175) * hole),
rotation_xyz=(math.radians(90), 0, 0)
)
left_hole = add_cylinder(
"HoleLeft{}".format(hole),
radius=inch(0.125),
length=100,
location_xyz=(inch(2.5), -inch(2), inch(2) + inch(1.175) * hole),
rotation_xyz=(math.radians(90), 0, 0)
)
boolean_diff(bracket, right_hole)
boolean_diff(bracket, left_hole)
# -----------------------------
# Optional bevel
# -----------------------------
if do_bevel:
bev = bracket.modifiers.new("Bevel", type="BEVEL")
bev.width = bevel_width
bev.segments = bevel_segments
bev.limit_method = 'ANGLE'
#bev.angle_limit = math.radians(35)
bev.use_clamp_overlap = False
bpy.context.view_layer.objects.active = bracket
bpy.ops.object.modifier_apply(modifier=bev.name)
API Documentation Links:
https://docs.blender.org/api/current/bpy.ops.mesh.html
https://docs.blender.org/api/current/bmesh.ops.html
Straight Line Winds
We had huge wind storms today – 85mph up at the airport. It was gusty all day, but it really picked up in the afternoon. I was working and heard wind noise. I looked out the window and saw a wall of brown that I realized was all of the dead needles blowing off the pine trees along the south side of our back yard. Then the trees all started to lay down – the willow first, but then the pines started reaching for the ground. One popped and flopped into the grass as the gust subsided and all of the other trees stood up.
Setting Windows Dynamic Port Range
In case anyone else ever needs to set a windows dynamic port range for magic RPC “stuff” — there’s a minimum range size of 255. If you make the range to small, you get an incredibly vague and not-useful “the parameter is incorrect” error. Increase num to at least the min value, and you don’t be going in circles trying to figure out what in your command doesn’t match the parameters in the documentation!
2026 Maple Season: More Taps
The Smoothie
Blender Scripting Lesson of the Week: Cylinders
Quick script for creating a cylinder using bpy
import bpy
# Clear all existing objects
for obj in list(bpy.data.objects):
bpy.data.objects.remove(obj, do_unlink=True)
# Set Units
scene = bpy.context.scene
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 0.001 # 1 BU = 1 mm
# Create cylinder
bpy.ops.mesh.primitive_cylinder_add(
vertices=32, radius=10.0, depth=20.0,
end_fill_type='NGON', calc_uvs=True,
enter_editmode=False, align='WORLD',
location=(0.0, 0.0, -2.0), rotation=(0.0, 0.0, 0.0),
scale=(1, 1, 1)
)
# Name cylinder
obj = bpy.context.active_object
obj.name = "MyCylinder"
# Frame Selected
for area in bpy.context.window.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
with bpy.context.temp_override(area=area, region=region):
bpy.ops.view3d.view_selected(use_all_regions=False)
break
break






