Twine macro: << cyclinglink >>

This simply produces a link whose text cycles between a number of values whenever you click on it. It otherwise leads nowhere. You can use it as a silly clicky trinket, a cheap alternative to the <<replace>> macro, or (as detailed below) as an input interface element.

Script code

macros.cyclinglink={handler:function(a,b,c){var rl="cyclingLink";
function toggleText(w){w.classList.remove("cyclingLinkInit");
w.classList.toggle(rl+"Enabled");w.classList.toggle(rl+"Disabled");"none")?"inline":"none")}switch(c[c.length-1]){case"end":var end=true;
c.pop();break;case"out":var out=true;c.pop();break}var v="";if(c.length&&c[0][0]=="$"){v=c[0].slice(1);
c.shift()}var h=state.history[0].variables;if(out&&h[v]===""){return
}var l=Wikifier.createInternalLink(a,null);l.className="internalLink cyclingLink";
l.setAttribute("data-cycle",0);for(var i=0;i<c.length;i++){var on=(i==Math.max(c.indexOf(h[v]),0));
var d=insertElement(null,"span",null,"cyclingLinkInit cyclingLink"+((on)?"En":"Dis")+"abled");
}else{l.appendChild(d)}}l.onclick=function(){var t=this.childNodes;
var u=this.getAttribute("data-cycle")-0;var m=t.length;toggleText(t[u]);
u=(u+1);if(!(out&&u==m)){u%=m;if(v){h[v]=c[u]}}else{h[v]=""}if((end||out)&&u==m-(end?1:0)){if(end){var n=this.removeChild(t[u]);


If the first parameter begins with the "$" sigil, then it will interpret it as a variable to be altered by clicking the link. When the player visits the page or clicks the link, the variable will be changed to match the text of the link. If the variable already has a string value when you load the passage, then the link text that matches the variable will be selected, instead of the first one.

If the last parameter is the word "end", then it will terminate the cycling link at the parameter before last. The containing that text will replace the link element altogether. Similarly, if the last parameter is the word "out", then it will disappear altogether after the final link text is clicked.

Usage examples:
* You look around, but only see <<cyclinglink "grass" "a flower" "a cloud" "the road">>. - This is a purely cosmetic, endlessly cycling link.
* You see a bowl containing <<cyclinglink "3 cookies" "2 cookies" "1 cookie" "a few crumbs" end>>. - This link changes to the words "a few crumbs" when you get to the end.
* You see a dial: <<cyclinglink $heat "off" "low" "high" "fearsome">>. - The $heat variable will be changed to "off" when the page loads (unless it was already set to "high" or "fearsome"), and then sets it to "low", "high" and "fearsome" as the player clicks the link.
* You see a fuel gauge: <<cyclinglink $fuel "100%" "50%" "10%" "0%" end>>.
* You see an air meter: <<cyclinglink $air "********" "******" "****" "**" out>>.

Example program 1 (cosmetic).
Example program 2 (mechanical).
Example program 3 (mechanical with CSS)..

New: Advanced CSS effects

I've gone to the trouble of writing a number of advanced CSS effects for use with this macro. You can see them all and obtain the CSS code for them by clicking here. These use some very recent CSS animation features in unusual combinations, but they've been tested in both Chrome and Firefox.

Implementation details:
* For CSS users: the <a> tag has the class names "cyclingLink" and "internalLink".
* Each option is a <span> inside the <a> tag. Clicking it causes the next one down to have the class "cyclingLinkEnabled", and the others to have the class "cyclingLinkDisabled". New: on passage load, each option also has the class "cyclingLinkInit", which is removed as each is clicked.
* When you click, the "data-cycle" attribute of the <a> tag increases by 1 (wrapping around to 0 at the end). You could select this with CSS, I guess, using [data-cycle=1] or somesuch.

Version history:

  1. 9-8-13 - Added 'cyclingLinkInit' class support.
  2. 27-3-13 - Bugfixes, added "out" parameter.
  3. 4-3-13 - Bugfix.
  4. 27-2-13 - Added CSS hooks and the "end" parameter.
  5. 26-2-13 - Added new variable-setting ability.
  6. 16-2-13 - Fixed typo preventing it from working.
  7. 29-1-13 - Initial.

Feel free to report any bugs to @webbedspace.

TwineMacro-CyclinglinkTest.html36.68 KB
TwineMacro-CyclinglinkTest2.html57.51 KB
TwineMacro-CyclinglinkTest3.html58.66 KB
TwineMacro-CyclinglinkCSS.html76.57 KB



This is a great macro for me, though I wonder if it'd be possible to set variables using this, but with alternative text. So for instance:

* You see a dial: cyclinglink $heat "off" "It is turned off right now." "low" "You set it to low." "high" "You set it to high." "fearsome" "Feeling brave, you dial it to 11."

So the variable state would switch to off, but the cycling link has a little more flavour to it? Of course, you could have the longer text as the variable values, but for the sake of easy monitoring of variables, I think this would elevate the macro from being great to awesome!

If I wanted to use the

If I wanted to use the advance CSS like this vertical dial (below) in a replace instead of a cycling link, how could I adapt it?

@keyframes cyc-vert-dial-out {
0% { top: 0em; }
100% { top: 2em; }
@keyframes cyc-vert-dial-in {
0% { top: -2em; }
100% { top: 0em; }
@-webkit-keyframes cyc-vert-dial-out {
0% { top: 0em; }
100% { top: 2em; }
@-webkit-keyframes cyc-vert-dial-in {
0% { top: -2em; }
100% { top: 0em; }
.cyclingLink {
overflow: hidden;
display: inline-block;
position: relative;
height: 2em;
vertical-align: middle;
white-space: pre;
.cyclingLinkEnabled {
display: inline-block !important;
height: 1em;
top: 0em;
left: 0em;
position: absolute;
.cyclingLinkDisabled {
top: -8em;
animation: cyc-vert-dial-out 1s; -webkit-animation: cyc-vert-dial-out 1s;
position: absolute;
.cyclingLinkEnabled {
top: 0em;
animation: cyc-vert-dial-in 0.8s; -webkit-animation: cyc-vert-dial-in 0.8s;
position: relative;
vertical-align: top;
.cyclingLinkInit, .cyclingLinkInit::before {
animation-iteration-count: 0 !important;
-webkit-animation-iteration-count: 0 !important;

Using cyclinglink with random words?

Is it possible to use the cyclinglink with a random word macro? For example: every time you click the cycling link it generates a random word, instead of the same words over and over?

Thank You

Awesome Code

Hey friends, I really want to say thanks for this code, I was struggling to find this and I get it here. you are a genius. Thanks!