Storyspace 3 has very rich scripting features, although at present itself is not scriptable using AppleScript. This brief tutorial looks at some of these, and how they can be incorporated to do some fairly unusual things for an authoring environment.
Most tutorials work through small parts of projects, but in reality, particularly when embarking on a substantial hypertext project, you will be working with scores or even hundreds of writing spaces. It is very tempting to leave these unstructured, in which case you will find yourself repeating mundane tasks over and over again.
One valuable tool to save you from that is the prototype: create one, set it up with custom attributes and so on, and use that as the basis for writing spaces with similar functions and features. For example, where my Trees in the Landscape hypertext book is clearly going to use dozens of writing spaces about paintings, it is worth making a
PaintingType prototype from which those can be made.
Create a writing space in the usual way, and name it
PaintingType. To turn it into a prototype, select that writing space in the Map view, open the Inspector, switch to the Properties Inspector, select the Prototype tab, and check the Prototype box.
All our paintings have common information, about the name of the artist, their dates, the name of the painting, its year, and so on. Rather than having to keep entering these in unstructured text in each writing space, it can be valuable to store these in custom attributes, which are then accessible to other writing spaces.
In the Inspector, switch to the Document Inspector, and select the User tab. In the popup tool menu next to the empty Attribute list, use the New user attribute command to create a new attribute. Give it the name
PArtist, with a string type, no default value, and some informative text in the description. Repeat this for other attributes, until there is one for each of the pieces of information we require about each painting.
Those custom attributes are now available throughout this document, but we will expose them for editing only in those writing spaces based on the
PaintingType prototype. Click on the + button at the top right of the Outline view, scroll down to the list of User attributes, and check each one to add it to the top of the Outline view.
Using the prototype and attributes
Create a new writing space in the usual way, and give it a working title such as
ConstableValeOfDedham. As there is now a prototype available, the lower right edge of the writing space icon in the Map view offers a tab, in which you should select the
PaintingType prototype. As soon as you do, all the custom attributes become visible and editable in the Outline view. Complete them as shown.
With those attributes, we can generate the text content of the writing space automatically. Although in this case it is not likely to change much, one way of ensuring that it is freshly generated when you open the writing space is to build it each time the space is visited, using the
OnVisit action. We can add this to the prototype, which ensures that it will happen for every child writing space.
PaintingType icon in the Map view, then in the Outline view click on the + button to add another attribute, the
OnVisit action, in the Storyspace list. Insert the following action script to generate the text content from our custom attributes:
$Text=$PArtist+" ("+$PLifeYears+"), "+PTitle+" ("+PMadeYear+"), "+PMedia+", "+PDimensions+" cm, "+PLocation+". "+PCredit+"."
which simply concatenates together all the elements in the string.
Switch the Outline view to Read, and click on the
ConstableValeOfDedham writing space in the Map view. The text content should now be generated automatically, and correctly formatted for display.
Viewing the painting in another app
We can also use the
OnVisit action to open a full-size image of the painting using another app, such as Preview, rather than making the reader fiddle around with the writing space window to get it to display the painting in its full glory. Storyspace 3 gives you access to OS X command line tools with its
runCommand command, and we can launch Preview and open a given JPEG image using a Terminal command such as
open -b com.apple.Preview ~/Documents/00sspace/myImage.jpg
We will here hard-code the folder location of our paintings for the sake of simplicity. Create a folder in your Documents folder named
00sspace, and put a test JPEG image there named
constablevalededhamfull.jpg. In the
PaintingType prototype, create another custom user attribute named
PImage, to hold a string containing the image file name. Then select the
OnVisit action, move the cursor to its (right) end, and append the script to open the file whose name is in the
; runCommand("open -b com.apple.Preview ~/Documents/00sspace/"+$PImage)
The opening semi-colon allows this second command line after that generating the text content of the writing space.
Now open the
ConstableValeOfDedham writing space, and insert its image file name,
constablevalededhamfull.jpg, as the value of its
PImage attribute. Whenever you click on that writing space, it should now open that image using Preview, if not already open.
There is an interesting side-effect: as the prototype does not contain a file name in its
PImage attribute, the command which it will pass will open all images in the folder. You can work around this using conditionals, or by setting the prototype to open just a small, dummy image.
The completed Storyspace 3 file for this is here: TitLf29
Doing more with runCommand
This is a potentially very powerful feature, which can also run AppleScripts if needed. As another example, I will consider a very different non-fiction hypertext book, about OS X. This links in with a recent series of articles here about CoreStorage.
Using the shell command
diskutil cs list
we can get a pretty-printed structured list of CoreStorage objects, which is of value. Within that, there will be a long UUID for the Logical Volume Group (LVG); using that (which I will here call LVGUUID), the command
diskutil cs info LVGUUID
will give further information.
We can call those commands using Storyspace’s
In a new, empty document, create a writing space named
CoreStorageList. Add two attributes,
MyString from the Sandbox list, and
onVisit from Storyspace. We will use
MyString to store the UUID drawn from the
OnVisit action. Edit
OnVisit to contain the following script:
$Text = runCommand(diskutil cs list); $MyString = $Text.substr(71,36)
This first of all calls the
diskutil cs list
command, and puts the result into the Text field. The second line of the action then extracts the LVG UUID and stores it in the
MyString attribute. Taking a fixed sub-string like this is of course error-prone, and I should really use Storyspace’s regular expression features to do the job properly, but it will suffice for this example.
As soon as you click on the
CoreStorageList writing space to visit it, the action will run, and you should see details of the CoreStorage LVG, if found, with the LVG UUID placed into
We can now use that UUID in another writing space, to call the next command. Create a new writing space, and link
CoreStorageList, and that to the new space, named
CoreStorageInfo, using simple text links. Add an
OnVisit action to
CoreStorageInfo, containing the script
$Text = runCommand("diskutil cs info "+$MyString(/CoreStorageList))
which concatenates the contents of the
MyString attribute of the
CoreStorageList writing space, containing the LVG UUID, to build the shell command, and writes the result into the text content of the space.
Switch to Read mode, select the
start writing space, and press Return to move down the chain. If your Mac has a Fusion Drive or other CoreStorage LVG, you will see successive details in the spaces.
The completed Storyspace 3 file for this is here: CoreStorage