Customizing SCORM Manifests in Captivate and Articulate Presenter

Someone recently asked me if it was possible to customize Captivate’s SCORM manifest to reduce the need for manual editing after publishing. In her case, the manifest needed to be edited to include SumTotal TotalLMS’s custom SCORM extensions.  The answer is yes. Here’s how.

Find the Captivate files

Captivate’s publishing files are located at:

C:\Program Files\Adobe\Adobe Captivate 4\Templates\Publish

Make your edits

Find the manifest files (manifest.xml for SCORM 1.2 and manifest2004.xml for SCORM 2004), then make your edits.

If you’re adding custom SCORM extensions such as SumTotal’s c2l_cp extensions, don’t forget to include the supporting XSD files. If you’re using SCORM 2004 you can drop the extra XSD file(s) into the “Manifest2004” folder. If you’re publishing to SCORM 1.2, you’ll need to manually add the custom XSD file to your published files.

Rinse, repeat

You’ll need to repeat the process for every computer in your office that has Captivate installed. Otherwise someone on a different computer may inadvertently publish the Captivate project using the factory publishing templates.

What about Articulate?

You can do the same thing with Articulate Presenter. Their publishing templates are located here:

C:\Program Files\Articulate\Presenter\players\

Dear Apple and Adobe


Update: Steve Jobs Responds! Well, not to my letter directly, but it hits on the major points and is a well-written explanation of Apple’s position.

Dear Apple and Adobe

I’m a long-time customer and have spent more money on your products than I have on just about any other aspect of my life. I’ve spent more money on your products than I’ve spent on my healthcare, vacations, kitchen appliances, children’s school supplies, or home entertainment system.

In return, you’ve increasingly shown a disregard for my needs and concerns, and have acted in ways that demonstrate all you want from me is my money.

For example, both of you have constantly forced me (or at a minimum pressured me) to buy updates to products I already paid for. For years I went along with it because I bought into the sales hype and assumed these updates would somehow make my life better.  In most cases, they did not.

Adobe, your constant tinkering with the Creative Suite has brought a few nifty tools to the world, but these new tools will not get me to overlook the incredible bloat you’ve unleashed on my computers — almost 6GB of program files on my Windows PC at work, and over 7GB of app files on my Mac at home. Your applications feel more unstable with every release, and your UI feels slow and unresponsive despite the extra RAM and other hardware upgrades on my machines. Some of the biggest security holes on my computers are due to your Acrobat software — the very same Acrobat software I’ve learned to hate because of how bloated, complicated, and unfriendly it has become. It feels like it gets worse with each release.

Apple, your innovation is refreshing. Adobe could learn a thing or two by examining your software: increased productivity through reduced feature sets and cleaner UI. Simple is usually best. However, despite your continued excellence in design, your behavior is repulsive. You’ve consistently screwed your early adoptors via your pricing schemes and forced millions of Americans to use a phone network they detest. (Why? Because AT&T was willing to give you a bigger cut of the revenue?) Worst of all, the totalitarianism displayed in your latest iPhone developer agreement is breathtaking. It appears your goal is to piss off everyone, even your staunchest allies… like Adobe.

Apple and Adobe, you used to play well together. You both benefited from your long-term relationship and grew into very large, very successful companies. I sincerely doubt either of you would have survived the 1990s intact if it weren’t for your partnership. Desktop publishing was the Mac’s forte and the one thing that kept it afloat when the buzzards were circling. And who provided the most popular DTP software? Adobe (and the companies Adobe acquired, like Aldus and Macromedia).

Adobe, I know you’re mad because Apple won’t let you put your Flash technology on the new iPhone platform (iPhone, iPod, iPad). Honestly, if I were controlling a platform, I would have major concerns, too. As I mentioned earlier, your track record for software quality seems to be in a steady decline. Your products have become infamous for security holes, bloat, and crashing. It didn’t used to be that way. Somewhere along the line you dropped the ball, and now it’s coming back to bite you. The good news is that it isn’t too late for you to reign things in and regain control of your software. Stop trying to please everyone by adding every conceivable feature under the sun, and really focus on the most important elements. Drop the cruft. Clean the cupboards. Get that lint out of your bellybutton. Once your software is respectable again, you’ll be in a much stronger position to complain about Apple.

