Getting started
Prior requirements
CSSmu.js requires the jQuery library to work. If your project doesn't already use it, download it here and include it in the <head> of your HTML document, as a <script> tag.

Then download CSSmu.js here and include it the same way.

Done ? Okay, now we're ready to go.
What we are going to achieve here is this animation :
The first thing to know is that the animation is composed of :

• A timeline for the electrons (let's assume the whole structure is some kind of atom and call the revolving white spheres this way). This same timeline is applied to the six electrons.

• A (simpler) timeline for the nucleus.

We'll start by setting our HTML elements. For now, let's just create the container, a first electron and another <div> containing it, which will later act as a path for it to follow. Like this :

<div id = "container">
<div class = "path">
<div class = "electron"></div>
</div>
</div>


Then we style them using a few CSS declarations, setting the structure's default aspect :

#container {
position:absolute;
width:250px; height:250px; left:50%; top:50%; margin-left:-125px; margin-top:-125px;
background-color:#DDDDDD;
border-radius:50%;
}

.path {
position:absolute; left:50%; top:50%; width:200px; margin-left:-100px;
}

.electron {
position:absolute;
background-color:#FFFFFF;
width:40px; height:40px; margin-left:-20px; margin-top:-21px;
border-radius:50%;
}

These CSS rules as well as every further one in this demo, are to be set the classic way, in your document's <head> or, even better, in one or multiple separate .css file(s) declared there.

If you have an habit with inline styles, I might not be the first person to tell you how bad and messy it is, but please note that in our case, they would most likely prevent the library from working at all.

Keep in mind that CSSmu's action is based on setting and unsetting classes to elements. Properties declared directly in HTML tags override their stylesheet-based equivalent. This also applies for external javascript-induced style changes like my_element.style.property = "value"
or $(my_element).css("property","value") .
Also, remember that some CSS properties require vendor prefixes
( -webkit- / -moz- / -o- / -ms- ) to work properly in all (modern) browsers.
This won't be shown in our snippets here, in order to keep things as clear as possible.
We should now have something looking like this :
Now let's start animating things. The first step will be giving our electron an horizontal motion, making it travel back and forth along the container's diameter.

This requires a few more CSS declarations after the .electron definition :

.electron.motion_f1 {left:0%}
.electron.motion_f2 {left:25%}
.electron.motion_f3 {left:50%}
.electron.motion_f4 {left:75%}
.electron.motion_f5 {left:100%}

This defines classes that will be used by CSSmu to build and run a first timeline. Each declaration is constructed this way :

motion is our timeline's custom name
_f followed by a number refers to a frame in the timeline

From here you can easily guess that our "motion" timeline will have 5 keyframes, moving elements with an "electron" class horizontally from one end of their parent element to the other.

Now to trigger this using CSSmu, in some <script> tag after the HTML elements or in a separate, linked .js file :

$(document).ready(function() {

CSSmu("motion").play();

});

If you want to use CSSmu right at the document's display, make sure jQuery is initialized first. This is why our function is placed inside a $().ready handler in this example.
With this simple CSSmu() call, a timeline is created, based on every occurrence of the .motion_f[frame] selector found in the stylesheets.

The timeline's play() method then triggers it, accordingly setting and removing the corresponding class to the right HTML elements (automatically defined as the timeline's targets upon initialization).
Okay, there's some movement here. But it doesn't really look like what we want yet. This is because for now the timeline's running with default settings, making it a 25-frames-per-second loop. Let's mess around with two of its properties : rate and mode . Make your CSSmu() call look like that :

CSSmu({name:"motion" , mode:"wave" , rate:6}).play();

And obtain this :
Looks a little better, doesn't it ? But there's still a problem with the clearly visible steps. There are two ways of fixing this :

• Defining more intermediate keyframes,
via CSS .electron.motion_f[frame] declarations.

• Cheating a little with CSS3's built-in transition property.
We'll go for that one and add a property to our electron class, in its initial declaration :

.electron {
position:absolute;
background-color:#FFFFFF;
width:40px; height:40px; margin-left:-20px; margin-top:-21px;
border-radius:50%;
transition:left 0.16s linear;
}


Yeah baby.
Now we need to add some (pseudo) z-axis motion to give our electron's motion a circular look. This will consist in a second timeline, applied to the same targets, and dealing with their size. So let's call it "size".

