Thursday, 5 February 2009

Interactive pdfs: using javascript

Recently I have betrayed my flash counterparts, turning to javascript, javascript for PDF's. If that sentence doesn't make you shudder, it should, and perhaps this blog post will reveal why. However my main purpose for writing this is to lighten the learning curve (and horror) for any developers who are striving to create interactive pdfs.

So the sceneario is this: you recive a PDF full of lovely images and designs, but you want the user to interact with elements on the screen; use buttons to navigate and reveal different layers and options. PDF's can contain a number of different media's: images, video and swf. You may also allow the users to submit forms which can be emailed, for example to a sales department who can deal with a request or feedback infromation.

Starting out
In order to start working you'll need Acrobat pro, I use Adobe Acrobat Pro 9. You'll need to specify an external text editor that you will be using to write your javascript, I use TextMate. Select Acrobat-> Preferences-> JavaScript select the radio button "Use external JavaScript editor" and browse for your appliacation.

A word of warning, you can edit code interally using Acrobat JavaScript Editor, however this works less than well and if your planning on writing a lot of code (i.e scripting functionality for a 20-30 page pdf) it will either crash or Acrobat will throw an error.

The documents I work with are created in Adobe's InDesign by a designer, exported in a magical way and sent to me for scripting. There are lots of tutorials describing how to do this and is beyond the scope of this blog post. A quick note, the more consisitant your designer can be with naming layers and fields: the easier your job will be.

A Debugger is available (Advanced -> Document processing -> JavaScript Debugger). You will find that the debugger is sadly lacking and generally uninformative, if you are lucky a reference to the line number of your error will be provided, if not, you're left guessing. Use console.println("this is flash's version of a trace statement!"); to output content to the debugger, this will help in your mystery hunt.

Adding javascript
To start adding code select Advanced -> Documet processing -> Document Javascripts
Select "add" and give your script a name, how about a creative name such as "myScript"?

At this point your external editor will open and your code will be surrounded with Acro Script. Ignore this, this is added by Adobe Acrobat, you won't be able to edit directly since it is created from your own code. For example you code a line which sends the user to page 14 when a button is clicked, you may get something like the following produced in Acro Script:

// //menu_safety 2.Page 8:Annot1:MouseUp:Action1 // /*********** belongs to: AcroForm:menu_safety 2.Page 8:Annot1:MouseUp:Action1 ***********/ pageNum=14; close_menu(pageNum); // //

As far as I can tell the language is horribly inefficient and by the time you have finished coding you will have literally thousands of lines of AcroScript.

Accessing fields and layers using javascript
To access elements (known as fields) within the pdf, use this.getField("my_button_name");
"this" referring to the actual pdf document. You can use this for any fields, including buttons and text input fields. Lets say that at the beginning of your pdf you have a screen sized button that you want to let the users "enter" the pdf and go to the next page, aka page 1 (page numbers start from zero). You may use the following code:
var mybtn=this.getField("enter_btn");
mybtn.setAction("MouseUp", "pageNum=1;");
//on mouseUp go to page number one!

Layers are a little more complex as far as I can tell you cannot access layers by name. You must access layers using their page number and the layers are returned as an array.
var ocgArray = this.getOCGs(pageNum);

One may then cycle through the layers stored within the array and act accordingly. The following function is passed the page number, an array of layers that I want to be visible, and an array of layers which I want invisible. The function cycles through the layers for the particular page, where if finds a match between the layer name and a layer I have specified in my array it acts accordingly setting its state to visible (true) or invisible (false)
Buttons also have states which can be used to control their visiblity, particulary useful if you want to disable an option once a button has been clicked, or maintain a button state upon the click. For example, quite often within my brochure a number of options are displayed as clickable buttons. A rollover state has been created using Indesign; ie the text turns orange and bold. I want to make it obvious which button has been selected by making selected buttons unclickable and maintaining this rolled over state of orange and bold text.

