Skip to content

Commit

Permalink
guide updates
Browse files Browse the repository at this point in the history
  • Loading branch information
williamngan committed Feb 2, 2019
1 parent 98c4a83 commit 0338bd7
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 34 deletions.
48 changes: 32 additions & 16 deletions guide/Animation-0700.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@
</div>
<a href="#menu" id="toc">&#x2261;</a>
<div id="post"><h1>Animation</h1>
<p>There are many great javascript animation libraries, like the elegant Popmotion and the full-featured GSAP, which you may use alongside Pts. For simple use cases, Pts' Tempo class offers an intuitive and lightweight alternative.</p>
<p>Often, an animation sequence is implemented as a curated list of tweens played in milliseconds. What if we take the idea one level higher, and think of the sequence like a dance? One-two-three, One-two-three...</p>
<p>Let's start by setting the beats. The common measurement is beats-per-minute (BPM). You can create a Tempo instance in two ways: by setting a BPM, or specifying the duration of a beat in milliseconds.</p>
<p>There are many great javascript animation libraries which you may use alongside Pts. For simple use cases, Pts' <a href="#link"><code>Tempo</code></a> utility class provides an intuitive and lightweight alternative.</p>
<p>Animation sequences are commonly implemented as a curated list of tweens played in milliseconds. But what if we take the idea one level higher, and think of it like a dance? Like One-two-three, One-two-three...</p>
<p>Let's start by setting the beats. Tempo is usually measured in beats-per-minute (bpm), so there are two ways to initiate a <a href="#link"><code>Tempo</code></a> instance: by setting a bpm, or specifying the duration of a beat in milliseconds.</p>
<pre><code>// 120 beats-per-minute, or 500ms per beat
let ta = new Tempo( 120 );
let tempo = new Tempo( 120 );

