How to add basic SCORM code to a Flash movie

Here’s a quick tutorial for adding basic SCORM functionality to an existing Flash file. This tutorial aims to demonstrate just how easy it can be to add SCORM functionality to an existing Flash movie.

In this tutorial, we’re going to keep things very simple; our SCORM code will only check the LMS for a prior completion, and if no completion is found, will set the course to complete at the appropriate point in the movie.

Here are the work files (ZIP, approx 3.5MB) if you’d like to add the code yourself while reading the tutorial. The zip file also contains the completed product.

Important notes:

  • This tutorial uses ActionScript 3 and SCORM 1.2, but the same principles apply for ActionScript 2 and SCORM 2004
  • The FLA files supplied in the ZIP download were created using Flash CS3; you will need Flash CS3 to open and manipulate the files. I will not be supplying any FLAs compatible with older versions of Flash (sorry)

The steps:

  1. Add the SCORM wrapper to the head of the HTML file
  2. Import the SCORM class into the Flash file
  3. Add some variables and create a SCORM instance
  4. Initialize the SCORM connection and check for prior course completion
  5. Add the SCORM completion code
  6. Publish the FLA
  7. Modify the manifest

Step one: Add the SCORM wrapper to the head of the HTML file

Open the index.html file in your HTML editor of choice. Note that we’re NOT using the standard HTML file produced by Flash’s publishing feature. It’s my opinion that the HTML produced by Flash is ugly, bloated, and doesn’t support standards well enough. We’ll roll our own using stripped-down markup, external CSS file for simple styling, and SWFObject for embedding (feel free to use another embedding method if you prefer).

Once you’ve opened the HTML file, add a link to the SCORM wrapper script in the document’s <head>:

<script type="text/javascript" src="SCORM_API_wrapper_v1.1.5.js"></script>

Your HTML file should look something like this:

Add a link to the wrapper JavaScript file in your HTML

Some developers may want to specify the targeted SCORM version using JavaScript (this can help avoid problems with some LMSs). To do so, simply add one more line of code to the head of the document after the SCORM_API_wrapper_v1.1.5.js link:

<script type="text/javascript">pipwerks.SCORM.version = "1.2";</script>

Believe it or not, that’s the only change that needs to be made to the HTML file! Save and close the file.

Step two: Import the SCORM class into the Flash file

Open the planets.fla file in Flash. Add the SCORM class to the Flash file using an import statement in Frame 1’s frame script:

import fl.controls.Button;
import flash.events.MouseEvent;
import pipwerks.SCORM;

The file should look something like this:

Add the import statement

This is a good time to test the FLA to ensure you have the correct file path for the SCORM class (it should be in a folder named pipwerks; this pipwerks folder should be located in the same folder as the FLA file). To test the FLA, go to Control > Test Movie. If the movie plays without errors, your file paths are ok.

Step three: Add some variables and create a SCORM instance

Declare the following variables in the first frame of your Flash file, after the import statements:

import fl.controls.Button;
import flash.events.MouseEvent;
import pipwerks.SCORM;

var lessonStatus:String;
var lmsConnected:Boolean;
var success:Boolean;

Next, you’ll need to create a new SCORM instance using the pipwerks.SCORM class. You can create a new SCORM object using the following code:

import fl.controls.Button;
import flash.events.MouseEvent;
import pipwerks.SCORM;

var lessonStatus:String;
var lmsConnected:Boolean;
var success:Boolean;
var scorm:SCORM = new SCORM();

Step four: Initialize the SCORM connection and check for prior course completion

Add a scorm.connect() call, which returns a boolean indicating whether it succeeded or not.

import fl.controls.Button;
import flash.events.MouseEvent;
import pipwerks.SCORM;

var lessonStatus:String;
var lmsConnected:Boolean;
var success:Boolean;
var scorm:SCORM = new SCORM();

lmsConnected = scorm.connect();

If the connection was successful, lmsConnected will evaluate to true. That means we can start requesting data from the LMS. Start by requesting the current completion status.

A few things to note: If the course status is “completed” or “passed”, we won’t need to keep the LMS connection active — we need to be careful not to overwrite the previous completion by accident. So, if the course has already been completed, we’ll just disconnect and call it a day.

