This is a legacy article. I no longer create or support Animate/Flash extensions, but these articles are preserved here as a reference for anyone to use.

The ability to create extensions is one of my favorite features in Flash Pro. You can extend Flash to include new features and automation in the form of Commands, Panels, and Tools. This series of tutorials will show you how to create your own extensions for Flash. There is a special scripting language that allows you to control Flash, and it is known as JSFL.

Table of Contents

Lesson 1: Introduction

JSFL (JS[JavaScript]FL[Flash])

JSFL is a variant of JavaScript specifically written to interact with the Flash authoring environment. Like Actionscript, JavaScript is based on the ECMAScript standard. So, if you have any familiarity with JavaScript, or ActionScript, you will find this knowledge useful in writing JSFL. It should be noted that JSFL and ActionScript are distinct languages with distinct purposes. The latter is compiled into a SWF, and that SWF can play in the ubiquitous Flash Player. Conversely, JSFL code is executed on the spot and is used to control Flash Professional itself. Thus, JSFL can accomplish nearly everything that a user can within Flash, such as create layers, create objects, select frames, manipulate Library items, open files, and save files. Additionally, JSFL allows you to script a few tasks that users cannot normally perform (at least not easily or quickly).

You create a new JSFL script by choosing File > New and selecting Flash JavaScript File in the New Document dialog box. The file extension for a JSFL script is always .jsfl. In this tutorial, you’ll start visually by copying user actions from the History Panel.

The History Panel

The History Panel functions as an advanced undo/redo. This panel also has the capacity to show the JSFL code necessary to duplicate each (enabled) user action.  Follow the steps below to create a JSFL command using the History Panel.

  1. Open a new Flash file.
  2. Open the History Panel: Window > Other Panels > History.
  3. Select the Rectangle Tool and draw a rectangle on the stage.  Notice that this action is recorded in the History Panel.
    Rectangle Step in History Panel
  4. Click on the fly-out menu on the top-right of the History panel. Here you can change the display format and tooltip display.
    History Panel fly-out menu
    Change the display to show JavaScript in Panel (if it’s not selected already).
    JavaScript displayed in History Panel
  5. Change to the Selection tool. Select the rectangle on stage and delete it.
  6. Grab the slider on the left side of the History Panel and drag it up so that it’s parallel to the original rectangle command. Note that sliding the arrow undid the deletion of the rectangle. This slider functions like an undo and redo.
    Undo/redo slider
  7. Drag the slider down to the deleteSelection command. Now select the original addNewRectangle command and hit the Replay button. This will create a rectangle with the same dimensions as the original rectangle.
    Selecting steps in the History Panel
  8. With the addNewRectangle command still selected, hit Copy Steps button in the bottom right of the History Panel.
  9. Drag the undo/redo slider to the very top of the History Panel to revert the document to its opened state.
  10. Open a new file: File > New. When the New Document dialog appears, choose Flash JavaScript File and click OK.
  11. Paste the stored command into the newly opened script, Edit > Paste.
  12. Hit the Run Script button within the script editor and return to the Flash document.
    JSFL History command shown in Script Editor
    Note that a rectangle has been drawn on the stage in the same place and with the same dimensions as the one that was drawn with the rectangle tool. This script can now be modified to do something more useful, like get the document size and draw a rectangle to match the dimensions of the document, or looped to create several rectangles at once.

Saving a Command

To save your JSFL script for later use in Flash, you’ll want to save your script to the Configuration/Commands directory. This will allow you to execute your script using the Commands menu (and optionally, a keyboard shortcut). The first step is to locate the Configuration directory for your installation of Flash.

Locating your configuration directory

To locate your Configuration directory, you can check these common locations, or simply create and run a new JSFL script with the following code:

fl.trace(fl.configURI);

This script will print the location of your Configuration directory in the Output panel. Note that each installation of Flash has its own Configuration directory.

The next tutorial in this series shows you how to use JSFL to manipulate other parts of your Flash document. If you’re interested in learning more JSFL, you can also check out Chapter 4 of Animation with Scripting.


Lesson 2: The DOM

This tutorial will focus on a couple of basics for using JSFL (defined in the previous above) to alter a Flash document. Everything that can be manipulated in JSFL is considered an object. The Document Object Model (DOM) is basically the hierarchy or structure (model) of objects within a particular document. If you’ve written JavaScript for a web browser, you’re probably somewhat familiar with accessing the DOM of an HTML document.

There’s an order to everything you do within a Flash document, whether you’ve realized before or not. The DOM makes this order explicit. Let’s start by looking at the most basic Stage object in Flash, known as an element. All Stage objects (e.g. bitmaps, groups, graphic symbols, and movieclip symbols) inherit the properties (things that describe the object) and methods (things that can be done to or by the object) of a basic element. The document object hierarchy for any element on Stage is as follows:

Flash > Document > Timeline > Layer > Frame > Element

Each element is on a single frame, that frame is stationed on a single layer, and so on, all the way up to the level of the document, then Flash itself at the very top. So, to access the 1st element, in the 1st frame, on the 1st layer, within the first Timeline (aka Scene), within the 1st open document in Flash, you could use the following JSFL code:

fl.documents[0].timelines[0].layers[0].frames[0].elements[0];

The 0s (i.e. documents[0]) access the first item in an Array (collection of objects). This is known as array notation. Take a look at the documentation for the Document object. It has a number of methods and properties. I frequently return to the documentation when writing new scripts. I recommend downloading the PDF of the entire section for quick reference.

Follow the steps below to utilize two of the Document properties to improve the script from the first tutorial (above):

  1. Create a new Flash Document (AS2 or AS3), using File > New.
  2. Create a new Flash JavaScript file (JSFL), using File > New.
  3. Add the following code to your JSFL script and click the Run Script button:

var dom = fl.getDocumentDOM();
dom.addNewRectangle({left:0, top:0,right:dom.width, bottom:dom.height}, 0);

Switch back to the new document that you created. You should see a rectangle (with the fill and stroke colors from your Toolbar) that fills the Stage.

Stage Size Rectangle created with JSFL

Let’s take a closer look at the code that you added to accomplish this. The first line creates a new variable with the name dom. This line also uses the Flash object (fl) to store a reference to the current document. That will save some typing in the next line and keep the script a little bit easier to read.

In the second line, you’ve replaced the top and left positions of the new rectangle to correspond with the x and y coordinates at the top-left corner of the Stage (0, 0). Additionally, you access the width and height properties from the dom variable to match the rectangle’s dimensions with those of the Stage.  This new rectangle is much more useful than the one created previously. For instance, this rectangle could now be used as a background, a mask, or (given a few more steps) to create a matte to hide the edges of the Stage. If you’re interested in learning more about creating mattes and masks with JSFL, check out Chapter 4 of Animation with Scripting.

Note from the structure listed above that you can also use the DOM to alter frames, layers, and timelines. For instance, the following code will create a new layer named artwork:

var dom = fl.getDocumentDOM();
dom.getTimeline().addNewLayer("artwork");

Try experimenting with methods and properties found in the documentation to make changes in Flash documents. I recommend using “test” documents, rather than actual work files, in case something unexpected happens.

A similar object structure exists in JSFL to manipulate Libary items. The next tutorial (below) dives deeper into the Library object.


Lesson 3: Manipulating the Library

Part of being a solid Flash user and a good collaborator is maintaining clean, navigable files. This means naming layers and library items clearly, deleting unused material, keeping folders organized, etc. Because these actions must be applied to all files and are quite repetitive, they’re good candidates for automation. You can use JSFL to script all of these actions into a single keystroke or mouse click. This tutorial will focus on creating a Command (saving a Command is explained in the first tutorial above) that will clean up the items in the Library.

The image below shows a sampling from a typical Flash Library. With only 14 items, this Library is not terribly difficult to sort through, but as the document grows and new items are added, this Library will become unwieldy.

There are a number of different ways to organize a Library. Sometimes it makes sense to organize your Library items by purpose, such as collecting all the artwork for a single animated character into one Library folder. Another common approach is to organize Library items into folders by type (i.e. movie clips in one folder, sound clips in another, and so on).

This tutorial will help you create a script to organize your Library by item type using methods and properties found in the Library object and the Item object. The Library object references the document Library itself, which contains a list Item objects. Those items will have unique methods and properties based on their types (such as the SymbolItem or the VideoItem), but every item in the Library, regardless of type, will inherit the methods and properties of the Item object.

Organzing Bitmaps

You’ll first create a script to organize a single item type. Bitmaps can mess up a Library pretty quickly, so you’ll begin by wrangling those.

1. Open an existing document with an unorganized Library, or create a new document and add some Library items to test the script on.

2. Create a new JSFL script (File > New > Flash JavaScript File).

3. Add the following variables to your script so that they can be easily reference in the rest of your code:

var dom = fl.getDocumentDOM();
var lib = dom.library;
var items = lib.items;

4. Add a folderName variable after the previous variables :

var folderName = "bitmaps";

5. Add the following line to check for the existence of the folder, and to create the folder if it doesn’t exist after the code in the previous steps:

if( ! lib.itemExists(folderName) ) lib.newFolder(folderName);

