Setting OS X Desktop Picture Based on Time of Day

I recently changed jobs (Hello, FireEye!) and was issued a new MacBook Air. I spend a lot of time looking at the screen and was getting bored with the supplied desktop pictures. I also start work very early most days (7am-ish), and thought it would be nice to have a desktop picture that matches the mellow-ness of such an early hour.

Of course, this leads to daydreaming — “scope creep” in professional parlance — and next thing you know, I started thinking “well, maybe I could also set it to show a nice evening-themed picture at night”. Then “maybe I can get it to change both screens” (I use a laptop with an external display).

I also liked the challenge of putting together a script as quickly as possible. (In my off-hours, of course!)

I downloaded some nice wallpaper images from National Geographic, then created six folders that correspond to the major periods of the day: morning (early and late), afternoon (early and late), and evening (early and late). I organized my National Geographic photos into those six folders, based on the mood each photo evokes. For example, this one is an early morning photo.

Then I rolled up my sleeves and got out the trusty old AppleScript Editor. The resulting AppleScript is posted on GitHub, if you’d like to take a gander.

The gist:

  • It selects a folder based on the time of day.
  • It randomly selects an image from within that folder and displays it as the desktop picture.
  • It supports more than one monitor, with an option to either display the same image on all monitors, or display different images on each monitor.

The resulting AppleScript must be run at a regularly scheduled interval. I’m currently using GeekTool to run the script every 15 minutes, but I might eventually switch to a crontab job for less overhead.

Regardless, I’m quite happy with the way it turned out, and have already started daydreaming about other things I can hack together with AppleScript.


New SCORM 1.2 Template for Adobe Captivate

By popular demand, the SCORM 1.2 edition of my revised SCORM publishing templates for Adobe Captivate 5.x is now available on GitHub.

Instructions can be found here.

While testing the SCORM 1.2 revisions, I noticed Captivate sometimes sends invalid data to the LMS, specifically for cmi.interactions.n.correct_responses.n.pattern, cmi.interactions.n.student_response, and cmi.interactions.n.weighting. I may fix these errors in a future update, but they’re relatively harmless, so I’ll leave them be for now.

Further Tweaks to the Adobe Captivate SCORM Publishing Template

Now that my version of the Adobe Captivate publishing template for SCORM 2004 is on GitHub, it has become a living document, bound to get updates (major and minor) from time to time. For those of you unfamiliar with GitHub, it’s a nifty site for storing code; it provides issues list for tracking bugs, it enables people to leave comments or make code suggestions, and it even lets you copy an entire open-source project with a single click!

Since the code for my templates will remain on GitHub, I highly suggest checking in from time to time to see if the code has been updated. I won’t be posting a blog entry on for every little edit I make to the code.

Speaking of edits, I made two or three tonight, spurred by an insightful comment from Jimmi Thøgersen.  He noticed a bug or two, and explained some of Saba’s bugginess — thanks Jimmi! If you know of any oddities or bugs, please let me know by posting an issue on GitHub.

Cleaning up Adobe Captivate’s SCORM Publishing Template, Part 7: Giving the Revisions a Home

I decided to post my revised Adobe Captivate publishing template to GitHub, where it can be easily copied, forked, and updated. Currently, the only files are for the Captivate 5.0 and 5.5 templates for SCORM 2004. I hope to add SCORM 1.2 soon, as well as replacing the default ‘standard.htm’ template, which doesn’t use any LMS-related code.

Update: The SCORM 1.2 template is now available.

If you take a look at Default.htm on GitHub, you’ll notice I’ve made a few changes since I wrote my series about editing the templates. I moved a few bits of markup/code around, added some configuration options (such as the ability to turn off centering, turn on logging, and require SCORM when loading), and added a ton of comments to explain some of the new options. Hopefully it’s all self-explanatory.

I also made a small edit to manifest2004.xml, and a few edits to scorm_support.js.

To use these template files, do the following:

  1. Make a backup of your entire publishing folder and put it somewhere safe!
  2. Go to Captivate’s Templates\Publish\SCORM\2004\ folder and replace Default.htm with the new file.
  3. Go to Templates\Publish\SCORM\2004\SCORM_support\ and replace scorm_support.js with the new file.
  4. While you’re in your SCORM_support folder, delete scorm_support.htm and scorm_support.swf, they won’t be used anymore.
  5. Go to Templates\Publish\ and replace manifest2004.xml with the new file.
  6. While you’re still in the Templates\Publish\ folder, replace standard.js with the new file.
  7. Restart Captivate and give it a try!

Find a bug? Think of a good edit for the template? Post a comment here, or better yet, file an issue on GitHub!

pipwerks SCORM Wrappers now available on GitHub

I’ve been considering adding my pipwerks SCORM wrappers to GitHub for a very long time, but my n00bness and general lack of free time were major obstacles. However, the time has finally come to buckle down and get these puppies OUT! So without further ado, I present:

I should note that these are my original SCORM wrappers (JavaScript, ActionScript 2 and ActionScript 3); I’ve been (very slowly) working on a completely new SCORM support codebase that I plan to release separately. However, these oldies are still running like a champ, so don’t be afraid to use them.

Many people have contacted me over the last few years with suggestions for improvements, but due to my general busy-ness I haven’t really made any modifications for a long time; I recently made a few small tweaks, including updating the StringToBoolean function that caused problems in Plateau, but the bulk of the code remains largely the same.

If you’re one of those die-hards eager to tweak the source code, you’re in luck! This is a public repository, which means anyone and everyone is now free to fork and edit the code as they see fit. If you have any suggestions or ideas, please go to GitHub and show us what ya got!

And for the curious, I’m using Tower to handle my Git commits — command lines are not my cup of tea. Tower is a very nice Git GUI that integrates seamlessly with GitHub. I’m new to Tower, but so far I like it very much.

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.