If the completion status isn’t “completed” or “passed”, we’ll need to explicitly set the course to “incomplete”.

import fl.controls.Button;
import flash.events.MouseEvent;
import pipwerks.SCORM;

var lessonStatus:String;
var lmsConnected:Boolean;
var success:Boolean;
var scorm:SCORM = new SCORM();

lmsConnected = scorm.connect();

if(lmsConnected){

   lessonStatus = scorm.get(”cmi.core.lesson_status”);

   if(lessonStatus == “completed”){

      //Course has already been completed.
      scorm.disconnect();

   } else {

      //Must tell LMS course has not been completed yet.
      success = scorm.set(”cmi.core.lesson_status”, “incomplete”);

   }

} else {

   trace(”Could not connect to LMS.”);

}

Step five: Add the SCORM completion code

Find the appropriate place in your movie to call the completion code. In this example, we’ll call the completion code when all four planets have been visited. There is already a ‘check’ for this condition in the function resetPlanets, so we can just add the code there.

function resetPlanets():void {

if(visitedMercury && visitedVenus && visitedEarth && visitedMars){

   success = scorm.set(”cmi.core.lesson_status”, “completed”);
   scorm.disconnect();
   lmsConnected = false;

   gotoAndPlay(”end”);

} else {

[ ... ]

Step six: Publish the FLA

Publish the FLA. Be sure to turn OFF the “HTML” option since we’re using our own HTML file. You should also ensure the target Flash version is Flash 9, since the “Planets” movie uses ActionScript 3 and a few filters that are only supported by Flash 9+.

Save and close the FLA.

Step seven: Modify the manifest

All SCORM-based courses require a manifest file (imsmanifest.xml) that contains important metadata about the course. For our example, we’ll simply grab an existing imsmanifest.xml file and update it to match our course.

  1. Open the imsmanifest.xml file
  2. Change the identifier attribute of the manifest element (at the top of the file) to something suitable for this course (no spaces): identifier=”MyPlanetsCourse”
  3. Find the organizations element (and organization child element) starting at line 15. Change the “default” and “identifier” attributes to something suitable for your organization. I’ll use “pipwerks”. Be sure to avoid spaces and illegal characters, such as punctuation (other than the underscore _)
  4. Find the two title elements, starting at line 17. Change both of them to something suitable for your course. For this example, I’ll change them both to “Planets!”
  5. You’ll need to list the files used by this course in the resource node. For this example, we need to make sure “href” is set to “index.html”, then we need to list the other files using file elements:
    <resource identifier="SCO_Resource_01" type="webcontent" adlcp:scormtype="sco" href="index.html">
       <file href="index.html"/>
       <file href="planets.swf"/>
       <file href="SCORM_API_wrapper_v1.1.5.js"/>
       <file href="swfobject.js"/>
    </resource>
  6. Save and close the imsmanifest file

Wrap-up

That’s all there is to it! As you can see, adding simple SCORM code is much easier than many people realize. It may seem daunting at first, but in reality all we’ve done here is:

  • Added one line of code to the HTML file
  • Added 19 very short lines of code to the FLA file
  • Edited a few IDs and file links in the imsmanifest.xml file

In my opinion, SCORM only becomes difficult if you try and use it to handle a course’s sequencing and navigation, which even SCORM experts are hesitant to do (it’s considered a “broken” feature by many key figures in the industry).

The bottom line is that if your existing FLA is self-sufficient before SCORM comes into the picture — it’s already set up to handle its own navigation internally via ActionScript and already has a mechanism for determining whether the user has ‘finished’ the movie, be it completing an activity or simply reaching the last frame of the SWF — SCORM becomes more of drop-in item, almost an afterthought. It doesn’t need to be a nightmare that scares developers away.

It’s my hope that my SCORM wrapper and ActionScript classes encourage more people to embrace SCORM as a simple, easy way to ensure their course(s) use standards and work in almost any LMS.

If there’s enough demand, I may create a more extensive demonstration that uses more SCORM features such as suspend_data and lesson_location. I’m open to suggestions.

As always, feedback is appreciated. :)

18 Responses to “How to add basic SCORM code to a Flash movie”

  1. wendy phillips

    This is terrific, thank you so much for sharing. What would be different if using AS2 instead of AS3?

  2. Philip Hutchison

    As far as the SCORM code is concerned, the only difference between ActionScript 2 and ActionScript 3 is which class file gets imported; once the correct class file is imported, the SCORM syntax used in your code will be the same.

  3. Matt

    I’m trying to get this to work with our LCMS tool, and I keep getting an error where your API isn’t found. The pipwerks.SCORM.isAvailable isn’t being found.

    Any ideas on why this is happening?

  4. Philip Hutchison

    That means the ActionScript can’t find the JavaScript wrapper. Double-check your HTML file to ensure the wrapper is present.

  5. Matt

    nevermind. Saba’s desktop preview tool is the issue.

  6. Tom D

    Wow, I really like what you’ve done here. Question: Let’s say a user has to quit before clicking on all the planets. What is the best method to store which planets have been clicked for the next session?

  7. Philip Hutchison

    @Tom

    Thanks. Most people use suspend_data to handle that; it’s read/write and has roughly the same capacity/functionality as a JavaScript cookie.

    If you store the clicks in an array, such as var clicked:Array = [ 1,1,1,0 ], you could send the ‘clicked’ data to the LMS using suspend_data:

    //Create and populate array
    var clicked:Array = [ 1,1,1,0 ];
    
    //Send data to LMS
    var success:Boolean = scorm.set(”cmi.suspend_data”, clicked.toString());
    
    if(success){
       trace(”data sent successfully”);
    }
    
    //Retrieve data from LMS
    var returned_data:String = scorm.get(”cmi.suspend_data”);
    clicked = returned_data.split(”,”);
    

    Note that suspend_data only takes a single string; if you want to store the clicked array plus extra data (something the LMS/SCORM doesn’t handle for you, such as the user’s Flash Player version), you’ll need to figure out a way to convert it all to a string before sending it to suspend_data. JSON works well for this.

    I’m considering making a more advanced version of the “Planets” example, using suspend_data to track which planets have been clicked, and to bookmark the ‘last viewed’ spot in the movie using lesson_location.

    I probably won’t get around to it for a while, though, since I only work on this stuff in my spare time. :)

  8. Tom D

    Thanks for the response. I was thinking of using suspend_data, but some of the swf’s I load were created in Captivate which I thought uses suspend_data for tracking slide views. If I pass this value before exiting, I shouldn’t have a problem.

    Since my course is non-linear, with JSON I could store the name:value pairs and I wouldn’t have to worry about getting the order correct in the array.

    Thank you for posting this. If I see you at an eLearning Conference, I’m definately buying you a beer.

  9. Philip Hutchison

    Captivate does use suspend_data for its own internal navigation/bookmarking, but only in limited circumstances:

    1. when the Captivate SWF is published with SCORM turned on in the publishing options, and
    2. when the Captivate SWF is viewed via the Captivate-generated HTML file

    If the Captivate SWF wasn’t published with SCORM tracking enabled, it can’t make any SCORM calls.

    Even if the Captivate SWF was published with SCORM tracking enabled, if you’ve taken the Captivate SWF out of the Captivate-generated HTML file, the Captivate file’s SCORM calls won’t work because they won’t be able to locate the corresponding JavaScript functions (and LMS API) in the HTML file.

    (Unless you copy all of the SCORM-related code from the Captivate HTML/JS files to your own project, which wouldn’t be a very smart thing to do.)

    Plus Captivate currently uses LocalConnection with a proxy SWF to make SCORM calls, while my SCORM ActionScript classes use ExternalInterface, so no conflicts there.

    Besides, when you load a Captivate SWF into your own Flash SWF, it automatically breaks Captivate’s built-in SCORM handling. Therefore you should be able to import Captivate SWFs into your Flash SWF and not have them affect your Flash-based SCORM calls at all.

    RE: Beer… mmm… :D

  10. Steve

    Great work!

    I’ve implemeted this and got it working great on Reload Scorm Player, SCORM TestTrack (tested all different ways of launching) and Moodle.

    Has anyone had any experience with this working on Plateau LMS?

    Many thanks,

    Steve

  11. Philip Hutchison

    @Steve

    Great, thanks for sharing!

    (and no, unfortunately I don’t have any access to Plateau)

  12. David Wirth

    Thanks for the awesome post. IT is great when experts share their expertise.

    I wanted to let folks know that The Academic ADL Co-Lab has been working with Flash and SCORM for a while and have developed a simple tool that is similar in functionality to what is described above. It is called LibSCORM.

    LibSCORM has an HTML and Flash version. You can read about it and download it from the following Website http://academiccolab.org/libscorm

    Our developers will look at the code you have supplied here to see if there might be some additional functionality we can add to LibSCORM.

  13. Philip Hutchison

    @David

    Thanks for the comment.

    Joe Nelson contacted me a few weeks back and told me about LibSCORM (I’m embarrassed to say I hadn’t heard of it before then). I think LibSCORM is an interesting product.

    What’s important to understand is that LibSCORM is designed to do a lot more than my wrapper and AS classes, and therefore is much more complex than my offerings. My wrapper and AS classes were designed solely to provide a simple, best-practices-compliant method for adding SCORM code to your own course system; LibSCORM aims to provide an entire course framework including navigation and data persistence.

    I think it’s safe to say LibSCORM is not a competitor to what I’m offering here, and I’d even recommend that people check it out if they’re looking for a starting point for building their own (SCORM 2004-only) custom course system. But if they already have a course system and just want to SCORM-ify it, I’d say grab my wrapper and have a go at it. :)

  14. Mark Butler

    This is fantastic! It’s addressed every issue I had with telling the LMS whether the user finished or not, and related server-side problems. Sadly, it created a new problem. Once my “Master” swf loads a portion of the lesson, it’ll play 15-20 frames and stop. Nothing I try seems to work. I can’t get my loadMovie to play! Please share your ultimate wisdom and tell me why this is most likely happening.

    The set-up is, I have a master swf that’s say, 30 frames long, each frame loads a new swf into a blank MC, they vary as to what is contained. Drag and drop, XML driven exercises , or just text scrolling on screen. It doesn’t matter what is loading, they hit the point where the audio would start and freeze. I don’t know if it’s because the preloader is being skipped, or it just doesn’t like audio, or what.

  15. Philip Hutchison

    @Mark

    The SCORM classes are independent of loadmovie and all other AS components/classes (SCORM.as doesn’t extend anything, and only uses ExternalInterface). It shouldn’t have any effect on your loaded SWFs.

    Without seeing your FLA/SWFs, I can’t really give you any specific advice. If you’d like to share links and perhaps walk through the code, please post this issue in the elearning development forum and we’ll go from there.

  16. Mark Butler

    I fixed the problem I posted about before (that’s by the by). However, I’ve just been told that, now that everything is working perfectly we need to add another function. We need the user to be able to pickup where they left off after they prematurely exit a course. It’s not working now, and I don’t have a single clue as to how to do it. I’m assuming that it’s a variable involving the APIwrapper.js. So, will there need to be some kind of code added on every frame that the next lesson in a course starts?

  17. Philip Hutchison

    Hi Mark

    Please use the forum for this kind of inquiry.

    Short answer:
    You can use SCORM 1.2’s “cmi.core.lesson_location” for storing bookmark data. Please read the ADL’s documentation.

    To get and set the bookmark data:
    scorm.get(”cmi.core.lesson_location”);
    scorm.set(”cmi.core.lesson_location”, “myBookmarkInStringFormat”);

    Regarding using this data for jumping around in the course, it’s up to the course developer to configure their ActionScript to set/get/use the bookmark data at appropriate times.

  18. Static on WAQ177 » pipwerks.com » Blog Archive » How to add basic SCORM code to a Flash movie

    [...] Phillip has a nice tutorial for implementing a quick and basic solution for scorm communication to a flash asset. There are also some nice assets up on his site if you want to delve deeper. [From pipwerks.com » Blog Archive » How to add basic SCORM code to a Flash movie] [...]

Leave a Reply

Use my LAST NAME as the code. It can be found in the page footer. Be careful not to misspell it.

Comment moderation is in use. Please do not submit your comment twice — it will appear shortly.

Comments for this post will be closed on 26 June 2008.