twine macro

Twine: <<autolink>>, a macro to automatically make links.

This macro, when surrounding a span of text, will search through the text, finds words that are also names of passages in the story, and converts them to internal links.

* Since Twine passage names are case-sensitive, this search is also case-sensitive.
* It currently only matches single ASCII words (letters and numbers) and hyphens contained within, but currently not apostrophe-containing words.

macros.autolink={handler:function(g,e,f,b){function tagcontents(starttag,endtag,k){var a=b.source.slice(k),l=0,c="";
for(var i=0;i<a.length;i++){var w=endtag.length;if(a.substr(i,w)==endtag){if(l==0){b.nextMatch=k+i+w;
return c}else{l--;c+=a.charAt(i)}}else{if(a.substr(i,starttag.length)==starttag){l++
}c+=a.charAt(i)}}return""}var k=b.source.indexOf(">>",b.matchStart)+2,d=tagcontents("<<"+e,"<<end"+e+">>",k),bs=String.fromCharCode(92),re=new RegExp("(["+bs+"w-]+)","g"),words,len;
re.lastIndex+=(len)}}while(words);new Wikifier(g,d)}};macros.endautolink={handler:function(){}}

Usage example:
* <<autolink>>The most popular pets are dogs and cats<<endautolink>> - Assuming the passage "dogs" exists, that becomes "dogs".

Not too sure of the name - might change it later.

Feel free to report any bugs to @webbedspace.

Twine: improved YouTube background audio macros

This code is largely based on some original macros posted to the Google Group by, er, somebody. These take a YouTube video ID and plays the audio of that video invisibly in the background of your Twine game. The player will require Flash installed, of course. (Last updated 16/3/14)

What I've done is upgrade it in the following ways:
* The volume slider is removed, on the basis that most authors will probably not have much call for it. Also, it required jQuery and jQuery UI, which not only inflated the footprint of the script, but may have interfered with other jQuery-using Twine scripts.
* It supports multiple sound tracks per story, and lets you play them simultaneous with each other if you so wish.
* The script will attempt to preload all of the videos, ensuring that they play as soon as their macros are called. (Note: currently it only preloads the tracks from the start, so this performance gain may not be seen when starting playback from the middle of the track.)
* A few more macros are provided, roughly in line with my HTML5 audio macros: <<unloopbgm>> and <<pausebgm>>.
* The code has less implicit globals. (This is a meaningless distinction.)
* There should be more informative error messages for specific error codes.

The macro names themselves are similar, but I made the following changes: <<playbgm>> now plays the audio once, and <<loopbgm>> causes it to constantly loop. Otherwise, they function identically.

Note: For browser security reasons, local HTML files are prohibited from accessing network files through a Flash embed. So, you have to test these macros by running the game from a web server.

Usage examples
*<<playbgm iHBWZn9re0U 32>> plays the YouTube video starting from 32 seconds in.
*<<playbgm iHBWZn9re0U>> plays the YouTube video from the beginning, or resumes it if it was paused.
*<<stopbgm iHBWZn9re0U>> stops the sound track.
*<<loopbgm iHBWZn9re0U>> makes the sound track constantly loop (although it may not quite be seamless).
*<<unloopbgm iHBWZn9re0U>> stops it from looping.
*<<pausebgm iHBWZn9re0U>> pauses the sound track.
*<<stopbgm iHBWZn9re0U>> stops playback and resets its position to the start.

Feel free to report any bugs to @webbedspace.

Twine: Combined <<Replace>> Macro Set

Last updated: 6-Jun-15
I've worked hard to combine my <<replace>>, <<timedreplace>>, <<revision>>, <<hoverreplace>> and <<once>> macros, and all their variations, into a single codebase, and included some new variations as well. Here's my combined "Replace Macro Set": (version 1.1.7)

The first good news is that you only need this much default CSS for all these macros:

.revision-span-in {
	opacity: 0;
.revision-span:not(.revision-span-out) {
	transition: 1s; -webkit-transition: 1s;
.revision-span-out {
	opacity: 0;
The reason I require this CSS is to enable people to modify it to make their own effects. You can, for instance, change this to an instant transition by removing the middle CSS block (with the "transition" property line.)

List of macros
This set includes the following "revision macros":
* <<insert>>, <<replace>>, <<continue>> — triggered by clicking their contents.
* <<timedreplace>>, <<timedinsert>>, <<timedremove>>, <<timedcontinue>>, <<timedcycle>> — triggered by time.
* <<hoverreplace>>, <<hoverremove>> — triggered by the mouse touching their contents, only temporarily.
* <<mousereplace>>, <<mouseremove>>, <<mousecontinue>>, <<mousecycle>> — triggered by the mouse touching their contents, permanently.
* <<once>>, <<later>> — triggered by visiting the passage a certain number of times in the game session.
* <<insertion>>, <<revision>>, <<removal>>, <<cycle>> — triggered by a separate "triggering macro".

It also includes these "triggering macros":
* <<revise>>, <<revert>>, <<randomise>> — hyperlinks.
* <<mouserevise>>, <<hoverrevise>> — sections that the mouse can touch.

Changed syntax
* <<replacewith>>, used to separate sections in <<timedreplace>>, has been replaced with <<becomes>>.
* You can now have multiple sections in most of the revision macros, by separating them with <<becomes>> or <<gains>> macros:

These function just like they do within <<revision>> macros - <<becomes>> replaces the previous section with the next section, and <<gains>> merely appends the next section.
* To reconcile differences between <<replace>> and <<timedreplace>>'s syntax, some macros (currently just the <<replace>>, <<mousereplace>> and <<hoverreplace>> varieties, as well as <<mousecontinue>>) have multiple syntax for specifying sections - the "normal" syntax, where each section is separated by <<becomes>>/<<gains>>, and a "shorthand" syntax, where the first several sections are strings within the opening tag:

The final section must be between the opening tag and the <<endreplace>> macro tag, though.
For most of these, the shorthand strings behave as if the <<becomes>> macro separates them. The exception to this is the "insert" named macros, wherein the strings will behave as if the <<gains>> macro separates them.

New macros
* <<later>> is the antonym of <<once>> - it displays its contained text on the second and subsequent visits.
* <<mousecycle>> creates a section of text that cycles between different versions whenever the mouse touches it. It's similar to <<cyclinglink>> in some respects, though you can't yet easily bind a variable to change when it changes.
* <<timedcycle>> constantly rotates through its sections without stopping. It is similar to <<timedloop>> and may well replace it in future.


In any of these examples, <<becomes>> can be substituted with <<gains>>.

Feel free to report any bugs to @webbedspace.
Don't use the attached file. It's out of date.

Twine macro: <<once>>

This little macro shows a span of text only the first time you encounter it - for all subsequent times you visit a passage containing it, it will be absent. This can be done with variables, but this form lets you use a single pair of macro tags. This can be good for, let's say, IF-style verbose opening descriptions of scenes or rooms.

Install my <<Replace>> Macro Set to use this macro.

You can use <<becomes>> or <<gains>> to specify text that should appear only on the second visit, or the third, and so forth.

Usage examples:
* <<once>>I'm going now. Goodbye.<<endonce>>
* <<once>>You arrive at the bathhouse.<<becomes>>You return to the bathhouse a second time.<<endonce>>
* <<once>>You arrive at the garage.<<becomes>>Back at the garage.<<becomes>>Third visit to the garage.<<endonce>>

* If many <<once>> macros containing exactly identical text are used in different passages, seeing one of them will hide the others.

Version history

  1. 16-6-13 - Updated regarding Combined Replace Macro Set.
  2. 12-5-13 - Initial.

Feel free to report any bugs to @webbedspace.

Twine macro: <<hoverreplace>> and <<mousereplace>>

This set of macros is a mouse-driven counterpart to <<replace>> and are essentially a simpler form of <<hoverrevise>>. They cause a span of passage text to change into a different span when the mouse moves over it. It comes in two main varieties: <<mousereplace>> replaces the span outright when the mouse touches it, whereas <<hoverreplace>> simply displays the alternative span while the mouse is hovering over it, and will change back when it leaves.

For convenience, there are also the following variations:

  1. <<mousecontinue>> functions like the <<continue>> macro, causing a single enclosing span to disappear when the mouse touches it, and revealing all subsequent passage text.
  2. <<mouseremove>> creates text that simply disappears when the mouse touches it.

Install my <<Replace>> Macro Set to use this macro.

Usage examples:
Separate both versions of the span using <<becomes>>.

  1. <<hoverreplace>>You see here a clock.<<becomes>>It's 8:09PM.<<endhoverreplace>> causes the text "You see here a clock" to become "It's 8:09PM." when the mouse hovers over it, and go back when the mouse leaves.
  2. <<mousereplace>>A [[bird]]!<<becomes>>It flew away.<<endmousereplace>> causes the text to become "It flew away." when the mouse touches it.

The <<mousecontinue>> and <<mouseremove>> variations don't use <<becomes>>:
  1. <<mousecontinue>>Move here to begin.<<endmousecontinue>> hides all further passage text until the mouse touches "Move here to begin.", whereupon those words vanish and the text is revealed.
  2. <<mouseremove>>Don't touch me!<<endmouseremove>> causes "Don't touch me!" to vanish when the mouse touches it.

<<becomes>> vs. <<gains>>
If you use <<gains>> instead, then the second version is appended to the first version.
  1. <<hoverreplace>>[[End game|Quit]]<<gains>> Are you sure??<<endhoverreplace>> adds the words "Are you sure??" after the link while you hover over it.
  2. <<mousereplace>>You see a barrel. <<gains>>It is empty.<<endmousereplace>> adds the words "It is empty." when your mouse touches the words.

Version history:
  1. 16-6-2013: Updated regarding Combined Replace Macro Set.
  2. 12-5-13 - Initial.

Feel free to report any bugs to @webbedspace.

Twine macro: <<else if>>, an improvement to <<if>>

Update: This macro is now built into Twine 1.4! It is no longer necessary to install it.

This is not strictly a new macro, but a replacement version of the <<if>> macro. You might have noticed that nesting the <<if>> macro can get a bit messy:

<<if $fire eq "warm">>
The fire isn't hot yet.
<<if $medal eq "water">>
You medal protects you.
<<if $dead gt 0>>
Not again!
You died!

The <<else if>> macro allows you to essentially have multiple <<if>> macros chained together, without needing to nest each of them within the <<else>> / <<endif>> tag pair of the other:

<<if $fire eq "warm">>
The fire isn't hot yet.
<<else if $medal eq "water">>
You medal protects you.
<<else if $dead gt 0>>
Not again!
You died!

The macro code is here:
Obsolete script removed: use Twine 1.4

You might wonder why I chose "else if" instead of "elseif"... I guess my mind flipped a coin and the 'natural language' side shone upward.

If someone else has already developed a similar macro, as I suspect they might, then do tell.

Feel free to report any bugs to @webbedspace.

Twine macro: <<hoverrevise>>, a mouseover extension to <<revise>>

The <<hoverrevise>> macro is an extension of the <<revision>> / <<revise>> macros. It lets you make a span of passage text briefly appear or disappear whenever you mouseover another span of text in the same passage.


Just install the latest version of <<revision>> (1.1.0 or later). It's included already.


You may want a "dissolve" type of transition to be applied to the text that appears or disappears. For that, give the <<insertion>> or <<removal>> macro a name that, say, contains "hover", and then use this CSS to exclusively target it:

.revision-span-in[class*=hover] {
	opacity: 0;
.revision-span[class*=hover] {
	transition: 1s;
	-webkit-transition: 1s;
.revision-span-out[class*=hover] {
	opacity: 0;

If you aren't using any normal <<revise>> macros, you could omit "[class*=hover]" to make every <<revision>> span have this transition.

Usage examples

Use this in conjunction with <<revision>>, <<insertion>> or <<removal>> spans, as you would with <<revise>>. The <<hoverrevise>> macro covers a full span of text, ending with <<endhoverrevise>>

To make the text "Aah! A ghost!" appear when you mouseover a span:

<<insertion hoverghost>>Aah! A ghost!<<endinsertion>>
<<hoverrevise hoverghost>>You'd better [[go to the chapel|chapel]]<<endhoverrevise>>

To make the text "Don't leave me" disappear when you mouseover a span:

<<removal words>>"Don't leave me"<<endremoval>>
<<hoverrevise words>>[[Go to the beach|beach]]<<endhoverrevise>>

To make the text "Cold" change to "Warm" when you mouseover a span:
<<revision hovermetal>>Cold<<becomes>>Warm<<endrevision>>
<<hoverrevise hovermetal>>[img[gold.png]]<<endhoverrevise>>

These are just a few of the possibilities allowed by this macro.

This wraps the contained text in a <span> with the class "hoverrevise" as well as "hoverrevise_" suffixed with the identifier you use (for instance, "hoverrevise_boo" for <<hoverrevise boo>>").
Feel free to report any bugs to @webbedspace.

Twine macro: <<revision>> and <<revise>>

The <<revision>> macro is a more powerful variation of the <<replace>> macro. It lets you alter a span of passage text by clicking a link from anywhere in the passage.

Install my <<Replace>> Macro Set to use these macros.

Basic usage
First, use the <<revision>> macro to define two different versions of some text:

You see here <<revision tome>>a closed book.<<becomes>>an open book.<<endrevision>> Each section of text separated by <<becomes>> is a different "version" of the text. The name "tome" in the macro is an identifier. You can use any single word you want as an identifier.

Then, you can create a link using the <<revise>> like so:
<<revise tome "Open the book.">>
This creates a link reading "Open the book" that changes any "tome" revision in the passage into the next version - in this case, changing "a closed book" into "an open book".

(Notice that the word "revise" is the verb form of "revision", reflecting the fact that the hyperlink serves as a verb for the player to perform.)

Running code in revisions
Just like with <<replace>>, any macros inside a revision are run as soon as they are made to appear:

<<revision button>>You see a button.<<becomes>>The button is pushed.<<set $button=true>><<endrevision>>
<<revise button "Push it.">>

The above code will set $button to true when you click the "Push it." link.

Multiple versions
You can have many versions of a span of text:

You see here <<revision books>>a closed book.<<becomes>>a chewed book.<<becomes>>paper scraps.<<endrevision>>
<<revise books "Chew book">>

In this case, the link "Chew book" will change "a closed book" into "a chewed book", then "paper scraps". When it reaches the end, the link vanishes.

Back and forth
The <<revert>> macro functions to reverse the effects of the <<revise>> macro.

<<revision box>>Here is a closed box.<<becomes>>Here is an open box.<<endrevision>>
<<revise box "Open the box.">>
<<revert box "Close the box.">>

The <<revert>> macro's link won't be displayed if it's at the first revision, just as the <<revise>> macro won't be visible if it's at the last revision.

Cycling link text options (New)
The <<revise>> and <<revert>> macros have a number of additional options similar to the <<cyclinglink>> macro. You can supply additional link text strings after the first, and it will change to the next string after you click it.
<<revise wall "Smash wall" "Smash it again" "Keep smashing">>

If the second parameter begins with the "$" sigil, then it will interpret it as a variable to be altered by clicking the link. When the player clicks the link, the variable will be changed to match the text of the link.
<<revise heat $warmth "Set it to warm" "Set it to hot" "Set it to boiling">>

If the last parameter is the word "end", then it will disable the link at the parameter before last, leaving just the text. If the last parameter is the word "out", then it will vanish altogether once it's reached the final string.
<<revise roast "Devour roast" "Munch some more" "You're too full now" end>>
<<revise amphora "Drink wine" out>>

Click here to read about <<hoverrevise>>.

<<becomes>> vs. <<gains>>
Just as the <<replace>> macro has a variation, <<insert>>, so too does <<becomes>>.

The vase contains:<<revision vase>>Two roses<<gains>>, an orchid<<gains>>, a pencil<<gains>>, a straw<<endrevision>>.
<<revise vase "Put something in the vase">>.

When you click "Put something in the vase", the text changes from "Two roses" to "Two roses, an orchid", then to "Two roses, an orchid, a pencil" and so forth.

You can mix and match <<gains>> and <<becomes>> at will:

<<revision count>>One<<becomes>>Two<<gains>>and a half<<becomes>>Three!<<endrevision>>

This changes from "One" to "Two", "Two and a half", and finally "Three!".

Normally, when a <<revision>> macro reaches the end of its revisions, its links disappear. If you change "revision" to "cycle", then you can keep clicking the link to return to the first revision.

You see here <<cycle pet>>a dog<<becomes>>a cat<<endcycle>>.
<<revise pet "Change pet">>

This will change "a dog" to "a cat" and vice-versa, with the link never expiring.

<<insertion>> and <<removal>>
Two other variations exist, which are roughly analogous to <<timedinsert>> and <<timedremove>>.
You look at the plate. <<insertion grain>>1 grain.<<becomes>>2 grains.<<becomes>>3 grains.<<endinsertion>>
For <<insertion>>, the first version "1 grain" is initially invisible. Clicking a <<revise>> link will make it visible. Then, it functions as normal.
You look at the plate. <<removal seed>>3 seeds.<<becomes>>2 seeds.<<becomes>>1 seed.<<endremoval>>
For <<removal>>, the <<revise>> link will remain when you get to "1 seed". Clicking it a final time will remove the text altogether.

Example program

Technical details

  1. Each version inside a <<revision>> macro is a <span> classed with "revision-span" as well as the kind of version they are ("becomes", "gains"). When they appear, they are given the class "revision-span-in" and their display is set to "inline". When they disappear, they gain the class "revision-span-out" and, after 1 second, their display is set to "none". All of these are inside a container <span> classed with the name of the macro ("insertion", "removal", "cycle", "revision") and the name of the identifier ("book" or whatever the author set it to be).

Version history:

  1. 27-9-2013: Fixed several bugs, including:
    <<revision>> macros were being called twice on passage load.
    <<revision>> macros were still taking effect while they were animated being removed by other macros.
    Multiple <<revision>> macros with the same ID weren't all being revised at the same time.
  2. 16-6-2013: Updated regarding Combined Replace Macro Set.
  3. 26-4-2013: Added extra options to <<revise>>.
  4. 20-4-2013: Added <<hoverrevise>> and support for <<randomise>>.
  5. 18-4-2013: Initial

Feel free to report any bugs to @webbedspace.

Twine macro: <<timedloop>>

This macro is similar to <<timedreplace>>, but instead of replacing one block of text with another, it just re-runs a passage section, re-drawing the text and running the contained macros again.

Much like <<timedreplace>>, the transition between each rewrite is handled by CSS. Here's a default "fade-in" transition:

.timedloop.replacement-in {
	opacity: 0;
.timedloop {
	transition: 1s;
	-webkit-transition: 1s;
.timedloop.replacement-out {
You can easily modify this CSS. If you want an "instant" transition, for instance, change "opacity: 0;" to "display:none;"

New: This now takes CSS time values, which are decimal numbers ending in "s" (for seconds) or "ms" (for milliseconds).

Here's a usage example:

<<set $red=1>>
<<timedloop 1s>>You have <<set $red += 1>><<print $red>> seed pods.<<endtimedloop>>
The text will initially read "You have 2 seed pods.", then change to "You have 3 seed pods." after 1 second, then "You have 4 seed pods." after another second, and so forth until you leave the passage. The time value is in half-seconds, like <<timedreplace>>.

Known bug: When you click a link to leave a passage, the loop will still run while the passage is transitioning out. This may cause unexpected behaviour (if, for instance, a <<timedgoto>> is inside the looped code).

Implementation details:
* If inserted text appears and descends below the bottom of the screen, the page should automatically scroll down to make it visible.
* Note: due to the way the browser and Twine interact, any changes made by code inside a <<timedloop>> tag after the first iteration will be forgotten if you use the Back or Forward browser buttons. This means that if you put long-term variable changes that affect future passages inside one, you should disable the Back button.

Version history:
* 11-4-2013: Fixed bug where the timeout wouldn't expire if you clicked a "refresher" link to the same passage.
* 5-4-2013: Initial.

Feel free to report any bugs to @webbedspace.

Twine macro: <<timedgoto>>, a simple timer

This is inspired by the Timer script used in Panic! by Astrid Bin and Stefano Russo. That script implements a sophisticated timer entity which can count down throughout the entire game, can draw itself in graph form in a canvas element, and can be paused and resumed. However, it requires multiple macros to set it up for each use, and it can be a bit cumbersome if you simply want the game to advance to a new passage after a delay.

I felt like writing a similar macro that would be shorter and more specific. This one, <<timedgoto>>, just automatically (and invisibly) goes to the given passage after the given amount of time has passed. Each use of the macro only functions within the passage that uses it - if you're using Sugarcane or single-passage Jonah and leave the passage by a normal link, it will be disengaged. Feel free to consider this a counterpart to <<timedreplace>>.

macros["goto"]=macros.timedgoto={timer:null,handler:function(a,b,c,d){function cssTimeUnit(s){if(typeof s=="string"){if(s.slice(-2).toLowerCase()=="ms"){return +(s.slice(0,-2))||0
}else{if(s.slice(-1).toLowerCase()=="s"){return +(s.slice(0,-1))*1000||0
}}}throwError(a,s+" isn't a CSS time unit");return 0}var t,d,m,s;

New: This now takes CSS time values, which are decimal numbers ending in "s" (for seconds) or "ms" (for milliseconds). You can use fractions of seconds as well as whole seconds.

Usage examples:
* <<timedgoto "underwater" 2.5s >> goes to the "underwater" passage if you stay at the current passage for 2 and 1/2 seconds.
* <<timedgoto $deathpassage 5s >> goes to the passage whose name is in the $deathpassage variable if you stay at the current passage for 5 seconds.
* <<timedgoto $playerType + "pit" 1s >> goes to the $playerType + "pit" passage if you stay at the current passage for 1 second.
* <<goto "Throne">> - This shorter version functions the same as <<timedgoto "Throne" 0s>>.
* This uses code parameters (that is, it accepts "strings", $variables, and "various"+$combinations of both, and its parameters are interpreted as Javascript), except that the final parameter (the time value) is separated from the rest and interpreted as a literal parameter.

Version history:

  1. 1-9-2013 - Fixed a bug where it caused problems with the (un-patched) browser Back button code.
  2. 18-4-2013 - Changed time units to CSS units, added "goto" variation.
  3. 5-3-2013 - Initial.

Feel free to report any bugs to @webbedspace.

Syndicate content