Apple, I don’t know what happened to you. You went from being a popular underdog to being the class bully. You’re in danger of becoming as popular as Microsoft in the European court system. From where I sit, your biggest mistake has been the idea that you can take over the world, one industry at a time. Of course, many companies are aggressive and set big goals for themselves, but they don’t stab their partners in the back as quickly and viciously as you seem to do. Your hubris and eagerness to expand into your partners’ markets is going to be your downfall. People have liked you because of your design sensibilities and because you were the hip underdog. You are no longer the hip underdog, and with time, other companies will create products that will be (almost) as stylish but also cheaper and with equivalent or greater capabilities.

The bottom line is that neither of you are choir boys, and I’m fed up with your bickering.

Adobe, stop playing the sympathy card. It’s a complete turn-off because I know how crappy your software can be. Granted, it’s unfortunate that so many people depend on Flash and Flash doesn’t work on the iPhone platform, but Flash is not a web standard. For all its shortcomings, the iPhone platform has one excellent quality: a top-notch HTML5 browser. Standardistas have been warning people not to go all-in with Flash for years, and now we see why. If it isn’t part of a standard, it will not be incorporated into some products. It’s the vendor’s choice. Simple as that.

Apple, stop trying to take over the world. We’ve seen what happens to other companies who try it, and it never looks pretty. Focus on your core values and let your partners do their thing without stepping on their toes.

Oh, and ditch AT&T already, will ya?



What feature is missing from your e-learning development tool?

I have some simple questions I’d love to get feedback on.

I’m curious about what people are looking for in their e-learning authoring tools, specifically:

  1. What feature is your current tool missing that you would love to see implemented? Support for team collaboration? Support for themes or custom CSS styling? Support for language localization? A beer dispenser? Etc.
  2. What feature does someone else’s tool have that you’re jealous of?

For me? I wish the most popular tools (Captivate, Articulate, Lectora, etc.) would output cleaner HTML and JavaScript. I also wish there was less reliance on Flash and PowerPoint. But if you read my blog regularly, you probably already knew that!

Please post your opinion in the comments below, and please ask others to give their 2 cents. (You can also reply via twitter if you prefer)

I’m really looking forward to your comments. Thanks!

Not so crazy about Moodle? Try Chamilo

Moodle, Moodle, Moodle. It’s popular. It has helped many people quickly set up their company’s web-based training. But truth be told, it doesn’t really do much for me. I have never found it fun or sexy or even intuitive. I imagine many people feel that way. So what’s Moodle got going for it, then? It’s FREE, it’s easy to set up, and there’s a thriving development community behind it that can help you when you get stuck.

Well, in case you didn’t know, there’s another game in town by the name of Dokeos. It’s not as well known in North America, but it’s huge in other countries. Dokeos mirrors Moodle in many ways: it’s easy to set up, uses the same technology (PHP/MySQL), is open-source, and has a very large developer community. Dokeos has a much different look and feel than Moodle, which I find a little cleaner and easier to use. (Disclaimer: I test drove Dokeos over a year ago and haven’t tried the latest versions)

But there’s trouble brewing in Dokeosland. Apparently there were significant differences of opinion regarding the future of Dokeos, prompting Yannick Warnier (the lead developer) as well as the entire development staff to leave the Dokeos project [link no longer available]. While this is probably very disconcerting to Dokeos users, Yannick and the former Dokeos developers are not leaving anyone hanging… they’ve forked Dokeos’ open-source code and used it to create a new LMS named Chamilo. It’s basically Dokeos under-the-hood, but with newer features and a new direction. They’re dedicated to the notion of open-source software, and are ensuring Chamilo stays open.

