Collaborative Twine

Ross Ramsay, one of my Patreon supporters, asked:

I was just curious if you had any plans to incorporate Dropbox or some way to synchronize and collaborate with the program? If you eventually add some kind of mobile system for this, it would be almost needed to sync between devices. As is, I’d use it to work with others, and sync between my work and home computer. With the ability to sync in some way, you might be able to use the mobile platform instead of having a dedicated mobile version for iOS and Android.

One great weakness of Twine is that it has no real way to collaborate with other authors. When I originally created Twine as a desktop app, sharing a Twine story meant sharing the file through whatever means at hand– email, a network share, Dropbox, what have-you.

Technically speaking, this option remains in the Twine 2 era. But in the era of Google Docs and Office 365, expectations have changed. Not only do people not want to mess around with file sharing — the expectation is that data lives in the cloud, which is to say “someone else’s server” — but there’s also an expectation that multiple people should be able to edit simultaneously. These are not unfair expectations to have! In particular, the idea of simultaneous editing just makes sense. But they impose additional levels of complexity on an application.

(It reminds me of the shift from modal, text-based applications to event-driven GUI apps. I am not old enough to have actually worked on an app back then, but I remember reading about this in programming books I devoured as a kid. In both cases, a fundamental change in perspective was required.)

I decided very early on in the Twine 2 design process that I did not want to be responsible for storing stories on a server I controlled. I’ve seen other systems — and continue to see new ones crop up — that do this, and when this happens, authors become captive audiences of those who run the servers. Without some kind of financial means to keep the lights on, these services only exist so long as their maintainers have interest — and in most cases, that can be measured in years, sometimes months. Imagine writing a story that just disappeared five years later! It would be a strange, even outrageous idea in the physical world. And yet we accept such ideas without much more than a sigh when they occur online.

There were other concerns to running a centralized Twine server, too. I believe that as long as you house content, you share responsibility for it — though this does not seem to be an attitude that everyone shares these days. I’m speaking here in moral terms, not really legal ones. I understand what safe harbor provisions are. Policing content for odious stuff like racism, pedophilia, and so on is not something I want to do. It’s a thankless but necessary job.

I also looked into integrating with services like Dropbox, but in my limited exploration, I found that they expected you to have your own server backend that will talk to their services, not have clients speak directly to them. Twine 2 doesn’t have a backend. In this respect, it still resembles its TiddlyWiki parentage. An important cavest — my understanding of this might be outdated. It’s been some time since I did that exploration.

In short, I would very much like to work on a collaborative Twine server but I don’t have the time or resources to do so right now. And before I started working on it, I’d need a real plan for sustainability that I was confident in. It would only be fair to people using it.

That said, I consider this subject an open question, not a sad conclusion.

Twine 2.1.3

This originally appeared on my Patreon.

This fixes a bad bug with 2.1.2 that could cause stories to become corrupted, so if you have downloaded 2.1.2, please upgrade to this as soon as you can.

This seems like a reasonable time to talk about how testing with Twine works. Initially, the test suite used a tool called Selenium that scripted actions in a web browser and verified the results. The problem with this approach is that it has turned out to be both brittle and flaky. Brittle because I would make a change to a small part of the code and 5 tests would break sometimes, and flaky because there were often difficult-to-debug timing issues with the tests that would cause them to succeed some of the time, and not others — on the same code. Not ideal.

(I know there are lots of happy users of Selenium, to which I say: good on you. But it hasn’t been good to me.)

With the Twine 2.1 series, I’ve been focusing on unit testing, which isolates each part of the code and tests each bit of it individually. It’s been a lot more reliable thus far, but it takes time to write all the tests. I’ve been focusing unit tests on the data layer, because bugs that cause data corruption are the worst in the world. They trash users’ work and leave me feeling horribly guilty. I’m the dog that ate your homework.

The bug that was in 2.1.2 didn’t have any testing associated with it. It was a sin of omission: if a grid spacing wasn’t specified when snapping passages to the grid, passages that are automatically created as you edit your story (e.g. when you type [[A link]]) would be assigned nonsense coordinates onscreen (NaN, if you speak JavaScript), which firstly caused them to not be displayed, and secondly could cause other passages to get their coordinates trashed, as Twine tries to keep passages from overlapping each other.