One possible way of achieving this is to store an image of the 'over' state of the button within the content of the corresponding layer. This layer is visible once a button is selected, so all that remains is to render the clicked button invisible upon selection.

Below is such an example (company name blurred out). The top Question is no longer a button but a static image (the button looked like the question below but is now invisible). The bottom question is a button complete with roll over state. The rest of the screen is filled with the layer which contains the image of the top most question and of course the corresponding answer image.

To hide and show a button, the syntax is simple:
var mybtn= this.getField(BUTTON_NAME);

//im here!
var mybtn=this.getField(BUTTON_NAME);
//im gone!
Extra functionaltiy: Printing, Searching and Links
A couple of small bits of functionality are things like printing, searching and hyperlinks.
For Hyperlinks, get the field using the syntax mentioned before and then: (nb: dont forget the quotes around the url or it wont work)
URLbut.setAction("MouseUp", "app.launchURL('', true);" );

To give users the option to search use the syntax below. However it is worth noting that this will also search your hidden layers and make them visible again! This will quite possible mess up the look of your pdf, but it will aslo confuse users.
searchBut.setAction("MouseUp", "app.execMenuItem('FindSearch');" );

Acrobat prompting users to view the invisible layer shown below.

I havent found a way of disabling the option of viewing invisible layers, however there are ways to correct the view after Acrobat has navigated the user to the page. You can set a page action which operates everytime the page opens. This happens after the user has been sent to the page via search and therefore can be used to recorrect the page. The code below will call the function startVis everytime a user navigates to page 12. startVis is a function which restores the default layer visiblities. There is another problem created by this solution, users who have searched content may find that the layer is no longer visible, you risk confusing the user. This solution makes the best of a bad situation, however if you find something better let me know!

