PowerSlide

From PowerUI
Jump to: navigation, search

In lots of projects there are sequences of events which are sometimes timed by audio or wait for the player to do something before continuing. This is where PowerSlide steps in - it's a system for creating sequences of things. That's a perfect fit for dialogue (speech) so you'll also find that PowerUI has a built in dialogue system too.

Components of PowerSlide

  • A single PowerSlide sequence is called a timeline.
  • A timeline has one or more tracks.
  • There are different types of track depending on what your timeline is (style, dialogue).
  • Each track has one or more slides.
  • You run a timeline on a particular element.

Keyframes and element.animate

PowerSlide is used alongside all other animation techniques. A style track is essentially a series of @keyframes animations and can be mixed in with other things, creating very complex sequences with only a small amount of input information.

Creating a PowerSlide Timeline

We're currently building an editor which will help make the process of making timelines even easier. In the meantime, you'll need to write/ build the JSON files that PowerSlide uses. They're designed to be very simple to follow and understand:

[                                                                 // A timeline with 2 tracks
  [ { /* Track #1, Slide #1 */ }, { /* Track #1, Slide #2 */ } ], // Track with 2 slides
  [ { /* Track #2, Slide #1 */ } ]                                // Another track
]

A PowerSlide JSON file is just an array of tracks, and each track is an array of slides. The type of track is discovered from the slides you use in it. However, most timelines are a single track, so you can declare just a single track if you'd like, such as the style track example below.

Style tracks

Here's a slide with a single style track from example scene #37:

[
  {
    "animation":"tipUp"
  },
  {
    "selector":".tipTitle",
    "animation":"titleIn"
  },
  {
    "selector":".tipMessage",
    "animation":"messageUp"
  }
]

This style track has 3 slides. At this point it would be a good idea to run example scene #37 to see what it actually does. It can be described like this:

  • Because no start or duration properties are defined, each slide takes 1/3rd the total duration.
  • The total duration is given when playing the timeline.
  • It plays the @keyframes tipUp animation on the element that the timeline was applied to.
  • Then when that's done, it plays the @keyframes titleIn animation on a child element which matches the .tipTitle selector.
  • When that's done, it plays the @keyframes messageUp animation on a child element which matches the .tipMessage selector.

For a more in depth look at style tracks, see the annotated PowerSlide json file in example scene #37.

Cue tracks

If you want to wait for something before continuing, that something is called a cue. You declare one or more wait points in a cue track and at a minimum, a cue track with one wait point looks like this:

[
  {
    "wait-at":"60%"
  }
]

There's two ways to cue a waiting timeline. Either use:

// Get an element:
var element = UI.document.getElementById("myPowerSlideTest");

// Run a timeline on it taking 3s (for the purpose of this example, we'll assume it has a wait in there):
element.slide("myTimeline.json",3);

// Add a listener for the event which fires when it waits:
element.addEventListener("timelinepause",delegate(PowerSlide.SlideEvent e){
    
    // It's now waiting! You wouldn't normally instantly cue it, but:
    element.cue();
    
    // e.timeline.cue(); works too.

});
  • Automatically hooking up an event. It's common to, for example, have a particular UI element or keypress to cue the timeline. As a convenient shortcut, that can be done in your cue like this:
[
  {
    "wait-at":"60%",
    "cued-by":".button-which-will-cue-it",
    "event":"mousedown"
  }
]

When the child element(s) targeted with the given selector receive the named event, the above cue method is automatically called. Essentially this just adds event listeners for the given event and the listener itself directly calls cue().

Dialogue tracks

Dialogue tracks define sequences of text - typically used in cutscenes (which are made interactive with cues). The important thing is a dialogue slide acts just like a wait by default (unless you give a start or duration). When you're making a dialogue track, a lot of things are optional or can be reused too. In the following example, we reuse the speaker value in order to avoid repeating it. As a handy shortcut, a line of text is recognized as a valid dialogue slide too:

[
  {"speaker":"player"},
  "Hello! My name is &Username;.",
  "All of this text will be said <b>by the player</b>.",
  "It's just an array of text. Because we aren't defining any timing information, it will be cued by the player.",
  "That typically means the player will see something like <i>'press x to continue'</i>.",
  
  {"speaker":"system"},
  "You feel a rush of excitement",
  
  {"speaker":"player"},
  "Ah. That was the system speaker - speaker names can be whatever you want",
  "'system' is reserved as meaning a narrator-style speaker usually present in RPGs.",
  "By convention, spaces are added between speakers, so you can clearly see when a speaker changes."
]

The above is from the dialogue wiki page - for more information about specifically using dialogue, see that page instead.

As a brief example, adding timing information e.g. for a non-interactive cutscene looks like this; we have to fully declare the slide in order to add start or duration to them:

[
  {
    "speaker":"joey",
    "duration":"1.2s",
    "markup":"Once upon a time.."
  },
  {
    "duration":"1s",
    "markup":"In a land far, far awa-"
  }
]

The above is an extract from example scene #42. Note that the speaker for the second slide is also assumed to be 'joey'. Like the previous example, you could also declare the speaker in a separate slide if you prefer, although it has the same effect (both are joey):

[
  {
    "speaker":"joey"
  },
  {
    "duration":"1.2s",
    "markup":"Once upon a time.."
  },
  {
    "duration":"1s",
    "markup":"In a land far, far awa-"
  }
]

Available events

These events are dispatched to all of the following, in this order:

  • The element with the timeline running on it (they all bubble to the document too).
  • A widget which was opened by the timeline. This mainly occurs on dialogue timelines where they pop open a widget to actually display the text.
  • The timeline object itself.

The available events are:

Name Event object type Purpose
timelinestart PowerSlide.SlideEvent When a timeline starts playing.
timelinepause PowerSlide.SlideEvent Called whenever a timeline hits a wait point and the timeline pauses.
timelineend PowerSlide.SlideEvent Called when the timeline completely finished.
timelinecancel PowerSlide.SlideEvent Called when the timeline was cancelled early. An example of when this happens is if you start another timeline on an element and it interrupts existing ones.
timelineiteration PowerSlide.SlideEvent If you set your timeline to repeat then this one will fire each time it does.
timelineallow PowerSlide.SlideEvent Fired right before displaying a dialogue slide to check if the user is allowed to continue. Cancel the event if they e.g. don't have the right skill levels/ missions completed to continue.
timelinetrackload PowerSlide.SlideEvent Fired when a track has loaded.
slidestart PowerSlide.SlideEvent When a particular slide has just started.
slideend PowerSlide.SlideEvent When a particular slide has just ended.
slideload PowerSlide.SlideEvent When a particular slide has loaded.

Running a timeline

There's two ways to run a timeline - either via the CSS timeline property (which is structured the same as the animation property):

.test{
    timeline:url(path.json) 3s;
}

Or via the DOM API - the element.slide/ element.runTimeline method (they do the same thing):

// Run a timeline in path.json for 3 seconds:
element.slide("path.json",3);

// Is the same as:
element.runTimeline("path.json",3);

They both return promises which complete when the timeline does:

element.runTimeline("path.json",3).then(delegate(object o){
    
    // Timeline complete!
    
});