I highly recommend giving Chamilo a spin. I’m looking forward to trying it myself.

Side note: if you’re looking for more alternatives to Moodle, you can also try Ilias. It’s pretty nice, too.

Fear of sharing, fear of failing

Janet Clarey posted a link to a great blog post by Rajesh Setty entitled Why some smart people are reluctant to share? Setty’s insights resound with me, not because I think I’m smart — quite the opposite, actually — but because the more I learn, the more I’m aware of my limitations.

Setty tried to determine why “smart people” are often reluctant to share their knowledge with others. His conclusion was:

Smart people want to give their best and as they learn more, they learn that they need to learn a lot more before they start sharing. They learn some more and they learn they need to learn some more. What they forget is that most of the expertise that they already have is either becoming “obvious” to them or better yet, going into their “background thinking.”

I agree with the points in Setty’s post completely, except in I’d substitute the word “experienced” for “smart.”

Setty’s line “Smart people want to give their best” seems to be something of a passing thought in his post. I’d like to give it more attention, because I believe conscientious experienced folks have a fear of giving bad advice.

Zeldman had it right when he said “If your old work doesn’t shame you, you’re not growing.” Experienced people look back at their younger, inexperienced self and either chuckle at their own gumption or get rosy-cheeked from embarrassment. I’m more of the rosy-cheeked guy. My old work shames me all the time, and it often causes me to hesitate when sharing my work or giving advice to others.

This may sound funny to some of you… anyone who follows this blog probably knows I spend a lot of time doling out technical advice via places like the SWFObject and eLearning Technology and Development Google Groups.  The truth is, I question myself in almost each and every post I write. Why? Because I’m experienced enough to know that maybe I shouldn’t be so quick and cocky with an answer. Maybe there’s a different solution I haven’t heard of. To paraphrase Setty, maybe I need to learn more first.

So why do I even try to give advice if I have a fear of giving bad advice? Because I want to learn more. I often find that helping others is the best way to teach myself. I’ve learned a ton through helping others, and find it rewarding in many ways. Except when I’m wrong, and then it plain sucks.

Best Practices in E-Learning

Someone recently posted a blog entry ranting about the use of the term “best practices” in our industry. I understand the frustration with thoughtless pronouncements about best practices, especially coming from people who may not know any better; it will often sound a lot like how mom used to say “eat this, it’s good for you” without really knowing whether it’s true. However, there is a big difference between best practices in terms of learning theory — something that’s difficult to quantify/prove — and technology.

A friend of mine, upon completing his MA in psychology, joked that his degree is the only one you can get where you can’t prove a thing that you’re taught. Learning theory is a form of psychology, and as such, you are guaranteed to run into a gazillion different opinions on how learning occurs: behaviorism, constructivism, cognitivism, yadda yadda yadda. Likewise, you will hear many opinions on what development models to follow (ADDIE vs agile vs something-or-other), evaluation methodology, and perhaps edge-case debates such as centralized learning structures versus de-centralized learning structures (social media peeps, I’m looking at you).

I guarantee these conversations will involve lots of name-dropping and liberal use of the term “best practice.” In these situations, I agree that there is no single answer to ANY of these issues, and context will be king.

Most technical issues, on the other hand, most certainly DO have best practices, and for good reason.

