Cool Frame C4D Script
September 2022, MIT License.
The script is completely free, you can correct any mistakes in the code or optimize it, but cannot re-sell it.
Installation
- Download the zip archive and extract it.
- Place the coolframe.c4d file in a drive/folder that’s not gonna move in the years to come. (eg: E:/Assets/Cinema4d/PythonScripts/coolframe.c4d)
- Open Cinema4d and go to Extensions > User Scripts > Script Folder
- Place the coolframe.py in that folder.
- Close and Re-Open Cinema4d, and go to Extensions > Script Manager, select the coolframe.py script.
- In the code, replace the directory by where you put coolframe.c4d in step 2.
- Before exiting the script editor, save the changes, and voilà!
Limitations
It is my first-ever script, so it might be quite buggy. To fully benefit of this script, you may need to add some Xpresso nodes to make more relations here and there.
Make sure that, in the object manager, all of the parent frames are calculated before their respective children, to ensure a smooth preview.
I feel like it could be useful for a lot of motion designers, so I’m just sharing a tool that I use all the time, for free.
(And I loved making that silly promo video)
Example Files
Quick view of the Python tag code for my fellow nerds 🤓
import c4d
def main():
obj = op.GetObject()
bc = c4d.BaseContainer()
obj.AddEventNotification(op, c4d.NOTIFY_EVENT_MESSAGE, 0, bc)
parent = obj[c4d.ID_USERDATA,14] #Parenting : Link to Parent frame
mix_x = obj[c4d.ID_USERDATA,15] #Parenting : Interpolation of X Position between the parent edges (in %)
mix_y = obj[c4d.ID_USERDATA,16] #Parenting : Interpolation of Y Position between the parent edges (in %)
margin_w = obj[c4d.ID_USERDATA,20] #Parenting : Margin for width
margin_h = obj[c4d.ID_USERDATA,22] #Parenting : Margin for height
mult_w = obj[c4d.ID_USERDATA,28] #Parenting : Multiplier of width
mult_h = obj[c4d.ID_USERDATA,31] #Parenting : Multiplier of height
radbool = obj[c4d.ID_USERDATA,23] #Parenting : Checkbox for radius
disap_tresh = obj[c4d.ID_USERDATA,33] #Disappearing Treshold
align_x = c4d.utils.RangeMap(obj[c4d.ID_USERDATA,34],0,2,1,-1,False) #Converts the left, center, right into usable data
align_y = c4d.utils.RangeMap(obj[c4d.ID_USERDATA,35],0,2,-1,1,False) #Converts the top, center, bottom into usable data
color_bool = obj[c4d.ID_USERDATA,37] #Use custom color?
icon_bool = obj[c4d.ID_USERDATA,39] #Use it for icon?
color_custom = obj[c4d.ID_USERDATA,38] #Custom color
default_color = c4d.Vector(0.29, 0.529, 1)
if obj[c4d.ID_USERDATA,19] == False:
width = obj[c4d.ID_USERDATA,3]
else:
width = parent[c4d.PRIM_RECTANGLE_WIDTH]*mult_w-(margin_w*2)
obj[c4d.PRIM_RECTANGLE_WIDTH] = width
minw = width*0.5
if obj[c4d.ID_USERDATA,21] == False:
height = obj[c4d.ID_USERDATA,4]
else:
height = parent[c4d.PRIM_RECTANGLE_HEIGHT]*mult_h-(margin_h*2)
obj[c4d.PRIM_RECTANGLE_HEIGHT] = height
minh = height*0.5
small = min(minh,minw)
rounding = obj[c4d.ID_USERDATA,9]
obj[c4d.PRIM_RECTANGLE_ROUNDING] = rounding
if radbool == True:
radius = parent[c4d.PRIM_RECTANGLE_RADIUS] - obj[c4d.ID_USERDATA,24]
else:
radius = obj[c4d.ID_USERDATA,5]
if small > radius:
obj[c4d.PRIM_RECTANGLE_RADIUS] = radius
else:
obj[c4d.PRIM_RECTANGLE_RADIUS] = small
#Custom color
if color_bool == False:
obj[c4d.ID_BASEOBJECT_USECOLOR] = 0 #Material
else:
obj[c4d.ID_BASEOBJECT_USECOLOR] = 2 #Custom color
obj[c4d.ID_BASEOBJECT_COLOR] = color_custom
if icon_bool == True:
obj[c4d.ID_BASELIST_ICON_COLOR] = color_custom
else:
obj[c4d.ID_BASELIST_ICON_COLOR] = default_color
#Disappearing Treshold
if height < disap_tresh:
obj[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = 0
elif width < disap_tresh:
obj[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = 0
else:
obj[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = 1
xoffset = obj[c4d.ID_USERDATA,7]
yoffset = obj[c4d.ID_USERDATA,8]
if parent == None:
parent_x = 0
parent_y = 0
pw = 0
ph = 0
rel_x_pos = (width*0.5)*align_x + xoffset
rel_y_pos = (height*0.5)*align_y + yoffset
else:
if parent[c4d.ID_USERDATA,26] == None:
parent_x = c4d.BaseObject.GetRelPos(parent)[0]
parent_y = c4d.BaseObject.GetRelPos(parent)[1]
pw = parent[c4d.PRIM_RECTANGLE_WIDTH]
ph = parent[c4d.PRIM_RECTANGLE_HEIGHT]
else:
parent_x = c4d.BaseObject.GetRelPos(parent[c4d.ID_USERDATA,26])[0]
parent_y = c4d.BaseObject.GetRelPos(parent[c4d.ID_USERDATA,26])[1]
pw = parent[c4d.PRIM_RECTANGLE_WIDTH]
ph = parent[c4d.PRIM_RECTANGLE_HEIGHT]
paw = c4d.utils.RangeMap(mix_x, 0, 1, pw*-0.5, pw*0.5, False)
pah = c4d.utils.RangeMap(mix_y, 0, 1, ph*0.5, -ph*0.5, False)
if obj[c4d.ID_USERDATA,11] == True: #If overflow X is active:
rel_x_pos = parent_x + paw + (width*0.5)*align_x + xoffset
else: #if overflow X is not active:
paw_of = c4d.utils.RangeMap(mix_x, 0, 1, (pw*-0.5 + width*0.5), (pw*0.5-width*0.5), False)
rel_x_pos = parent_x + paw_of + xoffset
if obj[c4d.ID_USERDATA,12] == True: #If overflow Y is active:
rel_y_pos = parent_y + pah + (height*0.5)*align_y + yoffset
else: #if overflow Y is not active:
pah_of = c4d.utils.RangeMap(mix_y, 0, 1, (ph*-0.5 + height*0.5), (ph*0.5-height*0.5), False)
rel_y_pos = parent_y + pah_of + yoffset
ext = obj[c4d.ID_USERDATA,26]
if ext == None:
obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = rel_x_pos
obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = rel_y_pos
else:
obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = 0
obj[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = 0
ext[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = rel_x_pos
ext[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = rel_y_pos
#Custom color
if color_bool == False:
ext[c4d.ID_BASEOBJECT_USECOLOR] = 0 #Material
else:
ext[c4d.ID_BASEOBJECT_USECOLOR] = 2 #Custom color
ext[c4d.ID_BASEOBJECT_COLOR] = color_custom
if icon_bool == True:
ext[c4d.ID_BASELIST_ICON_COLORIZE_MODE] = 1
ext[c4d.ID_BASELIST_ICON_COLOR] = color_custom
else:
ext[c4d.ID_BASELIST_ICON_COLORIZE_MODE] = 0
#Creating the extruded Object
def message(msg_type, data):
obj = op.GetObject()
if msg_type == c4d.MSG_NOTIFY_EVENT:
event_data = data['event_data']
if event_data['msg_id'] == c4d.MSG_DESCRIPTION_COMMAND:
desc_id = event_data['msg_data']['id']
if desc_id[1].id == 25:
extrude = c4d.BaseObject(5116) #Create the extrude
doc.InsertObject(extrude) #Insert the extrude into the scene
obj.InsertUnder(extrude) #Insert Frame under extrude
extrude.SetName(obj.GetName()+'_ext') #Rename it w/ the original frame name
obj[c4d.ID_USERDATA,26] = extrude #Place Extrude ref in Frame
extrude[c4d.EXTRUDEOBJECT_EXTRUSIONOFFSET] = 1 #Set Extrusion to 1
c4d.CallCommand(600000152) #Select Extrude
c4d.CallCommand(100004802) #Unfold
c4d.CallCommand(600000140) #select Frame