CSS frame declaration :
.electron.size_f1 ,
.electron.size_f5 {
width:40px; height:40px; margin-left:-20px; margin-top:-20px
}

.electron.size_f2 ,
.electron.size_f4 {
width:50px; height:50px; margin-left:-25px; margin-top:-25px
}

.electron.size_f3 {
width:60px; height:60px; margin-left:-30px; margin-top:-30px
}

.electron.size_f6 ,
.electron.size_f8 {
width:30px; height:30px; margin-left:-15px; margin-top:-15px
}

.electron.size_f7 {
width:20px; height:20px; margin-left:-10px; margin-top:-10px
}

/* Well, the "transform:scale" property would have done the trick too.
But let's say it's my old-school side speaking here */


Javascript call :

CSSmu("size").play();


Both timelines combined :

$(document).ready(function() {

CSSmu({name:"motion" , mode:"wave" , rate:6}).play();
CSSmu("size").play();

});


Needs a little rate adjustment to keep them synched,

$(document).ready(function() {

CSSmu({name:"motion" , mode:"wave" , rate:6}).play();
CSSmu({name:"size" , rate:6}).play();

});


along with a slight edit in the CSS declaration, for smoothness.

.electron {
position:absolute;
background-color:#FFFFFF;
width:40px; height:40px; margin-left:-20px; margin-top:-21px;
border-radius:50%;
transition:all 0.16s linear;
}


And there we go.
OMG, AMAZING ! LOOK HOW WELL THIS ELECTRON IS REVOLVING !


You may wonder why we didn't just change the electron's position and size in the same timeline. Well, this multiple-timeline approach allows a different frame count for each motion, and when looking to achieve more complex animations, it can be useful to have separate control over sub-motions. Anyway, fear not : as we'll soon be seeing, two or more timelines can be smartly grouped into a single one.

But for now, it's time to add a nucleus to our atom. Here's for the HTML part,

<div id = "container">
<div class = "path">
<div class = "electron"></div>
<div id = "nucleus"></div>
</div>
</div>


and here's the initial CSS declaration.

#nucleus {
position:absolute;
width:100px; height:100px; left:50%; top:50%; margin-left:-50px; margin-top:-50px;
background-color:#CCCCCC; opacity:0.7;
border-radius:50%;
}


The whole thing will probably look better if the electron travels around the nucleus, right ? We'll achieve that by shifting its z-index property according to its timeline's frame, and making it relative to a z-index we give to the nucleus.

Oh wait... we can't do this, the nucleus being outside the electron's parent. Well that's no big issue, let's just deal with the said parent itself instead. We do this in the CSS sheet, by :

/* adding a z-index to the nucleus */
#nucleus {
position:absolute;
width:100px; height:100px; left:50%; top:50%; margin-left:-50px; margin-top:-50px;
background-color:#CCCCCC; opacity:0.7;
border-radius:50%;
z-index:1;
}

/* adding a greater z-index to the path class,
putting it in front by default */

.path {
position:absolute; left:50%; top:50%; width:200px; margin-left:-100px;
z-index:2;
}

/* adding properties to the "path" class,
to be magically included in our existing "size" timeline */

.path.size_f1,
.path.size_f6,
.path.size_f7,
.path.size_f8 {z-index:0}

/* oh, and while we're at it, why not add a slight shadow effect
using the electron's background-color */