For starters, accessibility is a best practice. Why? Well, because it’s the right thing to do. No one should be denied an opportunity to learn simply because their ears or eyes or arms don’t work like yours do. Establishing a baseline level of accessibility is fairly easy to do, regardless of the size of your budget or your time constraints. For example:

  • For the hearing impaired: Text transcriptions and/or closed captioning for videos and Flash animations are as easy to set up as ever. Free/cheap video players like the Flash video component, the JW Player, and Flowplayer all support multiple captioning standards and make it easy to add captioning to a video. Rapid e-learning development tools such as Articulate Presenter and Adobe Captivate allow you to add captions or notes to your SWFs. (Side note: the text transcriptions for TED talks are an excellent example of what can be accomplished with just a little extra effort.)
  • For the visually impaired: If the content of your course is provided in a text format such as HTML, screen readers can read the text to the end user. What does this require of you? Well, if you use standard HTML, not much… just a little extra care in your layout and alternate text. If you embed an image, video, or animation, provide fallback text that describes the image or what happens in the video/animation. SWFObject (a free system for embedding SWF files in HTML documents) makes this easy to do.
    Similarly, Adobe has been working hard to make Flash Player and Adobe Reader more accessible to major screen readers. What do you have to configure to make it work? Nothing so far.
  • For those who can’t use a computer mouse: Thanks to initiatives like WAI-ARIA and companies like Adobe who are actively building keyboard support into their products, many script-based interactions (such as course navigation, quiz questions, and other activities) can be scripted to work without a mouse. Alternate input devices are often mapped to the keyboard input; if your course can be completed using a keyboard, you’re golden.
  • For the color blind: Accessibility can often be improved simply by adding text labels to color-coded objects and not relying on color alone.

I could go on for a while, but the point is that accessibility is definitely a best practice. It isn’t hard, and it certainly isn’t expensive to make a course accessible. It’s also the law if you receive any Federal funding.

There are definitely other technical best practices for e-learning:

  • SCORM: Technically not a standard but rather a collection of standards, SCORM is a best practice because it ensures your course will work on pretty much every major LMS (if you don’t like SCORM, AICC is equally valid). How can I say with confidence that SCORM is a best practice? Because in the bad old days before SCORM, developers had to spend weeks re-coding courses to work with each LMS’s proprietary code base. Once SCORM was widely adopted, the issue largely went away. No one wants to go back to the bad old days.
  • Valid HTML and CSS: If you write HTML and CSS, ensuring they validate means you know your pages will work in every major browser. We learned this lesson in the Netscape/Internet Explorer wars. Best practices on the web are still evolving; for example, sometimes it’s ok to write CSS that won’t validate if you know the repercussions and your code fails gracefully in older browsers. The best practice is simply that your pages work in most, if not all, browsers.
  • Don’t use proprietary code: See above. If your course uses ActiveX, which is only supported in Internet Explorer, your course won’t work in any other browsers. Almost anything implemented with ActiveX can be implemented using other non-proprietary methods. Again, the best practice is to ensure your pages work in most, if not all, browsers.
  • Follow sensible coding conventions: Well-written code that follows documented — and very well-reasoned — code conventions means your code will likely contain less errors, will be easier to update if the need arises, and will be more future-proof, avoiding expensive bugs like the Y2K bug, which could have been prevented with a bit of foresight. A great example of this type of code convention is Douglas Crockford’s JavaScript: The Good Parts.

There are definitely times when people throw around the phrase “best practice” and are simply talking out of their butts. “Never use yellow.” “Never use clip art.” “Never hire a penguin.” “Never let the learner do X.” “Always make the user do Y.” “Always use ___ format.” “Always use ___ pedagogy.”


Just remember that best practices DO exist, but not in every circumstance. And unless you want the evil eye from me and my compadres, remember to never use the phrase “best practice” unless you can back it up with evidence and sound reasoning.

Post script: I’ve noticed this bandying of best practices usually occurs when someone is trying to establish their expertise or exert control on a project, frequently in front of management-types. This is the same sort of thing Machiavelli did when he wrote The Prince, so why not treat them as Machiavelli would and … well, I guess another best practice is to know when to shut up, so I’ll stop here.

Ideas wanted for new SCORM wrappers

As you may have read in previous posts or tweets, I’m working on a new SCORM 2004 wrapper for both JavaScript and ActionScript that will contain advanced functionality and improved shortcuts.

For instance, I’m trying to write an easier way to work with the cmi.interactions model, and also trying to add more error-checking that will look for gotchas such as exceeding the length limit of suspend_data.

