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.
Author: Lisa
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
Yubikey Biometric on Fedora using FIDO2
# Insert key – was flashing green at first, flashing orange after software installed
# As root
# Install required packages
sudo dnf install pam-u2f fido2-tools yubikey-manager pamu2fcfg
# As the user
# See note below re: setting pin
# The FIDO2 PIN must be at least 4 characters, and supports any type of alphanumeric characters. Some YubiKeys can be configured to require a longer PIN. (https://docs.yubico.com/software/yubikey/tools/ykman/FIDO_Commands.html)
ykman fido access change-pin
# List current fingerprints – should be none, since no user is set up, will prompt for your pin
ykman fido fingerprints list
# Add your fingerprint – RI stands for “right index” and is essentially a display name for the fingerprint (https://docs.yubico.com/software/yubikey/tools/ykman/FIDO_Commands.html#ykman-fido-fingerprints-add-options-name)
# Green light is fast flashing & prompted to touch sensor. Not a slide, touch and remove finger. It prompts with how many more scans are needed & reports when the print is not read (capture failed, recenter your finger and try again)
# Key stopped flashing
ykman fido fingerprints add RI
# Set up pam to use key/print as auth
mkdir ~/.config/Yubico
chmod 700 ~/.config/Yubico
# Run command, when key flashes green touch it with the registered finger
pamu2fcfg –username “$USER” –origin “pam://$(hostname)” >> ~/.config/Yubico/u2f_keys
chmod 600 ~/.config/Yubico/u2f_keys
# Back as root
authselect current
# Results:
Profile ID: local
with features:
with-silent-lasting
with-mdns4
with-fingerprint
# If nothing is selected, run the following and use “-b sssd” instead of “-b local” below.
# authselect select sssd
authselect create-profile yubikey -b local
authselect select custom/yubikey with-silent-lastlog with-mdns4 with-fingerprint
# Edit two files
/etc/authselect/custom/yubikey/system-auth
/etc/authselect/custom/yubikey/password-auth
# Add this line near the top of the auth section, before the usual pam_unix.so / pam_sss.so lines:
auth sufficient pam_u2f.so authfile=.config/Yubico/u2f_keys cue userverification=1
authselect apply-changes
# Test before rebooting and losing the currently logged on session
ctrl-al`-f3 and log into the alt console
Note: You may be prompted for the FIDO2 PIN in cases like:
You haven’t enrolled fingerprints (or user verification isn’t available), and the system/app requires verification.
Too many failed fingerprint attempts and the key requires a PIN to re-enable verification.
Certain management actions (adding/removing fingerprints, resetting FIDO2, etc.).
# If not working, update the custom system-auth and password-auth to debug output
auth sufficient pam_u2f.so authfile=%h/.config/Yubico/u2f_keys cue userverification=1 debug debug_file=/var/log/u2f.log
# Initialize file, otherwise debug output goes to screen
touch /var/log/u2f.log
On GUI logon, you have to hit enter (or the arrow) like you are logging in with a password (but you don’t have to type the password) and touch the thing when it flashes green
If you register new fingerprints on the key, you do not need to regenerate your keys file
KDEWallet will prompt to store every new fingerprint you use.






