Reference / User Guide




CSSmu() - the main function
This function allows to create, address and edit timelines and groups. Its action depends on what, and how, arguments are passed.
CSSmu("myMotionName")
Will look in the stylesheets for every CSS selector where the class .myMotionName_f[framenumber] is applied, use them to create a timeline,
and return it.
CSSmu(
"myFirstMotion",
"mySecondMotion",
"myThirdMotion"
)

Passing multiple strings as arguments will result in a timeline group, where every sub-timeline is built on the same principle as above.
CSSmu(
"myMotionName",
{ property1:value1 , property2:value2 }
)

Can also be written :

CSSmu({
name:"myMotionName",
property1:value1,
property2:value2
})

A list of properties for the timeline or group can be passed as an object.
See below for details about accepted properties and values.
CSSmu(
"myFirstMotion" , "mySecondMotion",
{ property1:value1 , property2:value2 }
)

This way a group is created,
with the same properties applied to every sub-timeline.


A group can't contain multiple timelines based on the same name.

CSSmu( "myFirstMotion" , {name:"myFirstMotion" , property1:value1} )

Here the second argument won't be taken into account. The function will return a single timeline and ignore the property1:value1 statement as well. The arguments are processed in their declaration order, and only the one with the first occurrence of the name will be kept.
CSSmu(
{
name:"myFirstMotion",
property1:value1,
property2:value2
} , {
name:"mySecondMotion",
property1:value3
}
)

In this example a group is created, with different properties applied to its sub-timelines.


When creating a timeline group, the properties list objects passed to the function can act two different ways :

• If the name property is set, the list will be converted to a sub-timeline for the group.

• If not, the list will be applied to the whole group after its sub-timelines are created (and override equivalent declarations in the named lists).
Please note that passing only list objects without a name property to the function will result in nothing and return false .
CSSmu( my_motion_in_a_variable , {property1:value1} )
Will address a timeline or group previously stored in a variable, edit its properties and return it.
CSSmu(
my_motion_in_a_variable , my_other_motion_in_a_variable
)

Will create a group out of stored timelines, the same way as shown above with strings and properties lists. Passing groups here will work too, merging them into a single one.


Doing this :

var_2 = CSSmu( var_1 , {property1:value1} )

will not only store an edited version of var_1 into var_2 , but also edit var_1 itself. To keep the first variable unchanged, use the duplicate property.

var_2 = CSSmu( {duplicate:var_1 , property1:value1} )

The same applies to group edition :

my_edited_group = CSSmu( my_group , a_timeline )

will add a_timeline directly to my_group unless a duplicate is asked.
Passing properties lists to the function
The most basic use of CSSmu(), with simple strings as arguments, will result in default settings for the timelines created. Although these settings can be edited later via the timeline or group objects' methods, it can be interesting to specify them upon creation.

This can be done with a second type of argument : A list of properties, using a Javascript Object syntax :

{ property1 : value1 , property2 : value2 }
Here's what can be set this way.

name :
Indicates the right class selectors to be read by CSSmu in stylesheets.
This property is required to create a timeline, and as seen above, not setting it will change the list's behavior.
Must be a string.

The value for this property should not contain spaces or punctuation other than hyphens ( - ) or underscores ( _ ). Just keep in mind that it must be valid as a CSS class selector for the library to work properly.

rate :
Sets the timeline's rate, expressed in frames per second.
Default value is 25, can be an integer or a float.


mode :
Sets the timeline's playing behavior. Default value is "loop".

Accepted values are :

"loop"
"once"
"wave" (will loop back and forth)
"wave once"
"wave backwards" (the wave pattern will start backwards)
"wave backwards once"
"backwards"
"backwards once"
"once stay" (the last frame will remain displayed)
"wave once stay"
"wave backwards once stay"
"backwards once stay"


If needed, the values used as default rate and mode can be edited.
They are stored as CSSmu.defaultRate and CSSmu.defaultMode .
Just remember to override them before creating timelines.

defaultFrame :
Sets the frame at which the timeline must start when first launched.
Default is 1, must be an integer.


selectors :
Upon creation, a timeline gets its own target selectors list, fetching every concerned one in the CSS declarations. This property allows to override it.

The value can be :

• A string consisting of comma-separated selectors.

selectors:"#myelem1 , #myelem2 , p"
• An array containing selectors as strings.