I’m looking for good ideas. How do you handle your cmi.interactions? What kind of code shortcuts would you like to see? How can working with SCORM be made easier? I’d love to hear your ideas, just post them as comments below or send them to me on twitter.

This project — just like my previous wrappers — will be freeware, either MIT license or GNU license, so no worries about me running off and selling your ideas!

(FYI: for now I’m focusing on SCORM 2004 — SCORM 1.2 should be retired — but depending on how things work out I might add backwards-compatibility for SCORM 1.2.)

CaptivateController updated

Bug fixes!

The CaptivateController has been updated to fix the gotoSlideAndPlay and gotoSlideAndStop bugs.

Also, gotoSlideAndPlay and gotoSlideAndStop have been edited to use standard numbering in place of zero-based numbering. This means when you want to jump to slide 4, you use mycontroller.gotoSlideAndPlay(4) instead of mycontroller.gotoSlideAndPlay(3).

I had a number of requests for adding a ‘toggle table of contents’ method, but unfortunately it won’t be added at this time. It turns out that while you can toggle the TOC using the controller, it breaks the Captivate movie’s playbar — the playbar loses awareness of whether the TOC is visible or not. This is therefore not a feature I’m prepared to add. You can still toggle the TOC yourself using KCWebPlaza’s workaround (listed in the comments).

I will continue to monitor the TOC possibilities and would be happy to hear suggestions.

View the original post, download links and (somewhat spartan) documentation here.

Thanks to everyone who contacted me about the bugs.

Introducing the CaptivateController

This post has been updated to reflect changes to the CaptivateController since its initial release

It took me much much longer than I anticipated, but I am happy to announce the new CaptivateController utility. The CaptivateController is a JavaScript utility that helps you control Captivate SWFs as well as get/set Captivate variable values using simple JavaScript commands. For example:

//Assuming your SWF is embedded using the ID "Captivate"
var myMovie = CaptivateController("Captivate");
myMovie.pause(); //Pauses the Captivate SWF
var author_name = myMovie.get("cpInfoAuthor"); //Queries variables
myMovie.set("myCustomeCaptivateVariable", "myValue"); //Sets variable values

For those of you familiar with the pipwerks.captivate.control utility, this CaptivateController is not a simple rehash of the original; it is a complete re-write that adds a number of extra features, including:

  • Support for Captivate 2, Captivate 3, Captivate 4, and Captivate 5.x files
  • Auto-detection for skins; you can write the exact same JavaScript whether your SWF uses a skin or not
  • New query methods, including the ability to query a user-defined variable in a Captivate 4+ file
  • New set method for setting the value of a variable in Captivate 4+

The CaptivateController is intended to make your life easier — it deals with a number of inconsistencies so you don’t have to, including inconsistencies between Captivate 2/3 SWFs and Captivate 4 SWFs (there was a major shift under the hood, going from using GetVariable to using Captivate 4’s proprietary cpGetValue via ExternalInterface). It also handles inconsistencies with Flash Player in different browsers. Safari and Internet Explorer each provided their own small challenges.

There are still some inconsistencies that cannot be solved using JavaScript; for instance, Captivate 4 SWFs published using ActionScript 3 provide a richer set of system variables than Captivate 4 files published using ActionScript 2. I expected to have the same access to all system variables regardless of ActionScript version, but alas it was not meant to be. Captivate 5+ provides many m ore system variables than previous versions of Captivate.

Can check out the Automated Test Suite, which illustrates which variables are available for each flavor of Captivate SWF (has not been updated for Captivate 5+).


The CaptivateController weighs in at about 6kb (compressed) and has been successfully tested in Chrome (Mac/Windows), Firefox (Mac/Windows), Safari (Mac), and Internet Explorer (Windows).

Quickie documentation

I haven’t had the time to do a full write-up of the CaptivateController API, but the following information should be enough to get you started.

Don’t forget to check out the test suite. A list of Captivate Variables can be found on the Automated Test Suite, a list of Captivate 2-4 variables can be found here, and new CP5+ variables can be found here.