(No, there isn’t any way for an end user to change grid spacing, because it’s always felt unnecessary to me… but it’s always good to leave ourselves that option should we want it someday.)

Now the offending code has checks for grid spacing, and there is a specific test to check that it handles those situations correctly. So it shouldn’t happen again. Let’s hope. There is always a degree of uncertainty with software engineering.

Twine 2.1.2

This was originally posted to my Patreon.

It’s out now! You can download it from the main site ; I’ve also posted release notes  to the wiki. This release should fix a nasty bug affecting non-English speakers and also clean up some issues related to story format versions.

The localization issue was particularly insidious. What was happening was:

1. The app would do its initial startup and load in stories from the Twine/Stories directory, creating it if needed. This step would ask the localization code to translate the name “Stories”, but because localization data hadn’t been loaded yet, it would fall back to translating it to “Stories”, no matter what langauge you wanted to use.

(The reason for this fallback is so that if something gets really messed up, you can still at least get some words on the screen, even if they’re in a language you don’t speak.)

2. The rest of the app initialization would occur, including loading localization data.

3. A user would make a change and Twine would try to save it to that Twine/Stories directory… only this time, it would translate the folder name. So if you speak French, for example, it would try to save to a nonexistent Twine/Histoires directory and fail.

The solution was simple — load the localization data as early as possible — but it was tricky to diagnose.

Looking at the release notes page tonight, I realized the last release was about three months ago. I think we’re on that pace, roughly, for future releases as well — perhaps a little bit faster.

I’m also working on Snowman 2.0 and am close to a release on that, which is exciting. It’s not too too different, but I am changing some syntax, most notably the way you create <div>s and <span>s (which is buggy in the 1.x series).

The middle beast, a tremor of trepidation in his words, said, “You aren’t from a dark planet, are you?”

“No.” Calvin shook his head firmly, though the beast couldn’t se him. “We’re–we’re shadowed. But we’re fighting the shadow.”

(Madeleine L’Engle, A Wrinkle in Time)

Twine 2.1.1 released

This was originally posted at my Patreon.

Here’s what’s inside!

  • Thanks to contributions by users like you™, Twine now speaks German and Czech, and speaks Italian better
  • The SugarCube story format has been updated to 2.14.0
  • The Harlowe story formats have been fixed so that syntax highlighting while editing passages works correctly again
  • Using Twine on Internet Explorer 11 and mobile browsers has been improved (though there’s still room for improvement on iOS)
  • A bug where renaming passages with some punctuation in their names didn’t update incoming links correctly has been fixed

Defaults, standards, and Harlowe

For this post, I’m going to steal an excellent idea Emily Short had and answer a question Jeremiah McCall, a historian who maintains Gaming the Past, asked me over email with a blog post. He wrote:

Since [the story format] Harlowe is the default [in Twine 2], I am using Harlowe and I understand that SugarCube [another story format bundled with Twine 2] is a bridge from Twine 1.x.  I have scoured the net for a description of the strengths of Harlowe and why it is now default, but I don’t seem to be able to find anything. The few comparisons of Harlowe and SugarCube seem to favor the latter — though here and there are comments that Harlowe is more robust. I’m guessing (and hoping) that Harlowe will continue to develop and continue to be the default, but am I right in that? There seems to be a fair amount of resistance. Since I’m teaching Harlowe to others in hopes they will continue to use it, I’d be grateful for a quick insight. Right now I am under the vague impression that you and Mr. Arnott intend for Harlowe to be the standard from here on. Is that true and is there a quick reason why?

A quick explanation: a story format is essentially a runtime engine for works built in Twine. It takes the passages created in Twine and displays them in a Web browser. I intended the name ‘story format’ to a bit friendlier than ‘engine,’ and formats in Twine 1 were indeed more about formatting than behavior. In Twine 2, the situation has become a bit more complex, and thus the term ‘story format’ a bit dicier. Instead of choosing colors and whether clicking a link causes the story to expand or instead replace the existing text with new text, changing story formats in Twine 2 changes the entire approach an author takes to interactivity.