The exclamation point (!) inverts the truth value (i.e. to see that the item does not exist). Technically, the if statement is unnecessary, since the new folder will only be created if the path doesn’t already exist, but it’s a good practice to have the check, in case the functionality changes in a future version of Flash, or you want to update the script later to act differently if the folder has already been created.

6. Add the following code to loop through the library items and move only the bitmaps to the “bitmaps” folder:

for(var i=0; i<lib.items.length; i++){
var o = lib.items[i];
if(o.itemType=="bitmap") lib.moveToFolder(folderName, o.name);
}

When run on the Library shown above, the results appear as follows:

You can use the same logic to create and organize folders for any of the available item types.

Organizing Multiple Item Types

Now that the bitmaps are under control, why not take care of some other items? Follow the steps below to create and organize several folders.

1. Add a new array to the existing set of variables and create several new items based the folder names you want to appear in your Library:

var dom = fl.getDocumentDOM();
var lib = dom.library;
var items = lib.items;
var folderTypes = new Array();
folderTypes['bitmaps'] = "bitmap";
folderTypes['mcs'] = "movie clip";
folderTypes['graphics'] = "graphic";
folderTypes['audio'] = "sound";
folderTypes['fonts'] = "font";

Each new type should be assigned a value that matches the name of an itemType.

2. Then start a for in loop that encompasses the previous for loop the folderTypes that you’ve created:

for(var type in folderTypes) {
if(!lib.itemExists(folderName)) lib.newFolder(folderName);
for(var i=0; i<lib.items.length; i++){
var o = lib.items[i];
if(o.itemType=="bitmap") lib.moveToFolder(folderName, o.name);
}
}

3. Add folderName and itemType variables inside the for in loop to store information from the folderTypes array:

for(var type in folderTypes) {
var folderName = type;
var itemType = folderTypes[folderName];

4. Alter the hard-coded “bitmap” itemType to reference the itemType variable, so that it will update as the for in loop runs:

if(o.itemType==itemType) lib.moveToFolder(folderName, o.name);

Voilà! An organized Library:

You can customize the script to suit your individual or project-based needs.


Lesson 4: User Interaction

The ability to include user interaction into a JSFL script can provide a significant level of flexibility and feedback. Flexibility and feedback are especially useful when you plan to distribute your extension to others. Flexibility allows the script to run differently depending on current conditions. Is there a document open? Are items selected in the Library? Etc. If so, you can ask the user how to proceed. Feedback lets the user know that the script has run properly (or not), so that he/she can proceed with confidence. This tutorial will cover the primary types of user interaction available in JSFL.

Basic Interaction

There are 3 types of basic interaction: alerts, confirms, and prompts.

Alert

The alert method displays a modal message (i.e., nothing else can take place while the message box is open) with an OK button.

Sample code:

alert('this is an alert');

The alert box serves as a simple form of communication to indicate to the user that a process succeeded, failed, or somewhere in between. Since there is only 1 button in the prompt, and the prompt must be closed before the user can continue working in Flash, there is no new information that is retrieved from the user after the message is closed. This 1-way communication is unique to the alert prompt.

Confirm

The confirm method displays a modal box with an OK button and a Cancel button.

Sample code:

var success = confirm('Are you sure you want to do this?');

Because the confirm dialog box includes 2 buttons, a boolean (true/false) value is returned to indicate which button has been pressed. This allows the script to behave differently depending on the user’s choice:

if (success) {
//do something
} else {
//do something else
}

The confirm dialog can be used for any “fork in the road” where it might be beneficial for the user to have input before proceeding.

Prompt

The prompt method includes an OK button, a Cancel button, and a textfield in which a user can type a response.

var result = prompt('Enter your text:');

If the user clicks OK, then the value entered in returned. If the user clicks cancel, a value of null is returned. This allows you to use the entered value to determine what occurs in the script:

if (result == null) {
//do nothing
} else {
//use the value of result to proceed with the script
}

The prompt dialog is useful for allowing the user to name items and instances. You can also convert entered values to numbers using the parseInt and parseFloat JavaScript methods.

Advanced Interaction

In addition to the basic user interaction methods, you can also display a completely custom XMLUI panel, using the document.xmlPanel method. These panels can contain any number of interactive items, including: buttons, checkboxes, color selectors, drop-down lists, sliders, radio buttons, text boxes, text inputs, and even SWFs.

The content of the panel is defined by an XML file, using specific tags. The tags control the layout of the panel as well as the items that appear in the panel. The panel is then launched by accessing the stored XML file:

var dom = fl.getDocumentDOM();
var xpanel = dom.xmlPanel(absoluteFileLocation);

Here’s the content of the XML file that renders the Combine TextFields dialog with radio buttons above:

<?xml version="1.0" encoding="UTF-8"?>
<dialog id="combineTF" title="Combine TextFields" buttons="accept,cancel">
<vbox>
<label value="Sort from:" />
<radiogroup id="sortby" tabindex="5">
<radio label="top" accesskey="t" selected="true"/>
<radio label="left" accesskey="l" />
<radio label="bottom" accesskey="b" />
<radio label="right" accesskey="r" />
</radiogroup>
</vbox>
<spacer />
<hbox>
<label value="Separator:" />
<textbox id="separator" maxlength="20" multiline="false"
value="" tabindex="1" size="12" literal="false" />
</hbox>
</dialog>

Just like the prompt method, the xmlPanel method will return null if the user clicks Cancel. If the user clicks OK, an object is returned containing all of the values set in the XMLUI dialog box. You can then loop through the object’s properties as shown in the document.xmlPanel reference, or access them directly by name, for example:

var separator = xpanel["separator"];

The only full reference for the tags and syntax used to create XMLUI dialogs can be found in Extending Flash MX 2004, an excellent and important desk reference for anyone interested in Flash extensions. Even though the book is quite dated (in software years), much of the JSFL API remains the same, and the book is still useful, even if you only use it for the XMLUI reference (which I’m constantly using).


Lesson 5: SWF Panels

If you’ve been following this tutorial series thus far, this might be the tutorial you’ve been waiting for. The ability to load a SWF into the Flash Professional interface is definitely one of the coolest aspects of Flash extensibility. There are 2 distinct advantages to building a Flash panel:

  1. Endless visual possibilities
  2. The power of ActionScript

The 1st advantage should be fairly obvious to anyone familiar with Flash’s design and animation capabilities. The 2nd advantage may be slightly less obvious, since ActionScript and JSFL can appear so similar, but ActionScript (3, specifically) has a whole host of capabilities that JSFL does not (network connectivity, timed events, and the ability to interface with nearly any file type using ByteArray, to name a few). The topic of exploiting ActionScript capabilities in a panel actually deserves its own blog post, but for now it’s sufficient to say that SWF panels make cool stuff possible.

This tutorial will serve as a primer, getting you started on the basics of how to load your panel into the Flash interface and how to communicate with JSFL through your SWF.

A Simple Panel

A Flash panel is merely a published SWF that can be loaded into the Flash Professional interface via Window > Other Panels. You can design custom panels to look like the panels that come installed with Flash, or you can make them entirely unique.

Setting up the Flash file

Follow the steps below to create a simple panel.

  1. Create a new Flash file (AS3), File > New… > ActionScript 3.0.
  2. Save the file (File > Save As…) as myPanel.
  3. In the Properties panel, update the document size to 200 x 300 px. The default width for a panel is generally 200 pixels.
  4. If you like, update the Stage Color. When you click on the color selector, you can use the eye dropper to select the gray color within part of the Flash interface, so that your panel color matches the rest of Flash.
  5. Open the Components panel, Window > Components.
  6. Twirl open the User Interface folder and drag a Button component onto the Stage.
  7. Give the Button instance a name of btn in the Properties panel. An instance name will allow you to reference the button from ActionScript.
  8. Change the width of the button to 180 and adjust its position on Stage as needed.
  9. Add a label to the button of Create Rectangle.

For simplicity sake, you will use the script created in Part 2 of this series, but once you get the hang of this, you’ll be able to add as much complexity as you like.

Adding the Code

From a SWF, your ActionScript needs a way to talk with JSFL: enter the MMExecute function. This function will pass a string to be interpreted as JSFL. The JSFL code will only be executed when you’ve properly loaded your panel. Your JSFL code will not execute when you run Test Movie. More on how to install your panel in a moment.

When you pass JSFL code as a string, be careful to escape any characters such as quotation marks (using a backslash, e.g. /”) that will disrupt the string in ActionScript. Alternatively, if you use double-quotes for JSFL, you can use single-quotes to wrap your string, or vice versa. For example, to trigger a JSFL alert from ActionScript, you could use the following code:
MMExecute("alert('hello');");

Follow these steps to add the functional code to your panel:

  1. Create a new layer named actions and lock the layer.
  2. Select the first frame of the actions layer and open the Actions panel (Window > Actions).
  3. Add the following code inside your actions panel:

btn.addEventListener(MouseEvent.CLICK, onBtnClick);
function onBtnClick(e:MouseEvent):void {
var jsfl:String = new String();
jsfl += "var dom = fl.getDocumentDOM();";
jsfl += "dom.addNewRectangle({left:0, top:0,right:dom.width, bottom:dom.height}, 0);";
MMExecute(jsfl);
}

  1. Publish your SWF (Control > Test Movie).

The first line of the ActionScript adds a listener to the button component that will fire when the button is clicked. The next line begins the definition of the onBtnClick function that executes when the button instance is clicked. Inside the function, a string is created to house the JSFL code. That string is then passed to be executed as JSFL by the MMExecute function. Generally, I like to concatenate my strings on separate lines using the += operator, because it keeps my JSFL somewhat readable inside the ActionScript. You’ll learn how to store the JSFL code externally later in the tutorial (a technique that I much prefer).

Make sure you have no errors in your Compiler Errors panel. If you press the button right now in the Test Movie window, nothing will happen, but you’ll fix that in the next step.

Loading your panel into Flash Professional

In order to have your SWF show up as a panel, you will need to place it in the Configuration/WindowSWF folder. See the 1st tutorial for how to locate your Configuration directory. Follow the steps below to launch and run your panel.

  1. Place a copy of the myPanel.swf file inside the Configuraton/WindowSWF folder.
  2. Restart Flash.
  3. Create a new document, File > New > ActionScript 3.0.
  4. Open your new panel under Window > Other Panels > myPanel (the panel name will always be the file name minus the .swf extension).
  5. Click the Create Rectangle button inside the panel.

You should now see a rectangle matching the Stage dimensions with the stroke and fill colors from your toolbar.

Success!

Accessing an External Script

So far, you’ve run JSFL code as a string inside ActionScript. This works fine for simple panels like the one you built in the steps above, but what about more complex actions? I recommend using the fl.runScript function.

Running an entire Script

If you want to run an entire script, all you need to do is pass the complete path of your script. Suppose you wanted to include a myPanelActions.jsfl file in the WindowSWF directory with you SWF file, you could use the following ActionScript:
MMExecute("fl.runScript(fl.configURI + 'WindowSWF/myPanelActions.jsfl');");

That bit of code would execute the entire myPanelActions.jsfl script.

Running a single function

Now suppose you wanted to include several actions in a single JSFL script. So, now you have a createRectangle function inside your myPanelActions.jsfl file, along with several other functions. You could modify the onBtnClick function from above as follows:

function onBtnClick(e:MouseEvent):void {
MMExecute("fl.runScript(fl.configURI + 'WindowSWF/myPanelActions.jsfl', 'createRectangle';)");
}

That would allow you add several other buttons (and actions) to your panel, while keeping your ActionScript nice and clean. This technique also reduces the need to keep track of so many double- and single-quotes. Additionally, it’s much easier to debug (find and fix errors) by testing a separate JSFL script.

SWF Panel Examples

Now that you’ve got the hang of the basics, you can create all kinds of neat Flash panels. Here are some examples of publicly available Flash panels that I’ve created. Maybe they’ll provide some inspiration as to what you can create.

Queasy Tools

Queasy Tools is a macro-style panel that I created to clean up my Commands menu. It allows me to quickly tween and perform common actions that normally require several steps.

EaseCaddy

EaseCaddy is a panel that stores custom eases for animation. Note the advantages of making such a tool as a Flash panel (displaying the list, a visible graph of the ease, graphical buttons, etc).

FrameSync

FrameSync is a panel to speed up lip-syncing. It can pull frame labels from a symbol and display them in the panel. The labels can then be clicked to update the content on the Timeline. Because of ActionScript’s timing mechanisms, the panel can also refresh automatically to capture changes in user selections.

Hopefully these examples provide you with some ideas for your own SWF panels. Please feel free to post links to your Flash panel creations in the comments.

Bonus: Productivity Script

Once you’ve loaded your panel into the Flash interface, you don’t need to restart Flash each time you make an update to your panel. You simply need to close your panel and re-open it inside Flash.

Instead of running Test Movie, then copying my SWF to the config directory with each update, I created the following script that I use as a Command to publish my SWF directly to the WindowSWF folder:

var dom = fl.getDocumentDOM();
var fileName = dom.name.split(".fla").join(".swf");
var swfFile = fl.configURI + "WindowSWF/" + fileName;
dom.exportSWF(swfFile, true);

So you can even use JSFL to speed up extension production!


Lesson 6: Custom Tools

Flash offers the ability to create your own tools and store them in the Flash Toolbar. Tools are probably the most underutilized type of Flash extension. This tutorial will walk through the basics of creating a  tool.

Building a Tool

This tutorial will demonstrate how to create a line tool. Flash already has a line tool, but this will serve as a jumping off point that can be easily expanded into a more complex tool.

File setup

Similar to Commands and SWF Panels, Tools have their own folder in the Configuration directory (see the 1st tutorial for how to locate your Configuration directory). The Polystar tool (found with the Rectangle tool in the Toolbar) is a custom tool that comes installed with Flash. You can use the Polystar tool files in the Configuration/Tools directory as a guide when building new tools. Follow the steps below to create a tool from scratch.

  1. In Flash, create a new JSFL script (File > New > Flash JavaScript File).
  2. Save the script as TestTool.jsfl in your Configuration/Tools directory.
  3. Create a 16 x 15 pixel PNG image (using Flash, Photoshop, Fireworks, or your favorite image editor) and save it in the Tools directory as TestTool.png. This will serve as the icon in the Toolbar. I just created a diagonal line.

    You can also right-click and choose Save Image As… to save the image on this page.
  4. Optionally (pun intended), you can create a TestTool.xml file in the Tools directory. This file can be used to establish options for the tool that can be adjusted by the user. This tutorial will not cover creating options, but you can look at the Tools/PolyStar.xml options for inspiration.

Now that you files are set up, you’ll start adding code to your JSFL script.

Predefined Functions

One concept that is unique to creating a tool involves prescribed functions that Flash will call as your tool is put to use: configureTool, notifySettingsChanged, setCursor, activate, deactivate, mouseDown, mouseMove, and mouseUp. Most of these functions have to be present (and contain no errors) when Flash is started for your tool to load properly.

Add the following code to the top of your script:

function configureTool() {
theTool = fl.tools.activeTool;
theTool.setToolName( "testtool" );
theTool.setIcon( "TestTool.png" );
theTool.setMenuString( "Test Tool" );
theTool.setToolTip( "Test Tool" );
theTool.setOptionsFile( "TestTool.xml" );
theTool.setPI( "shape" );
}

The configureTool function is triggered by Flash on start-up.  The first line grabs the active tool, which happens to be your tool while your configureTool function is executing. The stored variable is then used to establish all of the basic setup options for the tool. The name Flash uses internally is assigned using setToolName. The file name called in setIcon should match the PNG that you saved to your Tools directory. The setMenuString and setToolTip methods determine how the tool name is displayed in the Flash interface and Toolbar (on rollover).  The setOptionsFile points to the options file that you (optionally) saved. Lastly, the setPI method determines which settings are shown in the Properties panel (“PI” used to stand for Properties Inspector, the previous name of the Properties panel). In this case, the shape (stroke, fill, and color) options will be displayed, since the end goal is to draw a line on Stage.

Add this function to the end of your script:

function notifySettingsChanged() {
theTool = fl.tools.activeTool;
}

The notifySettingsChanged function will be triggered after the user has changed any of the tool settings (those established in the XML options file). This function allows you to update any variables before taking further action. For instance, suppose you wanted to use you own stroke width setting, separate from the Properties panel. You would store the default stroke width in a variable, and update the variable to match any new settings once the notifySettingsChanged function is called. Since you’re not adding any options for this tutorial, this function is essentially empty, but it’s good to have it available in case you want to add this functionality later.

Add the following code to your script:

function setCursor() {
fl.tools.setCursor( 0 );
}

The setCursor function is also automatically triggered by Flash. You then use the fl.tools.setCursor method to determine what type of cursor is displayed when you tool is in use. The options are as follows:

  • 0 = Plus cursor (+)
  • 1 = black arrow
  • 2 = white arrow
  • 3 = four-way arrow
  • 4 = two-way horizontal arrow
  • 5 = two-way vertical arrow
  • 6 = X
  • 7 = hand cursor

Add the activate function to be called when the user selects your tool:

function activate() {
var theTool = fl.tools.activeTool;
}

Consequently, you’ll also want to add the following deactivate function for later use:

function deactivate() {
}

This function is generally called when the user selects a different tool. You can use this function to shut off any event listeners or end any processes that do need to execute while the tool is inactive.

Add the following to the end of your script:

function mouseDown() {
fl.drawingLayer.beginDraw();
startPt = fl.tools.snapPoint( fl.tools.penDownLoc );
}

The mouseDown function will be triggered by, you guessed it, the user pressing the mouse button (while over the Stage area). The first line inside this function will activate the drawingLayer using the beginDraw method. The drawing layer is a temporary visual feedback system for the user. It helps to indicate what the tool will accomplish before the user releases the mouse button and commits to an action.

When you tool is complete, it will display a preview using the drawing layer, as shown in the image above. Additionally, the starting point is stored for later using in the mouseDown function. The snapPoint method is used to snap the location to the nearest geometric object, but this snapping can be omitted.

Add the following function to your script:

function mouseMove(mouseLoc) {
if (fl.tools.mouseIsDown) {
var pt1 = startPt;
var pt2 = fl.tools.snapPoint( mouseLoc );
fl.drawingLayer.beginFrame();
path = fl.drawingLayer.newPath();
path.addPoint(pt1.x, pt1.y);
path.addPoint(pt2.x, pt2.y);
fl.drawingLayer.drawPath(path);
fl.drawingLayer.endFrame();
}
}

The mouseMove function is also built-in, and rather self-explanatory. It receives an argument with the current location of the mouse. The next line checks if the mouse button is down (pressed), if not, you won’t want to draw anything for this tool. Inside that if check, the starting point is stored as a new variable, in case you want to manipulate it without altering the startPt variable, and the current location of the mouse is stored. The beginFrame method clears out and initializes the drawing layer for new data. A path is then created, and the two stored points are mapped to the path. The drawPath method renders that path onto the drawing layer (so that the user can see it). The endFrame method signals the end of any temporary drawing for the moment.

The mouseMove function is then called repeatedly as the user moves the mouse.

As an alternative to creating a path and adding points, you could use the moveTo and lineTo methods to generate the temporary line:

fl.drawingLayer.moveTo( pt1.x, pt1.y );
fl.drawingLayer.lineTo( pt2.x, pt2.y );

While these methods may be more familiar to you from using ActionScript, you’ll see in the next bit of code why you’ve created a Path object instead for this scenario.

Add this last function to your script:

function mouseUp() {
fl.drawingLayer.endDraw();
path.makeShape();
}

The endDraw method exits the drawing mode completely. Since you’ve created a path object already, you simply render the path (using the default stroke and fill settings) via the makeShape method.

You script is now complete!

Loading the New Tool

Make sure the files you’ve created are all in the Configuration/Tools directory and follow the steps below to access and use your tool in Flash.

  1. Restart Flash.
  2. Access the Customize Tools Panel dialog box, via Edit > Customize Tools panel (Windows), or Flash > Customize Tools panel (Mac).
  3. Locate Test Tool in the Available Tools menu at the left. The Current Selection menu at the right indicates the tools currently assigned to the selected location in the Tools panel at the far left. If you can’t find your tool in the list, you likely have an error in your script. Try debugging your script and restarting Flash.
  4. Browse through the tools to specify the a location, click on the tool in the image of the Tools panel, then click the >> Add >> button. I chose to add the new tool with the Line Tool.
  5. Click OK to save the tool settings.
  6. Create a new document, File > New… > ActionScript 3.0. Note: your tool with work the same regardless of which version of ActionScript you’re using.
  7. Select the Test Tool (from underneath the Line Tool, or wherever you added the Test Tool).
  8. Draw a line on Stage by pressing the mouse button in one location, dragging to another location, then releasing.

And there you have it!

Additional Tips

So far, you’ve run through the bare-bones of creating a simple tool, but there are many bells and whistles that you can add. In addition to creating a settings XML file, you might consider adding some of the functionality covered in this section.

For instance, inside you mouseMove function, you might want to constrain you line to 45-degree (or 30-degree) angles when the shift button is pressed (the way many other design tools do):

if (fl.tools.shiftIsDown){
//code constrain angle
}

You may also want to check for a minimum distance when drawing on Stage, so that it’s more difficult for the user to accidentally draw a 1-pixel long line (see the PolyStar tool for an example of this).

If you play around with the tool as is, it will work pretty well on the main Timeline, but it might produce some funny results inside of nested symbols. That’s a symbol instance often has a registration point that doesn’t match the registration point of the Stage. In order to fix this, use a function to transform your coordinates to the current viewMatrix, like so:

function transformPoint( pt,  mat ) {
var x = pt.x*mat.a + pt.y*mat.c + mat.tx;
var y = pt.x*mat.b + pt.y*mat.d + mat.ty;
pt.x = x;
pt.y = y;
return pt;
}

A sample call to the function might look like this:

var pt1 = transformPoint( startPt, fl.getDocumentDOM().viewMatrix);

Lastly, debugging. If you’re having trouble with your tool loading, try running the script by double-clicking on the JSFL file (or clicking the Run Script button in the Flash Script Editor). In most cases, if you have a syntax error in your script, it will be displayed in the Output panel, along with a line number.

Instead of restarting Flash every time you make a code update to your tool, you can simply run the following JSFL code in a new script:
fl.reloadTools();

I have this script saved as a command, and I add the following line to clear out any old errors in the Output panel:

fl.outputPanel.clear();

That does it for this tutorial. If you want to know more about building tools, check out Extending Flash MX 2004.

Deco tools

Deco tools were added in Flash CS4 and CS5. You can also create your own Deco tool by placing a JSX file in the Configuration/ProcScripts directory. Note that a JSX file is the type of JavaScript used for other Creative Suite applications (not JSFL). There is very little documentation on creating a Deco tool. Here are some links with more info (1, 2, 3). The best way to start is to copy one of the existing JSX files and modify the code. This may be a topic in a future post.


Lesson 7: Distributing to Others

One of the absolute coolest things about Flash extensions is that you can easily share them with others. This tutorial will show you how to create package that can be emailed or posted to a website. That package can then be downloaded by others and installed using Extension Manager.

Extension Manager

Extension Manager (EM) is a free application that is automatically installed when you install any of the Adobe Creative Suite applications, including Flash Professional. If you have Flash installed, you have EM installed, whether you knew it or not. You can install extensions using EM, as well as package them.

Packaging an Extension

When you package an extension with EM, all of your extension files are collected into a single file or package. That package can then be distributed. Double-clicking on the package will automatically launch EM and begin the (brief) installation process. Before packaging your extension, you’ll need to create an MXI descriptor file.

The MXI file

An MXI file is a special XML file that contains information about the extension (title, author, version, copyright, license agreement, which files it includes, where to install the files, etc.). Here’s sample text from an MXI file:

<?xml version="1.0" encoding="UTF-8"?>
<macromedia-extension
name="Sample Extension"
version="1.0.0"
type="command">
<author name="Your Name" />
<products>
<product name="Flash" version="7" primary="true" />
</products>
<description>
<![CDATA[
This extension does A and B.
]]>
</description>
<ui-access>
<![CDATA[
The command can be found in ‘Commands > Sample Extension’
]]>
</ui-access>
<license-agreement>
<![CDATA[
]]>
</license-agreement>
<files>
<file source="Sample Extension.jsfl" destination="$flash/Commands" />
</files>
</macromedia-extension>

I generally start from an existing MXI, and make any necessary changes. In the sample text above, you’ll (minimally) want to change the following items: the name and version attributes in the root tag, the name attribute in the author tag, the files tag(s) (and attributes), as well as the description and ui-access tag content. The version attribute in the product tag determines the oldest version of Flash in which your extension can be installed (7 = MX 2004, 8 = Flash 8, 9 = CS3, 10 = CS4, and so on).

The version you choose will depend heavily on which JSFL commands your extension uses. Note the Version heading at the top of the each page within the Extending Flash documentation; that will tell you the earliest version in which a particular object, method, or property is available. The ui-access tag is an area where you can provide instructions to the user on how to launch your extension. Both the ui-access and description will appear in EM once the extension has been installed (see the image at the top of this page). Note that both tags also contain CDATA wrappers. The CDATA tags allow the content inside to be interpreted as plain text instead of XML content.

The MXI file can be edited in a simple text editor like Notepad (Windows) or TextEdit (Mac). You should have a file tag (inside the files tags) for each file used in your extension. For example, a basic tool, like the one in the previous tutorial (above), would require at least 3 file tags:

<files>
<file source="TestTool.jsfl" destination="$flash/Tools" />
<file source="TestTool.png" destination="$flash/Tools" />
<file source="TestTool.xml" destination="$flash/Tools" />
</files>

The source attribute should reference the location of the source file relative to the location of the MXI file, so that EM knows where to look for the files when packaging. For this reason, it’s easiest to keep the MXI file in the same directory as your source files. Note the use of $flash in the destination attribute. This is a handy-dandy way to reference the location of the user’s Flash Configuration directory, regardless of their version or language. The version of EM that the user (or their system) opens will determine which version of Flash that receives your extension.

Generating the package

After you’ve edited your MXI file in a text editor, open it in EM. It will ask where you want to save your packaged file (usually I opt to keep it with my MXI and source files). Once you’ve given your file a name and location, EM will package all the files referenced in the files tag of the MXI file and include them in a single MXP (or ZXP for CS5-specific extensions) file. You can now post this extension to your website or the Adobe Exchange and share it with others. All potential users of your extension have to do (after downloading ) is double-click your MXP file and they’re off and running.

Where to Go From Here

That wraps up this series on creating Flash extensions. Thanks for reading!

You can always learn from comparing your JSFL to that of others on the web. If you’re interested in learning more JSFL, don’t forget about the excellent Extending Flash MX 2004 book.

Get updates from Ajar Productions

Sign up today and get the InDesign Split Text premium extension for free!

Unsubscribe at any time. Powered by ConvertKit

Join the Conversation

Leave a comment

Your email address will not be published. Required fields are marked *