selectors:[ "#myelem1" , "#myelem2" , "p" ]
// or
selectors:Array( "#myelem1" , "#myelem2" , "p" )


restrictTo :
Use this as a filter if you have to target only one or a set of specific elements amongst the timeline's selectors list.

The value can be :

• A string consisting of comma-separated selectors.

restrictTo:"#myelem1 , #myelem2 , p"
• An array containing DOM elements, jQuery selectors, or selectors as strings.

restrictTo:[
my_elem_in_a_variable,
document.getElementById("myelem2"),
$("#myelem3"),
"#myelem4"
]
// or
restrictTo:Array(
my_elem_in_a_variable,
document.getElementById("myelem2"),
$("#myelem3"),
"#myelem4"
)


exclude :
The opposite of restrictTo , working the same way.
Use this to prevent action for one or a set of specific elements from the timeline's selectors list.


onFrame :
A list of callback functions to execute when the timeline reaches selected frames. Each frame/function couple has to be a two-values array, himself contained into one single array passed as the value.

onFrame:[
[1 , function(){ alert("hey this is frame one") } ],
[5 , function(){ do_this_on_frame_5(arguments) } ],
[13, my_function_for_frame_13 ]
]

// Would work with the
//   onFrame:Array( Array(1 , my_function) )
// syntax too


Passing a new onFrame property to a timeline, targetting a frame that already has one defined, will overwrite it.

To simply "erase" a previously defined onFrame property for a frame,
an empty function(){} or false can be passed as its callback.

onEachFrame :
A callback function to execute on each new frame reached by the timeline.
The value must be a function.