There are three story formats bundled with Twine 2. People tend to think of Twine and its story formats as a monolithic development effort, but that isn’t the case — each one is developed by different people on a volunteer basis. The formats are:

  • SugarCube, maintained by Thomas Michael Edwards. As Jeremiah alludes to, this is also available for Twine 1, is very mature, and has a ton of documentation, official and otherwise.
  • Harlowe, maintained by Leon Arnott. In my opinion, it’s a daring re-imagining of how to add interactivity to text that leverages a generous spoonful of functional programming. It’s a lot younger than SugarCube, which means that there isn’t as much documentation on how to do stuff with it.
  • Snowman, maintained by me. It does the absolute minimum in terms of functionality, instead leaving that to the stalwart libraries jQuery and Underscore. It’s great if you already know JavaScript and CSS, or are interested in learning them. If you aren’t, it’s a terrible choice.

(By the way, anyone can create a story format for Twine, and adding one is as easy as copying and pasting a URL. I really enjoy Illume, for example, when proofing work.)

Anyway, Harlowe is the default story format in Twine 2. I decided to make it the default for Twine 2 not only because I had, and continue to have confidence in Leon’s skills and vision, but I also saw Twine 2 as a chance to re-examine the assumptions Twine 1 made.

There are two things in particular that I think Harlowe gets right:

  • It’s succinct and readable. I think Leon has worked out a very simple syntax for code that doesn’t interfere with the flow of reading passage text.
  • It allows you to separate code from text. Harlowe allows you to mark a section of text as a “hook” which then can have code applied to it. This means that you can keep text and code compartmentalized — which I find really handy, because the mindset I bring to writing and editing prose is vastly different from the one I bring to code.

Harlowe may be the default, but in my opinion, it’s not a standard. I say that because there is no standard. I realize this makes Twine a little bit confusing; a system like Undum has a distinct, singular look and feel. But right now, I think the compromise is worth it. SugarCube, Harlowe, and Snowman serve different audiences, which means that Twine as a whole can be useful to that many more people.

Twine 2.1.0 is released

This was originally posted at my Patreon.

At long last! I’m pretty excited about letting people at it. We spent a lot of time in beta, but I’m hoping that investment will pay off.

You can download it from the home page. If you’re upgrading, please read the release notes carefully. A lot has changed. I think you will like what’s new and I’ve tested the upgrade path as best as I could — but I still worry that there will be bumps in the road.

Two things you might enjoy: what Birdland, one of my favorite Twine works, looks like in the new version , and (if you are a webdev nerd) how technology choices have changed between 2.0 and 2.1.

Life comes at you pretty fast in the frontend world

Putting the finishing touches on the Twine release tonight, I realized we have basically changed everything in our quote-unquote stack:

Twine 2.0.0 (2014) Twine 2.1.0 (2017)
ES5 ES6 + Babel
CSS LESS
Grunt npm scripts
Backbone + Marionette Vue + vue-router + Vuex
Browserify Webpack
Selenium Karma + Sinon + Chai

Still Alive But On Borrowed Time: Font Awesome, jQuery, SVG.js
Still Alive, Not Going Anywhere: CodeMirror, Jed, JSZip, Underscore

The prospect of linking all of these things is overwhelming, so, uh, if you don’t know what I’m talking about, try npm? And honestly, each row could be a post in itself, but I already have a blog backlog– so…

Near miss

In a recent IFTF blog post, I mentioned I hoped to get Twine 2.1.0 out by the end of the calendar year. Well… that hasn’t happened, obviously. The main cause was me coming down with two minor illnesses nearly back-to-back over the winter break — one head- and throat-based, one stomach-based. So most of my free time ended up being allocated to lying in bed with a fever instead of, you know, actual fun stuff.

We’re still in pretty good shape. There are a few bugs that need addressing before the release, but not too too many. I’m thinking mid- to late-January right now as a revised date.

In sort of related news, I think I’m now in good enough shape that I’ll still be able to do my presentation on gamebook history at MAGFest this year (it’ll be Thursday 1/5 at 4:30 PM). This is a reprise of the presentation I did last year with some added information here and there, so if you missed it last year or this will be your first year at MAGFest, consider stopping by. It’s not a super Twine-focused presentation, but I do think people into Twine would find it interesting, and I’m always happy to talk to folks afterwards.