this.setPageAction(12, "Open", "startVis(pageDefaults));

Set up some Security!
Generally this is the basics of creating interactive pdfs. I just want to include a word about settings.

Its likely that you wont want users to tamper with or steal your designs, so add some security, its easy!

Advanced-> security -> show security properties
Select password security: here you can add passwords and restrict actions. There are varying security options, prohibiting editing, restricting printing to low res, etc. Be aware that if you want to edit your pdf after this you will need to remove security and enter in your password.

When your finished don't forget to compress and reduce the bulk caused by all those layers!

Tuesday, 3 February 2009

Media servers: smartfox and red5

This post is a bit of a follow on from my post about socket servers for muliplayer games , I was asked to research a solution for providing streaming video which could be uploaded as well as downloaded; a kind of cross between you tube and I player.

My first thoughts were to look at SmartFox; it cheaper than Adobe media streaming, but seems quite well supported. It was chosen by iain as one of the best socket servers for multiplayer games, but it supports audio and video since it has paired up with Red5 so in my opinion is worth investigating as it is a proven implementation.

The following is my quick piece of research/summary into RedBox (SmartFox and Red). I didnt manage to finish this as I was told to look at all inclusive platforms (to be blogged about another day). I havent tried or played with RedBox yet, but it definitly seems worth considering should a project require its use.

Although SmartFox Server was originally designed for games and chat applications, I think it should be considered because it is a powerful and commercially used and accepted server. It now has an addon from Red 5 (another good open source server). Called RedBox This means that Smart fox now supports audio and video streaming capabilities. The advantages of using SmartFox instead of Red 5 directly seems to be with the extra features that SmartFox offer, which can be used in conjunction with RedBox; effectively giving you the best of both worlds: smart fox and Red5. According to their website “With the only use of Red5 or FMS you don't get any advanced room management, buddy lists, chat filters, security etc... “ Another point to remember, is that because SmartFox is commercial, it will probably be better supported that open source implementations.

Redbox brings the following extra features to the table:
  • live events –one broadcaster to many subscribers
  • remote A/V recording (video messages etc)
  • Video Streaming
  • Api for handlng A/V streaming
One of the examples provided by RedBox with the API download is a application demonstrating how to build a live shared library of videos, providing tools for easily retrieving the list of available clips and assigning extra custom properties to each video clip.

The API provided is split into three sections. The two we would be concerned with is the AVClipManager- handles the list of available a/v clips, streaming and playback. The AVCastManager, handles live video and audio broadcasts.

Redbox can be run on a separate dedicated server, good/scalable if there are going to be a high number of users.

Creating a multiline button in flex

I'm currently working on a charity website Wigout with some colleagues, raising money and awareness for breast cancer. The downloads sections needed some links which would enable the user to save content such as jpg printable posters, raffle tickets and so on. Although I could have used a number of methods to provide the user with a means of saving content, those who know me know im stubborn. I have been meaning to dabble with/ investigate the flex framework for a while now: this was my first 'toe dip' into this world.

Although maybe overkill, to solve the problem I have created a custom component ; a multiline button extending the button component provided with Flex.
I guess there may be a number of reasons why you may like to do this, obviously this inherits the properties and methods of the button, for example I have a nice colour change when a user rolls over the text, making it more obvious that this is a link. I could also add some events, such as switching the text once the button has been pressed, providing an indication that the file has been downloaded.

Above: 2 is a normal button; 3 is my shiny multiline button at work (button fill and border alpha is 0)

A quick search in Google brings up Alex's (adobe) blog showing a method for creating multiline radio buttons by extending the radio button class. Essentially ive used this pattern as suggested to apply to the button component, with a few minor changes.

override protected function createChildren():void
if (!textField)
textField = new NoTruncationUITextField();
textField.styleName = this;
addChild(textField as DisplayObject);

I needed to specify that the text field would be the same width (slightly less) than its container: the button, otherwise it reverted to a small default value. The original code "addChild(textField);" wouldn't work for me, producing the error:
1067: implicit coersion of a value of type mx.core:UITextField to an unrelated type Flash.display:DisplayObject
I cast it as a Display object which solved this issue. Although I admit im not entirely sure why I managed to get this error and Alex did not, difference in sdk's or flashplayer?

As far as changes go thats it, so full credit to Alex for providing a nice pattern. This also shows how easy it is to work with Flex with its powerful and customisable/ flexible framework. I can't wait to get stuck in some more...

Monday, 26 January 2009

Flash Voip Api's

I've been investigating some of the voip API's available for Flash and Flex projects. The possibility to create applications which engage and interact with the user on an audio level is exciting. Ribbits Killer App challenge should certainly provide some cutting edge inspiration.

After dabbling with Ribbits API briefly, I felt disappointed. Firstly its seems you cannot send text messages from the UK (its a US company), although this problem may be limited to applications in development; it may work live. I also felt that the amount of control provided by the API was lacking, in reality it does everything one could expect from a voip api: voicemail; messaging; call bridging; inbound and outbound calls; transcription; conference calls and so on. But for all the hype I want more control over data; how about giving the developer the ability to store the audio data on our own servers.

Obviously the ability to store audio in house is appealing since calls to Ribbits service cost money; a one time cost of a call with multiple accesses to an in house server is cheaper giving companies full access to data and seems like a more commercially viable solution.

A feature which i'd like to see implemented is audio search, this would be a great feature for rich app's which require phone in's and audio interaction: an audio search could pull out related calls. Although Ribbit does not provide this, perhaps one could achieve this by utilising their transcription service. Store a call id along with its transcription (audio to text), simply search the text and pull out related calls. This could also work for a negative filtering process, aka remove calls with swearing or inappropriate language,

Ribbit has an 'ideas' wall for suggested implementations of their services and reading it is a good way to get creative juices flowing. I am especially interested in implementations which can converge medias and input, platforms and provide for the 'whereevers/ whenevers'.

One point to note is Ribbit is based in America, I don't know much about telecommunications, but i get the impression the call would be routed via a server based in the US. This would be one explanation as to why the quality of the call is so poor, unfortunately I'm not sure whether using Ribbit is commercially viable because of quality issues. However my tests were conducted making calls between computers which were close to one another, other people may not experience the same issues. But its definitely a point to investigate. Also note that Ribbit does allow you to set the service up with your own telecommunications provider, which could be useful in improving quality/ service.

As far as other voip solutions go, another US company TringMe offers a very similar service, although the documentation is pretty poor for this api, but they do provide convenient little widgets :). One to watch is Adobes Pacifica which is said to be very high quality. I believe its still under development, though nothing seems to have been announced in a while. More info here.


