Code written by Jonathan DeLeon with AI assistance:
3D model by: abdoubouam
“Raspberry Pi Pico”
https://blendswap.com/blend/27180
Maya Build Animation Tool (Python):
A dockable tool for procedurally animating building/room layouts in Maya. This tool allows users to animate objects “falling” into a scene and later animating out. Features: – Define animation frame range – Set fall duration for each object – Choose between random or selection order for animation sequence – Auto-updating selection count – Set starting height for objects – Select animation spline type (Linear, Auto, Spline, etc.) – Save selection for easy recall
Code Sample:
"""
--------------------------------
Building Animation Tool for Maya
--------------------------------
This Python script, "Building Animation Tool", (v1.0.1),
is part of a project created by Jonathan DeLeon.
Copyright (C) 2025 Jonathan DeLeon (contact@JonathanDeLeon.com)
This script is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This script is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
--------------------------------
Usage / Instructions
--------------------------------
A dockable tool for procedurally animating building/room layouts in Maya.
This tool allows users to animate objects "falling" into a scene and later animating out.
Features:
- Define animation frame range
- Set fall duration for each object
- Choose between random or selection order for animation sequence
- Auto-updating selection count
- Set starting height for objects
- Select animation spline type (Linear, Auto, Spline, etc.)
- Save selection for easy recall
Usage:
1. Copy this script to your Maya scripts directory
2. Run the following commands in Maya's Python script editor:
import building_animation_tool
building_animation_tool.show()
"""
from PySide2 import QtWidgets, QtCore
from maya import OpenMayaUI as omui
from shiboken2 import wrapInstance
import maya.cmds as cmds
import random
def get_maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
class Animator:
def __init__(self, objects, start_frame, end_frame, randomize, height, fall_mode, fixed_dur, rand_min, rand_max, ease):
self.objects = objects
self.start_frame = start_frame
self.end_frame = end_frame
self.randomize = randomize
self.height = height
self.fall_mode = fall_mode
self.fixed_dur = fixed_dur
self.rand_min = rand_min
self.rand_max = rand_max
self.ease = ease
def animate(self):
if self.randomize:
random.shuffle(self.objects)
total_frames = self.end_frame - self.start_frame
num_objects = len(self.objects)
frame_per_object = max(total_frames // num_objects, 1)
for i, obj in enumerate(self.objects):
offset = i * frame_per_object
anim_start = self.start_frame + offset
if self.fall_mode == "Fixed":
anim_end = anim_start + self.fixed_dur
else: # Random
anim_end = anim_start + random.randint(self.rand_min, self.rand_max)
pos = cmds.xform(obj, q=True, ws=True, t=True)
start_pos = pos[:]
start_pos[1] += self.height
cmds.setKeyframe(obj, at='translateY', t=anim_start, v=start_pos[1])
cmds.setKeyframe(obj, at='translateY', t=anim_end, v=pos[1])
if self.ease:
cmds.select(obj, r=True)
cmds.selectKey(obj, attribute='translateY', time=(anim_start, anim_end), keyframe=True)
cmds.keyTangent(inTangentType="linear", outTangentType="spline")
class BuildingAnimatorUI(QtWidgets.QDialog):
def __init__(self, parent=get_maya_main_window()):
super(BuildingAnimatorUI, self).__init__(parent)
self.setWindowTitle("Building Animator Tool")
self.setMinimumWidth(300)
self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
self.build_ui()
def build_ui(self):
layout = QtWidgets.QVBoxLayout(self)
self.start_frame_box = QtWidgets.QSpinBox()
self.start_frame_box.setRange(1, 100000)
self.start_frame_box.setValue(1)
self.end_frame_box = QtWidgets.QSpinBox()
self.end_frame_box.setRange(1, 100000)
self.end_frame_box.setValue(100)
self.random_order_checkbox = QtWidgets.QCheckBox("Randomize Order")
self.selection_count_label = QtWidgets.QLabel("Selected Objects: 0")
self.start_height_box = QtWidgets.QDoubleSpinBox()
self.start_height_box.setRange(0, 1000)
self.start_height_box.setValue(10)
self.fall_mode_combo = QtWidgets.QComboBox()
self.fall_mode_combo.addItems(["Fixed", "Random"])
self.fall_mode_combo.currentIndexChanged.connect(self.toggle_fall_mode)
self.fixed_duration_box = QtWidgets.QSpinBox()
self.fixed_duration_box.setRange(1, 1000)
self.fixed_duration_box.setValue(10)
self.rand_min_box = QtWidgets.QSpinBox()
self.rand_min_box.setRange(1, 1000)
self.rand_min_box.setValue(5)
self.rand_max_box = QtWidgets.QSpinBox()
self.rand_max_box.setRange(1, 1000)
self.rand_max_box.setValue(20)
self.ease_fall_checkbox = QtWidgets.QCheckBox("Ease Fall (Spline)")
self.animate_button = QtWidgets.QPushButton("Animate!")
self.animate_button.clicked.connect(self.animate_objects)
layout.addWidget(QtWidgets.QLabel("Start Frame:"))
layout.addWidget(self.start_frame_box)
layout.addWidget(QtWidgets.QLabel("End Frame:"))
layout.addWidget(self.end_frame_box)
layout.addWidget(self.random_order_checkbox)
layout.addWidget(self.selection_count_label)
layout.addWidget(QtWidgets.QLabel("Starting Height Above:"))
layout.addWidget(self.start_height_box)
layout.addWidget(QtWidgets.QLabel("Fall Duration Mode:"))
layout.addWidget(self.fall_mode_combo)
self.fixed_label = QtWidgets.QLabel("Fixed Fall Duration:")
layout.addWidget(self.fixed_label)
layout.addWidget(self.fixed_duration_box)
self.random_layout = QtWidgets.QHBoxLayout()
self.random_layout.addWidget(QtWidgets.QLabel("Random Duration Min:"))
self.random_layout.addWidget(self.rand_min_box)
self.random_layout.addWidget(QtWidgets.QLabel("Max:"))
self.random_layout.addWidget(self.rand_max_box)
layout.addLayout(self.random_layout)
layout.addWidget(self.ease_fall_checkbox)
layout.addWidget(self.animate_button)
self.toggle_fall_mode()
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.update_selection_count)
self.timer.start(1000)
def toggle_fall_mode(self):
is_random = self.fall_mode_combo.currentText() == "Random"
self.fixed_label.setVisible(not is_random)
self.fixed_duration_box.setVisible(not is_random)
for i in range(self.random_layout.count()):
self.random_layout.itemAt(i).widget().setVisible(is_random)
def update_selection_count(self):
selection = cmds.ls(sl=True)
self.selection_count_label.setText(f"Selected Objects: {len(selection)}")
def animate_objects(self):
objects = cmds.ls(sl=True)
if not objects:
cmds.warning("No objects selected.")
return
start_frame = self.start_frame_box.value()
end_frame = self.end_frame_box.value()
randomize = self.random_order_checkbox.isChecked()
height = self.start_height_box.value()
fall_mode = self.fall_mode_combo.currentText()
fixed_dur = self.fixed_duration_box.value()
rand_min = self.rand_min_box.value()
rand_max = self.rand_max_box.value()
ease = self.ease_fall_checkbox.isChecked()
animator = Animator(objects, start_frame, end_frame, randomize, height, fall_mode, fixed_dur, rand_min, rand_max, ease)
animator.animate()
def show_building_animator_ui():
for widget in QtWidgets.QApplication.allWidgets():
if isinstance(widget, BuildingAnimatorUI):
widget.close()
ui = BuildingAnimatorUI()
ui.show()
show_building_animator_ui()