// 500ms per beat, or 120 BPM
let tb = Tempo.fromBeat( 500 );
// 500ms per beat, or 120 bpm
let another = Tempo.fromBeat( 500 );
</code></pre>
<p>The essential function in a Tempo instance is <code>every(...)</code>, which counts the beats for you. It's like a smart metronome.</p>
<pre><code>let everyTwo = ta.every( 2 );
let everyTen = ta.every( 10 );
<p>The essential function is <a href="#link"><code>Tempo.every</code></a>, which counts the beats and triggers the callback functions you specified. It's like a smart metronome.</p>
<pre><code>let everyTwo = tempo.every( 2 ); // count every 2 beats
let everyTen = tempo.every( 10 ); // count every 10 beats
</code></pre>
<p>The returned object from <code>every</code> has two chainable functions: <code>start( fn )</code> and <code>progress( fn )</code>. <code>start</code> lets you set a callback at the start of every period. For example:</p>
<pre><code>// at the start of every 2-beats period, add a dot
<p>The <code>every</code> function returns an object with two chainable functions: <code>start(...)</code> and <code>progress(...)</code>. The <code>start</code> function lets you set a callback to be triggered at the start of every period. For example:</p>
<pre><code>// at the start of every 2-beats period, do something
everyTwo.start( (count) =&gt; ... )
</code></pre>
<p><code>progress</code> lets you specify a callback during the progress of every period, so you can use it to interpolate values and tween properties.</p>
<pre><code>// during every 10-beats period, do this...
<p>The <code>progress</code> function lets you specify a callback during the progress of every period, so you can use it to interpolate values and tween properties.</p>
<pre><code>// during every 10-beats period, do something
everyTen.progress( (count, t, time, isStart) =&gt; ... )
</code></pre>
<p>Let's look at an example. Here the tempo is set to 60 BPM (or 1 second per beat), and we design the behaviors as such:</p>
Expand All @@ -46,9 +46,9 @@
<li>Every 2 beats, the circle's color changes and the rotation completes once</li>
</ul>
<p><img src="./assets/bg.png" alt="js:tempo_progress"></p>
<p>It's pretty easy to create animations that are in sync with rhythm. Let's try a few more example.</p>
<p>Pretty easy to create sychronized animation sequences, right? Let's try a few more example.</p>
<h2>Variations</h2>
<p><strong>Tween</strong>: Since the <code>t</code> parameter in <code>progress</code> callback function always go from 0 to 1, we can map the value to a <a href="../docs/?p=Num_Shaping">Shaping</a> function and change the tweening style.</p>
<p><strong>Tween</strong>: Since the <code>t</code> parameter in <code>progress</code> callback function always go from 0 to 1, we can map its value to a <a href="../docs/?p=Num_Shaping"><code>Shaping</code></a> function and change the tweening style. Another neat trick is to use <a href="../docs/?p=Num_Num#function_cycle"><code>Num.cycle</code></a> to map the <code>t</code> value from [0...1] to [0...1...0].</p>
<pre><code>everyTwo.progress( (count, t, time, isStart) =&gt; {
let tt = Shaping.elasticOut( t );
...
Expand All @@ -61,9 +61,25 @@ <h2>Variations</h2>
</code></pre>
<p><img src="./assets/bg.png" alt="js:tempo_stagger"></p>
<p><strong>Rhythm</strong>: Set a custom rhythm by passing a list of beats in the <code>every</code> function.</p>
<pre><code>let ta = tempo.every( [2, 2, 1, 1] ); // Taaa, Taaa, ta-ta.
<pre><code>let custom = tempo.every( [2, 2, 1, 1] ); // Taaa, Taaa, ta-ta.
</code></pre>
<p><img src="./assets/bg.png" alt="js:tempo_rhythm"></p>
<h2>Controls</h2>
<p>It's easy to control the speed of your animation by changing bpm by setting the <a href="#link"><code>Tempo.bpm</code></a> property. This makes it easier to synchronize your animations with music or in specific intervals.</p>
<pre><code>tempo.bpm = 100; // set new bpm
tempo.bpm += 20; // make it 20 beats faster per minute
</code></pre>
<p>Try moving your cursor horizontally to change the bpm in this example:</p>
<p><img src="./assets/bg.png" alt="js:tempo_control"></p>
<p>There are two ways to stop an animation. You can either add <code>return true</code> in the callback functions, or include a <code>name</code> in the third parameter of <code>start</code> or <code>progress</code> functions.</p>
<pre><code>let walking = (count, t) =&gt; {
// ...
return (count &gt; 5); // return true will stop this animation
}

tempo.progress( walking, 0, &quot;robot&quot; );
tempo.stop( &quot;robot&quot; ); // another way to stop this animation
</code></pre>
</div>

<ol id="menu"><a id="close" href="#">&times;</a><li><a href="Get-started-0100.html">Get started</a></li><li><a href="Pt-0200.html">Pt</a></li><li><a href="Group-0300.html">Group</a></li><li><a href="Op-0400.html">Op</a></li><li><a href="Space-0500.html">Space</a></li><li><a href="Typography-0600.html">Typography</a></li><li><a href="Animation-0700.html">Animation</a></li><li><a href="Technical-notes-9000.html">Technical notes</a></li></ol>
Expand Down
46 changes: 46 additions & 0 deletions guide/js/examples/tempo_control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
(function(){
// Pts.namespace( this ); // add Pts into scope if needed, you

let demoID = "tempo_control";

// Create Space and Form - you can also use Pts.quickStart(...) shorthand for less code
let space = new CanvasSpace("#"+demoID).setup({ retina: true, bgcolor: "#e2e6ef", resize: true });
let form = space.getForm();

// Create tempo instance
let tempo = new Tempo(120);

// A higher-order function to generate progress callback functions with color options
let lns = [];
let dials = ( i, c, s ) => {
return ( count, t ) => {
let tt = Shaping.quadraticInOut( t ); // shaping
lns[i] = Line.fromAngle( (i===0) ? space.center : lns[i-1].p2, Const.two_pi * tt, space.size.y/s );
form.strokeOnly( c, 10, "round", "round").line( lns[i] );
form.fillOnly( c ).point( lns[i].p2, 20, "circle" );
}
};


tempo.every( 6 ).progress( dials( 0, "#FFF", 4 ) )
tempo.every( 4 ).progress( dials( 1, "#123", 6 ) )
tempo.every( 2 ).progress( dials( 2, "#62E", 8 ) );

// track tempo animation
space.add( tempo );
space.add( (time, ftime) => {
let b = Num.clamp( (space.pointer.x - space.center.x)/5, -50, 50 );
tempo.bpm = 100 + Math.floor(b);
form.fillOnly("#123").text( [20, 32], `BPM is ${tempo.bpm}`);
});



// start
// Note that `playOnce(200)` will stop after 200ms. Use `play()` to run the animation loop continuously.
space.playOnce(200).bindMouse().bindTouch();

// For use in demo page only
if (window.registerDemo) window.registerDemo(demoID, space);

})();
56 changes: 40 additions & 16 deletions guide/md/_0700_Animation.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
# Animation

There are many great javascript animation libraries, like the elegant Popmotion and the full-featured GSAP, which you may use alongside Pts. For simple use cases, Pts' Tempo class offers an intuitive and lightweight alternative.
There are many great javascript animation libraries which you may use alongside Pts. For simple use cases, Pts' [`Tempo`](#link) utility class provides an intuitive and lightweight alternative.

Often, an animation sequence is implemented as a curated list of tweens played in milliseconds. What if we take the idea one level higher, and think of the sequence like a dance? One-two-three, One-two-three...
Animation sequences are commonly implemented as a curated list of tweens played in milliseconds. But what if we take the idea one level higher, and think of it like a dance? Like One-two-three, One-two-three...

Let's start by setting the beats. The common measurement is beats-per-minute (BPM). You can create a Tempo instance in two ways: by setting a BPM, or specifying the duration of a beat in milliseconds.
Let's start by setting the beats. Tempo is usually measured in beats-per-minute (bpm), so there are two ways to initiate a [`Tempo`](#link) instance: by setting a bpm, or specifying the duration of a beat in milliseconds.

```
// 120 beats-per-minute, or 500ms per beat
let ta = new Tempo( 120 );
let tempo = new Tempo( 120 );
// 500ms per beat, or 120 BPM
let tb = Tempo.fromBeat( 500 );
// 500ms per beat, or 120 bpm
let another = Tempo.fromBeat( 500 );
```

The essential function in a Tempo instance is `every(...)`, which counts the beats for you. It's like a smart metronome.
The essential function is [`Tempo.every`](#link), which counts the beats and triggers the callback functions you specified. It's like a smart metronome.

```
let everyTwo = ta.every( 2 );
let everyTen = ta.every( 10 );
let everyTwo = tempo.every( 2 ); // count every 2 beats
let everyTen = tempo.every( 10 ); // count every 10 beats
```

The returned object from `every` has two chainable functions: `start( fn )` and `progress( fn )`. `start` lets you set a callback at the start of every period. For example:
The `every` function returns an object with two chainable functions: `start(...)` and `progress(...)`. The `start` function lets you set a callback to be triggered at the start of every period. For example:

```
// at the start of every 2-beats period, add a dot
// at the start of every 2-beats period, do something
everyTwo.start( (count) => ... )
```

`progress` lets you specify a callback during the progress of every period, so you can use it to interpolate values and tween properties.
The `progress` function lets you specify a callback during the progress of every period, so you can use it to interpolate values and tween properties.

```
// during every 10-beats period, do this...
// during every 10-beats period, do something
everyTen.progress( (count, t, time, isStart) => ... )
```

Expand All @@ -41,11 +41,11 @@ Let's look at an example. Here the tempo is set to 60 BPM (or 1 second per beat)

![js:tempo_progress](./assets/bg.png)

It's pretty easy to create animations that are in sync with rhythm. Let's try a few more example.
Pretty easy to create sychronized animation sequences, right? Let's try a few more example.

## Variations

**Tween**: Since the `t` parameter in `progress` callback function always go from 0 to 1, we can map the value to a [Shaping](../docs/?p=Num_Shaping) function and change the tweening style.
**Tween**: Since the `t` parameter in `progress` callback function always go from 0 to 1, we can map its value to a [`Shaping`](../docs/?p=Num_Shaping) function and change the tweening style. Another neat trick is to use [`Num.cycle`](../docs/?p=Num_Num#function_cycle) to map the `t` value from [0...1] to [0...1...0].

```
everyTwo.progress( (count, t, time, isStart) => {
Expand All @@ -69,7 +69,31 @@ everyTwo.progress( fn, -100 ); // activate 100ms sooner
**Rhythm**: Set a custom rhythm by passing a list of beats in the `every` function.

```
let ta = tempo.every( [2, 2, 1, 1] ); // Taaa, Taaa, ta-ta.
let custom = tempo.every( [2, 2, 1, 1] ); // Taaa, Taaa, ta-ta.
```

![js:tempo_rhythm](./assets/bg.png)

## Controls

It's easy to control the speed of your animation by changing bpm by setting the [`Tempo.bpm`](#link) property. This makes it easier to synchronize your animations with music or in specific intervals.
```
tempo.bpm = 100; // set new bpm
tempo.bpm += 20; // make it 20 beats faster per minute
```

Try moving your cursor horizontally to change the bpm in this example:

![js:tempo_control](./assets/bg.png)

There are two ways to stop an animation. You can either add `return true` in the callback functions, or include a `name` in the third parameter of `start` or `progress` functions.

```
let walking = (count, t) => {
// ...
return (count > 5); // return true will stop this animation
}
tempo.progress( walking, 0, "robot" );
tempo.stop( "robot" ); // another way to stop this animation
```
4 changes: 2 additions & 2 deletions src/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ export class Tempo {
this._ms = 60000 / this._bpm;
}


// Get a listener unique id
protected _createID( listener:ITempoListener|Function ):string {
let id:string = '';
Expand Down Expand Up @@ -436,7 +436,7 @@ export class Tempo {
* Remove a `start` or `progress` callback function from the list of callbacks. See [`Tempo.every`](#link) for details
* @param name a name string specified when creating the callback function.
*/
end( name:string ):void {
stop( name:string ):void {
if (this._listeners[name]) delete this._listeners[name];
}

Expand Down

0 comments on commit 0338bd7

Please sign in to comment.