README.md 118 KB
Newer Older
1
# Harlowe - the default [Twine 2](https://github.com/klembot/twinejs) story format.
2

3
Documentation is at http://twine2.neocities.org/. See below for compilation instructions.
4

Leon Arnott's avatar
Leon Arnott committed
5
6
7
8
### 3.2.1 changes (unreleased):

#### Bugfixes

9
 * Fixed a bug where the effects of `(enchant:)` were temporarily suppressed whenever a `(dialog:)`, `(prompt:)` or `(confirm:)` was run at roughly the same time.
Leon Arnott's avatar
Leon Arnott committed
10
11
 * Fixed a bug where, when a transition finished, if the browser experienced lag due to a large number of other elements being present, the transitioning element's `visibility` could become `hidden` briefly before Harlowe removed the transition CSS from it.
 * Fixed a bug where Instant macros (`(set:)`, `(put:)`, `(move:)` and `(unpack:)`) would pollute the browser console with errors when Debug Mode was off.
12
 * Fixed a bug where Debug Mode's Enchantments panels' headers were being drawn incorrectly in Chrome.
Leon Arnott's avatar
Leon Arnott committed
13
14
15
 * Greatly improved the performance of Debug Mode's panels, reducing lag caused by a large number of entries being added to a panel at once.

### 3.2.0 changes (Jan 4, 2021):
16

17
#### Bugfixes
18

19
 * The bulleted list, numbered list and heading markup has been fixed to permit multi-line markup (such as multi-line hooks) within it. So, among other things, hooks' opening `[` and closing `]` can now be on the same line as a bulleted list item, numbered list item, or heading.
20
 * Fixed a long-standing bug involving the interaction between temp variables and the `(show:)` and `(link-show:)` macros. The previous behaviour, which was not my intention at all, meant that hooks shown with `(show:)` could only access temp variables available at the `(show:)` macro's location, rather than the hook's location (which is now the current behaviour). The same applies to `(link-show:)`, as well as to the new `(rerun:)` macro (below).
21
 * Fixed a long-standing bug where continuous ranges for arrays, such as `(a: 1,2)'s 4thlasttolast`, wouldn't work correctly. (What that example should do is provide the entire array, as is consistent with Python.)
22
 * Fixed a long-standing bug where `(click: ?Passage)` and `(click: ?Sidebar)` just flat-out didn't work at all.
23
 * Fixed a long-standing bug where, due to an operator precedence conflict, writing something like `$a's stops's (1)` would cause a Javascript error.
24
 * Fixed a long-standing bug where lambdas would produce an incorrect duplicate-name error if the temp variables used with their clauses contained capital letters.
25
 * Fixed a long-standing bug where hooks that had `(transition:)` transitions would restart their transition animations whenever the containing passage finished transitioning in. Previously, the only way to overcome this was to make the passage transition using `(transition-arrive:"instant")`.
26
 * Fixed a long-standing bug where you couldn't use the column markup to create empty columns by placing two column markup lines in succession, without an intervening blank line.
27
 * Fixed a long-standing bug where strings containing HookName syntax (such as `"?pear"`) were considered identical to actual hooknames (such as `?pear`). This was NOT intended behaviour and was not documented, and as such, certain design patterns that involved constructing HookName strings programmatically (such as `(replace:"?" + $name)`) will no longer work. A new macro, `(hooks-named:)`, has been added (see below) to provide this feature officially.
28
 * Fixed a bug where the default CSS for `(click: ?Page)` (a blue border around the page) wasn't visible. (Now, an `::after` pseudo-element is created for the enchantment, so that the border displays above all the page content.)
29
30
 * Fixed a bug where typing `is not an` instead of `is not a` (such as in `$wallet is not an array`) would cause an error.
 * Now, trying to access the `0th` or `0thlast` value in an array or string produces an error.
31
 * Now, `(mouseover:)` and `(mouseout:)` should work correctly with ?Page, ?Passage, and ?Sidebar.
32
 * Now, `(hook:)` works correctly when given to `(enchant:)`.
33
 * Fixed a bug where `(for:)` would emit infinite loop errors if 50 or more elements were given to it.
34
 * Fixed a long-standing bug where clicking the sidebar "undo" and "redo" icons would cause `(click:?Page)` in the preceding or following passages to automatically fire, even though you didn't actually click them.
35
 * Fixed a long-standing bug where block elements (like `(align:)` enchanted hooks) weren't transitioning in correctly when their passage appeared.
36
 * Significantly improved the performance of macros like `(enchant:)` and `(click:)` when they target a hook's `chars` or `lines`, such as by `(enchant: ?passage's hooks, $changer)`.
37
 * Fixed a bug where an `(enchant:)` given `?passage's chars` would crash Harlowe if the passage began with whitespace characters.
38
 * Fixed a bug where `(enchant:)` given a link changer such as `(link:)` or `(click:)` would cause a Javascript error. It now causes no error, but it does nothing. (The documentation that formerly cited this as an example usage has been changed.)
39
 * Fixed a bug where `(enchant:)` given `?passage's lines` would crash Harlowe if the passage contained zero line breaks.
40
 * Fixed a bug where `(enchant:)` given `?passage's lines` would often cause text nodes within lines, such as the text of a `(link:)` link, to be transplanted out of any elements containing them.
41
 * Fixed a bug where `(hover-style:)` combined with a link changer such as `(link:)` would cause the specified hover style, after the link was clicked, to permanently persist on the hook.
42
 * Fixed a bug where `(hover-style:)` couldn't actually override the default hover colour for links of any kind, due to a CSS conflict.
43
 * Fixed a bug where certain changers, like `(for:)`, caused a crash when attached to a command (like a `(print:)` macro, or a passage link).
44
 * Fixed a bug where closing an `(alert:)`, `(confirm:)` or `(prompt:)` dialog box when there was an `(event:)` hook in the passage would cause a crash.
45
 * Fixed a bug where revision changers like `(replace:)`, as well as `(enchant:)`, could affect text inside transitioning-out passages (including the passage itself, with `?passage`), which was noticeable when `(t8n-depart:)` was used with a passage link and the incoming passage contained one of those macros.
46
 * Fixed a bug where trying to use datanames with certain unusual types of data (changers, commands, datatypes) would give a bad Javascript error message instead of the intended error message.
47
 * Fixed a bug where the CSS used to position the new pure HTML dialogs didn't work on certain old browser versions.
48
 * Now, consecutive line breaks (which Harlowe reduces the cumulative height of) at the start of a passage are no longer the wrong height while that passage transitions in. (To handle this, consecutive line breaks are now made into `<tw-consecutive-br>` elements instead of `<br data-cons>` elements.)
49
50
 * Now, `(dropdown:)` explicitly uses the background of its containing hook, instead of being transparent, which the Windows version of Chrome displays as white, regardless of text colour.
 * Now, align, horizontal rule, and column syntax in the editor no longer occupies two lines unexpectedly.
51
 * `(save-game:)` can now save a greater range of variable data. Formerly, only changers, arrays, datamaps, datasets, booleans, strings and numbers could be stored in variables when you use `(save-game:)` - other values, such as commands, colours, gradients, or lambdas, would cause an error. Now, it should work with every kind of supported Harlowe value (i.e. those mentioned in the documentation) except user-created commands created with `(output:)` (see below). But, this means that save data from stories made in 3.1.0 is no longer compatible with 3.2.0.
52
 * Improved an error message that could appear if you erroneously put the spread `...` syntax inside parentheses, such as `(...$arr)`.
53
 * Altered the error message that appears when you don't give macros "enough values", which wouldn't properly exclude optional values.
54
55
 * Fixed some error messages involving accessing an invalid data value of a string, which would refer to the string as "an array".
 * Fixed a long-standing bug that caused error messages for certain invalid operators (such as unsupported SugarCube operators) to be replaced with an incorrect message.
56
 * Fixed a couple of crashes under Internet Explorer 10.
57

58
#### Alterations
59

60
61
 * With great humility, I've decided to change the behaviour regarding how temp variables interact with nested hooks. Formerly, temp variables created in an outer hook (or the outermost level of the passage) could be accessed in inner hooks, they couldn't be directly modified, because `(set:)`, `(put:)` and `(move:)` would instead create identically-named inner variables specific to that hook. I had originally planned to add a special kind of syntax to let inner hooks modify outer hooks' temp variables, such as `outer _a` – but, I've since accepted that this behaviour is too close to people's intuitions to require extra syntax to enable, and the existing behaviour too restrictive, especially regarding its interaction with `(if:)`. So now, using `(set:)` on a temp variable in a nested hook which shares a name with an outer temp variable will instead modify the outer temp variable. This change brings Harlowe temp variables closer in behaviour to SugarCube's temp variables – though, since SugarCube doesn't have a notion of "hooks", the notion of temp variables only being accessible in the hook in which they were first set is still unique to Harlowe.
   * It should be noted that the behaviour of `(for:)`'s temp variables is unchanged - this change will still leave any same-named temp variables outside of the hook unaltered by whatever happens inside the hook.
62
63
 * For a long time, the interaction between `(link:)` (as well as `(link-reveal:)` and `(link-repeat:)`) and other changers combined with it has been terribly inconsistent, with some changers applying to just the link, others to just the revealed hook, and most of them applying to both. I've decided after much heart-rending that I need to change this to a single hard-and-fast rule: changers combined with `(link:)` (and the others) will only apply to the revealed hook, NOT the link. This is to allow `(t8n:)`, `(box:)`, `(live:)` and other hook-specific changers to interact with `(link:)` as expected, and also to make `(link:)` links more consistent with `(click:)` links.
   * This also means that some unusual combinations of `(link:)` have different, more intuitive behaviour. For instance, combining `(link:)` with itself (such as by `(link:"A")+(link:"B")`) causes the first link to reveal the second link, which then, when clicked, reveals the attached hook. Also, `(for:)` combined with `(link:)` will now repeat the hook for the correct number of iterations.
64
 * Due to the above alteration, the link changers `(link:)`, `(link-reveal:)` and `(link-repeat:)` (as well as the `(click:)`, `(mouseover:)` and `(mouseout:)` changers) now accept an optional changer as their second value. This is used to style just the link, leaving the revealed hook unchanged.
