Generate Low-Poly Bus With Blender Python API For Website

Coded 3D Bus in Blender with Python & Shared It on the Web
Coded 3D Bus in Blender with Python & Shared It on the Web

Live stream set for 2025-08-02 at 14:00:00 Eastern

Ask questions in the live chat about any programming or lifestyle topic.

This livestream will be on YouTube or you can watch below.

Creating a Low-Poly Bus in Blender with Python and Displaying It on the Web

Blender is a powerful tool for 3D modeling—and with Python scripting, it becomes even more flexible. In this tutorial, I’ll show you how to generate a low-poly bus model using the Blender Python API, and then display it in a web browser using model-viewer.

Whether you’re new to Blender scripting or want to display your 3D creations online, this beginner-friendly guide has you covered.

🚌 Step 1: Generate the Low-Poly Bus Using Python in Blender

We’ll use Blender’s scripting interface to create the low-poly bus model. Below is a simplified Python script that you can paste directly into Blender 4.3+.

You can find the full source code here:

import bpy
import bmesh
from mathutils import Vector

def clear_scene():
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

def create_material(name, color):
    mat = bpy.data.materials.get(name)
    if not mat:
        mat = bpy.data.materials.new(name=name)
    mat.diffuse_color = (*color, 1)
    return mat

def create_low_poly_bus():
    clear_scene()

    orange = create_material("DoorOrange", (1.0, 0.5, 0.2))
    yellow = create_material("BusYellow", (1.0, 0.8, 0.0))
    black = create_material("WheelBlack", (0.05, 0.05, 0.05))
    glass = create_material("WindowGlass", (0.2, 0.5, 0.8))
    red = create_material("TailLight", (1.0, 0.1, 0.1))
    grey = create_material("Grille", (0.3, 0.3, 0.3))
    white = create_material("Headlight", (1.0, 1.0, 1.0))

    ### BUS BODY ###
    bpy.ops.mesh.primitive_cube_add(size=2)
    body = bpy.context.active_object
    body.name = "Bus_Body"
    body.scale = (3.0, 1.0, 1.2)
    body.location = (0, 0, 1.2)
    body.data.materials.append(yellow)

    ### WINDOWS ###
    window_positions = [-2, -1, 0, 1, 2]
    for i, x in enumerate(window_positions, start=1):
        bpy.ops.mesh.primitive_cube_add(size=1)
        win = bpy.context.active_object
        win.name = f"Bus_Window_{i}"
        win.scale = (0.5, 0.05, 0.5)
        win.location = (x, 1.05, 1.8)
        win.data.materials.append(glass)

    ### WHEELS ###
    wheel_positions = {
        "FL": (-2.2,  1.0),
        "FR": ( 2.2,  1.0),
        "RL": (-2.2, -1.0),
        "RR": ( 2.2, -1.0),
    }
    for key, (x, y) in wheel_positions.items():
        bpy.ops.mesh.primitive_cylinder_add(radius=0.4, depth=0.3, vertices=12)
        wheel = bpy.context.active_object
        wheel.name = f"Bus_Wheel_{key}"
        wheel.rotation_euler = (1.5708, 0, 0)
        wheel.location = (x, y, 0.04)
        wheel.data.materials.append(black)

    ### FRONT WINDOW ###
    bpy.ops.mesh.primitive_cube_add(size=1)
    front_win = bpy.context.active_object
    front_win.name = "Bus_Front_Window"
    front_win.scale = (0.9, 0.05, 0.6)
    front_win.location = (3.05, 0, 1.6)
    front_win.rotation_euler = (0, 0, 1.5708)  # Rotated 90° on Z axis
    front_win.data.materials.append(glass)

    ### ROOF LIGHTS ###
    for i, x in enumerate([-1.5, 0, 1.5], start=1):
        bpy.ops.mesh.primitive_cube_add(size=0.3)
        light = bpy.context.active_object
        light.name = f"Bus_RoofLight_{i}"
        light.scale = (1, 0.3, 0.1)
        light.location = (x, 0, 2.5)
        light.data.materials.append(red)

    ### FRONT GRILLE ###
    bpy.ops.mesh.primitive_cube_add(size=1)
    grille = bpy.context.active_object
    grille.name = "Bus_Grille"
    grille.scale = (0.6, 0.05, 0.3)
    grille.location = (3.05, 0, 0.8)
    grille.rotation_euler = (0, 0, 1.5708)  # Rotated 90° on Z axis
    grille.data.materials.append(grey)

    ### HEADLIGHTS ###
    for side, y_offset in [("L", 0.4), ("R", -0.4)]:
        bpy.ops.mesh.primitive_cube_add(size=0.3)
        headlight = bpy.context.active_object
        headlight.name = f"Bus_Headlight_{side}"
        headlight.scale = (0.15, 0.05, 0.15)
        headlight.location = (3.05, y_offset, 1.1)
        headlight.data.materials.append(white)

    ### BACK DETAIL (Optional: Slight inset to rear)
    bpy.ops.mesh.primitive_cube_add(size=1)
    back_plate = bpy.context.active_object
    back_plate.name = "Bus_Back_Panel"
    back_plate.scale = (0.9, 0.05, 1.0)
    back_plate.location = (-3.05, 0, 1.2)
    back_plate.rotation_euler = (0, 0, 1.5708)  # rotate 90° on Z axis
    back_plate.data.materials.append(orange)

    bpy.ops.mesh.primitive_cube_add(size=0.2)
    tail_light = bpy.context.active_object
    tail_light.name = "Bus_TailLight"
    tail_light.scale = (0.2, 0.05, 0.2)
    tail_light.location = (-3.05, 0.5, 1.0)
    tail_light.data.materials.append(red)

	# Create an empty object named "Bus"
	bpy.ops.object.empty_add(type='PLAIN_AXES')
	bus_root = bpy.context.active_object
	bus_root.name = "Bus"

	# List all your bus part names here
	bus_parts = [
		"Bus_Back_Panel",
		"Bus_Body",
		"Bus_Front_Window",
		"Bus_Grille",
		"Bus_Headlight_L",
		"Bus_Headlight_R",
		"Bus_RoofLight_1",
		"Bus_RoofLight_2",
		"Bus_RoofLight_3",
		"Bus_TailLight",
		"Bus_Wheel_FL",
		"Bus_Wheel_FR",
		"Bus_Wheel_RL",
		"Bus_Wheel_RR",
		"Bus_Window_1",
		"Bus_Window_2",
		"Bus_Window_3",
		"Bus_Window_4",
		"Bus_Window_5"
	]

   # Parent all parts to the "Bus" empty
   for part_name in bus_parts:
       obj = bpy.data.objects.get(part_name)
       if obj:
           obj.parent = bus_root
       else:
           print(f"Warning: {part_name} not found")

   # Deselect all, then select only the "Bus" empty
   bpy.ops.object.select_all(action='DESELECT')
   bus_root.select_set(True)
   bpy.context.view_layer.objects.active = bus_root
   bpy.ops.object.parent_set(type='OBJECT')

   # Define export path (adjust as needed)
   export_path = os.path.join(os.path.expanduser("~"), "low_poly_bus.glb")

   # Export selected (the "Bus" empty and children) as GLB
   bpy.ops.export_scene.gltf(
       filepath=export_path,
       export_format='GLB',
       export_selected=True,
       export_apply=True
   )