Neil kinda gave a talk/ walk through of Puremvc on the 20th. I've summarized the key points of the meeting, but also have some concerns about the framework and its uses.

Puremvc is quite a verbose framework, therefore should only be used in contexts which warrant the extra weight. The applications which require its use should be complex large desktop or web applications. An example of its use, shown by Neil was an air (desktop) scheduling application. An example of a web application that I think could benefit from the Puremvc framework would be SumoPaint (an online paint application which mimics Photoshop).

Neil made a point of warning that Puremvc is not suitable for games or 3d applications, because of heavy reliance on the view and its affect on performance. Puremcv adds a lot of bloat and layers to an application which would have a negative impact on a fast paced game, or a heavy rendering process.

It seemed as though most members of the meeting were struggling with some of the abstract concepts during the session. Indeed it was pointed out that there is a high learning curve to using Puremvc. Writing an application in Puremvc isn't something you can simply leap into, since the flow of notifications is difficult to follow. Neil mentioned that this may be a good thing, since its forces him to plan and draw out an architecture before writing any code. However it does create a high barrier to entry for anyone not familiar with the framework.

Neil recommended use of the Muliticore as apposed to the single core for flexibility. Multicore stops some of the core classes being instantiated as singletons; it allows cores to communicate with each other in larger, more complex applications which are ultimatly more flexible.

The documentation for Puremvc is very good, although I found from personal experience one of the fastest ways to gain an understanding of the framework is to study the flow of instanciation and notifications. Since this notification process is considered difficult to follow, its beneficial to study a small sample application and draw out the flow as you guide yourself through the application. I think this gives more of an instantanous reference making the application more transparent as a learner.

Although I can see how a framework such as Puremvc is benificial to developers creating large web applications; I am concerned about its use. Its easy to get wrapped up in creating "beautiful code" but without remembering a framework or design patterns original purpose its easy to end up with something that looks like its visited Jocelyn Wildenstein's plastic surgeon. Websites and small applications don't require the level of abstraction offered by Puremvc; and the reality is bulked out code, which is needlessly complex and probably quite confusing to update and maintain. The end solution becomes a bunch of classes which do not provide obvious answers as to their purpose, responsibilities and relationships.

When all said and done, good code should always be flexible and maintainable which are qualities boasted by Puremvc. Ironically the complexity/ abstract(-ness?) of the system counteracts these qualities by creating a high barrier to its use. Imagine switching your team over to the Puremvc framework for your larger applications, granted once your employees have completed training they will have the skills and tools to create sophisticated flexible applications.

However, now imagine (as with many digital creative agencies) you have a busy period, in the first scenerio you hire freelancers to come in and take some of the heat. In this scenerio you can't pick your usual freelances because they have no knowlege of the framework; if you do the projects are going to take a lot longer as they get up to speed. In the second scenario, you hire some new junior developers, again training takes alot longer but even usual junior tasks such as maintence become complex and daunting. I can imagine that debugging becomes a hugly more complex process as data flow becomes difficult to follow. Having said this I do believe that any training is a worthwhile investment and the knowelege will only benifit the quality of future projects, but my point is that when code becomes difficult to maintain that also means that its inflexible. By my book inflexible unmaintainable code = bad, so choose your weapon wisly.