.electron.size_f1 ,
.electron.size_f6 ,
.electron.size_f7 ,
.electron.size_f8 {background-color:#EFEFEF}


Let's congratulate ourselves now. We've got a working electron / nucleus system. But we're not totally done, this electron has yet to be multiplied.

<div id = "container">

<div id = "path1" class = "path">
<div class = "electron"></div>
</div>

<div id = "path2" class = "path">
<div class = "electron"></div>
</div>

<div id = "path3" class = "path">
<div class = "electron"></div>
</div>

<div id = "path4" class = "path">
<div class = "electron"></div>
</div>

<div id = "path5" class = "path">
<div class = "electron"></div>
</div>

<div id = "path6" class = "path">
<div class = "electron"></div>
</div>

<div id = "nucleus"></div>

</div>


Now to give each one its own angle in CSS :

#path2 {transform:rotate(30deg)}
#path3 {transform:rotate(60deg)}
#path4 {transform:rotate(90deg)}
#path5 {transform:rotate(120deg)}
#path6 {transform:rotate(150deg)}


Which results in this, because the timelines apply to every member of the electron / path classes at the same time.


In order to get the six electrons out of sync, we might want to apply to each one its own timeline, so we can start them at different times. Or, more accurately speaking, we're going to apply to each one its own duplicate of the same timeline.

Let's begin by giving each electron an id. Here's our definitive HTML structure.

<div id = "container">

<div id = "path1" class = "path">
<div id = "electron1" class = "electron"></div>
</div>

<div id = "path2" class = "path">
<div id = "electron2" class = "electron"></div>
</div>

<div id = "path3" class = "path">
<div id = "electron3" class = "electron"></div>
</div>

<div id = "path4" class = "path">
<div id = "electron4" class = "electron"></div>
</div>

<div id = "path5" class = "path">
<div id = "electron5" class = "electron"></div>
</div>

<div id = "path6" class = "path">
<div id = "electron6" class = "electron"></div>
</div>

<div id = "nucleus"></div>

</div>


Then we need to make our timelines duplicable. To do this, we'll create them as a group instead of two separate timelines, and store this group in a variable instead of playing it immediately.

This is done by replacing our two CSSmu() calls by this single one :

var electron_motion = CSSmu(

{ name:"motion" , mode:"wave" },
{ name:"size" },
{ rate:6 } // No name declared, this will apply to the whole group

);


Finally we need a function to create a copy of electron_motion , apply it to an electron, and play it. We'll have this function called six times, let's say each time the preceding copy reaches its frame 6.

// We'll use a global variable as a counter
var electrons_count = 0;


function launch_next_electron() {

if (electrons_count < 6) {

electrons_count++;

var new_restrictedTargets = "#electron" + electrons_count + " , ";
new_restrictedTargets += "#path" + electrons_count;

CSSmu({
duplicate:electron_motion,
restrictTo:new_restrictedTargets,
onFrame:[
[6,launch_next_electron]
]
})
.play();

}
}


Here you can see two new CSSmu features :

• the restrictTo property, used to target one or more specific elements instead of the whole default selectors list.

• the onFrame property, allowing to set callback functions to specific frames.

Now when we call launch_next_electron() here's what we get :


Quite good-looking, but still not perfect. The last three electrons didn't start with an even delay, messing the animation's symmetry up. This is due to the first timelines reaching their frame 6 again before the end of the process, thus triggering the function a second time instead of letting the expected sequence happen. To solve this problem,

well...

I'm planning to add a "once" mode to onFrame calls but it doesn't exist yet. So for now we need to code a little workaround.

The solution here is to tell each timeline which electron it has to trigger, so when its frame 6 callback is executed, nothing happens if its target is not next in line. For this we need to :

• Set a new global variable along with electrons_count :

var next_electron = 1;


• Increment it only when a new timeline is launched. This is done during the initial group creation :

var electron_motion = CSSmu(

{ name:"motion" , mode:"wave" },
{ name:"size" },
{
rate:6,
onPlay:function(){next_electron++}
}

);


• Allow the launcher function to control what's the next electron to animate :

function launch_electron(next) { // Now takes an argument

if (electrons_count < 6 && next == next_electron) {

electrons_count++;

var new_restrictedTargets = "#electron" + electrons_count + " , ";
new_restrictedTargets += "#path" + electrons_count;

CSSmu({
duplicate:electron_motion,
restrictTo:new_restrictedTargets,
onFrame:[
[6,function(){launch_electron(next + 1)}]
]
})
.play();

}
}


launch_electron(next_electron); // Or launch_electron(1);


And one very last detail : the nucleus pulsing effect is still missing.
So here are its CSS frames,

#nucleus.pulse_f1{
width:106px; height:106px; margin-left:-53px; margin-top:-53px
}

#nucleus.pulse_f2{
width:104px; height:104px; margin-left:-52px; margin-top:-52px
}

#nucleus.pulse_f3{
width:98px; height:98px; margin-left:-49px; margin-top:-49px
}

#nucleus.pulse_f4{
width:100px; height:100px; margin-left:-50px; margin-top:-50px
}


and here's the call to its timeline.

CSSmu(
{ name:"pulse" , rate:16 , mode:"wave" }
)
.play();


This time we're done !



The complete code can be seen (and played with) in this codepen.