I did a Twitter thing. The story, “Online mobs, startup bullshit. A thread:”, consists of 263 tweets, or 13 daisy-chained tweet threads. Its working title was “Revolt”, stolen from the excellent Martin Gurri book The Revolt of The Public and it’s about the ways that political mobilization has changed in the 21st century, particularly post 2011; but it’s also about startup bullshit.

Start here:

Why the weird tweet fiction thing? For one, I’ve never run across compelling Twitter fiction. I know that’s almost definitely my fault for not digging deep enough, as I’m sure there is good stuff out there. In fact if more than a dozen people read this post I’m doubly sure I will be notified of a vast trove of Twitter fiction that will put lie to everything I am about to say. However, all the attempts I’ve seen end up reading as if the author copy-pasted a short story into 280 character paragraphs, and I wanted to take advantage of the medium in a way that the other things I’ve read have not.

Tweets are (kinda) dialog. Most accounts tweet in their own voice and most message threads read like conversations. Given that, I decided to structure my composition as a screenplay rather than a typical prose story. That brought me to the second problem. What happens when there are interactions with other major characters? After stewing on it for a while I decided the most natural thing would be to structure those tweets as quote/retweets.

Too much would be overkill but by adding a few of the key supporting characters as Twitter accounts in dialog with the narrator/protagonist I feel like the reader gets just enough of the effect without it becoming tedious.

Fun! Now how the hell do I actually put 263 tweets onto Twitter? As Eben would say, Haha fuck.

Lucky for me I’m also a software dev.

def to_beets(text)
  clean  = text.lines.reject{|l| l =~ /^\s+$/}
  tokens = clean.map do |chunk|
    chunk.strip!
    if chunk =~ /^@[A-Z]+$/
      {type: :at, handle: chunk}
    elsif chunk =~ /^[A-Z]+$/
      {type: :protagonist}
    else
      raise Exception.new("Tweet too long:\n\t #{chunk}") if chunk.length > 280
      {type: :text, value: chunk}
    end
  end
  
  # Could thread this fucker through the accumulator but that's
  # ugly.
  last_token = nil
  tokens.reduce([]) do |beets, token|
    if token[:type] == :text
      beets << last_token.merge(body: token[:value])
    else
      last_token = token
    end
    beets
  end.reduce([]) do |beets, beet|
    if beet[:type] == :at
      beets.concat [beet, { type: :protagonist, body: :quote }]
    else
      beets.concat [beet]
    end
  end
end

The script is just for me so I can do cute shit like naming beats “beets” and chaining a reduce off an end. Sue me.

The first order of business was exporting the tweetplay (see what I did) to text format. Scrivener exports to Multimarkdown so that part was taken care of. Text files in hand, I wrote a quick and dirty Ruby script to parse the file into tweets. The quote tweets were a little tricky as I had to first post as the user being quoted, save the URL of the tweet, and then switch back to the protagonist account to continue the thread. Also, since nobody’s perfect, I knew I wasn’t going to only run the script once so I tracked the ids of every tweet so I could clear them all out with a single command. [for the nerds: yes, I can also pull the tweets from the api but I wanted the default to be surgical removal]

Debugging was a pain. Twitter only allows you to tweet 300 times per three hour window and that meant I would post one time, wait for 3 hours, clear the tweets and post again. Fun. Still, at least I wasn’t copy-pasting 263 tweets, then manually deleting them. I think I know why Twitter fiction is so rare.

Anyway, I hope you enjoy the story and if not maybe the story behind the story is interesting enough to make up for it. This was a fun project and like all wild-ass personal projects with no hope of being seen, the fun was the point. When I finish my rewrite of Petifleur and The Colored City I’m sure I’ll do another weird writing thing to clear the head.