yΠ.js > Let's begin

Ⅰ. Prerequisities


<script type="text/javascript" 
src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="core/ypi_min-1.5.js"></script>
<script type="text/javascript" src="core/custom.js"></script>            
            

And external file with the current chapter.

Ⅱ. Chapter file

Defines XML structure of cases and assigned reactions (in one chapter). Here is example of simple dialog definition file. You can type it manually, or use on-line editor to generate output. There are three ways how to define dialog (manual XML or editor's GUI or editor's YPI Script). It is recommended to create main case skeleton first with topic goals. And then add more complexity.

Elements

Case
Attribute Usage Description
id id="n1" Case id.
text text="sample text {[markup]}" Text of dialog (with markup holders).
target target="my_avatar" Name of associated avatar.
sound sound="/Sound/sample.mp3" Path to sound file.
React
Attribute Usage Description
rel rel="n1" Related to case by id.
text text="sample text {[markup]}" Text of reaction (with markup holders).
goto goto="n1" Go to case by id.
setter setter="_p+=3,_r=9" Set property.
invoke invoke="action1;action2" Force registered actions by name.
condition condition="_p=3|_x=3" Condition to display this reaction.
prop prop="69" Enables automatic transition. Propability of this transition is 69%.
Txt
Attribute Usage Description
rel rel="n1" Related to case by id.
text text="sample text {[markup]}" Text of reaction (with markup holders).
setter setter="_p+=3,_r=9" Set property.
condition condition="_p=3|_x=3" Condition to display this content.

It is possible to access attribute values as object properties directly in "params" of event handled methods or with method getParams of Avatar object. First capital of property name of object "params" is always upper case. However attributes in XML file should be lowercase (text="..." => params.Text ).

You can define your custom markup and custom attributes too.

Properties&Operators


			_x=12
				

You can set or update your custom global property by attribute setter of react element. More properties are deliminated by ','.


			_x+=-1
				

Supported operators are '-' , '=' , '+='. If you want to decrement. Just increment negative value.

Conditions


                  (_x>5&_x<10)|(_y>5&_y<10)              
                

Conditions of reactions (or bubble text) visibility are supported since version 1.5.6 . There is now interpreter for simple conditional expressions (without using javascript eval method). Supported operators are '<' , '>' , '=' , '|' , '&' or '^'. In XML file some of this characters should be escaped, but it should work without escaping too (close your eyes and use character '^' not '&' ).

Actions

Sometimes you may need to invoke some custom action. Action is simply method previously registered by name . There is parameter Invoke of react element for action invocation. More actions names are deliminated by ','.

Ⅲ. Let's integrate

Avatar is some html entity with unique id and bubble near it (also entity with unique id). There can be more than one avatar on page. Each avatar has its own life cycle, delay timer and behavior definition. But panel with reactions is global and avatars are linked with target attribute in one chapter. So they can talk to each other if you instruct them to do that.

Object: Avatar
getName() method Returns name
getAlias() method Returns alias.
getParams() method Returns [object: Params]
getTextId() method Returns id of current part of bubble text.
getTextAbout() method Returns about text (since v1.5.9).
show() method Show text bubble.
skip() method Skip current bubble text delay.
repeat() method Repeat last case speech.
about(txt) method Show text about: txt - text
mute() method Force bubble fade out.
isSpeaking() method Returns if avatar is speaking now.
registerCustomAction(key, options) method Register custom action: key - action key, options - {}

Initialize

At first you need to add jQuery and yΠ.js script on your page. Create div with id "avatar1". It is place for picture. Then add some div with id "npc_bubble_1". That will be bubble with content. Wherever you are going to place div with id "dialog" there will be area with reactions. Then call the ypi.df.init method.


	ypi.df.init({
            language: "EN",
            initState: "n1",
            isAutostart: false,
            isSoundEnabled: false,
            isCommercial: false,
            onload: function (options) {
                // init stuff
                avatar_1 =  ypi.df.createAvatar({
                        Name: "avatar1", 
			Alias: "John Doe", 
			BubbleId: "npc_bubble_1",
			Speed: 150,
			onbubble: parseCustomMark,
                        behavior: basicBehavior
                });               
	    }
    });
	

The most important event handle is onload. Here you can create your avatar or more of them.