Friday, 16 January 2009

Socket Servers and bulding multiplayer games in Flash

The speech last night at Brighton Flash was quite interesting. It was fairly informal but down to earth and Iain was speaking about realistic implementations of multiplayer flash games in a commercial setting. I was slightly disappointed he didn't mention any of his 3d work for the bbc, but then this wasn't particularly relevant to the topic of the speech, since Meta4orce is single player.

A large proportion of the talk was dedicated to selecting the right socket server. This is important because as Ian put it "once you've made your decision you're pretty much stuck with it", aka make sure you choose the correct server for the project. However he did show us a game he's currently developing which he has implemented using two different servers: SmartFox and ElectroServer, essentially as an experiment for comparison. In order to do this he's created a class for all server specific activities, so from what I gather one one 'server class' for each server, decoupling it from the game processing.

He advised not to be a smart ass and create your own server, since these implementations have been tested thoroughly and are optimized for a large number of users, therefore would be less likely to break.

There are four main servers which were mentioned, each have their own pros and con's.

Red 5 is open source, so free/cheap. The downside is that from what I gather there are less tutorials than those for Smart fox and ElectroServer. Its written in Java which seems to be the standard for Flash Socket servers. Its pretty general so can support Streaming Audio/ Video, Remoting etc. This server wasn't spoken about too much, but someone at the meet did mention that it had a feature which the others don't, object remoting : making a flash object and pairing it with a java object on the server side.

Smartfox- The most costly solution out of all the servers mentioned. However it is very well documented and supported as it is a popular solution. Unfortunately it was written by an Italian so some of the English is a bit poor with bad spelling, but funny rather than too much of a hassle. Smart fox comes with its own gui admin tool where you may edit the config files, included rooms, banned word list, max users, you can kick and ban users and keep track of the health of the server. Ian did mention that although this feature is nice, its more of a crutch and not completely necessary. I cant recall is this server allows binary rather than XML to be sent- worth investigating. Disney's club penguin uses this server.

Electroserver- Very similar to Smart fox and seems to work at a similar speed, as in the differences aren't very noticeable. You can extend the classes using java or actionscript 1. Electroserver also uses Strong typing, its better practice and you know what kind of data you will be receiving back from the server. Ian mentioned that although Electroserver and Smart fox are very similar technologies, he is currently preferring Electroserver, simply because its nicer to use, the classes are cleaner and prefers the architecture. This server can use binary rather than XML, so reduces the size of the data being sent to the server- faster.

DarkStar- OpenSource- can support a huge number of users and has been used for live commercial projects which prove this. Again its written in Java with a flash api. Although Ian did not recommend this for anyone who preferred not to extend classes server side. I think perhaps, in contrast to the other servers, you cant modify this server functionality from within

Red 5, Smartfox and Electroserver, you can affect server functionality client side. Ian did not recommend this for a project with a large number of users, since its less efficient and the server would be prone to fall over (smartfox was the server he was using at the time, with PHP for
persistent user data). He gave an example of a game he produced where modifications were only made in flash with no extra server side programming. Although the game works well, when the game received a huge influx of users, (I think he said about 700) the server fell over and needed restarting, and a couple hours later again. Despite this draw back he did emphasis that the game does work well and that the games usual user count are about 70 at a time.

A couple of other useful points...

  • -Although clients prefer data capture it does put off users if they have to fill in a form before playing. 'quick play' buttons are very useful and login facilities need to offer the player an incentive such as keeping their game character.
  • -Storing game stats and other persistent data can done using another technology in combination with a socket server, for Zwock PHP was used.

