SEAMLESS LOOPING ANIMATION SCRIPT FOR CINEMA 4D (VIBRATE TAG ALTERNATIVE)
Notice the seamless loop? The Vibrate Tag can’t do it, so here’s a Python Tag solution I built with ChatGPT.
The script creates a perfectly looping animation for your objects.
THE SCRIPT
import c4d
import math
import random
def main():
obj = op.GetObject()
if obj is None:
return
# === MAIN SETTINGS ===
enable_pos = True
enable_rot = False
enable_scale = True
amp_pos = c4d.Vector(2, 2, 2) # cm
amp_rot = c4d.Vector(10, 20, 5) # degrees
amp_scale = 0.05 # "breathing" in % (0.15 = 15% up and down)
loop_frames = 180
freq = 1.0 # shake frequency (position/rotation)
freq_scale = 1.0 # "breath" frequency (scale)
# ——— SEED for unique behavior
seed = 35426 # you can change this for different objects
# === Random phases based on seed ===
rnd = random.Random(seed)
phase_offset_x = rnd.uniform(0, 2 * math.pi)
phase_offset_y = rnd.uniform(0, 2 * math.pi)
phase_offset_z = rnd.uniform(0, 2 * math.pi)
phase_offset_scale = rnd.uniform(0, 2 * math.pi)
# === CALCULATIONS ===
time = doc.GetTime()
fps = doc.GetFps()
frame = time.GetFrame(fps)
phase = (frame % loop_frames) / float(loop_frames)
# shake with unique phases
vibr = c4d.Vector(
math.sin(phase * math.pi * 2 * freq + phase_offset_x),
math.sin(phase * math.pi * 2 * freq + phase_offset_y),
math.sin(phase * math.pi * 2 * freq + phase_offset_z)
)
# uniform scale "breathing" with random phase
scale_phase = math.sin(phase * math.pi * 2 * freq_scale + phase_offset_scale)
scale_val = 1 + scale_phase * amp_scale
# === APPLY ===
if enable_pos:
obj.SetRelPos(c4d.Vector(
vibr.x * amp_pos.x,
vibr.y * amp_pos.y,
vibr.z * amp_pos.z
))
if enable_rot:
obj.SetRelRot(c4d.Vector(
math.radians(vibr.x * amp_rot.x),
math.radians(vibr.y * amp_rot.y),
math.radians(vibr.z * amp_rot.z)
))
if enable_scale:
obj.SetRelScale(c4d.Vector(scale_val, scale_val, scale_val))
Note:
👉 The script is not perfect: seamless looping works only for whole-number frequencies (1, 2, 3, etc).
👉 To keep the original object position, use Freeze Transform before applying the tag.
Good news:
👉 True seamless loop (with the loop period set via loop_frames)
👉 You can start motion from any frame by adjusting fade_start.