Page Flip Animation in Blender Using Python

Page Flip Animation Via Blender Python API
Page Flip Animation Via Blender Python API

🎥 Generate Page Flip Animation Via Blender Python API

Have you ever wanted to automate animations in Blender using Python? In this beginner-friendly tutorial, I’ll show you how to create a smooth page flip animation using the Blender 4.4 Python API — no prior coding experience required!

This script is perfect for students, artists, animators, and developers curious about Blender scripting. You’ll also find resources below if you’re just getting started with Python programming.

📚 From My Book: Mastering Blender Python API

This tutorial is inspired by concepts from my book, Mastering Blender Python API, where I walk you through real-world projects like:

  • Automating 3D animation tasks
  • Creating procedural geometry
  • Developing custom Blender tools

If you’re serious about becoming a power user in Blender, this book is a must-have on your shelf!

📖 Learn more about the book »

🔧 What You’ll Learn

  • How to use the Blender Python API to animate a plane object
  • Create bending deformation using modifiers
  • Animate rotation and modifiers across frames
  • Use Eevee with correct lighting for clean rendering

📦 Requirements

  • Blender 4.4 or later
  • Basic familiarity with Blender UI
  • No coding experience necessary!

🎬 Watch the Tutorial Video

Animated Screencast For Blender Python API Page Flip

📷 Screenshots

Page flip in Blender viewport
Blender Scripting Tab Displaying Page Flip In Blender Viewport

Rendered page flip in motion
Blender Rendered Output Displaying Page Flip

👨‍🏫 Need Help Learning Python?

If Blender scripting feels overwhelming, I also offer a complete beginner course called Learning Python — designed for artists and non-programmers.

🎓 Check out the course and the book »

🤝 Book a One-on-One Tutorial

Need personalized help? I’m available for 1-on-1 online tutoring sessions focused on:

  • Blender scripting
  • Python fundamentals
  • Automating creative workflows

📅 Click here to schedule a session »

📥 Get the Script

You can find the full working script with camera, lighting, Eevee-ready rendering, and procedural animation in the Python script:

import bpy
import math
import mathutils
from mathutils import Quaternion

# Frame Rate #
fps = 30
frames = 100

# Clear Existing Objects #
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

# Create A Plane As The Page #
bpy.ops.mesh.primitive_plane_add(size=1)
page = bpy.context.object
page.name = "Page"
page.scale.x = 0.5
bpy.ops.object.transform_apply(scale=True)

# Subdivide For Smooth Deformation #
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.subdivide(number_cuts=32)
bpy.ops.object.mode_set(mode='OBJECT')

# Create Empties For Bending And Rotation Pivots #
bpy.ops.object.empty_add(type='PLAIN_AXES', location=page.location)
bend_empty = bpy.context.object
bend_empty.rotation_euler.x = math.radians(90)
bend_empty.scale = (0.25, 0.25, 0.25)
bend_empty.name = "BendPivot"

bpy.ops.object.empty_add(type='PLAIN_AXES', location=page.location)
rot_empty = bpy.context.object
rot_empty.name = "RotPivot"

# Parent The Page To The Rotation Empty #
page.parent = rot_empty

# Add Child Of Constraint On Page Targeting bend_empty #
child_of = page.constraints.new('CHILD_OF')
child_of.target = bend_empty

# Add Simple Deform (Bend) Modifier To Page #
mod = page.modifiers.new(name="SimpleBend", type='SIMPLE_DEFORM')
mod.deform_method = 'BEND'
mod.origin = bend_empty
mod.deform_axis = 'Z'

# Animation Settings #
scene = bpy.context.scene
scene.frame_start = 1
scene.frame_end = frames

# Quaternion Rotation Mode For Smooth Rotation #
rot_empty.rotation_mode = 'QUATERNION'

# Insert Rotation Keyframes (Quaternion) #
rot_empty.rotation_quaternion = Quaternion((1, 0, 0, 0))
rot_empty.keyframe_insert(data_path="rotation_quaternion", frame=1)

rot_empty.rotation_quaternion = Quaternion((0, 1, 0), math.radians(90))
rot_empty.keyframe_insert(data_path="rotation_quaternion", frame=50)

rot_empty.rotation_quaternion = Quaternion((0, 1, 0), math.radians(180))
rot_empty.keyframe_insert(data_path="rotation_quaternion", frame=100)

