iftechfoundation / twine-cookbook Goto Github PK
View Code? Open in Web Editor NEWTwine Cookbook
Twine Cookbook
A piece of text (e.g. a link to open a door) only appears if the player has previously visited another passage (e.g. where they found the right key).
Image support and functionality is pretty mixed across story formats, but there should still be examples on the two most commonly used ways of including images in Twine 2 stories: Base64-encoding and referencing a file.
Examples of how to create headers and footers using passage tags (Harlowe), special passage names (SugarCube), and templated window.story.render() usage (Snowman) .
The text of a passage changes depending on the number of passages the player has visited. e.g. at the start of a game, it's morning; later on, it becomes afternoon and the description of a place changes.
Examples of how to use (capture and reaction to) story format events.
SugarCube: Passage Events
Snowman: *.sm.passage events.
Given the Twee 3 specification, expand the Twee page in the Cookbook. Include information about Twee Notation and compilers. Optionally include more details about the versions of Twee and their general differences.
Two similar ideas:
I worked out a way to use geolocation to trigger passages; I'm not much good, so it'd be nice if someone could make it all more elegant. My write-up is here
A link that only reveals itself to be clickable when the reader mouses over it, or doesn't change at all.
Examples of undoing in different formats based on examples of setting values and then undoing them to show how to 'rewind' in a story.
Harlowe: (undo:)
SugarCube: <<back>>
and Engine.backward()
Snowman: Checkpoints based on previous Twine forum thread.
The player has a certain amount of time to click a link in a passage, or else they're automatically taken to another one. (c.f. Queers in Love at the End of the World).
An entry on loading and potentially using one of the add-ons supplied by @tmedwards in the SugarCube documentation downloads page. It would also list the ability to use the existing add-ons as other possible solutions to the entries on Cycling Links and the Typewriter Effect topic areas already in the Cookbook.
This would be a topic area with a single entry for SugarCube.
Would cover the LoadScreen API in SugarCube. (It should also be possible to produce the same effect in Snowman using getScript() and some JavaScript).
Adding a new entry on Harlowe 3.0 for (cycling-link:)
Topic area covering SugarCube functionality and Snowman functionality of the same type.
I'm new to all this and the cookbook and Harlowe manual have both proved absolute lifesavers. However, I've noticed that the Harlowe code example for cycling choices used in the cookbook doesn't appear to work when typed into twine 2, even when it's just copy-pasted.
It involves a lot of "if $choicecount>=it then set to 1" and it just seems a little overwhelming as a beginner.
I couldn't spot any proposed alternatives, so I took the liberty of providing my own that seemed a little less clunky (at least from here, I'll happily admit that I'm learning a lot of this as I go)
Isn't it easier to just rotate the array and always display the first entry? If you update the button every second then you can just keep on clicking. You can even add a back button by copying the code and changing it to rotate -1
EXAMPLE
(set: $choicecount to (a: ["One"], ["Two"], ["Three"]))
(live:1s)[(display: 1st of $choice)]
[Next]<next|
(live:1s)[(click: ?next)[(set: $choicecount to (rotated:1,...$choicecount))]
Setting up a simple "go" button has proven a little difficult, but I've had some success using a secondary passage that loads up the choices. as its basically only functioning as a directory that the reader doesn't see
EXAMPLE 2
CHOICE PASSAGE
(set: $choicecount to (a: ["One"], ["Two"], ["Three"]))
(live:1s)[(display: 1st of $choice)]
[Next]<next| [Go]<go|
(live:1s)[(click: ?next)[(set: $choicecount to (rotated:1,...$choicecount))]
(live:1s)[(click: ?go)[(go-to: "Loader Passage")]
LOADER PASSAGE
(if: 1st of $choicecount = ["One"] [(go-to: "Passage One")]
(if: 1st of $choicecount = ["Two"] [(go-to: "Passage Two")]
(if: 1st of $choicecount = ["Three"] [(go-to: "Passage Three")]
There's probably an easier solution somewhere, but if this is any help for the cookbook, please take it. If I'm just creating more issues than I've solved I'm sorry for wasting time but I'd appreciate any criticism so I can get better at this.
Based in part on the ideas of #16, this would review how to use jQuery's getScript() function in Harlowe and Snowman and the importScripts() function in SugarCube to retrieve, load, and use an external JavaScript library across Twine 2.
I just realized that the examples and recipes I wrote for arrays are in the repo here, but when I committed them I forgot to add them to the table of contents so they're inaccessible in the built page. I can submit PR later if you don't get to it.
How to simulate the outcome of a die roll -- either the standard d6 or the more esoteric variations.
The markdown document for the SugarCube "Moving through a 'dungeon'" example has the wrong filename: sugarcube_displayswapping.md
.
Please, do not use <<end…>>
style closing tags (I'm looking at you <<endif>>
). They have been deprecated for a very long time now and are no longer even mentioned in the documentation.
Like #22, this may seem basic, but the structure of conditional and command statements is different enough across story formats that it is worth including examples of things like Harlowe's (else-if:)
and SuagrCube's <<switch>>
that either aren't available or are different in the other story formats.
Getting the current date, time, and doing basic time manipulation. Assume using Date() for SugarCube and Snowman examples where functionality is not already supplied by story format or included libraries.
Greyelf suggested I post this here.
Not really an issue in Harlowe, since authors will typically have different save and load buttons, so they can just use (if:)
s to get whatever effect they want. In SugarCube, using Config.saves.isAllowed()
to deactivate saving causes the save to just fail silently, which could cause users to lose data if they assume it worked, or think there's a bug or something. The following code is based on something TheMadExile wrote up for me a long time ago, and shows an alert when saving is disabled and the user attempts it:
Config.saves.isAllowed = function () {
if (tags().includesAny('no-save', 'menu', 'creation', 'startup') /* etc... */ ) {
$(document).one(':dialogclose', function () {
// show alert when save dialog is closed by the save attempt
UI.alert("You can't save right now.");
});
return false;
}
return true;
};
The player can click a cycling link whose final value is remembered later in the game (e.g. choosing a hair color for the protagonist).
The markdown documents for both the Snowman and SugarCube "Dice Rolling" examples have the wrong titles. Snowman's claims SugarCube (v2.18), while SugarCube's claims Harlowe (v2.0).
In SugarCube: using <<unset>>.
In Snowman: using JavaScript's delete.
Adding entry for Harlowe 3.0 for (drop-down:)
I just wanted to point out that SugarCube has an integration module for Typed.js on its website (under add-ons, dead last), that will probably be a better solution than the widget for most authors. I can see the value in providing code that authors can make and understand themselves, but I think it'd be wise to at least mention its existence.
The build process of the GitBook command line tools creates a _book folder/directory.
As it is a good practice to run that process to test/debug any changes being made to the cookbook, I suggest it would be a good idea to exclude that folder from the repository.
See: sugarcube_savinggames_twee.txt, line: 19
<<link "Save to the first slot?">>
<<script>>
if (Save.ok()) {
Save.slots.save(0);
}
<</script>>
<</link>>
The above test should use Save.slots.ok()
, as Save.ok()
will return true
if either slots or the autosave is available. You don't want the autosave check masking an issue with the slots.
As the title states, there's a typo in the section for having a link reveal itself permanently upon mouseover.
It reads
$('.reveals') .addClass('hidden') .one('mouseenter', function () { $(this).removeClass('hidden'); });
It should be .on instead of .one
Adding a side-bar to the right side of the page.
How to import a Google webfont and style text in it.
This technique is already present in many of the Version 1 examples, but it is not spelled out as such in most case. This set of examples would (optionally) define the term encapsulation and demonstrate how to use the (display:)
, <<include>>
, and render()
functionality of Harlowe, SugarCube, and Snowman respectively to separate complex ideas into easier-to-handle modules.
Break out the CSS page into its own section with details on the differences between what selector each included story format uses (<tw-story>
for Harlowe, .passage
, and .main
for Snowman) for their content area and how to style links and other common selector issues.
This section should include or otherwise summarize the upcoming Twine 2 HTML Elements specification.
For inclusion in the cookbook, if deemed of good enough quality. The <<quicktimebar>>
macro creates a simple "reverse progress" bar which starts out filled (and in a nice green shade), then becomes smaller with time and acquires an angry red tint until the time runs out, at which point whichever code is nested inside is ran, like a <<link>>
's code would. If navigating away from the passage, nothing executes.
Example code (a 5-second timer, 20em
wide, showing an alert popup when nothing happens to stop it):
<<quicktimebar 5 20em>><<run UI.alert("Too late!")>><</quicktimebar>>
CSS:
div.quicktime-bar {
position: relative;
border: 1px solid #777;
background: black;
height: 1em;
}
div.quicktime-value {
position: absolute;
top: 0;
left: 0;
height: 100%;
background: #00ff00;
}
JavaScript:
Macro.add("quicktimebar", {
isAsync : true,
tags: null,
handler: function() {
var payload = this.payload[0].contents.replace(/\n$/, '').trim();
var duration = (Number(this.args[0]) || 60) * 1000;
var width = this.args[1] || "100%";
var id = "bar_" + Math.floor(Math.random() * 0x100000000).toString(16);
var bar = document.createElement("div");
bar.classList.add("quicktime-bar");
bar.id = id;
bar.style.width = width;
var value = document.createElement("div");
value.classList.add("quicktime-value");
value.style.width = "100%";
bar.appendChild(value);
this.output.appendChild(bar);
var toHex = function(num) {
var res = Math.round(Number(num)).toString(16);
return (res.length === 1 ? "0" + res : res);
};
var functionToRun = this.createShadowWrapper(
payload
? function() { Wikifier.wikifyEval(payload); }
: null
);
jQuery(document).one(":passagedisplay", function() {
var timeStarted = (new Date()).getTime();
var workFunction = setInterval(function() {
if(!bar.isConnected) {
// Navigated away from the passage
clearInterval(workFunction);
return;
}
var timePassed = (new Date()).getTime() - timeStarted;
if(timePassed >= duration) {
// Timed out - run the inner SugarCube code
value.style.width = "0";
clearInterval(workFunction);
setTimeout(functionToRun, 40);
return;
}
// Update the quicktime bar
var percentage = 100 - 100 * timePassed / duration;
var color = "#"
+ toHex(Math.min(255, 510 - 5.1 * percentage))
+ toHex(Math.min(255, 5.1 * percentage)) + "00";
value.style.backgroundColor = color;
value.style.width = (100 - 100 * timePassed / duration) + "%";
}, 40);
});
},
});
Most of the styling can be done with CSS. The colour change happens near the end of the workFunction
function and can be changed there or commented out - or overridden via an !important
CSS rule.
Attribution: Whatever, I'm glad to help.
Examples of how to use (loop:) (Harlowe), <<for>>
(SugarCube), and for() (Snowman) to iterate over different data structures and how to show, find, and sort things.
Examples in SugarCane of the following to matching existing sets:
Examples of how to assign and use multiple values across story formats. Based on, and drawing heavily from, examples like those found in SugarCube's documentation.
Examples could be as simple as a handful of numerical values and how to adjust them using (link:)/<<link>>
or as complex as including some random events (connecting to the Rolling Dice example) for how to build very simplified RPG mechanics of events/battle outcomes affecting values.
Examples demonstrating multiple approaches (if possible in story format) for showing static data using <progressbar>
, <meter>
, and other CSS methods.
(This topic area should be different than the Timed Progress Bars entries that already exist. These should be about showing static and not dynamic data changes.)
How to embed/display/include passages in other passages. Covering (display:) in Harlowe, <<include>>
in SugarCube, and window.story.render() in Snowman.
Examples for reading, saving, and removing 'game saves' or equivalent functionality.
Harlowe: (save-game:)
SugarCube: Save API
Snowman: Web Storage Example
SugarCube is the only story format that directly supports audio functionality. However, it is still possible to use audio in Harlowe and Snowman with some work. Along the lines of #25, there should also be examples of how to use audio and/or other media across story formats.
Using a Story Variable to conditionally control which CSS is used to the style the look and/or layout of your story.
As per suggestion, see if GitBook's HTML rendered content will still show the table of contents without the search functionality. Both use JavaScript (and the examples themselves would not work without it), but it might still be possible.
An alternative might also be to have the published PDF and EPUB versions on the site as well.
Using one or more Passage Tags to conditionally control which CSS is used to the style the look and/or layout of your story.
Harlowe 3.0: (t8n-depart:) and (t8n-arrive:)
SugarCube: Either using CSS or working with Passage Navigation events.
Snowman: CSS transitions.
Just as the title says, this would be a review of how to "set" and show variables across story formats. While this is usually one of the first things learned when using a story format, it also differs across them enough that a review of how to set, change, and show values is worth including.
Possible Suggestions:
<<set>>
in SugarCube, and "s" scope in SnowmanA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.