# Run it
create_low_poly_bus()

Note: If you’re new to Python scripting in Blender, check out my book Learning Python.

⚙️ Running the Script via Command Line

To run the Python script outside Blender’s UI, open a terminal or command prompt and run:

blender --background --python create_low_poly_bus.py

Make sure create_low_poly_bus.py is your saved script file, and that Blender is installed and in your system’s PATH.

🌐 Step 2: Export the Model to .glb Format

Once your low-poly bus is generated in Blender:

  1. Go to FileExportglTF 2.0 (.glb).
  2. Check Include Selected Objects and Apply Modifiers.
  3. Save your model as low_poly_bus.glb.

💻 Step 3: Display the Model in a Web Browser with model-viewer

Create an HTML file with the following content:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Low Poly Bus Viewer</title>
    <script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
    <style>
      model-viewer {
        width: 100%;
        height: 500px;
      }
    </style>
  </head>
  <body>
    <h1>Low Poly Bus</h1>
    <model-viewer
      src="low_poly_bus.glb"
      alt="A low poly bus model"
      auto-rotate
      camera-controls
      ar
      shadow-intensity="1"
      background-color="#FFF">
    </model-viewer>
  </body>
</html>

Open the HTML file in your browser. Your 3D bus is now live on the web!

📷 Screenshots

Low poly house Python code
Blender Scripting Workspace Displaying Low Poly House Python Code

Low poly house in Blender
Blender Layout Workspace Displaying Low Poly House

Low poly house in Web browser
Web Browser Displaying Rendered Low Poly House

Don’t forget to check out my screencast on generating 3D models with Blender Python API. In the video, I walk through the entire process, from coding the script to displaying the model in the browser.

🎬 Embedded Live Screencast

Screencast For Blender Python API Low Poly House

📚 Learn More and Go Further

Want to go deeper with Python and Blender scripting?

💬 Need Help? Book a 1-on-1 Session

I offer personalized online Python tutoring, including Blender scripting sessions. You can reach me via my contact page:

👉 Book a session

🧠 Final Thoughts

With just a few lines of Python and a simple HTML viewer, you can automate 3D modeling in Blender and bring your creations to life online. Give it a try and let me know how it works for you!

About Edward

Edward is a software engineer, web developer, and author dedicated to helping people achieve their personal and professional goals through actionable advice and real-world tools.

As the author of impactful books including Learning JavaScript, Learning Python, Learning PHP, Mastering Blender Python API, and fiction The Algorithmic Serpent, Edward writes with a focus on personal growth, entrepreneurship, and practical success strategies. His work is designed to guide, motivate, and empower.

In addition to writing, Edward offers professional "full-stack development," "database design," "1-on-1 tutoring," "consulting sessions,", tailored to help you take the next step. Whether you are launching a business, developing a brand, or leveling up your mindset, Edward will be there to support you.

Edward also offers online courses designed to deepen your learning and accelerate your progress. Explore the programming on languages like JavaScript, Python and PHP to find the perfect fit for your journey.

📚 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.
🎓 Ready to Learn? – Check out his Online Courses to turn your ideas into results.

Leave a Reply

Your email address will not be published. Required fields are marked *