Indexed Access to Animatable Properties in 3ds Max Objects

As an alternative to using named property accesses, you can access in an object any animatable property that is visible as a track in Track View by indexing the 3ds Max object value as though it were an array. This simplifies such tasks as iterating over all the animatable properties in an object and accessing sub-controllers that don't have unique names, such as within list controllers.


<maxwrapper_object>.numSubs : Integer, read-only

Yields the number of accessible sub-animatables, or tracks, in an object. This is the number of immediate children subAnims, and may include as yet invisible tracks in the track view, such as visibility tracks on a node or yet-to-be animated vertices in an FFD. This property operates on any MAXWrapper subclass.


getSubAnimName <maxwrapper_object> <index> [asString:<Boolean>]

Returns the name of the indexed subAnim in the supplied MAXWrapper.

If the optional asString keyword is supplied and set to true, the name is returned as a string. If false or not specified, a Name Value is returned.


getSubAnimNames <maxwrapper_object>

Returns an array of names in subAnim index order.


getSubAnim <maxwrapper_object> <index>

Returns the indexed subAnim. See the index operator below.



Returns the subAnim with the specified index or name. You can apply the index operator, [<index_number>], to any MAXWrapper object (nodes, modifiers, controllers, materials, etc.) to access a numbered subAnim.

For example:

for i in 1 to $foo.numSubs do print $foo[i] -- iterate them

$bar.position.controller[3] -- third subAnim in a position list controller

ffd_mod[i].value -- position of i'th FFD control point


You cannot set subAnims with the index operator, this is a read-only access.

In place of an index, you can also use a subanim name. It can be any expression that yields a string or name value. So, whereas in releases prior 3ds Max 4, getting at the position subAnim in a node require you to remember index 3 for the transform subanim and 1 for its position subanim, in other words


$foo[3][1] -- position within transform within node

you can use instead:


The names you can use are those seen in the track view or retrieved with the functions getSubAnimName() or getSubAnimNames().


SubAnim Class

MAXScript defines a SubAnim class, instances of which provide a general representation for sub-animatables. Whenever you use the index operator on a 3ds Max object, it returns a SubAnim instance.

For example:

$box01[3] -> SubAnim:Transform

The third subAnim in a node is typically the transform track.


<subAnim>.name : String, read-only

Returns the name of the track subAnim as shown in TrackView.

<subAnim>.parent : Node, read-only

Returns the true owner of the subAnim.


The true object owning the subAnim can be different than what was originally specified when creating the subAnim, and MAXScript automatically hides certain types of subAnims, automatically promoting the subAnims within them.

For example:


sa = s.baseobject[0]






--The actual owner of the Radius subAnim is the sphere's parameter block.


<subAnim>.index : Integer, read-only

Returns the index of the subAnim.

<subAnim>.value : Value

The current value of the track subAnim, equivalent to <controller>.value. Returns undefined if no appropriate value exists or the track has not yet been assigned a controller. The .value property yields the value at the current MAXScript time. You can assign to this value to set the track's value at that time.

<subAnim>.controller : Controller

The controller for the track SubAnim. Returns undefined if a controller has not yet been assigned or if the SubAnim is not animatable. You can assign a new controller to a track by assigning to the .controller property of its subAnim.

<subAnim>.keys : KeyArray, read-only

Yields the key array for that track or undefined if not keyable or a controller has not yet been assigned. This property is read-only.

<subAnim>.isAnimated : Boolean, read-only

Yields true if there is an animated controller present. This property is read-only.

<subAnim>.object : MAXWrapper, read-only

Yields the subAnim object, or undefined if not assigned. This property is read-only. The .object property may return any kind of MAXWrapper object, depending on what the parent object decides to put there. For example, <node>[1].object is the visibility controller or undefined if not yet assigned, <node>[2].object contains the bindings of any space warps bound to the node, or undefined if none have been bound, <node>[3].object is the transform controller, <node>[4].object is the node's object, either the modified object if there are modifiers present or the base object if not, <node>[5].object is the material assigned to the node or undefined if no material has been assigned, and <node>[6].object is the Image Motion Blur Multiplier controller or undefined if not yet assigned,.

For example:

b = box()

b[4].object -- returns a reference to the Box base object

<subAnim>.numSubs : Integer, read-only

The number of immediate subAnim children.

If you attempt to access subAnim properties, such as .value, .numSubs, .category, etc., on certain subAnims that had yet to be assigned controllers, such as scene node visibility tracks, these properties return null values such as 0, or undefined, as appropriate.


getSubAnim <subAnim> <index>

Returns the indexed subAnim. See the index operator below.



Returns the indexed subAnim. You can work down through nested subAnims (nested tracks) by indexing into subAnims themselves.

For example,


yields the rotation track subAnim since <node>[3] is always the transform track and the second track in it is always the rotation track. Indexing a SubAnim always yields another SubAnim. For those familiar with SubAnims in the 3ds Max SDK, it should be noted that MAXScript SubAnims descend automatically through 'hidden' subAnim levels, reflecting the structure seen in Track View.


that you can get at the base object's Track View parameters by indexing into the base object:


getSubAnimNames b[4] -- returns #(#length, #width, #height, ...)

b[4][2].value -- returns current width value

i = 3

b[4][i].controller = float_list() -- assign height controller