“Control” methods available in the API

Method Notes
gotoSlideAndPlay(slidenumber) Uses 1-based numbering: gotoSlideAndPlay(3) will take you to Slide 3. If you prefer Captivate’s built in zero-based numbering, use useZeroIndex(true) to change the numbering to a zero-based index.
gotoSlideAndStop(slidenumber) Uses 1-based numbering: gotoSlideAndStop(3) will take you to Slide 3. If you prefer Captivate’s built in zero-based numbering, use useZeroIndex(true) to change the numbering to a zero-based index.
  • Takes number, 0-100
  • Returns current volume level, 0-100
  • Volume only works in CP4+
hidePlaybar() Doesn’t seem to work consistently via JavaScript
showPlaybar() Doesn’t seem to work consistently via JavaScript
  • Enables/disables user interaction on TOC
  • Only works in CP4+
  • Enables/disables user interaction on TOC
  • Only works in CP4+
useZeroIndex(boolean) Specifies whether gotoSlideAndPlay and gotoSlideAndStop should use zero-based numbering (0 = slide 1). Set to true to use zero-based numbering. The default is false. Warning: This should only be invoked if you wish to use a zero-based index for gotoSlideAndPlay and gotoSlideAndStop.


//Assuming your SWF is embedded using the ID "Captivate"
var myMovie = CaptivateController("Captivate");
myMovie.pause(); //Pauses the Captivate SWF
myMovie.mute(); //Mutes the Captivate SWF

Commands can also be chained together, like so:

var myMovie = CaptivateController("Captivate");
myMovie.pause().mute(); //Pauses then mutes Captivate SWF

Query methods

The primary query technique is to use .query(“captivate_variable_name”). For example,

var myMovie = CaptivateController("Captivate");
//Retrieves the author's name, if available
var author = myMovie.query("cpInfoAuthor");

You can also use this method to query user-defined variables:

var myMovie = CaptivateController("Captivate");

//Retrieves the variable My_custom_variable_name, if available
var myUserDefinedvariable = myMovie.query("My_custom_variable_name");

I have created some additional query methods below. Some are designed to help avoid worrying which version of Captivate is being used (ie they work with both CP3 and CP4), and others provide data directly from the Flash SWF (not using CP variables).

Method Notes
captivateVersion() Returns major number, currently either 2 or 4 (Captivate 3 SWFs self-identify as CP2 SWFs, nothing can be done about this.)
asVersion() Returns either 2 or 3
FPS() Returns the frames per second of the SWF
hasSkinSWF() Returns a boolean indicating whether the SWF is using a skin
hasTOC() Returns a boolean indicating whether the movie has a Table of Contents
hasPlaybar() Returns a boolean indicating whether the SWF has a playbar
width() Returns a number indicating width in pixels
height() Returns a number indicating height in pixels
volume() Returns a number (0-100) indicating volume level. Note: volume only works in CP4+
percentLoaded() Standard Flash SWF method, not specific to Captivate.
getname() Returns the SWF’s ID. Standard Flash SWF method, not specific to Captivate.
geturl() Returns the SWF’s URL. Standard Flash SWF method, not specific to Captivate.

You can also grab a reference to the SWF itself by using .swf. This is the equivalent of document.getElementById():

var myMovie = CaptivateController("Captivate");
myMovie.swf === document.getElementById("Captivate");

Set method

There is a new set method (added November 2011) that enables developers to easily set the value of a Captivate variable using JavaScript. For example:

var myMovie = CaptivateController("Captivate");
myMovie.set("myCustomCaptivateVariable", "myValue");

Here is a test page demonstrating the set method.


Download the CaptivateController The CaptivateController is now hosted on GitHub! The CaptivateController is licensed under an MIT license, and is free to use.

DISCLAIMER: This controller is provided as-is. Use this controller at your own risk. I cannot be held responsible for any problems you may encounter while using the controller. kthxbai.