Method:
ypi.df.createAvatar({})
Create and return object avatar: Avatar.
Params:
Name string Name of avatar. Default value is avatar_1...avatar_n
Alias string Name of alias.
BubbleId string Bubble place holder Id. Default value is npc_bubble_1 ... npc_bubble_n.
Speed number Speech speed (for bubble visibility delay).
IdleInterval number Interval to repeat if no reaction occurse [ms]. However it can be pretty annoying for user. Next interval is last idle time * n. Where n is number of repeats.
TextAbout string Some about text description (since v1.5.9).
behavior event When it is time to define avatar's behavior.
function(avatar){};
onbubble event When bubble is fading in.
function(options,avatar){};
onsetter event When it is time to set properties.
function(avatar){};
onplay event Load and play sound. Returns true if timing delay to show is handled by this method.
function(avatar){};
onseek event Play sound sample during visibility of bubble. Returns true if timing of bubble visibility delay is handled by this method.
function(avatar){};
onmute event When bubble is fading out.
function(avatar){};
onstop event When current case speech is finished.
function(avatar){};
on404 event When file not found.
function(url){};
Method: ypi.df.init({})
Initialize all.
Params:
language string Country code. It is suffix for chapterUrl.
chapterUrl string URL to dialog definition file.
dataFormat string One of additional supported formats. But "XML" by default.
initState string Initial case.
isAutostart boolean Start conversation automatically after initialization.
isCommercial boolean Usage type identification flag.
isSoundEnabled boolean Enable or disable onsound and onseek event invocation.
isExprEnabled boolean Enable or disable interpret of condition expression. It is enabled by default (supported since v1.5.6).
attrCase string[] Custom attributes of element case.
attrReact string[] Custom attributes of element react.
onload event Occurs on dialog initialization.
function(params){};
onsound event When sound occurs. However for implentation you need to choose available soundlib.
function(params){};
onfinish event No available reactions detected. That is the end of whole speech.
function(params){};
onanswer event When some answer occurs.
function(params){};
onrender event Before rendering answer. Returns custom layout of $answer.
function(params){};

Start conversation

Method: ypi.df.invokeInit()
Start conversation

	$(document).ready(function () {           
		ypi.df.invokeInit(); 	
	});	

Now should be all prepared to call ypi.df.invokeInit method when DOM is ready. Don't forget to set chapterUrl and isAutostart if you want to start conversation automatically. But it is possible to start conversation with method ypi.df.gotoChapter any time after initialization.

Method: ypi.df.gotoChapter({})
Load chapter and invoke target case.
Params:
chapterUrl string URL to dialog definition file.
nodeId string Target case.

	// for chapter #start_1
	$("#start_1").click(function () {
		ypi.df.gotoChapter({ 
			chapterUrl: "/ch_1.xml",
			nodeId: "n1" 
		});
	});
	
	// for another case in same chapter as #start_3
	$("#start_2").click(function () {
		ypi.df.gotoChapter({
			chapterUrl: "/ch_2.xml", 
			nodeId: "n1" 
		});
	});
	
	// for another case in same chapter as #start_2
	$("#start_3").click(function () {
		ypi.df.gotoChapter({ 
			chapterUrl: "/ch_2.xml",
			nodeId: "n12" 
		});
	});	

For example if you have span with specified id on your page.

PHP integration

If you need to integrate yPI.js into your PHP generated page, you can use code in ypijs-php repository. There is also YPI Plugin for WordPress ypijs-php-wp repository.


 $requiredSripts = array($this::SCRIPT_YPI_MIN_URL,$this::SCRIPT_HELPER_URL);
 $initAttr=array(
                            'initState'=>$this::INIT_STATE,
                            'chapterUrl'=>$this::SCRIPT_CHAPTER_URL,
                            'isAutostart'=>true,
                            'isSoundEnabled'=>true,
                            'attrCase'=>array($this::CUSTOM_CASE_ATTRIBUTE_TRACK));
        
 $avatarAttr = array(
                            'Name'=>$this::AVATAR_ID,
                            'Alias'=>$this::AVATAR_ALIAS,
                            'BubbleId'=>$this::BUBBLE_ID,
                            'Speed'=>$this::SPEECH_SPEED,
                            'onbubble'=>new JSFunc($this::FUNCTION_PARSE_MARK,null),
                            'behavior'=>new JSFunc($this::FUNCTION_BEHAVIOR,null));
        
 $this->ypiBase= new YpiControl($initAttr,$requiredSripts);
 $this->avatar1 = $this->ypiBase->createAvatar($this::CLASS_PATH_AVATAR ,$avatarAttr);
 $this->reactions=$this->ypiBase->createControlPanel($this::CLASS_PATH_REACTIONS);

Part of integration to PHP Nette Framework. Original file is here

ASP.NET integration

It is now possible to use yPi.js as component in your ASP.NET applications (including Microsoft Sharepoint). You can use YpiControl.dll from "Release" folder in ypijs-.net repository


<%@ Register TagPrefix="ypi" Assembly="YpiControl" Namespace="Ypi.Controls" %>

Register component for your page.


 <ypi:Avatar ID="Avatar1" YpiBaseName="ypiBase" Alias="Joe Doe" runat="server" />
 <ypi:YpiPanel runat="server"/>
 <ypi:YpiControl ID="ypiBase" runat="server" ChapterUrl="welcome.xml" InitState="n1" 
IsAutostart="true" />

And then place everywhere in page content.