65
 * The behaviour of `(text-colour:)` regarding links has been changed. Formerly, `(text-colour:)` couldn't change the colour of links inside hooks unless it was used with `(enchant:)` and wasn't used with `?passage` or `?page`. This meant that changing the colour of individual links was, unintuitively, not possible without `(enchant:)`. Now, a simpler rule is in place: `(text-colour:)` will always change links' colours, unless it's used with `(enchant: ?passage)` or `(enchant:?page)`. (This exception means that all of `(enchant:)`'s behaviour is unchanged with this release.)
66
 * The behaviour for multiple `(click:)` macros affecting the same hook (such as in `|A>[B] (click: ?A)[1] (click: ?A)[2]`) has changed to be slightly more intuitive: formerly, as you clicked the hook, the last `(click:)` would activate first (so, `[2]` then `[1]`). Now, they activate from first to last. This also applies to `(mouseover:)` and `(mouseout:)`.
67
68
 * Now, the text input box in `(prompt:)` is wider, and is auto-focused when the dialog appears, allowing the player to type into it without having to click it.
 * `(hook:)` now gives an error if it's given an empty string.
69
 * Commands are now considered equal by `is` and other operators if they have identical data values given to them. So, for instance, `(print: "34") is (print:"34")` will now produce `true`.
70
 * Now, `contains`, `is in` and `is not in` will emit an error if it's used to check if a string contains a non-string value, such as a number or boolean. This brings it into consistency with a few other operations, like trying to set a string's `1st` to something other than a single character.
71
 * Slightly altered the behaviour of `matches` when both sides are datatypes - now, identical datatypes will match each other, instead of only matching if one side is `datatype`.
72
 * The `(str-repeated:)` and `(repeated:)` macros now no longer error if the given number of repetitions is 0. (They will return empty strings and arrays, respectively.)
73
 * Now, `?hook's links` will contain the hook itself, if it's a link, or has been given a link changer or enchantment.
74
 * Now, pressing Return or Enter in a `(prompt:)` text input box should submit the text, as if "OK" was clicked.
75
76
 * Now, `(enchant:)` can correctly apply `(transition:)` transitions to existing hooks and text. Enchanting an existing hook with a transition will cause it to animate immediately, even if it was already visible - so, it's best used at the top level of passages, and in headers or footers.
 * Now, `(enchant:)` can also accept a 'via' lambda as its second argument, to apply a slightly different changer to each hook or text - `(enchant: ?passage's lines, via (text-color:(hsl: pos * 10, 1, 0.5)))` uses the new "pos" identifier (see below) to give each line of the passage a different colour.
77
 * Now, `(alert:)`, `(confirm:)` and `(prompt:)` accept optional strings for their dialogs' link text (which are "Cancel" and "OK" if no strings are provided).
78
 * Macros and expressions (such as bare variables) inside the strings given to `(alert:)`, `(confirm:)` and `(prompt:)` will now run. This wasn't strictly a bug, but it was inconsistent given that markup is available in them.
79
 * The default CSS for `(mouseover:)` and `(mouseout:)` (a dotted gray border and translucent cyan border, respectively) has been brightened slightly to be more visible. Also, it has been altered to work correctly with the new `(box:)` macro.
80
 * Reworded the error message produced by trying to get an array element that's outside the array's length (such as `(a: 1,2)'s 5th`).
81
 * Removed unused, undocumented CSS for the following (also unused) elements: `<tw-outline>`, `<tw-shadow>`, `<tw-emboss>`, `<tw-condense>`, `<tw-expand>`, `<tw-blur>`, `<tw-blurrier>`, `<tw-smear>`, `<tw-mirror>`, `<tw-upside-down>`, `<tw-fade-in-out>`, `<tw-rumble>`, `<tw-shudder>`, and `<tw-shudder-in>`. The CSS applied to these was mostly functionally identical to their corresponding `(textstyle:)` styling.
82
 * The `(text-style:)` styles "rumble" and "shudder" no longer need to set `display:inline-block` on the hook.
83
 * The shadow of the `(text-style:)` style "emboss" has been slightly adjusted.
84
 * Now, attaching `(transition:)` to a passage link instead of `(transition-depart:)` or `(transition-arrive:)` will cause an error instead of doing nothing.
85
 * Now, when Harlowe detects that a hook containing block elements is being transitioned, the `<tw-transition-container>` element will be given `display:block`. This is to fix a number of transition animation bugs, though it may cause certain structures to animate differently during transition.
86
 * `(mouseover:)`, `(mouseout:)` and their related macros, which use mouse-hovering input that isn't possible on touch devices, will now fall back to simply being activated by clicks/touches on touch devices.
87
 * After much fretting and fussing, I've decided to un-deprecate `(subarray:)` and `(substring:)`, because my intended subsequence syntax - `$a's 1stTo2ndlast` and `$a's (range: $b, $c)` - has a not-uncommon edge case where it fails - when `$c` in the preceding example is negative - and I've abandoned plans to alter it to accommodate this case. This un-deprecation changes nothing about how they behaved, but the documentation has been rewritten to include them.
88
 * Slightly adjusted the animation of `(text-style:"rumble")` and `(text-style:"shudder")` so that the text shifts position from its centre, rather than its left edge.
89
 * `(all-pass:)` can now be shortened to `(pass:)`. This alias is meant for cases when you only want to check a single value, like in `(pass: $noLetterE, "Gadsby")`, rather than a sequence of values.
90
91
 * `(background:)` can now be shortened to `(bg:)`.
 * `(text-rotate:)` is now aliased to `(text-rotate-z:)`, for consistency with the new macros below.
92
 * `(alert:)` has been renamed to `(dialog:)`, retaining the original name `(alert:)` as an alias for it. Moreover, it can now accept any amount of link text, as well as a bound variable to set to the text of whichever link you click. Also, changers like `(t8n:)` can now be attached to the `(dialog:)` macro.
93
 * `(reload:)` has been renamed to `(restart:)`, retaining the original name as an alias for it.
94
 * `(rgb:)` now accepts fractional values for the R, G, and B components.
95
96
97
98
99
 * The default CSS for `<tw-sidebar>` now sets its `display` to `flex` and gives it `flex-direction:column; justify-content:space-between;`. This should have no effect on its appearance in usual circumstances (see below).
 * Added a responsive `<meta>` tag to the HTML template, along with some very basic media queries. You might remember that responsive CSS was present in 1.2.4 but removed in 2.0.0, but all that ever did was change the font size, which wasn't helpful most of the time. These media queries now only perform the following when the viewport width is below or at 576px (the cutoff used by Bootstrap):
   * `<tw-story>`'s padding changes to `5% 5%` instead of `5% 20%`.
   * `<tw-sidebar>` loses `left: -5em; width: 3em; position:absolute; flex-direction:column;`, thus causing it to be placed atop the passage horizontally.
   * `<tw-dialog>` loses `max-width: 50vw;`.
100
 * Made the syntax highlighting dark mode colours 50% brighter.
101
 * Markup that's inside the verbatim markup will no longer be syntax-highlighted as if it was outside it.
102

103
#### Additions
104

105
##### Coding
106

107
 * Added negated versions of several operators. You may now write `is not in`, `is not a`, `does not contain` and `does not match` as more intelligible negations of `is in`, `contains` and `matches`.
108
 * Added the `pos` identifier, which is used in lambdas to provide the position of the data value (from those passed into the macro) that the lambda is currently processing. `(altered: via it + pos, 0,0,5,0,0)` equals `(a:1,2,8,4,5)`.
109
 * Added `2bind`, a "two-way bind" variation of `bind` which causes the `(cycling-link:)` and `(dropdown:)` macros, as well as the new `(seq-link:)`, `(checkbox:)` and `(input-box:)` macros, to automatically match the current value of the bound variable, and update itself whenever another macro changes the variable.
110
 * Datatypes can now be converted into "spread datatypes" using `...`, such as by writing `...str`. This allows the datatype, inside arrays or string patterns (see below), to match zero or more values of that type. `(a: ...str)` can match `(a:"Oat")`, `(a:"Oat","Wheat")` or `(a:"Oat","Wheat","Maize")`.
111
 * Added the HookName data name `visited` (as in `?passage's visited`), which allows you to select links that point to visited passages, and change the unique colour these links have.
112
113
 * Colours now have an alpha `a` data value, containing the alpha value given to the `(hsl:)` and `(rgb:)` macros - `(hsl: 130, 1, 0.5, 0.2)'s a` is 0.2.
 * Colours now have an `lch` data value, which contains a datamap of LCH color space values for that colour (corresponding to the numbers given to the new `(lch:)` macro). Because LCH's values conflict with HSL's, the LCH values are inside this datamap instead of directly accessible from the colour itself.
114
 * `(text-style:)` now lets you provide multiple style names, as a shortcut to combining multiple changers. `(text-style:"italic","outline")` is the same as `(text-style:"italic")+(text-style:"outline")`.
115
 * As an error-checking feature, you can now force your story's variables to only ever hold certain datatypes, so that data of the wrong type can't be set to them. `(set: num-type $funds to 0)` will, for the rest of the story, cause an error to occur if a non-number is ever put into $funds, such as by `(set: $funds to "200")`. This not only works with plain datatypes, but with complex data structures, using the `matches` operator's rules: `(set: (a:str,str)-type $b to (a:'1','1'))` will cause an error to occur if any data that doesn't match `(a:str,str)` is put into $b. You can use this syntax with temp variables and the new `(unpack:)` macro, too.
116
   * Additionally, you can force a variable to remain constant throughout the story using the new `const` datatype. `(set: const-type $robotText to (font:"Courier New"))` specifies that any further changes to $robotText should cause an error.
117
 * Lambdas' temp variables may now optionally have types as well, such as by writing `each str-type _name where _name contains "el"`. This checks that the correct types of data are given to the lambda.
118
 * Arrays and strings now have a `random` data name, which retrieves a random value from these structures. `(a:5,8,9)'s random` produces 5, 8 or 9. This works well with the `(move:)` macro, allowing you to randomly move values out of an array without necessarily needing to use `(shuffled:)`.
119
 * Arrays and strings now have `start` and `end` data names, which are designed to be used with `is` and `matches`. You can check if a string or array begins or ends with a certain other string or subarray by writing, for instance, `start of "Gossamer" is "Goss"`.
120
 * Added the `lambda` and `macro` datatypes (see below), and the `boolean` datatype can now be shortened to `bool`.
121
122
123
124
125
126
127
128
 * Added the following special datatypes:
   * `even`, which matches only even numbers.
   * `odd`, which matches only odd numbers.
   * `integer` (alias `int`) which matches only whole numbers.
   * `alphanumeric` (alias `alnum`), which matches strings that only contain letters and numbers.
   * `digit`, which matches strings that only contain digits.
   * `whitespace`, which matches strings that only contain whitespace.
   * `lowercase` and `uppercase`, which match single lowercase or uppercase characters.
129
   * `anycase`, which matches any character which has different lowercase or uppercase forms.
130
   * `linebreak`, which matches only a linebreak character.
131
   * `empty`, which matches only empty arrays, strings, datamaps and datasets.
132
 * Added a `transparent` built-in colour value.
133

134
##### Macros
135

136
137
138
139
###### Markup

 * Added unclosed collapsing whitespace markup `{=` (`{` followed by any number of `=`) to match the unclosed hook markup.

140
141
###### Metadata

142
 * Added some new macros, `(storylet:)` and `(open-storylets:)`, to support "storylets", an alternative way to link between groups of passages that's preferable for writing non-linear "episodic" interactive fiction. Instead of writing direct links between each episode, you instead write a requirement at the start of each episode, specifying (using a 'when' lambda) when would be the best time to let the player visit the passages. An example is `(storylet: when $season is "spring")`. Then, when you want the player to go to an episode, you use macros like `(open-storylets:)` to get a list of which storylet passages are available right now, and create links or other structures from there. Thanks to Emily Short for popularising the "storylet" design pattern.
143
144
 * Added an `(urgency:)` macro, which, when used alongside `(storylet:)`, alters the order in which `(open-storylets:)` sorts this passage, placing it higher than storylets with a lower "urgency" value.
 * Added an `(exclusivity:)` macro, which, when used alongside `(storylet:)`, causes it to be the only passage available in `(open-storylets:)` whenever it's open. Use this for very plot-critical storylets that mustn't be missed. For multiple passages with `(exclusivity:)`, the highest exclusivity values override lower ones.
145
 * Added a `(metadata:)` macro, which, when placed in a passage, adds values to the `(passage:)` datamap for that passage, allowing you to store any arbitrary data on it for your own use. This takes the same values as `(dm:)` - string names and data values in alternation.
146
147
148
149
150
151

###### Colours

 * Added an `(lch:)` macro (alias `(lcha:)`), an alternative colour creation macro (comparable to `(hsl:)`) that uses the LCH colour space (which is the CIELAB colour space, familiar to graphic designers, but expressed radially using a HSL-style hue angle).
 * Added a `(complement:)` macro, which takes a colour and produces its complement by rotating its LCH hue by 180 degrees.
 * Added a `(palette:)` macro, designed for rapid prototyping, which produces a four-colour palette based on a given colour, for use with `(text-colour:)`, `(background:)` and `(enchant:)`.
152
 * Added `(stripes:)`, a variant of `(gradient:)` which creates a striped background (for use with `(background:)`) when given a given stripe width, angle, and colours.
153

154
155
###### Values

156
 * Added a `(hooks-named:)` macro, which can be used to construct a HookName using a string. The slightly unusual name of this macro is meant to avoid confusion with `(hook:)`.
157
158
 * Added a `(trunc:)` macro, which is similar to `(round:)`, but rounds toward zero, "truncating" the fractional component. It is named after the Excel function that performs the same rounding.
 * Added a `(plural:)` macro, which takes a number and a string, and combines them, automatically pluralising the string if the number isn't 1. `(plural:2,"duck")` produces `"2 ducks"`. Pluralisation is performed by adding "s" - a second string may be given which specifies a more correct plural form of the word (such as `(plural:4,"elf","elves")`).
159
 * Added a `(str-nth:)` macro (alias `(string-nth)`) which takes a number and produces the English ordinal of that number (such as `"2nd"` for `2`, and `"-41st"` for `-41`).
160

161
162
163
164
165
###### Data Structures

 * Added a `(permutations:)` macro, which, when given a sequence of data, produces an array containing all possible arrangements of that data, in arrays.
 * Added a `(source:)` macro, which can turn any data value into its source code representation. `(source: (text-style:"bold") + (click: ?hat's 1st))` produces the string `'(text-style:"bold")+(click:?hat's 1st)'`.
 * Added a `(rotated-to:)` macro, a variation of `(rotated:)` which, rather than rotating the values by a given number, takes a lambda and rotates them until the first one that matches the lambda is at the front. `(rotated-to:where it > 3, 1,2,3,4)` produces `(a:4,1,2,3)`.
166
167
 * Added `(unpack:)`, a variation of `(put:)` used for assigning multiple values from an array, datamap or string into multiple variables at once. You can now write `(unpack: (a:1,2,(a:3)) into (a:$x, $y, (a:$z)))`, and the array on the left will overwrite the array on the right, causing $x to become 1, $y to become 2, and $z to become 3, without needing to write multiple `(set:)` statements. You may also put values or datatypes at positions in the right side, such as in `(put: (a:1,2,3) into (a:1,2,$x))`, to check that the right side indeed has matching values at those positions, and to cause an error if they do not.
   * The `(move:)` macro now also supports unpacking, by providing it with the same kind of statements as `(unpack:)`.
168
169
 * Added `(split:)` (also known as `(splitted:)` to emphasise that it has an adjectival name) which takes a string or string pattern (see below) and uses it as a separator value with which to split up the other string given to it, producing an array of substrings.
 * Added `(joined:)`, which joins together the strings given to it, using the first string as a separator value. `(joined:"! ", "Liberty", "Equality", "Fraternity", "")` produces the string `"Liberty! Equality! Fraternity!"`.
170
 * Added `(trimmed:)`, a macro that removes instances of the given string pattern from the start and end of the given string (defaulting to whitespace if no pattern was given).
171
172
173

###### Datatypes

174
 * Added several macros that, when used together, let you construct custom string datatypes called "string patterns" that match very specific kinds of strings. These are roughly comparable to regular expressions in other programming languages. 
175
176
177
178
   * `(p:)` takes a sequence of strings or string datatypes, and produces a datatype that only matches strings that match the entire sequence, in order.
   * `(p-either:)` takes one or more strings or string datatypes, and produces a datatype that only matches strings that match any one of the values.
   * `(p-opt:)` is a variation of `(p:)` that optionally matches the sequence - it matches strings that match the sequence, or are empty.
   * `(p-many:)` is a variation of `(p:)` that matches strings that match the sequence many times. You can specify the minimum and/or maximum amount of times the string can match the sequence.
179
   * `(p-ins:)` is a case-insensitive version of `(p:)`, which also treats any sub-patterns given to it as case-insensitive.
180
   * `(p-not:)` matches any character except those that match the given single-character strings, or datatypes corresponding to single characters.
181
 * You can also use the preceding macros with `(unpack:)`. For instance, `(unpack: "Dr. Iris Cornea" into (p: (p-opt:"Dr. "), (p: str-type _firstName, whitespace, str-type _lastName)-type _fullName))` creates three variables, _firstName, _lastName and _fullName, from a single string.
182
 * Added `(datatype:)` and `(datapattern)` macros. `(datatype:)` produces the datatype that matches the given value, if it exists. `(datapattern)` is a variation that, when given arrays or datamaps, produces a data pattern that can be used with the `matches` operator, among other things, to check if the structure of one value matches the other. `(datapattern: (passage:))` produces `(dm:"name",str,"source",str,"tags",(a:str))`.
183
184
185

###### Changers

186
 * Added a variation of the `(enchant:)` macro, called `(change:)`, which simply applies the given changers once, without creating an ongoing effect that causes additional inserted text to be affected by it.
187
 * Added a changer variation of `(enchant:)`, `(enchant-in:)`, which restricts the effect of the enchantment to just the attached hook. This also lets you deploy (enchant:) effects alongside other changers in variables. Note that `(enchant-in:)` cannot be supplied to itself or `(enchant:)`.
188
 * Added some shorthands for using `(enchant-in:)` with certain common hook names: `(link-style:)` is a shorthand for using `(enchant-in:)` with `?Link`, `(line-style:)` is a shorthand for using `(enchant-in:)` with `?Page's lines`, and `(char-style:)` is a shorthand for using `(enchant-in:)` with `?Page's chars`. Because the Harlowe code for enchanting just the lines or characters within a hook is messy with the latter two constructions (you can't say "this hook's lines", for instance, and instead must specify the equivalent of "the page's lines which are in this hook") these macros have been created as a more intuitive alternative. Their naming is in keeping with the precedent set by `(hover-style:)`.
189
 * Added a `(text-size:)` style changer macro (also known as `(size:)`) that scales the attached hook's font size and line height by the given multiplier.
190
 * Added an `(opacity:)` style changer macro, which allows the CSS opacity of hooks to be altered. This also allows sidebar icons' opacity to be altered, using (change:) and other tools.
191
 * Added a `(transition-delay:)` macro (also known as `(t8n-delay:)`) which adds an initial delay to transitions before they begin animating. This can only enchant hooks, not links.
192
193
 * Added a `(transition-skip:)` macro (also known as `(t8n-skip:)`) which, when included with a transition, allows the player to speed up the transition by a given number of milliseconds per frame, by holding down any keyboard key, mouse button, or by touching the screen.
 * Added an `(after:)` changer macro, which is essentially a `(live:)` changer that only ever runs the hook once. However, unlike `(live:)`, it takes an optional second number that allows the player to speed up the delay by the given number of milliseconds per frame, by holding down any keyboard key, mouse button, or by touching the screen.
194
 * Added a `(collapsed:)` changer macro, which causes the attached hook's whitespace to collapse, as if by the `{` and `}` collapsing whitespace markup. This can also be used with `(enchant:)`.
195
 * Added a `(verbatim:)` changer macro (alias `(v6m:)`), which causes the attached hook or command to be printed verbatim, as if by the verbatim markup.
196
 * Added a `(text-indent:)` changer macro, which applies a leading indent to the attached hook, and can be applied to each line in the passage using, for example, `(enchant:?passage's lines, (text-indent:12))`.
197
198
 * Added a `(box:)` changer macro, which turns the attached hook into a box with given width and horizontal margins, a height scaling with window height, and a scroll bar if its contained prose exceeds its height.
 * Added a `(float-box:)` changer macro, a variant of `(box:)` which turns the hook into a separate pane floating on the window, using `position:fixed`. These have an explicit vertical position as well as horizontal position.
199
 * Added a `(text-rotate-x:)` and `(text-rotate-y:)`, which are 3D versions of `(text-rotate:)`, rotating the hook around the X or Y axis, making it appear to lean into the page with perspective.
200
 * Added the changer macros `(border:)`, `(border-size:)`, and `(border-colour:)` (aliases `(b4r:)`, `(b4r-size:)`, `(b4r-colour:)`) which add and adjust CSS borders for hooks. `(border:)` will automatically make the attached hook have `display:inline-block`, so that it remains rectangular and the border can properly enclose it.
201
 * Added a `(corner-radius:)` macro, which rounds the corners of the hook (using the CSS "border-radius" property, which, despite its name, works on elements without borders). It will also add padding, proportional to the amount of corner rounding, so that the corners don't encroach on the inner text.
202
 * Added a `(button:)` macro, which is designed especially for links. It is essentially a convenient shorthand for `(align:"=><=")+(box:"X")+(border:"solid")+(css:"padding:0px")+(corner-radius:16)`.
203
204
205
206
207
 * The following `(text-style:)` styles have been added:
   * "double-underline", "wavy-underline", "double-strike" and "wavy-strike", which are variants of "underline" and "strike". Be aware these will not work in Internet Explorer.
   * "fidget", which jolts the hook by one pixel in cardinal directions pseudorandomly.
   * "buoy" and "sway", which are slow, gentle movement animations to serve as counterparts to "rumble" and "shudder".
 * The following `(transition:)` transitions have been added:
208
   * "zoom", which makes the transitioning entity zoom in or out from the mouse cursor's position (or the last place the touch device was touched).
209
210
   * "fade-up", "fade-down", "fade-left", and "fade-right", which are combinations of "dissolve" with gentler sliding transitions.
   * "fade", which is an alias for "dissolve" (for consistency with the above, as well as the "fade-in-out" text style).
211
   * "blur", which uses the new CSS blur filter to make a hook appear or disappear in a blur. Note that this will not work in any version of Internet Explorer.
212
 * Added `(append-with:)`, `(prepend-with:)` and `(replace-with:)`, changers which modify the hook by adding a given string of code to the start or end of it, or replace it entirely. This is intended for use with things like dialogue tags or punctuation that's commonly used throughout the story.
213
 * Added two debugging changers, `(test-true:)` and `(test-false:)`, inspired by Chapbook's `ifalways` and `ifnever` mods, that ignore all of the values given to them (as well as their data types) and instead act like `(if:true)` or `(if:false)`, respectively. As with their inspirations, these are designed for quick debugging checks.
214

215
216
217
218
###### Commands

 * Added an `(input-box:)` macro, which places a `<textarea>` element in the passage, sized using the same values given to the `(box:)` macro, and optionally bound to a variable.
 * Added a `(force-input-box:)` macro, designed for linear narratives, that creates what seems to be a normal `(input-box:)`, but which, when typed into, instantly replaces the entered text with portions of a predefined string.
219
 * Added a `(checkbox:)` macro, which creates a labeled `<input type=checkbox>` element in the passage, which is bound to a boolean variable. You'll usually want to use a `2bind` binding with this macro.
220
 * Added a `(meter:)` macro, used for creating a videogame bar-graph meter that's bound to a numeric variable. You can provide this with a colour or gradient for the bar, and a text label, as well as make the bar left-aligned, right-aligned or centered.
221
222
 * Added a `(link-rerun:)` macro, which is similar to `(link-repeat:)`, but which replaces the hook on each click rather than appending to it.
 * Added a `(rerun:)` macro, which replaces a given hook with its original source, eliminating any changes made to it by `(replace:)` or other macros. This also runs any macros inside the hook an additional time.
223
 * Added an `(animate:)` macro, which causes an already-present hook to transition in again, using a specified transition and time.
224
225
226
 * Added a `(hide:)` macro, which removes the contents of a given hook from the passage, but allows the `(show:)` macro to restore the contents later. Hooks hidden with `(hide:)` will not re-run any containing macros when `(show:)` is used on them later.
 * Added a `(seq-link:)` macro, a variation of `(cycling-link:)` which does not cycle - it simply turns into plain text on the final string.
 * Added a `(verbatim-print:)` command macro (alias `(v6m-print:)`), a combination of `(verbatim:)` and `(print:)`. This is designed especially for printing player-inputted strings that may, for whatever reason, contain markup.
227
 * Added a `(verbatim-source:)` command macro (alias `(v6m-source:)`), a combination of `(verbatim-print:)` and `(source:)`, intended for debugging.
228
 * Added a debugging macro, `(ignore:)`. If you wish to temporarily disable a command in the passage you're currently testing, simply change its name to "ignore" and it will ignore all of the values given to it, without causing an error.
229
 * Added `(click-undo:)`, `(mouseover-undo:)`, and `(mouseout-undo:)`, to complement `(click-goto:)` and the rest.
230
 * Added `(link-fullscreen:)`, a command macro that creates a link that, when clicked, toggles the browser's fullscreen mode on and off. It takes two link text options, one for entering fullscreen, and one for exiting it, which are automatically updated to match the browser's current fullscreen state. Note that this will only make the `<html>` element fullscreen, for numerous reasons (mainly that enchanting the `<tw-story>` element with `(enchant:?page,` will deactivate fullscreen if it's the fullscreen element, due to the macro call wrapping `<tw-story>` in another element). Also note that because most browsers allow users to exit fullscreen mode at any time, there's no way to force fullscreen mode into one state or another. Also note that, because browsers only allow fullscreen mode to be entered from interaction elements, like links or buttons, there can't be a low-level "toggle fullscreen" command macro as an alternative to this.
231
 * Added `(checkbox-fullscreen)`, a version of `(link-fullscreen:)` that produces a checkbox instead of a link.
232
 * Added `(link-storylet:)`, a command macro that creates a link to the nth open storylet (or, if a 'where' lambda is given, the first open storylet whose (passage:) datamap matches the lambda).
233
 * Added `(icon-undo:)` and `(icon-redo:)`, two commands that replicate the default sidebar's "undo" and "redo" icons. Use these to reinsert these into the sidebar if you've modified it using `(replace:)` or `(append:)`, or simply place those icons into your passage text if you wish. You can change the icon to use a different Unicode character if you wish. You can also add text labels to these icons, which appear below them.
234
 * Added `(icon-restart:)` and `(icon-fullscreen:)`, two additional commands that can be used, with `(prepend:)` and `(append:)`, to add "fullscreen" and "reload" buttons to the sidebar. The "fullscreen" icon works similarly to the `(link-fullscreen:)` macro described above, while the "reload" icon performs similarly to `(reload:)` when clicked. These offer the same options as `(icon-undo:)` and `(icon-redo:)`.
235
 * Added `(icon-counter:)`, which produces a numeric display element that live-updates to match a bound number variable (rounded to a whole number). The element is roughly the same size as the sidebar icons, and designed to be used in the sidebar alongside them.
236
 * Added a debugging command, `(mock-visits:)`, which lets you re-create a game state where certain passages have been visited a certain number of times, so that the `visits` keyword and the `(history:)` array produce desired results. This command will cause an error unless it's used in debug mode.
237
238
 * Added a debugging command, `(assert:)`, which can be used to write an "assertion" expression about the game state of your story that should always be `true`, such as `(assert: $HP <= $maxHP)`. If some bug causes the assertion to produce `false`, a helpful error will be produced.
 * Added a debugging command, `(assert-exists:)`, which checks whether a hook matching the passed-in HookName, or a text occurrence matching the passed-in string, exists in the passage. If not, an error is produced.
239

240
##### Custom Macros
241
242

 * A new macro, `(macro:)`, allows you to write custom macros for Harlowe and store them in variables. `(set: $earthName to (macro: [(output:(either:"Terra","Earth"))]))` produces a custom macro that can be called by writing `($earthName:)`.
243
 * Added three macros, `(output:)` (alias `(out:)`), `(output-data:)` (alias `(out-data:)`) and `(error:)`, which are used to output final values for your custom macros. `(output-data:)` is used for macros that produce data values, such as `(min:)` or `(lowercase:)`, whereas `(output:)` is used for macros that produce commands that display complicated markup, such as `(cycling-link:)`. `(error:)` can be used to output custom error messages.
244
 * Added CodeHooks, which are special kinds of hooks that go inside macro calls, rather than just in passage prose. These are used to write the inner code of custom macros. You can use `(if:)`, `(for:)`, `(set:)`, and most other macros inside one. Their contents are invisible at runtime - only the result produced by `(output:)` or `(output-hook:)` is visible - so you can comment your code by simply writing prose inside it.
245
 * The aforementioned `-type` syntax is also used to define the parameters of custom macros. Place a datatype (such as `str` or `dm`) in front, and a temp variable after it (such as `str-type _name`) to specify an input value for the macro. `(set: $ASCIImeter to (macro: num-type _HP, num-type _maxHP, [(output-data: (str-repeated: _HP,"=")+(str-repeated:_maxHP - _HP,"."))])` produces a custom macro that can be called by writing `($ASCIImeter: 2,10)` and produces an error when you write `($ASCIImeter: 2)` or `($ASCIImeter: 2, "10")`.
246
   * You may also specify that a macro accepts a sequence of values, similar to macros like `(a:)` or `(either:)` by writing `...` before a parameter. `(set: $mean to (macro: ...num-type _a, [(output:(folded:making _total via _total + it, ..._a) / _a's length)]))` can be given any amount of numbers, and puts them into an array inside `_a`.
247

248
##### Debug Mode
249

250
 * Added a draggable area that, when clicked and dragged, lets you resize the debug mode panel horizontally.
251
 * Added a debug mode panel listing which enchantments are present in the passage, and the changers they contain. This highlights `(enchant:)` effects, as well as `(click:)`, `(mouseover:)` and `(mouseout:)`.
252
 * Added a debug mode panel listing which storylet passages are currently available, and their 'where' lambdas. This panel is only visible if you have `(storylet:)` macros in your story.
253
 * The debug mode variables panel now has a "(source:)" button for each variable containing a complex value (i.e. not a string, boolean, number), letting you examine and copy that variable's value as Harlowe code.
254
 * The debug mode variables panel now has a "Copy $ variables as (set:) call" button at the bottom, which copies to the clipboard a string of Harlowe code that will (set:) each global variable to their currently displayed value.
255
 * The debug view now reveals command macros and expressions, such as `(enchant:)`, which don't print anything and are normally hidden during play.
256
 * Added an alternative debug view, "DOM view", which labels the unique elements on the page with their current HTML tag and a few relevant attributes, as well as spacing out the elements to better distinguish them. The elements that will be highlighted this way are `<tw-story>`, `<tw-passage>`, `<tw-sidebar>`, `<tw-include>`, `<tw-hook>`, `<tw-expression>`, `<tw-link>`, `<tw-dialog>`, `<tw-columns>`, `<tw-column>`, and `<tw-align>`.
257
 * Now, whenever the first error of your story is displayed, debug mode will automatically, immediately enable itself, so you can begin debugging there and then.
258

259
##### Other
260

261
 * Added a "toggle fullscreen" button to the sidebar, underneath the "undo" and "redo" buttons. It should only appear if fullscreen mode is permitted by the browser. The same caveats about fullscreen mode for `(link-fullscreen:)` are present here.
262
 * The syntax highlighter no longer highlights syntactic elements inside strings. While this had some fringe benefit in cases where strings contained code to be printed, I've decided it's too distracting in more usual cases.
263
 * The syntax highlighter now colourises macro names based on their returned data type.
264
 * Added a `<noscript>` element to the output HTML, containing a sentence instructing that JavaScript should be enabled to play the story (as per SugarCube).
265

266
### 3.1.0 changes (Sep 24, 2019):
267

268
#### Bugfixes
269

270
271
272
 * Fixed a bug where the CSS that makes sequences of consecutive line breaks cumulatively smaller in height was incorrectly being applied to non-consecutive `<br>`s that only had plain text between them - for instance, single line breaks separating words or phrases with no other formatting, or line breaks in the verbatim markup.
 * `(alert:)`, `(confirm:)` and `(prompt:)` no longer error when playing in certain browser environments, including testing within certain versions of the desktop Twine app itself. (For more details, see "Alterations".)
   * Additionally, user script error messages (and Harlowe crash messages) should now successfully appear in those environments as well.
273
 * Fixed a bug where header and footer tagged passages were not being transcluded in alphabetical order (instead using passage creation order) on recent versions of Chrome.
274
275
   * Additionally, header and footer tagged passages are now sorted in the "natural sort" order used by `(sorted:)`, so that, for instance, a header passage named "10" appears after a header passage named "2".
 * Fixed a long-standing bug where `(append:)` and `(prepend:)`, when given multiple target hooks or strings, wouldn't perform the appends or prepends in a single pass - `A(append:"A","B")[B]` would produce `ABB` instead of `AB`, against intuition.
276
 * Fixed a bug where using an external temp variable as a property inside a lambda (such as `_foo` in `where _foo of $bar contains it`) wouldn't work.
277
 * Fixed a bug where the error message for giving `(event:)` the wrong type of lambda was incorrectly worded.
278
279
 * Fixed a bug where using the sidebar's "redo" button wouldn't cause the debug panel's "Turns" dropdown to update.
 * Fixed a bug where the debug mode's variables button's label sometimes had the wrong number on it.
280
281
 * Fixed a bug where an error given to the spread `...` syntax, such as `(a: ...(a:2/0))`, wouldn't be displayed, instead producing an unrelated error.
 * Fixed a bug where an error in the passage name given to `(passage:)`, such as `(passage: (str:1/0))`, wouldn't be displayed, instead producing an unrelated error.
282
 * Fixed a long-standing bug in `(substring:)` where negative indices wouldn't work correctly if the string contained any Unicode "astral plane" characters (any characters not in the Basic Multilingual Plane).
283
 * Fixed a bug where lambdas weren't being printed correctly (for example, as `a "via ... " lambda`) in certain error messages.
284
285
 * Fixed a bug where certain `(text-style:)` changers, specifically 'outline', 'shadow', 'blur', 'blurrier', 'emboss' and 'smear', often didn't work when added to `(text-color:)` changers, and vice-versa.
 * Fixed a bug where using `(show:)` to reveal a hidden hook more than once (that is, to reveal a hook already revealed) would cause its code and prose to be run and shown more than once, behaving similarly to `(link-repeat:)`.
286
 * Fixed a limitation where certain commands (including `(show:)`, `(cycling-link:)`, `(enchant:)`, `(click-goto:)`, `(mouseover-goto:)`, `(mouseout-goto:)` and `(link-show:)`) wouldn't correctly interact with temp. variables or hook names after being `(set:)` into a variable in one passage and then used in another (although there's not very much utility in doing this).
287
 * Fixed a bug where the debug view notification messages for `(set:)`, `(move:)` and `(put:)` (that tell you what value the variable now contains) were not being produced.
288

289
#### Alterations
290

291
292
293
 * As you know, passage links can contain markup like `[[$passageVar]]`, and that markup is evaluated as if it were an expression to determine the correct passage name. But formerly, if there really was a passage whose named lined up exactly with the markup (in this example, a passage whose name literally was "$passageVar") then it wasn't (easily) possible to link to it. This is now changed, so Harlowe will always prioritise exact matches first, and these passages can be successfully linked to.
 * Furthermore, if a link's passage name is an exact match to a passage, then the markup inside that passage name will now be ignored. For instance, `[[//Bleah//]]` will, if it links to a passage, be rendered as "//Bleah//" instead of "Bleah" in italics, and `[[board_shorts]]` will no longer be considered to have a temp variable named `_shorts` inside it.
 * The aforementioned rules for passage names in links now apply to `(link-reveal-goto:)` links as well as normal `(link-goto:)` links.
294
 * `(alert:)`, `(confirm:)` and `(prompt:)` have been reimplemented from the ground up as pure HTML dialogs, instead of using the browser built-in `alert()`, `confirm()` and `prompt()` Javascript functions. This brings a few big changes: they now, by default, follow the colour scheme of Harlowe (black text on white, with links for buttons), can be affected by user CSS, and should appear and behave the same on every platform. However, they should still have the *exact same semantics* as their former versions: passage rendering and code execution should still halt while the dialogs are on-screen, links, `(mouseover:)` and `(mouseout:)` elements should not be interactable while they're on-screen, `(live:)` and `(event:)` macros shouldn't fire when they're on-screen, and `(confirm:)` and `(prompt:)` should still display their dialogs at evaluation time (i.e. when a macro expression containing them is rendered). Do report any bugs or behaviour that doesn't correspond to this description.
295
 * `(prompt:)` has additionally been changed, such that clicking "Cancel" now makes it evaluate to the default value (the second string passed to it) regardless of the contents of the text area. Formerly, it evaluated to `""` (an empty string). This isn't to be considered a compatibility break, as it's already and still possible for an empty string to be returned by emptying the text area and clicking "OK".
296
 * `(rgba:)` and `(rgb:)`, as well as `(hsla:)` and `(hsl:)` have been merged - the "a" version is now the alias of the other, and the fourth "alpha" value is optional for both. This should have no effect on existing code that uses these macros.
297
 * Now, `(history:)` can be given an optional "where" lambda to provide only passage names whose passages match the lambda. The lambda is given the same passage datamaps which are returned by `(passage:)`. `(history: where its tags contains "Forest")` is essentially a shorthand for `(find: where (passage: it)'s tags contains "Forest", ...(history:))`.
298
 * The debug view colours for various macros have been updated to recognise more macro names.
299
 * Raw `<textarea>` tags will no longer have their contained text converted to HTML elements as if it was Harlowe syntax.
300
 * Now, using `(enchant:)` to enchant the `(text-colour:)` of ?Page or ?Passage will no longer override the text-colour of links - only by enchanting the enclosing hooks, or the ?Link hook, can change their non-hover colour.
301
 * The default CSS for `<pre>` elements now has a smaller `line-height`.
302
 * When a Javascript error in a story's user script is thrown, the stack trace in the resulting dialog is now more concise, no longer printing Harlowe engine stack frames.
303

304
#### Additions
305

306
##### Coding
307
308

 * Added a `visits` identifier (aliased as `visit`) to join `it` and `time`. It equals the number of times the current passage was visited, including this visit. The purpose of this identifier is to make it easier to replicate the Twine 1 `<<once>>` macro, which only displayed text on the first visit to a passage, and whose absence was a long-standing weakness in Harlowe. Previously, it could be replicated using the rather cumbersome `(if: (passage:)'s name is not in (history:))`, but now, it can be replicated using `(if: visits is 1)`, which expresses the intent much better and approaches the original's brevity. Furthermore, it makes it much easier to specify hooks to display on third, fourth, or even-numbered visits, using `(if: visits is 3)`, `(if: visits % 2 is 0)` and so forth. The reason this is an identifier and not a macro (like `(passage:)`) is because I want identifiers to be used for small, "volatile" information that's specific only to the current context, such as `it` and `time`. (`(history:)`, in retrospect, could have been an identifier.)
309
 * Also added an `exits` identifier (aliased as `exit`), which equals the number of "exit" elements in the passage (links, `(mouseover:)` or `(mouseout:)` elements).
310
 * Added the special hookname properties, "chars", "lines", and "links", which can be used to select special kinds of structures inside hooks.
311
   * `?hook's chars` selects each individual character within a hook, as if they were wrapped in hooks themselves. This is meant to revive the memorable `.char`-selecting CSS functionality in Twine 1, and can, in particular, be used with `(enchant:)` and `(hover-style:)`.
312
   * `?hook's lines` selects individual lines of text within a hook. A line is any run of text or code between line breaks (or the passage's start and end) - a word-wrapped paragraph of prose is considered a single "line" as a result.
313
   * `?hook's links` selects hyperlinks, similar to `?Link`, but only within the given hook.
314
 * Now, you can create consecutive subsets of arrays, strings and hooknames by writing two positions, such as `1st` and `3rd`, and joining them together with `to`, and using that as a data name - `$arr's 1stto3rd` is the same as `$arr's (a:1,2,3)`, and `"Jelly"'s 3rdlasttolast` is "lly". This is a more readable alternative to using arrays of positions. Note that, as with `2nd` etc., these are case-insensitive, so you can write these using the capitalisation `3rdlastToLast` if you wish. (Note that this isn't intended to replace subsets whose ranges are defined by variables, such as in `$a's (range:$p1, $p2)`.)
315

316
##### Macros
317

318
 * Added `(cond:)`, a macro similar to `(if:)` but which conditionally chooses between two data values, rather than hooks. `(cond: visits is 1, "Strange", "Familiar")` is "Strange" on the first visit and "Familiar" afterward. Since it's not a changer, you can use it in expressions within other macros freely. Additionally, you can add further conditions - `(cond: $gender is "masc", "god", $gender is "femme", "goddess", $gender is "pan", "goddex", "deity")` - to choose among several values precisely.
319
 * Added `(nth:)`, a macro that takes a sequence of values and chooses one at a given position, similar to the `'s` or `of` indexing syntax for arrays. `(nth: 2, $mary, $edith, $gwen)` is the same as `(a: $mary, $edith, $gwen)'s 2nd`. It serves as a more readable alternative to the indexing syntax in certain situations, such as using it with `visit` in cases like `(nth: visit, "hissing", "whirring", "clanking")`.
320
 * Added `(more:)`, a convenient shorthand for `(event: when exits is 0)`. When there are no more exits, it will run and display even "more" prose. Loosely inspired by the Ink language's "gather" syntax, its main purpose is to be used alongside `(link:)`, as a shortcut for putting `(show:)` inside it - `(link:"Duck")[It swims on the lake.(show:?next)] |next)[It dives underwater.]` can be rewritten as `(link:"Duck")[It swims on the lake.] (more:)[It dives underwater.]`.
321
 * Added a `(passages:)` macro, which returns an array containing the `(passage:)` datamaps for every passage in the game, but also can be given a "where" lambda to filter that array.
322
 * Added a gradient data type, a `(gradient:)` macro, and a `gradient` datatype name. This can be used to quickly create special images called gradients, which are smooth linear fades between various colours. These are implemented using CSS `linear-gradient`s, and the `(gradient:)` macro has similar syntax to it. Currently, these can only be used with `(background:)`.
323

324
##### Markup
325

326
 * Added "unclosed hook" markup: `[==` (`[` followed by any number of `=`, similar to the aligner markup) is an opening bracket that automatically closes when the passage or enclosing hook ends, so you don't need to include the closing bracket yourself. This is inspired by the `<<continue>>` custom macro I wrote for Twine 1 (not to be confused with SugarCube's macro of the same name), and is designed for convenient use with changers that you may want to apply to the entire remainder of the passage, such as `(link:)`, `(event:)`, `(t8n:)` and such. `(link: "Next.")[=` replicates the behaviour of `<<continue "Next.">>` easily.
327

328
##### Debug Mode
329

330
331
 * Added a new toggleale pane to the debug mode panel, "Source", which displays the current passage's source code. This is designed to supplement the "debug view" option, which shows the passage's current state, by letting you compare it to the original code. This pane currently has no syntax highlighting, such as that used in the Twine editor.
 * Added another toggleable pane, "Errors", which displays a record of every error that has been displayed in the story, so far, up to a limit of 500. This should be of assistance when dealing with errors inside `(live:)` hooks, or other hooks whose content appears and disappears abruptly.
332
333
 * The debug mode variables pane now lists the contents of datamaps, arrays and datasets, as separate rows.
 * Colours in the variables pane now have a colour swatch in their listing.
334

335
### 3.0.2 changes (Apr 17, 2019):
336

337
#### Bugfixes
338

339
 * Fixed a startup bug that potentially caused `(dropdown:)` menus to stop affecting their bound variables for the rest of the game.
340
 * Now, `(alert:)`, `(prompt:)` and `(confirm:)` produce errors if they are used in a browser that doesn't support Javascript's `prompt()`, `alert()` or `confirm()` functions, instead of crashing the page.
341
 * Fixed the `(str:)` macro alias added in 3.0.0 mysteriously not actually having been added.
342

343
### 3.0.1 changes (Apr 14, 2019):
344

345
#### Bugfixes
346
347
348

 * Fixed a bug where the SessionStorage state-preserving system introduced in 3.0.0 would interfere with the "Test story starting here" feature in the Twine editor.

349
#### Alterations:
350
351
352

 * If the `(loadgame:)` macro encounters an error while loading save data (such as, a passage it refers to no longer exists in this version of the story) then a polite dialog box (a simple JavaScript `prompt()`) will appear suggesting that the save data might be outdated, and asking the reader whether or not the save data should be deleted.

353
### 3.0.0 changes (Jan 11, 2019):
354

355
#### Bugfixes
356

357
 * Fixed a bug where the story crashes on startup if the page's URL contains a hash identifier that doesn't have "stories" in it (such as in `story.html#what`).
358
 * Fixed a bug where the story crashes on startup if, for some reason, localStorage exists but cannot be accessed.
359
 * Fixed a bug where same-precedence arithmetic operators (`+` and `-`, or `/` and `*`) had incorrect associativity (so, `3 - 5 + 2` was interpreted as `3 - (5 + 2)` instead of `(3 - 5) + 2`).
360
 * Temp variables finally work correctly with changers that defer a hook until some event occurs, like `(link:)`, `(click:)` and such. Now, you can reference temp variables inside the hook, such as in `(link:"Read")[It reads: _engraving]`, just as you can with other kinds of changers.
361
 * Fixed a bug where supplying multiple shortened `is` or `is not` comparisons, in a form such as `$a is $b and $c`, would produce an incorrect result.
362
 * Fixed a bug where the debug view's `(set:)` messages were worded incorrectly when setting global variables.
363
 * A more useful error message is given if you write a link with no passage name (such as `[[Go->]]`).
364
 * Fixed a bug where you could + a changer, a hookname, or a colour to any arbitrary command, like a `(goto:)` command.
365
 * Fixed a bug where having a `(for:)` macro's lambda's `where` clause return something other than a boolean, such as in `(for: each _a where 127)[]`, wouldn't produce an error message.
366
 * Fixed a bug where `contains` would wrongly error if used to check if an empty string `""` contained anything.
367

368
#### Alterations
369

370
 * Now, when playing, the current game session will attempt to preserve itself across browser reloads and back-forward navigation using browser SessionStorage. This means that reloading the page (without closing the window or tab) should also automatically reload the player's position in the story, as if by `(load-game:)`. This does not apply when using `(reload:)`, however, which always returns the story to the beginning. If an error occurs while loading this data (such as, a passage it refers to no longer exists in this version of the story) then it will be silently ignored.
371
 * The `(replace:)`, `(append:)` and `(prepend:)` macros now no longer target any hooks or text that haven't been rendered yet - so, `(replace: "cool")[hot] cool water` won't work because the `(replace:)` runs before "cool water" has rendered, but `cool water (replace: "cool")[hot]` and something like `(link: "heat")[(replace: "cool")[hot]] cool water` will. This finally normalises what was formerly very inconsistent behaviour across these three macros - `(replace:)` couldn't target forthcoming hooks but could target later text, and `(append:)` and `(prepend:)` would do the others' behaviour on forthcoming hooks.
372
 * The `(text:)` macro now has another alias, `(str:)`. This alias will now be the preferred name for this macro in the documentation, mainly due to the arrival of other string macros that begin with "str-", and additionally to avoid semantic conflict with the various "text-" changer macros like `(text-style:)`.
373
374
 * To more clearly separate the concepts of "printing data" and "running commands" in Harlowe, the `(print:)` macro will no longer run commands passed to it (that is, `(print:(go-to:"Foo"))` and `(go-to:"Foo")` will no longer do the same thing - the former will just print out a descriptive string, as if printing out a changer). Commands can now only be run by placing them directly in the passage (either as plain calls, inside variables, or wrapped in strings that (print:) receives).
 * Passage links no longer have a `passage-name` attribute indicating which passage they lead to, which the player could inspect using developer tools.
375
 * If links' text contains an error message (for instance, in the case of `(link-replace:"(print:2+true"))[]`), then the link can no longer be clicked (so that the error message can be expanded).
376
 * Error messages should now explain in slightly more detail what kind of lambda a macro requires (`"a "where ..." lambda"`, for instance).
377
 * Now, a `(transition:)` added to `(link:)`s, `(click:)`s, `(mouseover:)`s and other such macros will no longer cause the links or other elements to use the named transition themselves - instead, it will only be applied to the attached hook when it is made to appear.
378
 * `(show:)` will no longer produce an error if it tries to show a hook that's already visible, for consistency with other macros that accept hooknames, like `(click:)`. (Actually, it never did this in the first place, due to a bug.)
379
 * The "undo" and "redo" buttons in the story's sidebar are now brighter by default.
380
 * Various lambda macros that accept multiple values - namely `(for:)`, `(all-pass:)`, `(some-pass:)`, `(none-pass:)`, `(find:)`, and `(altered:)` - no longer error if no values are given after the lambda - for instance, `(for: each _a, ...$arr)[]` now no longer errors if `$arr` contains 0 elements.
381
 * Syntax highlighting: Tweaked a few colours to be more readable in dark mode, and removed the "smart quote" skewing to signify matching pairs of quote marks (as it was interfering with the cursor position sometimes).
382

383
#### Additions
384

385
##### Datatypes
386
387
388

 * Added `is a` and `is an` operators, which can be used to determine what datatype a variable or piece of data is - `$message is a string` is true if the variable is a string. The datatype names are `number` or `num`, `string` or `str`, `boolean`, `array`, `datamap` or `dm`, `dataset` or `ds`, `command`, `changer`, and `color` or `colour`.
 * Added a `matches` operator, which functions similarly to `is a`, but can also be used to check if a data structure's shape resembles a pattern - a similar data structure with datatype names as "holes" in it. `(a: 2, 3) matches (a: num, num)` checks that the first array contains exactly two numbers. `(dm: "Faction", str) matches (dm: "Faction", "Slugbikers")` checks that the second datamap contains only one name with a string value. Nested patterns - `(a: (a: num), num, num)` - are also usable.
389
 * Added a `bind` operator, which is used to "bind" variables to certain interaction macros, like `(cycling-link:)`, described below.
390

391
##### Macros
392

393
 * You can now attach changers to command macros, including `(print:)`, `(display:)` and `(link-goto:)`, as well as regular passage links. This allows you to style them without needing to wrap them in a separate hook. (A subset of commands, like `(enchant:)` and `(stop:)`, still can't have changers attached, however.)
394
395
396
397
398
399
 * Added `(transition-depart:)` and `(transition-arrive:)` (aliases `(t8n-depart:)` and `(t8n-arrive:)`), macros which, along with an optional `(t8n-time:)`, allow you to finally change the passage transition used by links, by just attaching them to the front: `(t8n-depart:"dissolve")[[Think it over]]` will create a link that, when clicked, goes to the "Think it over" passage and fades out the current passage using a dissolve transition. These can be used in tandem for a number of interesting effects: `(t8n-depart:"dissolve")+(t8n-arrive:"pulse")[[That memory...]]` will work as expected. You can also use these with `(link-goto:)`, `(link-undo:)`, and work with `(enchant: ?Link)` too.
 * The following transitions have been added:
   * "instant", which makes the transitioning entity instantly appear or disappear. (Try placing `(enchant:?Link, (t8n-arrive:"instant"))` in your header passages for snappy transitions throughout the story.)
   * "rumble", which shakes the transitioning entity vertically as it appears or disappears (similar to `(text-style: "rumble")`).
   * "slide-up", "slide-down", "slide-left" and "slide-right", which slide the transitioning entity in or out from offscreen.
   * "flicker", which coarsely flickers the transitioning entity as it appears or disappears, reminiscent of flickering fluorescent lights.
400
 * Added `(cycling-link:)`, a popular interaction macro from Twine 1. Clicking a cycling link changes its text to the next string in the given list, and can optionally set a variable to that same string. An example usage is `(cycling-link: bind $flower, "rose", "violet", "daffodil")`. This can use an attached `(t8n:)` to transition each string in as it's clicked. (I'd meant to include for a very long time, but it needed several other features in this update to fully meet the UX standards of Harlowe.)
401
 * Added `(dropdown:)`, an interaction macro similar to `(cycling-link:)` that creates a dropdown `<select>` menu instead, and binds a variable to whichever string is currently selected.
402
 * Added a string-specific shorthand of `(repeated:)` called `(str-repeated:)` (and aliased as `(string-repeated:)`). `(str: ...(repeated: 14, "-+*+"))` is the same as `(str-repeated: 14, "-+*+")`.
403
 * Added `(reversed:)`, a macro which constructs an array with the given elements in reverse order, and `(str-reversed:)`, a shorthand that reverses a single string's characters. (Prior to now, you could accomplish this with `(folded: _e making _a via (a: _e) + _a, (a:), ...$arr)`, but this offers a far easier formulation.)
404
 * Added `(click-goto:)`, `(mouseover-goto:)` and `(mouseout-goto:)`, which are combinations of `(click:)`, `(mouseover:)` and `(mouseout:)` with `(goto:)`, similar to `(link-goto:)`.
405
 * Added `(link-reveal-goto:)`, a combination of `(link-reveal:)` and `(go-to:)` that lets you run commands like `(set:)` before going to another passage. An example usage is `(link-reveal-goto: "Link text", "Passage name")[(set: $x to 1)]`.
406
 * Added `(link-show:)`, a link which, when clicked, shows the given hidden hooks, as if by `(show:)`. Just like `(show:)`, it can also have changers attached to it.
407
 * Added `(event:)`, a changer similar to `(live:)` which live-renders the hook only once, and only when the given lambda, which is run every 20ms, produces true. It accepts a "when" lambda, which is just a version of "where" that's grammaticaly appropriate for `(event:)`.
408

409
### 2.1.0 changes (Dec 07, 2017):
410

411
#### Bugfixes
412

413
 * Now, using `(enchant:)` to change the `(text-colour:)` of `?Link` (normal links) will correctly override the default CSS link colour.
414
 * Fixed a bug where the alternative macro spellings `(text-color:)` and `(color:)` were displayed as erroneous in the editor.
415
 * Now, `(enchant:)` correctly displays an error when the changer provided to it includes a `(replace:)`, `(append:)` or `(prepend:)` command.
416
 * Re-fixed the bug where `(pow:)` only accepted 1 value instead of 2, and also fixed `(sqrt:)` and the `(log:)` variants, which weren't working at all.
417
 * Fixed a parsing bug where `5*3-2`, without whitespace around the minus sign, would break the order of operations.
418

419
#### Alterations
420
421
422

 * Changed the `~~` markup to produce a strikethrough style using an `<s>` element, instead of a censor-bar style using a `<del>` element. The censor-bar style, which was used in all previous versions but not ever properly documented, was bugged to always be black even if the text colour was not black. It can be replicated in stories by simply using a `(background-colour:)` macro (preferably set to a variable) in its place.
 * Removed the default `line-height` CSS for `<h1>` and other header elements, because it was causing problems with line-wrapped headers.
423

424
#### Additions
425

426
##### Debug Mode
427
428
429
430

 * Added a button to hide/show the variables pane at will.
 * Reduced the maximum CSS height of the variables pane from 90vh (90% of the window's height) to 40vh.
 * Gave variable rows a flex-shrink of 0, which I'm told prevents rows from contracting to unreadability when the pane requires scrolling.
431
 * The variables pane should now also list temporary variables, and their locations. This currently only lists those that have been explicitly (set:) or (put:), and ignores those that are created inside (for:) loops.
432

433
### 2.0.1 changes (Apr 26, 2017):
434

435
#### Bugfixes
436
437

 * Fixed a bug where `(enchant:)` applied to ?Page couldn't override CSS properties for `<tw-story>` (including the default background colour and colour).
438
 * Fixed a Passage Editor display bug where the left margin obscured the first letter of lines.
439

440
### 2.0.0 changes (Feb 15, 2017):
441

442
#### Bugfixes
443

444
 * Fixed a bug where comparing a value with an error (such as `2 is (3 + 'X')`) would suppress the error.
445
446
447
 * Fixed a bug where subtracting non-subtractable values (such as booleans) wouldn't produce an error, instead implicitly converting the values to numbers, and potentially producing the Javascript value `NaN`.
 * Fixed a bug where subtracting arrays and datasets wouldn't correctly compare contained data structures - for instance, `(a:(a:1)) - (a:(a:1))` wouldn't work correctly.
 * Fixed a bug where the `(dataset:)` macro, and adding datasets, wouldn't correctly compare data structures - for instance, `(dataset: (a:),(a:))` would contain both identical arrays, as would `(dataset: (a:)) + (dataset: (a:))`.
448
   * Additionally fixed a bug where data structures were stored in datasets by reference, allowing two variables to reference (and remotely alter) the same data.
449
450
 * Fixed a bug where using `(move:)` to move a subarray or substring (such as `(move: $a's (a:2,3) to $b))` wouldn't work.
 * Fixed a bug where using `(set:)` to set a substring, when the given array of positions contained "length" (such as `(set: $a's (a:1,"length")) to "foo")`), wouldn't produce an error.
451
 * Fixed a bug where the `(count:)` macro would give the wrong result when the data to count (the second value) was an empty string.
452
453
 * Now, a `(print:)` command that contains a command will only execute the contained command if itself is actually displayed in the passage - the code `(set: $x to (print:(goto:'X')))` would formerly perform the (goto:) immediately, even though the (print:) was never displayed.
 * Now, datasets contained in other datasets should be printed correctly, listing their contents.
454
 * `(alert:)`, `(open-url:)`, `(reload:)` and `(goto-url:)` now correctly return command values rather than the non-Harlowe value `undefined` (or, for `(open-url:)` a Javascript Window object). This means that `(alert:)`'s' time of execution changes relative to `(prompt:)` and `(confirm:)` - `(set: $x to (prompt:"X"))` will display a JS dialog immediately, but `(set: $x to (alert:"X"))` will not - although this is conceptually reasonable given that `(prompt:)` and `(confirm:)` are essentially "input" commands obtaining data from the player, and `(alert:)` is strictly an "output" command.
455
 * Now, line breaks between raw HTML `<table>`, `<tr>`, `<tbody>`, `<thead>` and `<tfoot>` elements are no longer converted into erroneous `<br>` elements, which are moved to just above the table. Thus, one can write or paste multi-line `<table>` markup with fewer problems arising.
456
 * Fixed bugs where various macros (`(subarray:)`, `(shuffled:)`, `(rotated:)`, `(datavalues:)`, `(datamap:)`, `(dataset:)`) would end up passing nested data structures by reference (which shouldn't be allowed in Harlowe code). For instance, if you did `(set:$b to (rotated: 1, 0, $a))`, where $a is an array, then modifying values inside $b's 1st would also modify $a.
457
 * Fixed a bug where setting custom values in a datamap returned by `(passage:)` would save the data in all subsequent identical `(passage:)` datamaps. (For instance, `(set: (passage:'A')'s foo to 1))` would cause all future datamaps produced by `(passage:'A')` to have a "foo" data name containing 1.) The `(passage:)` macro, or any other built-in macros' return values, are NOT intended as data storage (and, furthermore, are not saved by `(savegame:)` etc).
458
459
 * Fixed the bug where a `(goto:)` command inside a hook would prevent subsequent commands inside the hook from running, but subsequent commands outside it would still continue - for instance, `(if:true)[(go-to:'flunk')](set:$a to 2)` would still cause the `(set:)` command to run.
 * Fixed the bug where `(current-time:)` wouldn't pad the minutes value with a leading 0 when necessary.
460
 * Fixed the bug where referring to a variable multiple times within a single `(set:)` command, like `(set: $a to 1, $b to $a)`, wouldn't work as expected.
461
 * The "pulse" transition (provided by `(transition:)`) now gives its attached hook the `display:inline-block` CSS property for the duration of the transition. This fixes a bug where block HTML elements inside such hooks would interfere with the transition animation.
462
 * Revision changers (`(replace:)`, `(append:)`, `(prepend:)`) that use hook names can now work when they're stored in a variable and used in a different passage. So, running `(set: $x to (replace:?1))` in one passage and `$x[Hey]` in the next will work as expected.
463
 * Differing revision changers can be added together - `(append: ?name) + (prepend: ?title)`, for instance, no longer produces a changer which only prepends to both hooks.
464
 * Fixed various mistakes or vaguaries in numerous error messages.
465

466
#### Alterations
467

468
##### Removed behaviour
469

470
 * In order to simplify the purpose of hook names such as `?room`, you can no longer convert them to strings, `(set:)` their value, `(set:)` another variable to them, or use them bare in passage text. The `(replace:)` macro, among others, should be used to achieve most of these effects.
471
 * Using `contains` and `is in` on numbers and booleans (such as `12 contains 12`) will now produce an error. Formerly, doing so would test whether the number equalled the other value. (The rationale for this was that, since the statement `"a" contains "a"` is the same as `"a" is "a"`, then so should it be for numbers and booleans, which arguably "contain" only themselves. However, this seems to be masking certain kinds of errors when incorrect or uninitialised variables or properties were used).
472
 * Now, various macros (`(range:)`, `(subarray:)`, `(substring:)`, `(rotated:)` etc.) which require integers (positive or negative whole numbers) will produce errors if they are given fractional numbers.
473
 * It is now an error to alter data structures that aren't in variables - such as `(set: (a:)'s 1st to 1)` or `(set: (passage:)'s name to "X")` - because doing so accomplishes nothing.
474
 * Attaching invalid values to hooks, such as `(either:"String")[text]`, `(a:2,3,4)[text]` or `(set: $x to 1) $x[text]`, will now result in an error instead of printing both the value and the hook's contents.
475
 * Writing a URL in brackets, like `(http://...)`, will no longer be considered an invalid macro call. (To be precise, neither will any macro whose `:` is immediately followed by a `/`, so other protocol URLs are also capable of being written.)
476

477
##### Markup
478

479
 * Now, if you write `[text]` by itself, it will be treated as a hook, albeit with no name (it cannot be referenced like `?this`) and no attached changer commands. This, I believe, simplfies what square brackets "mean" in passage prose. Incidentally, temporary variables (see below) can be `(set:)` inside nameless unattached hooks without leaking out, so they do have some semantic meaning.
480
 * Now, you can attach changer macros to nametagged hooks: `(if: true) |moths>[Several moths!]`, for instance, is now valid. However, as with all hooks, trying to attach plain data, such as a number or an array, will cause an error.
481
 * Hook-attached macros may now have whitespace and line breaks between them and their hooks. This means that `(if: $x)  [text]` and such are now syntactically acceptable - the whitespace is removed, and the macro is treated as if directly attached. (This means that, if after a macro call you have plain passage text that resembles a hook, you'll have to use the verbatim markup to keep it from being interpreted as such.)
482

483
##### Code
484
485
486
487

 * Now, when given expressions such as `$a < 4 and 5`, where `and` or `or` joins a non-boolean value with a comparison operation (`>`, `<=`, `is`, `contains`, etc.), Harlowe will now infer that you meant to write `$a < 4 and it < 5`, and treat the expression as that, instead of producing an error. This also applies to expressions like `$a and $b < 5`, which is inferred to be `5 > $a and it > $b`. This is a somewhat risky addition, but removes a common pitfall for new authors in writing expressions. (Observe that the above change does not apply when `and` or `or` joins a boolean - expressions like `$a < 4 and $visitedBasement`, where the latter variable contains a boolean, will continue to work as usual.)
   * However, this is forbidden with `is not`, because the meaning of expressions like `$a is not 4 and 5`, or `$a is not 4 or 5` is ambiguous in English, and thus error-prone. So, you'll have to write `$a is not 4 and is not 5` as usual.
 * Now, when working with non-positive numbers as computed indexes (such as `$array's (-1)`), Harlowe no longer uses `0` for `last`, `-1` for `2ndlast`, and so forth - instead, `-1` means `last`, `-2` means `2ndlast`, and using `0` produces an error. (So, `"Red"'s (-1)` produces "d", not "e".)
488
 * Now, you can optionally put 'is' at the start of inequality operators - you can write `$a is < 3` as a more readable alternative to `$a < 3`. Also, `$a is not > 3` can be written as well, which negates the operator (making it behave like `$a is <= 3`).
489
 * Now, trying to use the following words as operators will result in an error message telling you what the correct operator is: `=>`, `=<`, `gte`, `lte`, `gt`, `lt`, `eq`, `isnot`, `neq`, `are`, `x`.
490
 * Passage links can now be used as values inside macros - `(set: $x to [[Go down->Cellar]])` is now valid. You may recall that passage links are treated as equivalent to `(link-goto:)` macro calls. As such, `(set: $x to [[Go down->Cellar]])` is treated as identical to `(set: $x to (link-goto:"Go down","Cellar"))`.
491
 * Revision macros such as `(replace:)`, `(append:)` and `(prepend:)` can now accept multiple values: `(replace:?ape, ?hen)`, for instance, can affect both hooks equally, and `(replace:'red', 'green')` can affect occurrences of either string.
492
493
 * Now, adding two `(append:)` or `(prepend:)` macros which target the same hook, such as `(append:?elf) + (append:?elf)`, no longer creates a changer that appends/prepends to that same hook twice.
 * Hook names, even added together, can now be recognised as the same by the `is` operator if they target the same hooks (including sub-elements).
494
 * The `(move:)` macro now accepts multiple `into` values, like `(put:)`.
495
 * The `(count:)` macro now accepts multiple data values, and will count the total occurences of every value. For instance, `(count: "AMAZE", "A", "Z")` produces 3.
496
 * Now, `debug-header` tagged passages are run after `header` tagged passages in debug mode, for consistency with the order of `debug-startup` and `startup`.
497
 * Link macros like `(link-replace:)` will now produce an error when given an empty string.
498

499
##### HTML/CSS
500

501
 * The default Harlowe colour scheme is now white text on black, in keeping with SugarCube and Sugarcane, rather than black text on white. The light colour scheme can be reinstated by putting `(enchant: ?page, (text-colour:black)+(background:white))` in a passage with the `header` tag.
502
 * The `<tw-story>` element is now kept inside whatever element originally enclosed it, instead of being moved to inside `<html>`.
Leon Arnott's avatar
Leon Arnott committed
503
 * Now, the default CSS applies the default Harlowe `font` (Georgia) to the `<tw-story>` element instead of `html` - so, to override it, write CSS `font` properties for `tw-story` (which is what most custom CSS should be altering now) instead of `html` or `body`.
504
 * Fixed a bug where the "Story stylesheet" `<style>` element was attached between `<head>` and `<body>`. This should have had no obvious effects in any browser, but was untidy anyway.
505
506
 * Altered the CSS of `<tw-story>` to use vertical padding instead of vertical margins, and increased the line-height slightly.
 * Altered the CSS of `<h1>`, `<h2>`, `<h3>`, `<h4>`, `<h5>` and `<h6>` elements to have a slightly lower margin-top.
507
 * Now, `<tw-passage>` elements (that is, passages' HTML elements) have a `tags` attribute containing all of the passage's tags in a space-separated list. This allows such elements to be styled using author CSS, or selected using author Javascript, in a manner similar to Twine 1.4 (but using the `[tags~= ]` selector instead of `[data-tags~= ]`).
508
 * Removed the CSS directives that reduce the font size based on the player's device width, because this functionality seems to be non-obvious to users, and can interfere with custom CSS in an unpleasant way.
509
 * Now, hooks and expressions which contain nothing (due to, for instance, having a false `(if:)` attached) will now have `display:none`, so that styling specific to their borders, etc. won't still be visible.
510

511
#### Additions
512

513
##### Markup
514

Leon Arnott's avatar
Leon Arnott committed
515
 * Added column markup, which is, like aligner markup, a special single-line token indicating that the subsequent text should be separated into columns. They consist of a number of `|` marks, indicating the size of the column relative to the other columns, and a number of `=` marks surrounding it, indicating the size of the column's margins in CSS "em" units (which are about the width of a capital M). Separate each column's text with tokens like `|===` and `==||`, and end them with a final `|==|` token to return to normal page layout.
516
 * Now, it's possible to attach multiple changers to a single hook by joining them with `+`, even outside of a macro - `(text-style:'bold')+(align:'==>')+$robotFont[Text]` will apply `(text-style:'bold')`, `(align:'==>')` and the changer in the variable $robotFont, as if they had been added together in a single variable. Again, you can put whitespace between them – `(text-style:'bold') + (align:'==>') + $robotFont  [Text]` is equally valid, and causes the whitespace between each changer and the hook itself to be discarded.
517
 * Now, you can make hooks which are hidden when the passage is initially displayed, to be revealed when a macro (see below) is run. Simply replace the `<` and `>` symbol with a `(` or `)`. For example: `|h)[This hook is hidden]`. (You can think of this as being visually similar to comic speech balloons vs. thought balloons.) This is an alternative to the revision macros, and can be used in situations where the readability of the passage prose is improved by having hidden hooks alongside visible text, rather than separate `(replace:)` hooks. (Of course, the revision macros are still useful in a variety of other situations, including `header` passages.)
518

519
##### Code
520

521
 * Arrays, strings and datasets now have special data names, `any`, and `all`, which can be used with comparison operators like `contains`, `is` and `<=` to compare every value inside them. For instance, you can now write `(a:1,2,3) contains all of (a:2,3)`, or `any of (a:3,2) <= 2`, or `"Fox" contains any of "aeiou"` (all of which are true). You can't use them anywhere else, though - `(set: all of $a to true)` is an error (and wouldn't be too useful anyway).
522
 * Now, certain hard-coded hook names will also select elements of the HTML page, letting you style the page using enchantment macros. `?page` selects the page element (to be precise, the `<tw-story>`), `?passage` selects the passage element (to be precise, the `<tw-passage>`), `?sidebar` selects the passage's sidebar containing undo/redo icons (`<tw-sidebar>`), and `?link` selects any links in the passage. (Note that if you use these names for yourself, such as `|passage>[]`, then they will, of course, be included in the selection.)
523
 * Added temporary variables, a special kind of variable that only exists inside the passage or hook in which they're `(set:)`. Outside of the passage or hook, they disappear. Simply use `_` instead of `$` as the sigil for variables - write `(set: _a to 2)`, `(if: _a > 1)`, etc. Their main purpose is to allow you to make "reusable" Twine code - code which can be pasted into any story, without accidentally overwriting any variables that the story has used. (For instance, suppose you had some code which uses the variable `$a` for some quick computation, but you pasted it into a story that already used `$a` for something else in another passage. If you use a temporary variable `_a` instead, this problem won't occur.)
524
   * Also note that temp variables that are `(set:)` inside hooks won't affect same-named temp variables outside them: `(set: _a to 1) |hook>[(set: _a to 2)]` will make `_a` be 2 inside the hook, but remain as 1 outside of it.
Leon Arnott's avatar
Leon Arnott committed
525
 * Lambdas are a new data type - they are, essentially, user-created functions. You can just think of them as "data converters" - reusable instructions that convert values into different values, filter them, or join multiple values together. They use temporary variables (which only exist inside the lambda) to hold values while computing them, and this is shown in their syntax. An example is `_a where _a > 2`, which filters out data that's smaller than 2, or `_name via "a " + _name`, which converts values by adding 1 to them. Various new macros use these to easily apply the same conversion to sequences of data.
526
 * Colour values now have read-only data names: `r`, `g` and `b` produce the red, green and blue components of the colour (from 0 to 255), and `h`, `s` and `l` produce, in order, the hue (in degrees), and the saturation and lightness percentages (from 0 to 1).
527
 * You can now access sub-elements in hook names, as if they were an array: `(click: ?red's 1st)` will only affect the first such named hook in the passage, for instance, and you can also specify an array of positions, like `?red's (a:1,3,5)`. Unlike arrays, though, you can't access their `length`, nor can you spread them with `...`.
528
 * You can now add hook names together to affect both at the same time: `(click: ?red + ?blue's 1st)` will affect all hooks tagged `<red|`, as well as the first hook tagged `<blue|`.
529

530
##### Macros
531

Leon Arnott's avatar
Leon Arnott committed
532
 * Added `(undo:)`, a command similar to `(go-to:)` which performs the same function as the undo button in the default sidebar. Use it as an alternative to `(go-to: (history:)'s last)` which forgets the current turn as well as going back.
533
   * Also added a link shorthand of the above, `(link-undo:)`, which is used similarly to `(link-goto:)`.
Leon Arnott's avatar
Leon Arnott committed
534
 * Added `(for:)`, a command that repeats the attached hook, using a lambda to set a temporary variable to a different value on each repeat. It uses "where" lambdas, and accepts the "each" shorthand for `where true`, which accepts every value. `(for: each _item, ...$array) [You have the _item]` prints "You have the " and the item, for each item in `$array`.
535
 * Added `(find:)`, which uses a lambda to filter a sequence of values, and place the results in an array. For instance, `(find: _item where _item's 1st is "A", "Arrow", "Shield", "Axe", "Wand")` produces the array `(a: "Arrow", "Axe")`. (This macro is similar to Javascript's `filter()` array method.)
Leon Arnott's avatar
Leon Arnott committed
536
 * Added `(altered:)`, which takes a lambda as its first value, and any number of other values, and uses the lambda to convert the values, placing the results in an array. For instance, `(altered: _material via _material + " Sword", "Iron", "Wood", "Bronze", "Plastic")` will create an array `(a:"Iron Sword", "Wood Sword", "Bronze Sword", "Plastic Sword")`. (This macro is similar to Javascript's `map()` array method.)
537
538
 * Added `(all-pass:)`, `(some-pass:)` and `(none-pass:)`, which check if the given values match the lambda, and return `true` or `false`. `(all-pass: _a where _a > 2, 1, 3, 5)` produces `false`, `(some-pass: _a where _a > 2, 1, 3, 5)` produces `true`, and `(none-pass: _a where _a > 2, 1, 3, 5)` produces `false`.
 * Added `(folded:)`, which is used to combine many values into one (a "total"), using a lambda that has a `making` clause. `(folded: _a making _total via _total + "." + _a, "E", "a", "s", "y")` will first set `_total` to "E", then progressively add ".a", ".s", and ".y" to it, thus producing the resulting string, "E.a.s.y".
539
540
 * Added `(show:)`, a command to show a hidden named hook (see above). `(show: ?secret)` will show all hidden hooks named `|secret)`. This can also be used to reveal named hooks hidden with `(if:)`, `(else-if:)`, `(else:)` and `(unless:)`.
 * Added `(hidden:)`, which is equivalent to `(if:false)`, and can be used to produce a changer to hide its attached hook.
541
 * Added the aliases `(dm:)` and `(ds:)` for `(datamap:)` and `(dataset:)`, respectively.
542
543
 * Added `(lowercase:)` and `(uppercase:)`, which take a string and convert it to all-lowercase or all-uppercase, as well as `(lowerfirst:)` and `(upperfirst:)`, which only convert the first non-whitespace character in the string and leave the rest untouched.
 * Added `(words:)`, which takes a string and produces an array of the words (that is, the sequences of non-whitespace characters) in it. For instance, `(words: "2 big one's")` produces `(a: "2", "big", "one's")`.
544
 * Added `(repeated:)`, which creates an array containing the passed values repeated a given number of times. `(repeated: 3, 1,2,0)` produces `(a: 1,2,0,1,2,0,1,2,0)`.
545
 * Added `(interlaced:)`, which interweaves the values of passed-in arrays. `(interlaced: (a: 'A','B','C','D'),(a: 1,2,3))` is the same as `(a: 'A',1,'B',2,'C',3)`. (For functional programmers, this is just a flat zip.) This can be useful alongside the `(datamap:)` macro.
546
 * Added `(rgb:)`, `(rgba:)`, `(hsl:)` and `(hsla:)`, which produce colour values, similar to the CSS colour functions. `(rgb:252,180,0)` produces the colour #fcb400, and `(hsl:150,0.2,0.6)` produces the colour #84ad99.
Leon Arnott's avatar
Leon Arnott committed
547
 * Added `(dataentries:)`, which complements `(datanames:)` and `(datavalues:)` by producing, from a datamap, an array of the datamap's name-value pairs. Each pair is a datamap with "name" and "value" data, which can be examined using the lambda macros.
548
 * Added `(hover-style:)`, which, when given a style-altering changer, like `(hover-style:(text-color:green))`, makes its style only apply when the hook or expression is hovered over with the mouse pointer, and removed when hovering off.
549
 * Now, you can specify `"none"` as a `(text-style:)` and produce a changer which, when added to other `(text-style:)` combined changers, removes their styles.
550

551
### 1.2.4 changes (Apr 26, 2017):
552

553
#### Bugfixes
554
555
556
557
558
559
560
561

 * `(random:)` now no longer incorrectly errors when given a single whole number instead of two.
 * `(alert:)`, `(open-url:)`, `(reload:)` and `(goto-url:)` now return empty strings rather than the non-Harlowe value `undefined` (or, for `(open-url:)` a Javascript Window object). This differs slightly from 2.0, which returns more useful command values.
 * Additionally, backported the following fixes from 2.0.0:
   * Fixed a bug where comparing a value with an error (such as `2 is (3 + 'X')`) would suppress the error.
   * Fixed a bug where subtracting non-subtractable values (such as booleans) wouldn't produce an error, instead implicitly converting the values to numbers, and potentially producing the Javascript value `NaN`.
   * Fixed the bug where `(current-time:)` wouldn't pad the minutes value with a leading 0 when necessary, and '12' was printed as '0'.

562
### 1.2.3 changes (Jan 17, 2017):
563

564
#### Bugfixes
565
566

 * Fixed a bug where the "outline" `(textstyle:)` option didn't have the correct text colour when no background colour was present, making it appear solid black.
567
 * Fixed a bug where changer commands couldn't be added together more than once without the possibility of some of the added commands being lost.
568
 * Fixed a bug where `(pow:)` only accepted 1 value instead of 2, and, moreover, that it could return the Javascript value `NaN`, which Harlowe macros shouldn't be able to return.
569
 * Fixed a bug where the verbatim markup couldn't enclose a `]` inside a hook, a `}` inside the collapsing markup, or any of the formatting markup's closing tokens immediately after an opening token.
570
 * Fixed a bug where the Javascript in the resulting HTML files contained the Unicode non-character U+FFFE, causing encoding problems when the file is hosted on some older servers.
571

572
#### Alterations
573
574

 * Now, setting changer commands into variables no longer prevents the `(save-game:)` command from working.
575

576
### 1.2.2 changes (Feb 16, 2016):
577

578
#### Bugfixes
579
580
581

 * Fixed a bug where the `(textstyle:)` options "shudder", "rumble" and "fade-in-out", as well as all of `(transition:)`'s options, didn't work at all.
 * Fixed a long-standing bug where `(mouseover:)` affected elements didn't have a visual indicator that they could be moused-over (a dotted underline).
582
 * Fixed the `(move:)` macro corrupting past turns (breaking the in-game undo functionality) when it deletes array or datamap items.
583
 * Fixed the `<===` (left-align) markup token erasing the next syntactic structure to follow it.
584
 * Fixed a bug where attempting to print datamaps using `(print:)` produced a Javascript error.
585
 * Fixed a long-standing bug where spreading `...` datasets did not, in fact, arrange their values in sort order, but instead in parameter order.
586
 * Fixed a long-standing bug where a string containing an unmatched `)` inside a macro would abruptly terminate the macro.
587

588
#### Alterations
589
590
591

 * Giving an empty string to a macro that affects or alters all occurrences of the string in the passage text, such as `(replace:)` or `(click:)`, will now result in an error (because it otherwise won't affect any part of the passage).

592
### 1.2.1 changes (Nov 20, 2015):
Leon Arnott's avatar
Leon Arnott committed
593

594
#### Bugfix
Leon Arnott's avatar
Leon Arnott committed
595
596
597

 * Fixed a bug where `(if:)`, `(unless:)` and `(else-if:)` wouldn't correctly interact with subsequent `(else-if:)` and `(else:)` macro calls, breaking them. (Usage with boolean-valued macros such as `(either:)` was not affected.)

598
### 1.2.0 changes (Nov 08, 2015):
599

600
#### Bugfixes
601
602
603
604
605
606
607