# Bending Keyframes #
mod.angle = 0
mod.keyframe_insert(data_path="angle", frame=1)

mod.angle = math.radians(-75)
mod.keyframe_insert(data_path="angle", frame=45)

mod.angle = math.radians(-135)
mod.keyframe_insert(data_path="angle", frame=50)

mod.angle = math.radians(-75)
mod.keyframe_insert(data_path="angle", frame=55)

mod.angle = 0
mod.keyframe_insert(data_path="angle", frame=100)

# Smooth Shading #
bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.view_layer.objects.active = page
page.select_set(True)
bpy.ops.object.shade_smooth()

# Set Interpolation #
if rot_empty.animation_data and rot_empty.animation_data.action:
    for fcurve in rot_empty.animation_data.action.fcurves:
        for kp in fcurve.keyframe_points:
            kp.interpolation = 'LINEAR'

if page.animation_data and page.animation_data.action:
    for fcurve in page.animation_data.action.fcurves:
        if fcurve.data_path.startswith('modifiers["SimpleBend"].angle'):
            for kp in fcurve.keyframe_points:
                kp.interpolation = 'BEZIER'

# Add A Camera #
bpy.ops.object.camera_add(location=(0, -3, 1), rotation=(math.radians(75), 0, 0))
camera = bpy.context.object
camera.name = "Camera"

# Set Camera As Active #
scene.camera = camera

# Helper to aim a light
def aim_light(light_obj, target_loc):
    direction = target_loc - light_obj.location
    rot_quat = direction.to_track_quat('-Z', 'Y')
    light_obj.rotation_euler = rot_quat.to_euler()

# Bright key light
bpy.ops.object.light_add(type='AREA', location=(4, -3, 5))
key_light = bpy.context.object
key_light.name = "KeyLight"
key_light.data.energy = 5000
key_light.data.size = 4
aim_light(key_light, mathutils.Vector((0, 0, 0)))

# Fill light
bpy.ops.object.light_add(type='AREA', location=(-4, -3, 3))
fill_light = bpy.context.object
fill_light.name = "FillLight"
fill_light.data.energy = 2000
fill_light.data.size = 5
aim_light(fill_light, mathutils.Vector((0, 0, 0)))

# Backlight for depth
bpy.ops.object.light_add(type='AREA', location=(0, 3, 2))
rim_light = bpy.context.object
rim_light.name = "RimLight"
rim_light.data.energy = 1000
rim_light.data.size = 5
aim_light(rim_light, mathutils.Vector((0, 0, 0)))

# Set world ambient lighting (environment)
world = bpy.data.worlds["World"]
world.use_nodes = True
bg = world.node_tree.nodes["Background"]
bg.inputs["Color"].default_value = (1, 1, 1, 1)
bg.inputs["Strength"].default_value = 1.5  # Increase for brighter ambient

# Set render engine to EEVEE
scene = bpy.context.scene

# World ambient lighting
world = bpy.data.worlds["World"]
world.use_nodes = True
bg = world.node_tree.nodes["Background"]
bg.inputs["Strength"].default_value = 2.0               # brighten scene

# Create better paper material
mat = bpy.data.materials.new(name="PaperWhite")
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links

# Clear default nodes
for node in nodes:
    nodes.remove(node)

# Nodes
output = nodes.new('ShaderNodeOutputMaterial')
diffuse = nodes.new('ShaderNodeBsdfDiffuse')
glossy = nodes.new('ShaderNodeBsdfGlossy')
mix = nodes.new('ShaderNodeMixShader')

output.location = (600, 0)
diffuse.location = (0, 100)
glossy.location = (0, -100)
mix.location = (300, 0)

# Inputs
diffuse.inputs['Color'].default_value = (1, 1, 1, 1)
glossy.inputs['Color'].default_value = (1, 1, 1, 1)
glossy.inputs['Roughness'].default_value = 0.05
mix.inputs['Fac'].default_value = 0.2  # Mostly diffuse, some gloss

# Connect
links.new(diffuse.outputs['BSDF'], mix.inputs[1])
links.new(glossy.outputs['BSDF'], mix.inputs[2])
links.new(mix.outputs['Shader'], output.inputs['Surface'])

# Assign to page
if page.data.materials:
    page.data.materials[0] = mat
else:
    page.data.materials.append(mat)

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 *