Ⅳ. Let's customize

It is recommended to place your custom setup in file custom.js . You are working with avatar identifier (getName method of object Avatar). So you can add some mouse event functionality (repeat last text after mouse out etc.).

Custom markup


	ypi.df.registerMarkup(
		"markup_name",
		function(params,source){
		// usage: {[markup_name foo="bar"]} 			
		if (params['foo'] == undefined) {
			return;
		}	
		// bar	
	});

There is one way how to register new markup before calling ypi.df.invokeInit method. Markups are handled shortly before text in bubble is displayed.


        //bar
        $('<strong></strong>')
        .html(params['foo']).appendTo(options.Element.selector);

If you want to replace {[markup_name foo=bar]} with bar.

You can use custom span Id instead of options.Element.selector (bubble span associated with current avatar). In that case bar can be displayed anywhere in current document.

Custom attributes

Sometimes may be useable to parse values from custom attributes. Just define them in string arrays attrCase and attrReact in init method. Then it is possible to access your custom attribute values directly in params of event handled methods. For example, attribute called "googleTrackId" you can access with GoogleTrackId. Sometimes are custom attributes better choice than custom markup. Especially if you want to access them in any event handled method or custom action.

Custom action

Method: [object:Avatar].registerCustomAction(key, options)
Params:
key string Action key.
options.Action method Action method.
options.Scope string Scope trigger prefix.

	avatar_1.registerCustomAction("foo",{Action:function(params,y) {
		alert(y); // bar
	}, Scope: "scope"});
 

After avatar_1 was created you can register custom action or more of them. When it is done, then invoke actions by ypi.df.invokeActions method in any event handled method. There is trigger prefix to determine scope of custom action execution.

Method: ypi.df.invokeActions(params,scope)
Params:
params [object:Params] Params with Invoke attribute.
scope string Scope trigger prefix.

	actionBag={};
	// invoke contact form
	actionBag.contact = function(params, source)
	{
		$("#hidden_form").fadeIn("slow");
	}
	// google analytics
	actionBag.trace = function(params, source)
	{
	     _gaq.push([params.Trace_id]);			
	}

	... 

	avatar_1.registerCustomAction("contact_form",
        {Action:actionBag.contact,Scope:"onstop"});
	avatar_1.registerCustomAction("google_trace", 
        {Action:actionBag.trace, Scope:"onanswer"});

Example of some handy actions.

Ⅴ. Lifecycle: Dialog

Folowing state diagram represents lifecycle of dialog object.

State of dialog
Initial

Avatars are defined and will be later initialized in onload event.

Pre-ready

Dialog is now wainting to ypi.df.invokeInit method call.

Load chapter

Trying to load chapter XML file.

Ready

Dialog XML file loaded and chapter is ready. If isAutostart property is enabled next state occurse immediately with initial case defined in property initState. Otherwise dialog is wainting now to ypi.df.gotoChapter method call

Invoke case

Trying to select and parse requested case from chapter.

Render bubble

Displaying bubble. Events onbubble and onsound (if soundlib is enabled) occurse now.

Render reactions

After onrender event is handled, dialog is now ready waiting to user reaction (onanswer event). If IdleInterval property is set it will repeat last speech if user reaction not occurse.

Finished

There are no available reactions. It is possible to load next chapter or invoke case by calling ypi.df.gotoChapter method.

Lifecycle: Avatar

Also represented by state diagram.

State of avatar
Created

Avatar was created and initialized (in onload handle method). Then it is time to set custom behavior handle method.

Waiting

Avatar is now waiting to activate.

Activate

Current avatar is choosed by attribute target during case processing. Now it is time to handle onplay event (if sound is enabled).

Speeking

Current avatar is speeking now (displaying text part). Events onbubble and onseek occurse (if sound is enabled). After some display time method mute is called.

Mute

Current avatar's bubble is fading out. There is onmute event too. Now trying to invoke displaying next text part if exists.

Stopped

At this moment there is no text part to display. Going to waiting mode after onstop event is handled.

Ⅵ. Extended UX

There are several ways to turn your avatar presentation much more attractive to boost user experience. You can use rendering and multimedia capabilities of modern browsers.

Audio support

There are onplay and onseek events to handle this. Depends on used soundlib too. Every method has its adwantages and disadwantages. Sometimes is good to preload other possible samples when current one is playing now. However, you need to preload all next possibilities. And then choose only one sample from preloaded to immediate playing. This can be problem if there are a lot of transition possibilities.

Animation support

Not matter if you are using 2D or 3D model of avatar (WebGl etc.). There can be your custom property Animate to choose current animation movement by name.

Ⅶ. Conclusion

Product yΠ.js is released under MIT license and backlink to ypijs.org is required. Of Course it can be with rel="nofolow" attribute. For extended custom functionality or integration requests, please try to contact me .

ypijs.org © 2014