Generate Tensegrity Tables With Blender Python API For Website

3D GENERATOR: Python + Blender + Web
On 8 min, 12 sec read

Tensegrity Tables from Code to Web: Your Blender Python & Model-Viewer Project

Ever wanted to create cool 3D models with code and show them on your website? This beginner-friendly blog post will guide you through generating a fascinating Tensegrity Table (a structure held together by continuous tension and discontinuous compression) using a Python script inside Blender, and then displaying that 3D model right in your web browser using Google’s awesome <model-viewer> element! Get ready to combine the power of Python, 3D design, and web development.

Step 1: Generating the Low-Poly Tensegrity Table in Blender with Python

Blender, the free and open-source 3D suite, has a powerful Python API (Application Programming Interface). To keep things simple and easy to understand for beginners, we will use a **low-poly** approach, building the struts from simple **cubes** and the cables from **edges**.

Here is the Python script you need. Save it as low_poly_tensegrity_table.py:




import bpy
import math
from mathutils import Vector

# --- Configuration ---
FILE_NAME = &quot;square_floating_table.glb&quot;
TABLE_HEIGHT = 1.0          # Vertical distance between the plates
SIDE_LENGTH = 1.5           # Side length of the square tabletop and base
TOP_THICKNESS = 0.05        # Thickness of the tabletop
BASE_THICKNESS = 0.05       # Thickness of the base
STRUT_HEIGHT = 0.2          # Height of the floating central strut
STRUT_THICKNESS = 0.05      # Thickness of the floating central strut
CABLE_THICKNESS = 0.008
LOW_POLY_VERTICES = 8       # Vertex count for low-poly appearance
JOINT_SIZE = 0.04

# --- Constants for Z-Positioning ---
TABLE_TOP_Z = TABLE_HEIGHT + TOP_THICKNESS / 2 
BASE_BOTTOM_Z = -BASE_THICKNESS / 2 
STRUT_TOP_Z = TABLE_HEIGHT / 2 + STRUT_HEIGHT / 2
STRUT_BOTTOM_Z = TABLE_HEIGHT / 2 - STRUT_HEIGHT / 2
STRUT_CENTER_Z = TABLE_HEIGHT / 2

# --- Utility Functions ---