onEachFrame:function(){ // code }
// or
onEachFrame:my_function


Like for onFrame , an empty function(){} or false can be passed to cancel a previously set value.


The following event properties can be defined and reset the same way.

onStart :
A callback function to execute when the timeline passes by its first frame.


onEnd :
A callback function to execute when the timeline passes by its last frame.


onPlay :
A callback function to execute when the timeline is played.


onPause :
A callback function to execute when the timeline is paused.


onStop :
A callback function to execute when the timeline is stopped.


When set for a group rather than a single timeline, these callbacks will trigger when the group's main sub-timeline reaches the corresponding frame. To change this behavior and have the callback function execute for every sub-timeline, use the following properties instead :

each_onFrame
each_onEachFrame
each_onStart
each_onEnd
each_onPlay
each_onPause
each_onStop

They are to be defined the same way, but will only work when part of a group's global properties list (with no name property).

duplicate :
This property accepts, as a value, a previously created timeline or group.
It makes a copy of it, including all its properties.

Assuming a timeline is first created and stored :

var my_timeline = CSSmu(
"myMotionName",
{ mode:"wave" , rate:12 , restrictTo:"#elem666" }
)

It can be duplicated into a new one which will be, for example, restricted to another element,

CSSmu( { duplicate:my_timeline , restrictTo:"#another_elem" } )
or the copy can be part of a new group.

CSSmu(
{duplicate:my_timeline},
"anotherTimeline",
{restrictTo:"#another_elem"}
)


In this latter case, if my_timeline is a group instead of a single timeline, it is duplicated as well, then a new sub-timeline named "anotherTimeline" is added to it, and finally the restrictTo property is applied to the whole group.


Timeline & Group objects
What we call timelines in CSSmu.js, are objects containing various properties and methods. We've seen how to create and set them up, now let's have a look at how to use them.

Basically, a timeline consists of data, useful to play a sequence the desired way, where the right elements will react in the document, and the right events will happen at the right moment.

A timeline group is made of several of these objects, able to be triggered or set up in a synched way.


Properties
Everything that's required by a timeline to operate properly is stored as its properties. They can be accessed the classical way :

// If my_timeline is a variable
// storing a previously created timeline object,


my_timeline.propertyname
// will give the value of its property called "propertyname".


Quite obviously, properties can also be edited this way.

my_timeline.propertyname = new_value
However, as many of them work together and should be edited together to keep the timeline acting properly (or are only there for "internal" purpose and should not be edited at all), it is not advised to do so.

Every required property edit should be made using the timelines' methods, which will be documented further.

Here is a complete list of the existing properties :


name (string)

The name set when creating the timeline, which is used for class attribution while the sequence is played.

Will remain false for a group.


type (string)

Set to "timeline" or "group" upon the object's creation, and is later used when CSSmu has to detect how to deal with said object.


frameCount (integer)

The timeline's frame count. It is automatically detected in the CSS stylesheets upon creation.

In the case of a group, the value will be the same as its main sub-timeline's.


frameRate (integer or float)

The timeline's rate, expressed in frames per second.
Default value is 25.

Will remain 0 for a group.


frameInterval (integer)

The timeline's frameRate value, converted to an interval in milliseconds,
to leave between each frame display.

Will remain 0 for a group.


mode (string)

The timeline's playing behavior. Default value is "loop".

Will remain false for a group.


isPlaying (boolean)

Is true when the timeline or group is playing, false otherwise.


currentFrame (integer)

The timeline's currently displayed frame's number. Default value, before playing, is 0.

A group's currentFrame changes accordingly with its main sub-timeline's.


timer (integer)

Used only to store and control the setInterval() function browsing through the timeline's frames.

Will remain false for a group.


selectors (strings array)

The timeline's list of affected CSS selectors, automatically set upon creation. When playing the sequence, these selectors are used to target the right elements and give them additional classes corresponding to the frame to display.

Will remain empty for a group.


restrictedTargets (strings and/or DOM elements array)

A list of selectors, or direct elements, for the timeline to exclusively take into account when applying frame-display classes.

Will remain empty for a group.


excludedTargets (strings and/or DOM elements array)

A list of selectors, or direct elements, for the timeline to exclude when applying frame-display classes.

Will remain empty for a group.


isMainSubTimeline (boolean)

Is true if the timeline is part of a group and has been defined as
its main sub-timeline.

Will remain false for a group.


parentTimeline (timeline group object)

The group object the timeline belongs to, or false if it is part of no group.

A group's parentTimeline is the group itself (and is never called or used).


subTimelines (timeline objects array)

The list of timeline objects composing a group.

Will remain empty in the case a single timeline.


mainSubTimeline (timeline object)

The group's main sub-timeline, defined upon creation.

When creating a group, one of its sub-timelines has to be defined as the main one. This is used when an event such as onFrame , onEnd , etc. is declared for the group itself.

By default a group has no frameset of its own, and playing it will actually result in playing all its sub-timelines simultaneously. So a group uses his main sub-timeline's frameCount and currentFrame properties as its own.
As of CSSmu.js version 1.0.1, a group's mainSubTimeline is automatically set to the longest timeline (in terms of frameCount) composing it. It doesn't take rate properties into account, so in some cases the resulting behavior could be strange.

If needed, a method allows to override this property for a group and choose another sub-timeline as its main one.
A single timeline's mainSubTimeline is itself (and is never called or used).


mainSubTimelineName (string)

The group's main sub-timeline's name property, defined upon creation.

A single timeline's mainSubTimelineName is its own name .


frameCallbacks (functions array)

The timeline or group's list of frame-specific callback functions,
defined via onFrame .

Each function's index in this array eventually corresponds to the frame calling it. The array is empty by default, indexes are only created when filled.


tmp_frameCallback (function)

Temporarily stores an element of the timeline or group's frameCallbacks array just before it needs to be called.

Is false by default.

Without this internal trick, pointing to this when defining a frame-specific callback function would lead to the array instead of the timeline.


onEachFrameCallback (function)

Stores the callback function defined via onEachFrame .
Is false by default.


onStartCallback (function)

Stores the callback function defined via onStart .
Is false by default.


onEndCallback (function)

Stores the callback function defined via onEnd .
Is false by default.


onPlayCallback (function)

Stores the callback function defined via onPlay .
Is false by default.


onPauseCallback (function)

Stores the callback function defined via onPause .
Is false by default.


onStopCallback (function)

Stores the callback function defined via onStop .
Is false by default.

Methods
Timelines and groups both come with a set of methods (or functions). Some are exclusive to the single timeline model, some to groups, most of them are shared, but can give slightly different results depending on where they are called from.

These methods can be sorted in four categories :

• Controls,
allowing to trigger and pilot the timeline or group.

• Event handlers,
defining, once a sequence is launched, what must happen next, and when.

• Construction and setting operations,
allowing to edit and structure timelines on the fly.

• Relative timeline selectors,
useful when a timeline has to address another one.


Methods found in the construction / settings category are already used when creating a timeline via the CSSmu() function.

Actually, the following example

var tl = CSSmu("a_name" , { rate:12 , mode:"backwards" })
gives exactly the same result as

var tl = CSSmu.create_Timeline("a_name");
tl.setRate(12);
tl.setMode("backwards");

The whole library can be driven without even calling CSSmu as a function.
It's really just a matter of syntax style preference.
Along with this choice in syntax, a mixed approach can of course be used.

// To create a group from
// a first timeline (var tl1) and
// the duplicate of a second one (var tl2) :


CSSmu(tl , {duplicate:tl2})
// is the same as
CSSmu(tl , tl2.duplicate())


One last thing to know about how methods work, is that most of them can be chained together. Rewriting the example from the previous frame in a mixed, chained way, and adding a play() instruction to it, could result in

var tl = CSSmu("a_name").setRate(12).setMode("backwards").play()
When chained, methods keep a logical left-to-right processing order.
Here is a complete list of the existing methods :
Methods : Sequence controls
play()
Plays the timeline or group.
The sequence will start at currentFrame , without prior reset.

Additionally, triggers the onPlayCallback() function if set.


pause()
Pauses the timeline or group.

Additionally, triggers the onPauseCallback() function if set.

In some cases, onPlayCallback() and onPauseCallback() are set, but their execution is not wanted. For example, when setRate() is called, the timeline is internally paused and played again in order to take its new rate into account, and a "discrete" way of doing this is required.

For this, an optional argument called ignore_callback can be passed to play() and pause() .

// ignore_callback is a boolean
tl.pause(true);
tl.play(true);
// this way, no callback functions will be triggered.

// Note :

tl.play(false)
// and
tl.play()
// are the same.


stop()
Stops the timeline or group.
Its currentFrame will then be reset to 0.

Additionally, triggers the onStopCallback() function if set.


toggle()
Toggles the timeline or group between its playing and paused status.


setCurrentFrame(frame_number)
Sets the timeline or group's currentFrame .
This has no incidence on what is displayed, as long as the timeline or group
is not playing.


displayFrame(frame_number)
Sets the timeline or group's currentFrame and displays it.
This method is cyclically called when a timeline is playing.


clean()
Cleans the timeline or group's displayed scene, by removing all classes induced by it from the HTML elements.

// An example :

tl.pause()
// stops the sequence,
// keeps currentFrame,
// leaves currentFrame displayed.

// While

tl.stop()
// stops the sequence,
// resets currentFrame,
// cleans display.

// So, in order to :
// stop the sequence,
// keep currentFrame - saving it for a next play() call,
// but clean what the timeline currently displays :

tl.pause().clean()



The actual effect of all these control methods, when called by a group,
will be to simultaneously trigger themselves for every sub-timeline composing the group.
Methods : Event handlers
The following methods take a callback function as argument.
Meaning either :

• A named function
  of the form my_function_name
  without brackets / arguments

• Some code in an anonymous function
  like for example function(){
my_function_name();
another_function(with_arguments);
if (condition) {
// do things
}
}
onFrame(frame_number , callback_function)
Defines an action to execute when the timeline or group
reaches frame frame_number .


onEachFrame(callback_function)
Defines an action to execute at every frame reached by the timeline or group.


onPlay(callback_function)
Defines an action to execute when the timeline or group is played.


onPause(callback_function)
Defines an action to execute when the timeline or group is paused.


onStop(callback_function)
Defines an action to execute when the timeline or group is stopped.


onStart(callback_function)
Defines an action to execute when the timeline or group
passes by its frame 1 (whether it plays in "backwards" mode or not).


onEnd(callback_function)
Defines an action to execute when the timeline or group
passes by its last frame (whether it plays in "backwards" mode or not).



The default behavior of a group regarding these events, will be to trigger them according to its main sub-timeline's current frame.

To have them triggered for each of its sub-timeline's corresponding events, use the following each_ variants instead.

They are for groups only, and having a single timeline call them will give the same result as with the variants described above.
each_onFrame(frame_number , callback_function)
See : onFrame()


each_onEachFrame(callback_function)
See : onEachFrame()


each_onPlay(callback_function)
See : onPlay()


each_onPause(callback_function)
See : onPause()


each_onStop(callback_function)
See : onStop()


each_onStart(callback_function)
See : onStart()


each_onEnd(callback_function)
See : onEnd()



To cancel a previously set event callback, it is possible to :

• Pass false instead of a function

• Pass an empty function(){}
To address, from inside a callback function, the timeline or group
triggering it, the this operator can be used.

// Example :

var tl = CSSmu("my_timeline_name");
tl.onPlay( function(){ alert(this.name) } );
tl.play(); // will alert "my_timeline_name"

Methods : Building & editing
— Basic settings —

setRate(rate)
Sets the timeline or group's rate, expressed in frames per second.
Can be an integer or a float.


setMode(mode)
Sets the timeline or group's playing behavior. Accepted values are :

"loop"
"once"
"wave" (will loop back and forth)
"wave once"
"wave backwards" (the wave pattern will start backwards)
"wave backwards once"
"backwards"
"backwards once"
"once stay" (the last frame will remain displayed)
"wave once stay"
"wave backwards once stay"
"backwards once stay"


updateSettings(properties_list_object)
Allows to set various properties for the timeline or group. This method accepts, as argument, a properties list object, built the same way as described in the main function section, with the same properties / values.

Two slight differences with lists passed directly to CSSmu() , though :

• Here, a name property will be ignored instead of resulting in a new timeline.
• This method accepts only one property list object at a time.


— Operations on targets list —

addSelector(selectors_list)can be written : addSelectors(selectors_list)
Adds selectors to the timeline's targets list.
The arguments can be :

• A single string consisting of comma-separated selectors.

tl.addSelectors( "#myelem1 , #myelem2 , p" )
• One or multiple selectors as strings.

tl.addSelectors( "#myelem1" , "#myelem2" , "p" )
• An array containing one or multiple selectors as strings.

tl.addSelectors( [ "#myelem1" , "#myelem2" , "p" ] )
// or
tl.addSelectors( Array( "#myelem1" , "#myelem2" , "p" ) )


removeSelector(selectors_list)can be written : removeSelectors(selectors_list)
Removes selectors from the timeline's targets list.
The arguments can be :

• A single string consisting of comma-separated selectors.

tl.removeSelectors( "#myelem1 , #myelem2 , p" )
• One or multiple selectors as strings.

tl.removeSelectors( "#myelem1" , "#myelem2" , "p" )
• An array containing one or multiple selectors as strings.

tl.removeSelectors( [ "#myelem1" , "#myelem2" , "p" ] )
// or
tl.removeSelectors( Array( "#myelem1" , "#myelem2" , "p" ) )


resetSelectors()
Reverts the timeline's target selectors list to its default, automatically parsed from stylesheets version.


clearSelectors()
Erases the timeline's target selectors list.


restrictTo(elements_or_selectors_list)
Works like a filter, allowing the timeline to target only one or a set of specific elements amongst its selectors list.
The arguments can be :

• A single string consisting of comma-separated selectors.

tl.restrictTo( "#myelem1 , #myelem2 , p" )
• One or multiple DOM elements, jQuery selectors, or selectors as strings.

tl.restrictTo(
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
)

• An array containing one or multiple DOM elements, jQuery selectors,
  or selectors as strings.

tl.restrictTo( [
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
] )
// or
tl.restrictTo( Array(
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
) )


exclude(elements_or_selectors_list)
Works like a filter, allowing the timeline to target only one or a set of specific elements amongst its selectors list.
The arguments can be :

• A single string consisting of comma-separated selectors.

tl.exclude( "#myelem1 , #myelem2 , p" )
• One or multiple DOM elements, jQuery selectors, or selectors as strings.

tl.exclude(
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
)

• An array containing one or multiple DOM elements, jQuery selectors,
  or selectors as strings.

tl.exclude( [
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
] )
// or
tl.exclude( Array(
"#myelem1",
$("#myelem2"),
document.getElementById("myelem3"),
my_elem_4_in_a_variable
) )



The actual effect of all these setting methods, when called by a group,
will be to simultaneously trigger themselves for every sub-timeline composing the group.

— Structural operations —

addSubTimeline(timeline_object)
Includes a previously created timeline to the group, if it has no sub-timeline already existing under the same name.

This method works for groups only.


addGroup(group_object)
When called by a group, will act like a recursive addSubTimeline() ,
including each of the passed group's sub-timelines into the calling one.

Passing a single timeline instead of a group gives the same result as a classical addSubTimeline() call.

This method can be called by a single timeline as well. In this case, unless a duplicate of it is used instead, the timeline will become a group, composed of its former self and the timeline(s) passed as argument.

This methods accepts only one object at a time.


In the following case,

var A = CSSmu(my_tl , my_tl2);
var B = CSSmu(my_tl3 , my_tl4);

writing var C = A.addGroup(B)
will not only store a new combination of A and B into C ,
but will also edit A directly, resulting in a situation where A == C .

To prevent this and leave the calling object unchanged,
it is required to use a duplicate of it.

var C = A.duplicate().addGroup(B)

setMainSubTimeline(timeline_object_or_name)
Sets the passed sub-timeline as the group's mainSubTimeline .
The sub-timeline's name as a string is accepted too.

The timeline passed as argument must be one of the group's sub-timelines, otherwise nothing happens.

This method works for groups only.


duplicate()
Returns a copy of the timeline or group, including all of its current properties.


become(timeline_or_group_object)
Fully transforms the timeline or group into the passed timeline or group.

The main purpose of this method is to provide a flexible, internally-useable way of doing :

var A = CSSmu("name1" , { // some properties });
var B = CSSmu("name2" , { // some other properties });
A = B;


Note that it is allowed to transform a timeline into a group and vice versa.

Methods : Timeline selectors
siblingTimeline(timeline_name_or_index)
This method works only for single timelines, provided they are part of a group.

Addresses a sub-timeline from the same parent group, whose name corresponds to the string passed as argument.

If the argument is an integer, the returned sub-timeline will be the one with a corresponding index in the parent group's subTimelines array.


subTimeline(timeline_name_or_index)
This method works only for groups.

Addresses the group's sub-timeline whose name corresponds to the string passed as argument.

If the argument is an integer, the returned sub-timeline will be the one with a corresponding index in the group's subTimelines array.


Misc & Noteworthy
Although the previous sections describe everything required to make full use of CSSmu.js, there might remain a few last things to point out.
CSSmu core properties
A full section of this reference is dedicated to CSSmu() as a function. It's actually a little more than that.

CSSmu is itself an object, with its own properties and methods, required at some point in the process of timeline creation, edition and control. They should not be very useful outside of the above mentioned functions and methods, but here is a list, just in case.


— Config properties —

defaultRate
The value used as default frame rate for every new timeline.

Initially : 25.


defaultMode
The value used as default playing mode for every new timeline.

Initially : "loop".


frameMarker
The string part between a timeline name and a frame number that must be looked for in frame-specific CSS class declarations, when stylesheets are parsed.

Initially : "_f".


rootSelector
The default selector that will be inserted in a timeline's targets list upon CSS parsing, when the timeline/frame-defining class is found alone (not attached to any element).

It allows to handle situations where only declarations like

.myTimeline_f1 #elem1 {}
are made. Otherwise #elem1 , here, would have no container found to be affected by the timeline.

Initially : "body".
Can be deactivated if set fo false.


If these have to be edited, they can be redeclared like any classical variable. This should be done prior to any timeline creation.

— Core methods —

create_Timeline(timeline_name)
This method is executed inside the CSSmu() function,
whenever a timeline needs to be created.


create_Group(optional_timelines_list)
This method is executed inside the CSSmu() function,
whenever timelines need to be grouped.


CSSmu("timeline_name")
is equivalent to
CSSmu.create_Timeline("timeline_name")

as well as

CSSmu("timeline_name" , "another_timeline_name")
is equivalent to
CSSmu.create_Group("timeline_name" , "another_timeline_name")

But these methods don't handle properties lists.

getSelectors(timeline_name)
This method is executed inside CSSmu.create_Timeline() and allows to build the timeline's selectors list, by parsing CSS stylesheets.


getFrameCount(timeline_name)
This method is executed inside CSSmu.create_Timeline() and allows to define the timeline's frame count, by parsing CSS stylesheets.


harmonize_arguments(messy_list)
This method is used many times during the process of creating and structuring timelines or groups. It can be seen as a kind of "equalizer", used to format various possible arguments received by methods into clean, useable arrays.


transferProperties(to, from)
This is used in the timeline and group's become() method. The two arguments have to be timelines or groups, and here the one referred as from will give all its properties to the one referred as to.
About CSS frame declarations
For timelines to be effective, corresponding CSS declarations must be set.
The principle is to define, for a given timeline, the new aspect of targetted elements on each frame.

This is done by preparing additional classes for these elements, which will be used by the library. The "formula" for these classes are as follows :

element.timelineName_fframeNumber { property:value }
Where :
element is any CSS selector, corresponding to the target element(s),
timelineName is the timeline's custom name, used later when crating / triggering it via CSSmu.js functions,
frameNumber defines which frame of the timeline will be affected by the present declaration.

When a timeline is created, for example via CSSmu("myTimeline") , every selector found in the stylesheets followed by a .myTimeline_fFrameNumber class will be added to the timeline's selectors list.

As the timeline is played, each of its selectors found this way will cycle through declared frame-specific aspects, by gaining and losing corresponding .myTimeline_fFrameNumber classes.

Upon CSS parsing, CSSmu("myTimeline") will rely on numerical values found after .myTimeline_f occurrences to define the timeline's frame count.

As a result, if only .myTimeline_f15 is found, and nothing is declared for frames 1 to 14, the corresponding timeline will still have 15 frames, but nothing will visually happen when playing through the first 14.
As of CSSmu.js version 1.0.1, every frame for which a visual result is wanted requires to be defined, even if it involves no changes from the previous frame.

#myElement.myTimeline_f1 {background-color:red}
#myElement.myTimeline_f4 {background-color:blue}
/* This is valid, but here #myElement will have no background-color
on frames 2 and 3, or revert to the value defined outside
frame-specific declarations. */


#myElement.myTimeline_f1 ,
#myElement.myTimeline_f2 ,
#myElement.myTimeline_f3 {background-color:red}
#myElement.myTimeline_f4 {background-color:blue}
/* This way the background-color will remain red until frame 4. */


Next versions of the library will allow to differentiate frames and keyframes, providing a simpler and lighter way to keep properties across multiple frames.

When multiple elements have to react to the same timeline, a "container" approach can be better, to minimize the amount of targets.

A structure like

<div id = "elem1"></div>
<div id = "elem2"></div>
<div id = "elem3"></div>
<div id = "elem4"></div>

can be contained this way :

<div id = "container">
<div id = "elem1"></div>
<div id = "elem2"></div>
<div id = "elem3"></div>
<div id = "elem4"></div>
</div>

And although it requires a little tweak in CSS declarations,

/* from */
#elem1.myTimeline_f1 {}
#elem2.myTimeline_f1 {}
#elem3.myTimeline_f1 {}
#elem4.myTimeline_f1 {}

/* to */
#container.myTimeline_f1 #elem1 {}
#container.myTimeline_f1 #elem2 {}
#container.myTimeline_f1 #elem3 {}
#container.myTimeline_f1 #elem4 {}

it leads to a process economy on the javascript side, having to toggle classes for only one element instead of many. This may help keeping better performance, especially if a large amount of elements must react.

If a timeline doesn't seem to affect the right elements when played, its selectors list can be checked, for example by showing it in the browser's console.

In most browsers, this can be accessed by a right-click anywhere on the page, choosing "Examinate / Inspect this element", and then toggling the "Console" section in the newly-open window.

To have a timeline's selectors list display there :

// var my_timeline = CSSmu("myTimelineName");
   console.log(my_timeline.selectors);


If a selector is missing in the result, it can then easily be added via the timeline's addSelector() method.

The frame-by-frame approach allows maximum precision. But having to define each and every frame might become quite a heavy drawback when it comes to large sequences.

Actually, a dedicated timeline editor with a visual, WYSIWYG-type interface, is planned as a further development step for CSSmu.js. Until the day this one is released, a few tricks may help with complicated or redundant stylesheet writing.

First, if the desired motion's linearity allows it, a mix can be made with the built-in CSS3 transition feature.

For example, the full CSS syntax for an element moving 200 pixels to the left in about one second, with a 25fps rate kept for a decently fluid result, would be :

#myElem {position:absolute; left:0px}

#myElem.myMotion_f1 {left:0px}
#myElem.myMotion_f2 {left:8px}
#myElem.myMotion_f3 {left:16px}
#myElem.myMotion_f4 {left:24px}
#myElem.myMotion_f5 {left:32px}
#myElem.myMotion_f6 {left:40px}
#myElem.myMotion_f7 {left:48px}
#myElem.myMotion_f8 {left:56px}
#myElem.myMotion_f9 {left:64px}
#myElem.myMotion_f10 {left:72px}
#myElem.myMotion_f11 {left:80px}
#myElem.myMotion_f12 {left:88px}
#myElem.myMotion_f13 {left:96px}
#myElem.myMotion_f14 {left:104px}
#myElem.myMotion_f15 {left:112px}
#myElem.myMotion_f16 {left:120px}
#myElem.myMotion_f17 {left:128px}
#myElem.myMotion_f18 {left:136px}
#myElem.myMotion_f19 {left:144px}
#myElem.myMotion_f20 {left:152px}
#myElem.myMotion_f21 {left:160px}
#myElem.myMotion_f22 {left:168px}
#myElem.myMotion_f23 {left:176px}
#myElem.myMotion_f24 {left:184px}
#myElem.myMotion_f25 {left:192px}
#myElem.myMotion_f26 {left:200px}

/* Actually 26 frames are required for the pixel amount to be properly divisible and include a "0px" state. So to play in one accurate second, the timeline's rate should be 26 instead of 25. */

This can be simplified a lot by adding a transition property in the base declaration and later changing the timeline's rate to 1. The frame-specific definitions now only require two "key" lines.

#myElem {
position:absolute; left:0px;
transition: left 1s linear;
}

#myElem.myMotion_f1 {left:0px}
#myElem.myMotion_f2 {left:200px}


Of course, there are cases where such simplification is not an option (non-linearity, Internet Explorer, etc). Then a good way to explore would be CSS preprocessors like Sass, Less, or other. One of their strengths is to allow functions and "mixins", which can be good workarounds for these redundancy or heaviness inconveniences.

For example, the following three lines in Sass

@for $i from 1 through 26 {
#myElem.myMotion_f#{$i} {left:#{($i - 1) * 8}px}
}

result, once compiled, in the 26-lines-long frameset declaration shown above.

One last thing to mention here is CSS priority. It applies when defining timelines, and if not respected and understood, can lead to unsatisfactory results.

CSS selectors, by the way they are declared, gain various levels of specificity. The rule is : when multiple declarations target the same element and define different values for the same style property, the most specific declaration will override the others.

This article explains CSS specificity order it in detail.
If when a timeline is played nothing or only part of the desired motion happens although everything seems valid, the probability is great that the frame-specific declarations are in fact overridden by some other ones for the same elements.

For example, based on the following HTML structure

<div id = "container" style = "font-weight:bold" >
<div id = "myElem" class = "elemClass1 elemClass2" ></div>
</div>

initially styled this way,

#myElem {
width:100px;
height:100px;
}

#container .elemClass1 {
background-color:red;
}

.elemClass1.elemClass2 {
font-size:24px;
}


most of the following property changes won't show when playing the timeline.

.elemClass1.myTimeline_f1 {
width:200px;
height:300px;
background-color:blue;
font-size:16px;
font-weight:normal;
}

Analyzine the situation property by property, it can be noticed that :

#myElem , containing width and height declarations, points to an id whereas .elemClass1.myTimeline_f1 points to classes which is less specific. Width and height won't change.

#container .elemClass1 points to the same class the timeline frame should edit. However it gains specificity by targetting a member of this class which is contained in another element. The background-color won't change.

.elemClass1.elemClass2 and .elemClass1.myTimeline_f1 have the same level of specificity. In this case, declaration order prevails. The font-size will actually change, but wouldn't if .elemClass1.myTimeline_f1 was declared before .elemClass1.elemClass2 .

• an inline declaration (a "style" attribute written directly in the HTML tag) will override any stylesheet-based one. So the font-weight won't change.

Here's how to make sure the .myTimeline_f1 declaration is as specific as possible given the present HTML structure :

/* should be declared after the initial, non-timeline statements */

#container .elemClass1.elemClass2.myTimeline_f1 {
width:200px;
height:300px;
background-color:blue;
font-size:16px;
font-weight:normal !important;
}

Now the selector is bulletproof, even though in the present case, #elemClass1.myTimeline_f1 would be sufficient.

A !important statement is still required here to override the inline font-weight declaration. Anyway, inline styling is a bad idea.
Any remaining questions ? Feel free to ask : contact@auer404.com