Multiplayer games are about creating an illusion-

  • -Its good to create a number of 'bot' opponents, this is particularly important during the early days of release. If a player enters a lobby and theres noone else to play, they will exit immediately. Create realistic bots, Ian actually has an algorithm for producing realistic opponent names. Depending on the game, you can swap real players in for bots as more people join the game. This depends on the context of the game as can get quite confusing for players.
  • -In addition to the problem of an empty lobby, users don't want to wait a long time to enter a game. Therefore if noone joins after a set amount oftime, Ian recommends sending bots in to fill up the spaces
  • -With fluid movement of games characters, you wont be wanting to send every move the player makes. Send a limited number of coordinates per second. Then ease between the coordinates to create an illusion of fluid movement. For example with a car game send the coordinates, direction, speed etc to work out where to move the car, when you receive the next location of the car move to minimize the offset.

  • -Fighting/ shoot em ups- this genre (in flash) its important to get the level design correct. Generally these games are quite open plan because of lag and the offset of characters, everyone is literally playing a different game. They think they are playing the same game and its important not to shatter that illusion, player A may fire a bullet, player B ducks behind a wall, to Player B it appears that the bullet missed, but to player A it may have hit. Iain also suggests giving a player feedback straight away, show player A blood splats from player B, even if in the end logic has decided not to take health away from player B. There are complex ways to get around this problem involving calculations of players future positions etc, although iain didn't think this would be necessary for a flash game and was overly complex.
  • -Game differences such a conflict between what clients think has actually happened- Iain suggests this can be decided at random, or that the games host's version of the game is always correct.

  • -Although users like chat areas it creates legal obligations- pedophiles, child molestation etc etc etc. The Disney virtual world has a huge number or moderators in comparison to developers. One game he produced has a number of preselected messages you can send to players during game play. An interesting feature is that the number of the message is sent to the server and depending on the selected language/country the actual message which appears is translated.
  • -Score boards are an invitation to hackers to see their name plastered all over your web page. To get round this for Zwock, Iain made sure that the highest score you could get for a game was limited, therefore to get to the top of the league table to had to play games over and over.
  • - Obviously turned based games are obviously a lot easier to implement.

As an example of a game with very good implementation, Iain showed us stick arena . The talk at Brighton Flash was certainly inspirational and very useful regarding the practical implications of producing commercial muliplayers. Personally I can't wait to get stuck in.

I hope this information is useful, I've tried to remember the topics as best I can. But as I mentioned some topics will require some further investigation.

Saturday, 25 October 2008

Clipping in Away3d

As promised I've conducted a series of experiments to try and understand the differences between the various 3d engines for flash. Since I lack the time to learn and produce a movie using each api, i have concentrated on Away3d and Sandy. A study of all 4 of the engines I have previously mentioned can be found here.

Since discussing some of the drawbacks of Away3d and clipping problems, I have researched methods to solve this issue. As suggested by Peter Kapelyan one of the easiest methods to correct clipping in Away3d or Papervision is to simply add extra triangles. Since the problem occurs when part of a face extends past the camera, this is an obvious solution, thus creating a smaller section to be culled.

The following examples show a plane created with Away3d. Creating a plane with 3x3 segments results in extreme clipping and really is a problem. Upon increasing to 4x4 the problem is immediately less obvious; 5x5 segments completely irradiates the problem. Of course increasing the number of faces is going require more processing power and memory usage and is ultimately less efficient. It it is important to take this in perspective; as far as I am aware Away3d is quite a fast 3d engine. Sandy suffers from clipping as much as Away3d when segments are reduced to two. Essentially you must nearly double the number of faces used if converting from Sandy to Away3d (3 -5 segments). This is a primitive study and does not give indication of scalability; hence there is the possibility that differences between the two engines could become more or less exaggerated with complex scenes.

please be patient waiting for these to load they are loading from a very slow server 0_o
use keypad up and down to move along the plane

Away 3d 3x3 segments

Away 3d 4x4 segments

Away 3d 5x5 segments

Sandy 3x3 segments

Some interesting blogs regarding first impressions on a variety of 3d engines and workarounds for issues such as clipping. coobico, saumyaray, Ian Lobb.