def clear_scene():
    &quot;&quot;&quot;Removes all objects from the current scene.&quot;&quot;&quot;
    bpy.ops.object.select_all(action=&#039;DESELECT&#039;)
    bpy.ops.object.select_all(action=&#039;SELECT&#039;)
    bpy.ops.object.delete(use_global=False)

def create_material(name, color, metallic=0.0, roughness=0.5):
    &quot;&quot;&quot;Creates a simple PBR material.&quot;&quot;&quot;
    if name in bpy.data.materials: return bpy.data.materials[name]
    mat = bpy.data.materials.new(name=name); mat.use_nodes = True
    bsdf = mat.node_tree.nodes[&quot;Principled BSDF&quot;]
    bsdf.inputs[&#039;Base Color&#039;].default_value = color
    bsdf.inputs[&#039;Metallic&#039;].default_value = metallic
    bsdf.inputs[&#039;Roughness&#039;].default_value = roughness
    return mat

def apply_material(obj, mat):
    &quot;&quot;&quot;Applies a material to a given object.&quot;&quot;&quot;
    if obj.data.materials: obj.data.materials[0] = mat
    else: obj.data.materials.append(mat)

def create_cylinder_between_points(start_loc, end_loc, radius, name, material, vertices=LOW_POLY_VERTICES):
    &quot;&quot;&quot;Creates a cylinder and aligns it between two vector locations.&quot;&quot;&quot;
    center = (start_loc + end_loc) / 2; direction = end_loc - start_loc
    length = direction.length
    bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=length, location=center)
    obj = bpy.context.object; obj.name = name; apply_material(obj, material)
    if length &gt; 0.0001:
        rotation_quat = direction.normalized().to_track_quat(&#039;Z&#039;, &#039;Y&#039;)
        obj.rotation_euler = rotation_quat.to_euler()
    return obj

def create_joint(location, size, name, material):
    &quot;&quot;&quot;Creates a low-poly sphere at a connection point.&quot;&quot;&quot;
    bpy.ops.mesh.primitive_uv_sphere_add(
        segments=LOW_POLY_VERTICES, ring_count=LOW_POLY_VERTICES // 2,
        radius=size / 2, location=location
    )
    obj = bpy.context.object; obj.name = name; apply_material(obj, material)
    return obj

# --- Main Generation Logic ---

def generate_square_floating_table():
    clear_scene()
    
    # Define Materials
    WOOD_MATERIAL = create_material(&quot;Wood_Material&quot;, (0.5, 0.25, 0.0, 1.0), roughness=0.8)
    CABLE_MATERIAL = create_material(&quot;Cable_Material&quot;, (0.1, 0.1, 0.1, 1.0), metallic=0.0, roughness=0.9)
    JOINT_MATERIAL = create_material(&quot;Joint_Material&quot;, (0.1, 0.3, 0.5, 1.0), metallic=0.2, roughness=0.4) 
    
    # --- 1. Define Points ---
    
    half_side = SIDE_LENGTH / 2
    
    # Base Corners (Z-level of base surface)
    base_surface_z = BASE_BOTTOM_Z + BASE_THICKNESS/2
    base_pts = [
        Vector(( half_side,  half_side, base_surface_z)),
        Vector((-half_side,  half_side, base_surface_z)),
        Vector((-half_side, -half_side, base_surface_z)),
        Vector(( half_side, -half_side, base_surface_z))
    ]
    # Tabletop Corners (Z-level of top surface)
    top_surface_z = TABLE_TOP_Z - TOP_THICKNESS/2
    top_pts = [p + Vector((0, 0, TABLE_HEIGHT)) for p in base_pts]
    
    # Cable Anchor Points (Midpoints of table/base edges)
    # These points are closer to the center to suspend the central strut
    anchor_radius = SIDE_LENGTH * 0.25 
    
    base_anchor_pts = [
        Vector(( anchor_radius,  0, base_surface_z)),
        Vector((0, anchor_radius, base_surface_z)),
        Vector((-anchor_radius, 0, base_surface_z)),
        Vector((0, -anchor_radius, base_surface_z))
    ]
    top_anchor_pts = [p + Vector((0, 0, TABLE_HEIGHT)) for p in base_anchor_pts]
    
    # All points for joint creation
    all_points = base_pts + top_pts + base_anchor_pts + top_anchor_pts + [Vector((0,0,STRUT_TOP_Z)), Vector((0,0,STRUT_BOTTOM_Z))]

    # --- 2. Create Tabletop and Base (Compression Plates) ---
    
    # Table Top (Square Cube)
    bpy.ops.mesh.primitive_cube_add(
        size=SIDE_LENGTH,
        location=(0, 0, TABLE_TOP_Z),
        scale=(1, 1, TOP_THICKNESS / SIDE_LENGTH)
    )
    obj = bpy.context.object; obj.name = &quot;Table_Top&quot;; apply_material(obj, WOOD_MATERIAL)
    
    # Base (Square Cube)
    bpy.ops.mesh.primitive_cube_add(
        size=SIDE_LENGTH,
        location=(0, 0, BASE_BOTTOM_Z),
        scale=(1, 1, BASE_THICKNESS / SIDE_LENGTH)
    )
    obj = bpy.context.object; obj.name = &quot;Base_Bottom&quot;; apply_material(obj, WOOD_MATERIAL)

    # --- 3. Create Central Strut (Compression) ---
    bpy.ops.mesh.primitive_cube_add(
        size=STRUT_THICKNESS,
        location=(0, 0, STRUT_CENTER_Z),
        scale=(1, 1, STRUT_HEIGHT / STRUT_THICKNESS)
    )
    obj = bpy.context.object; obj.name = &quot;Central_Strut&quot;; apply_material(obj, WOOD_MATERIAL)

    # --- 4. Create Cables and Joints (Tension) ---
    
    # a) Main Tensegrity Cables (4 diagonal, providing overall stability)
    # These run from the base corners to the OPPOSITE side tabletop corners (i+2 is more stable than i+1)
    for i in range(4):
        create_cylinder_between_points(
            base_pts[i], top_pts[(i + 2) % 4], CABLE_THICKNESS / 2, f&quot;Cable_Main_{i+1}&quot;, CABLE_MATERIAL
        )
        
    # b) Central Strut Suspension Cables (8 total, connecting strut to plates)
    strut_top = Vector((0, 0, STRUT_TOP_Z))
    strut_bottom = Vector((0, 0, STRUT_BOTTOM_Z))
    
    for i in range(4):
        # Top Strut to Tabletop Anchors
        create_cylinder_between_points(
            strut_top, top_anchor_pts[i], CABLE_THICKNESS / 2, f&quot;Cable_Strut_Top_{i+1}&quot;, CABLE_MATERIAL
        )
        # Bottom Strut to Base Anchors
        create_cylinder_between_points(
            strut_bottom, base_anchor_pts[i], CABLE_THICKNESS / 2, f&quot;Cable_Strut_Bottom_{i+1}&quot;, CABLE_MATERIAL
        )

    # c) Place Spheres (Joints) at all cable attachment points
    for i, loc in enumerate(all_points):
        create_joint(loc, JOINT_SIZE, f&quot;Joint_{i}&quot;, JOINT_MATERIAL)


# --- Execution ---

if __name__ == &quot;__main__&quot;:
    generate_square_floating_table()
    print(f&quot;\n--- Square Tensegrity Table (Floating Strut Design) generation complete! ---&quot;)

This script clears the scene, uses simple math to calculate the positions of the three struts, creates those struts as **low-poly cubes**, connects the top and bottom points with **simple edges** (our cables), and then exports the final model as a **GLB file**.

How to Run the Python Script from the Command Line

To run your low_poly_tensegrity_table.py script using the Blender Python interpreter, open your Terminal (macOS/Linux) or Command Prompt/PowerShell (Windows) and use the following format:

/path/to/blender -b -P low_poly_tensegrity_table.py
  • Replace /path/to/blender with the actual path to your Blender executable (e.g., on Windows: "C:\Program Files\Blender Foundation\Blender\blender.exe").
  • The -b flag tells Blender to run in background mode (headless), meaning the graphical user interface won’t load-it’s faster!
  • The -P flag specifies the Python script Blender should execute.

This command will run your script, which should be set up to export the generated Tensegrity Table as a 3D file format suitable for the web, like GLB or GLTF.

Step 2: Displaying the Model on the Web with <model-viewer>

Once you have your low_poly_tensegrity.glb file exported from Blender, it’s time to put it on a webpage! The <model-viewer> custom web element makes embedding interactive 3D models incredibly easy, often without needing complex frameworks.

  1. Include the Library: In the <head> of your HTML file, include the <model-viewer> script:
    &lt;script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"&gt;&lt;/script&gt;
  2. Add the Element: Place the <model-viewer> tag in the <body> of your HTML, pointing to your exported model file:
    &lt;model-viewer
    src="low_poly_tensegrity.glb"
    alt="A Low-Poly Tensegrity Table generated with Blender Python"
    shadow-intensity="1"
    camera-controls
    touch-action="pan"
    auto-rotate&gt;
    &lt;/model-viewer&gt;

The attributes like camera-controls and auto-rotate allow users to interact with your 3D model (rotate, zoom, pan) right in their browser!

📸 Screenshots & Screencast

Low poly tensegrity table Python code
Blender Scripting Workspace Displaying Low Poly Tensegrity Table Python Code

Low poly tensegrity table in Blender
Blender Layout Workspace Displaying Low Poly Tensegrity Table

Low poly tensegrity table in Web browser
Web Browser Displaying Rendered Low Poly Tensegrity Table

Screencast For Blender Python API Low Poly Tensegrity Table

Resources to Keep Learning

Ready to dive deeper into Python and Blender scripting? Check out these resources!

My Books:

My Course:

One-on-One Tutoring:

  • Need personalized help with Python, including the Blender Python API? I’m available for one-on-one online Python tutorials.

    Contact me for availability: https://ojambo.com/contact

Happy coding and happy modeling!

🚀 Recommended Resources


Disclosure: Some of the links above are referral links. I may earn a commission if you make a purchase at no extra cost to you.

About Edward

Edward is a software engineer, author, and designer dedicated to providing the actionable blueprints and real-world tools needed to navigate a shifting economic landscape.

With a provocative focus on the evolution of technology—boldly declaring that “programming is dead”—Edward’s latest work, The Recession Business Blueprint, serves as a strategic guide for modern entrepreneurship. His bibliography also includes Mastering Blender Python API and The Algorithmic Serpent.

Beyond the page, Edward produces open-source tool review videos and provides practical resources for the “build it yourself” movement.

📚 Explore His Books – Visit the Book Shop to grab your copies today.

💼 Need Support? – Learn more about Services and the ways to benefit from his expertise.

🔨 Build it Yourself – Download Free Plans for Backyard Structures, Small Living, and Woodworking.