This set of macros/functions aims to provide an easy way to set up content that is revealed bit-by-bit via user interaction.
Using nested <<linkreplace>> and <<linkappend>> works, but gets tedious and is often prone to errors. The CTP (Click To Proceed: original-est name ever) macros make it a bit easier by turning them into blocks instead of nests.
If using the Twine desktop/web app, copy contents of CTP.js to Story JavaScript, and contents of CTP.css to Story Stylesheet.
If using a compiler like Tweego, drop CTP.js and CTP.css to your source folder.
See more examples.
<<ctp "testID">>
This is the first string.
<<ctpNext clear>>
Second! It cleared the first one out!
<<ctpNext nobr>>
Third, but with nobr...
<<ctpNext 2s>>
The fourth shows up 2 seconds late.
<<ctpNext t8n>>
And the final one. With a transition!
<</ctp>>
<<link "Next">>
<<ctpAdvance "testID">>
<</link>>
<<link "Back">>
<<ctpBack "testID">>
<</link>>Keywords for controlling behavior:
clear: Clears the content of the previous block. Use for replacing.nobr: Appends content to the same line as the last block instead of going to a new line.t8nortransition: Custom CSS animation based transition (250ms fade-in by default).- (delay): A valid CSS time value (e.g.
3sor250ms) to delay the display of the block by.
Additional keywords for individual blocks (<<ctpNext>>, <<ctpHead>>, <<ctpTail>>) in a chain (these are used to break out of behavior set by the <<ctp>> macro):
noClear: Overridesclearand keeps previous blocks in place instead of replacing.br: Overridesnobrand adds a line break before the current block.noT8nornoTransition: Overridest8nortransitionand removes the transition for the current block.- (delay): Overrides the delay set by
<<ctp>>for the current block.
-
id: (string) Unique ID to be used to identify the chain of content. The naming rule follows the same as those of SugarCube variable names (learn more here). -
keywords: (optional|string) Keywords (full list here) can be used to alter the behavior of the macro throughout the entire chain. Keywords on<<ctp>>apply to all blocks.
Example:
<<ctp "ID_of_the_year">>
Bare minimum...
<</ctp>>To be used inside <<ctp>> to separate the content into blocks.
keywords: (optional|string) Keywords (full list here) can be used to alter the behavior of the macro for the current block.
Example:
<<ctp "fancyCTP">>
One.
<<ctpNext clear>>
Two with clear.
<<ctpNext nobr>>
Three on the same line.
<<ctpNext 500ms>>
Delayed four.
<<ctpNext t8n>>
Fading five.
<</ctp>>To be used inside <<ctp>> as a block prepended to the chain which is re-evaluated at every <<ctpAdvace>> and <<ctpBack>>. As long as it is inside <<ctp>>, the position does not matter.
The main body of the CTP chain is always rendered first, before <<ctpHead>> or <<ctpTail>>.
keywords: (optional|string) Keywords (full list here) can be used to alter the behavior of the macro for the current block.
Example:
<<ctp "fancyCTP">>
<<set _ctp to CTP.getCTP("fancyCTP")>>
This is the first block. Declare any variables to be used by ctpHead in here.
<<ctpHead>>
<<if _ctp.log.index is 1>>
<!-- do stuff if this is the second block -->
<</if>>
<<ctpNext>>
This is the second!
<</ctp>>To be used inside <<ctp>> as a block appended to the chain which is re-evaluated at every <<ctpAdvace>> and <<ctpBack>>. As long as it is inside <<ctp>>, the position does not matter.
The main body of the CTP chain is always rendered first, before <<ctpHead>> or <<ctpTail>>.
keywords: (optional|string) Keywords (full list here) can be used to alter the behavior of the macro for the current block.
Example:
<<ctp "fancyCTP">>
<<set _ctp to CTP.getCTP("fancyCTP")>>
This is the first block. Declare any variables to be used by ctpHead in here.
<<ctpNext>>
This is the second!
<<ctpTail>>
<<if _ctp.log.index is 1>>
<!-- do stuff if this is the second block -->
<</if>>
<</ctp>>The 'proceed' part of Click To Proceed... Used to move the train forward and show the next blocks.
id: (string) Unique ID which was set up in<<ctp>>.
NOTE: Use with user interaction (inside a <<link>> or <<button>>) or inside a <<timed>> macro to ensure the DOM is loaded and has the element on the page for the macro to target.
Example:
<<ctp "ID_of_the_year_once_again">>
<!-- stuff -->
<</ctp>>
<<link "Next">>
<<ctpAdvance "ID_of_the_year_once_again">>
<</link>>Turns back time and goes back one block.
id: (string) Unique ID which was set up in<<ctp>>.
NOTE: Use with user interaction (inside a <<link>> or <<button>>) or inside a <<timed>> macro to ensure the DOM is loaded and has the element on the page for the macro to target.
Example:
<<ctp "ID_of_the_year_yet_again">>
<!-- stuff -->
<</ctp>>
<<link "Back">>
<<ctpBack "ID_of_the_year_yet_again">>
<</link>>Returns a CTP object created with the <<ctp>> macro.
id: (string) ID of theCTPobject.clone: (optional|boolean) Whether to return a deep clone. False by default, making the function return a reference to the original object.
Example:
CTP.getCTP("testID");The CTP custom object is set up as follows:
id: (string) Unique ID.
selector: (string) CSS selector to target to output to. When used by the macro, this is the slugified form of id.
Example:
var ctpTest = new CTP({
id: "ctpTest",
selector: "#ctp-test-id"
});Other properties which are used under the hood:
stack: (array) Contains the content of all blocks.
log: (object) Keeps track of blocks and their behaviors:
index: (whole number) Current index of block (zero-based).delayed: (boolean) Whether the current block is delayed or not.
Object methods:
Adds content to the end of the stack and returns the CTP object for chaining.
content: (string) The actual content in the block.keywords: (optional|string) Space-separated list of keywords (clear, nobr, t8n, transition) to modify the behavior of the blocks.
Example:
ctpTest
.add("This is the first string.")
.add("Second! It cleared the first one out!", "clear")
.add("Third, but with nobr...", "nobr")
.add("And the final one. With a transition!", "t8n");Does the same as <<ctpAdvance>>, moving to the next block. Returns the CTP object for chaining.
Example:
ctpTest.advance();Does the same as <<ctpBack>>, reverting to the previous blocks. Returns the CTP object for chaining.
Example:
ctpTest.back();Returns the HTML output for a single block at the index passed into it.
index: (whole number) Index of block to return.noT8n: (optional|boolean) If true, all transitions are removed. False by default.
Example:
ctpTest.entry(2);
// Assuming ctpTest is the same as in the previous examples, this returns:
// <span class="macro-ctp-entry macro-ctp-entry-index-2">Third, but with nobr...</span>Returns the HTML output for the entire chain from the last 'clear' to the current index.
keywords: (optional|string) Space-separated list of words to alter the behavior of the output:noClear: Renders all the blocks from start to finish without considering if anything was cleared in between.noT8n: Removes all transitions.
Example:
// Assuming current index is 3
ctpTest.out()
/* Returns:
*
* <span class="macro-ctp-entry macro-ctp-entry-index-1">Second! It cleared the first one out!</span>
* <span class="macro-ctp-entry macro-ctp-entry-index-2">Third, but with nobr...</span>
* <br>
* <span class="macro-ctp-entry macro-ctp-entry-index-3">And the final one. With a transition!</span>
*/Complete usage:
JavaScript:
State.variables.ctpTest = new CTP({
id: "ctpTest",
selector: "#ctp-test-id"
});
State.variables.ctpTest
.add("This is the first string.")
.add("Second! It cleared the first one out!", "clear")
.add("Third, but with nobr...", "nobr")
.add("And the final one. With a transition!", "t8n");In Passage:
<div id="#ctp-test-id">
<<= $ctpTest.out()>>
</div>
<<link "Advance">>
<<run $ctpTest.advance()>>
<!-- Because $ctpTest was created manually, using the <<ctpAdvance>> macro won't work. To be able to use <<ctpAdvance>>, the CTP object needs to be set as a property of State.variables["#macro-ctp-dump"] as that is what is used internally to store CTP objects created via the macros. -->
<</link>><<ctp "testID">>
<<set _ctp to CTP.getCTP("testID")>>
This is the first string.
<<ctpHead>>
<<if _ctp.log.index gt 0>>
<<button "Back">>
<<ctpBack "testID">>
<</button>>
<</if>>
<<ctpNext clear>>
Second! It cleared the first one out!
<<ctpNext nobr>>
Third, but with nobr..
<<ctpNext 500ms>>
The fourth shows up half a second late.
<<ctpNext t8n>>
And the final one. With a transition!
<<ctpTail>>
<<if _ctp.log.index lt _ctp.stack.length - 1>>
<<button "Next">>
<<ctpAdvance "testID">>
<</button>>
<</if>>
<</ctp>>