config.d.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. import { Passage, PassageBase } from "./passage";
  2. import { SaveDetails, SaveObject } from "./save";
  3. type SaveObjectHander = (save: SaveObject, details: SaveDetails) => void;
  4. type DescriptionHandler = (this: Passage) => string | null;
  5. export interface ConfigAPI {
  6. readonly audio: {
  7. /**
  8. * Determines whether the audio subsystem automatically pauses tracks that have been faded to 0 volume (silent).
  9. * @default true
  10. * @since 2.28.0
  11. * @example
  12. * Config.audio.pauseOnFadeToZero = false;
  13. */
  14. pauseOnFadeToZero: boolean;
  15. /**
  16. * Determines whether the audio subsystem attempts to preload track metadata—meaning information about the track
  17. * (e.g., duration), not its audio frames.
  18. *
  19. * NOTE: It is unlikely that you will ever want to disable this setting.
  20. * @default true
  21. * @since 2.28.0
  22. * @example
  23. * Config.audio.preloadMetadata = false;
  24. */
  25. preloadMetadata: boolean;
  26. };
  27. readonly history: {
  28. /**
  29. * Determines whether the story's history controls (Backward, Jump To, & Forward buttons) are enabled within the UI bar.
  30. * @default true
  31. * @since 2.0.0
  32. * @example
  33. * Config.history.controls = false;
  34. */
  35. controls: boolean;
  36. /**
  37. * Sets the maximum number of states (moments) to which the history is allowed to grow. Should the history exceed the limit,
  38. * states will be dropped from the past (oldest first). A setting of 0 means that there is no limit to how large the history
  39. * may grow, though doing so is not recommended.
  40. * @default 40
  41. * @since 2.0.0
  42. * @example
  43. * // No history limit (you should never do this!)
  44. * Config.history.maxStates = 0;
  45. * // Limit the history to a single state
  46. * Config.history.maxStates = 1;
  47. * // Limit the history to 150 states
  48. * Config.history.maxStates = 150;
  49. */
  50. maxStates: number;
  51. };
  52. readonly macros: {
  53. /**
  54. * Determines whether the `<<if>>` macro returns an error when the = assignment operator is used within its conditional —
  55. * e.g., `<<if $suspect = "Bob">>`. Does not flag other assignment operators.
  56. *
  57. * NOTE: This setting exists because it's unlikely that you'll ever want to actually perform an assignment within a
  58. * conditional expression and typing = when you meant === (or ==) is a fairly easy to mistake make—either from a finger
  59. * slip or because you just don't know the difference between the operators.
  60. *
  61. * @default true
  62. * @since 2.0.0
  63. * @example
  64. * // No error is returned when = is used within an <<if>> or <<elseif>> conditional
  65. * Config.macros.ifAssignmentError = false;
  66. */
  67. ifAssignmentError: boolean;
  68. /**
  69. * Sets the maximum number of iterations allowed before the `<<for>>` macro conditional forms are terminated with an error.
  70. *
  71. * NOTE: This setting exists to prevent a misconfigured loop from making the browser unresponsive.
  72. *
  73. * @default 1000
  74. * @since 2.0.0
  75. * @example
  76. * // Allow only 5000 iterations
  77. * Config.macros.maxLoopIterations = 5000;
  78. */
  79. maxLoopIterations: number;
  80. /**
  81. * Sets the default KeyboardEvent.key value that causes the currently running <<type>> macro instance to finish
  82. * typing its content immediately.
  83. * @default " " (space)
  84. * @since 2.33.1
  85. * @example
  86. * // Change the default skip key to Control (CTRL)
  87. * Config.macros.typeSkipKey = "Control";
  88. */
  89. typeSkipKey: string;
  90. /**
  91. * Determines whether the <<type>> macro types out content on previously visited passages or simply outputs it
  92. * immediately.
  93. * @default true
  94. * @since 2.32.0
  95. * @example
  96. * // Do not type on previously visited passages
  97. * Config.macros.typeVisitedPassages = false;
  98. */
  99. typeVisitedPassages: boolean;
  100. };
  101. readonly navigation: {
  102. /**
  103. * Allows the destination of passage navigation to be overridden. The callback is passed one parameter, the original
  104. * destination passage title. If its return value is falsy, the override is cancelled and navigation to the original
  105. * destination continues unperturbed. If its return value is truthy, the override succeeds and that value is used as
  106. * the new destination of the navigation.
  107. *
  108. * @since 2.13.0
  109. * @example
  110. * Config.navigation.override = function (destinationPassage) {
  111. * // code
  112. * };
  113. *
  114. * @example
  115. * // Force the player to the "You Died" passage if they let $health get too low.
  116. * Config.navigation.override = function (dest) {
  117. * var sv = State.variables;
  118. * // If $health is less-than-or-equal to 0, go to the "You Died" passage instead.
  119. * if (sv.health <= 0) {
  120. * return "You Died";
  121. * }
  122. * };
  123. */
  124. override: (passageName: string) => any;
  125. };
  126. readonly passages: {
  127. /**
  128. * Determines whether alternate passage descriptions are used by the Saves and Jump To menus—by default an excerpt
  129. * from the passage is used. Valid values are boolean true, which simply causes the passages' titles to be used, an
  130. * object, which maps passages' titles to their descriptions, or a function, which should return the passages'
  131. * description.
  132. *
  133. * NOTE:
  134. * * As boolean: You should ensure that all encounterable passage titles are meaningful.
  135. * * As object: If the mapping object does not contain an entry for the passage in question, then the passage's
  136. * excerpt is used instead.
  137. * * As function: The function is called with the passage in question as its this value. If the function returns falsy,
  138. * then the passage's excerpt is used instead.
  139. * @default null
  140. * @since 2.0.0
  141. * @example
  142. * // Uses passages' titles
  143. * Config.passages.descriptions = true;
  144. *
  145. * // Uses the description mapped by the title
  146. * Config.passages.descriptions = {
  147. * "title" : "description"
  148. * };
  149. *
  150. * // Returns the description to be used
  151. * Config.passages.descriptions = function () {
  152. * if (this.title === "title") {
  153. * return "description";
  154. * }
  155. * };
  156. */
  157. descriptions: true | { [x: string]: string } | DescriptionHandler | null;
  158. /**
  159. * Determines whether passage titles are combined with the story title, within the browser's/tab's titlebar, when
  160. * passages are displayed.
  161. * @default false
  162. * @since 2.0.0
  163. * @example
  164. * Config.passages.displayTitles = true;
  165. */
  166. displayTitles: boolean;
  167. /**
  168. * Determines whether rendering passages have their leading/trailing newlines removed and all remaining sequences of
  169. * newlines replaced with single spaces before they're rendered. Equivalent to including the nobr special tag on
  170. * every passage.
  171. * @default false
  172. * @since 2.19.0
  173. * @example
  174. * Config.passages.nobr = true;
  175. */
  176. nobr: boolean;
  177. /**
  178. * Allows custom processing of passage text. The function is invoked each time the <Passage>.processText()
  179. * method is called. It is passed an abbreviated version of the associated passage's Passage instance —
  180. * containing only the tags, text, and title properties. Its return value should be the post-processed text.
  181. * @since 2.30.0
  182. *
  183. * **NOTE**: Does not affect script or stylesheet tagged passages, for Twine 1/Twee, or the Story JavaScript or
  184. * Story Stylesheet sections, for Twine 2.
  185. *
  186. * **NOTE**: The function will be called just before the built-in no-break passage processing if you're also using
  187. * that—see the Config.passages.nobr setting and nobr special tag.
  188. *
  189. * @since 2.30.0
  190. * @example
  191. * // Change instances of "cat" to "dog".
  192. * Config.passages.onProcess = function (p) {
  193. * return p.text.replace(/\bcat(s?)\b/g, 'dog$1');
  194. * };
  195. */
  196. onProcess: (passage: PassageBase) => string;
  197. /**
  198. * Sets the title of the initial passage, the very first passage which will be displayed.
  199. *
  200. * @default Twine 2: none; Twine 1/Twee: "Start"
  201. * @example
  202. * Config.passages.start = "That Other Starting Passage";
  203. */
  204. start: string;
  205. /**
  206. * Determines whether outgoing passage transitions are enabled. Valid values are the name of the property being
  207. * animated, which causes the outgoing passage elements to be removed once that transition animation is complete,
  208. * or an integer delay (in milliseconds), which causes the outgoing passage elements to be removed once the delay
  209. * has expired.
  210. *
  211. * **NOTE**: If using an integer delay, ideally, it should probably be slightly longer than the outgoing transition
  212. * delay that you intend to use — e.g., an additional 10ms or so should be sufficient.
  213. *
  214. * @since 2.0.0
  215. * @example
  216. * // Remove outgoing elements when their opacity animation ends
  217. * Config.passages.transitionOut = "opacity";
  218. *
  219. * // Remove outgoing elements after 1010ms (1.01s)
  220. * Config.passages.transitionOut = 1010;
  221. *
  222. * // CSS styles:
  223. * // At the very least you will need to specify a .passage-out style that defines the transition's end state. For example:
  224. *
  225. * .passage-out {
  226. * opacity: 0;
  227. * }
  228. * // That probably won't be very pleasing to the eye, however, so you will likely need several styles to make something
  229. * // that looks half-decent. For example, the following will give you a basic crossfade:
  230. *
  231. * #passages {
  232. * position: relative;
  233. * }
  234. * .passage {
  235. * left: 0;
  236. * position: absolute;
  237. * top: 0;
  238. * transition: opacity 1s ease;
  239. * }
  240. * .passage-out {
  241. * opacity: 0;
  242. * }
  243. */
  244. transitionOut: string | number;
  245. };
  246. readonly saves: {
  247. /**
  248. * Determines whether the autosave, if it exists, is automatically loaded upon story startup. Valid values are
  249. * boolean true, which simply causes the autosave to be loaded, the string "prompt", which prompts the player via a
  250. * dialog to load the autosave, or a function, which causes the autosave to be loaded if its return value is truthy.
  251. *
  252. * **NOTE**: If the autosave cannot be loaded, for any reason, then the start passage is loaded instead.
  253. * @since 2.0.0
  254. * @example
  255. * // Automatically loads the autosave
  256. * Config.saves.autoload = true;
  257. *
  258. * // Prompts the player about loading the autosave
  259. * Config.saves.autoload = "prompt";
  260. *
  261. * // Loads the autosave if it returns a truthy value
  262. * Config.saves.autoload = function () {
  263. * // code
  264. * };
  265. */
  266. autoload: boolean | "prompt" | (() => boolean) | null;
  267. /**
  268. * Determines whether the autosave is created/updated when passages are displayed. Valid values are boolean true,
  269. * which causes the autosave to be updated with every passage, an array of strings, which causes the autosave to
  270. * be updated for each passage with at least one matching tag, or a function, which causes the autosave to be
  271. * updated for each passage where its return value is truthy.
  272. *
  273. * **WARNING**: When setting the value to boolean true, you will likely also need to use the Config.saves.isAllowed
  274. * property to disallow saving on the start passage. Or, if you use the start passage as real part of your story and
  275. * allow the player to reenter it, rather than just as the initial landing/cover page, then you might wish to only
  276. * disallow saving on the start passage the very first time it's displayed (at story startup).
  277. * @since 2.0.0
  278. * @since 2.30.0: Added function values and deprecated string values.
  279. * @example
  280. * // Autosaves every passage
  281. * Config.saves.autosave = true;
  282. *
  283. * // Autosaves on passages tagged with any of "bookmark" or "autosave"
  284. * Config.saves.autosave = ["bookmark", "autosave"];
  285. *
  286. * // Autosaves on passages if it returns a truthy value
  287. * Config.saves.autosave = function () {
  288. * // code
  289. * };
  290. */
  291. autosave: true | string | string[] | (() => boolean) | null;
  292. /**
  293. * Sets the story ID associated with saves.
  294. * @default slugified story title
  295. * @since 2.0.0
  296. * @example
  297. * Config.saves.id = "a-big-huge-story-part-1";
  298. */
  299. id: string;
  300. /**
  301. * Determines whether saving is allowed within the current context. The callback is invoked each time a save is
  302. * requested. If its return value is false, the save is disallowed. If its return value is truthy, the save is
  303. * allowed to continue unperturbed.
  304. * @default undefined
  305. * @since 2.0.0
  306. * @example
  307. * Config.saves.isAllowed = function () {
  308. * // code
  309. * };
  310. */
  311. isAllowed: (() => boolean) | null;
  312. /**
  313. * Performs any required pre-processing before the save data is loaded. The callback is passed one parameter, the
  314. * save object to be processed. If it encounters an unrecoverable problem during its processing, it may throw an
  315. * exception containing an error message; the message will be displayed to the player and loading of the save will
  316. * be terminated.
  317. *
  318. * @see SaveObject
  319. * @default undefined
  320. * @since 2.0.0
  321. * @deprecated since 2.36.0 in favor of the Save Events API.
  322. * @example
  323. * Config.saves.onLoad = function (save) {
  324. * // code
  325. * };
  326. */
  327. onLoad: SaveObjectHander | null;
  328. /**
  329. * Performs any required post-processing before the save data is saved. The callback is passed one parameter, the
  330. * save object to be processed.
  331. *
  332. * NOTE: See the save objects section of the Save API for information on the format of a save.
  333. * @default undefined
  334. * @since 2.0.0
  335. * @since 2.33.0: Added save operation details object parameter to the callback function.
  336. * @deprecated since 2.36.0 in favor of the Save Events API.
  337. * @example
  338. * Config.saves.onSave = function (save) {
  339. * // code
  340. * };
  341. */
  342. onSave: SaveObjectHander | null;
  343. /**
  344. * Sets the maximum number of available save slots.
  345. *
  346. * @default 8
  347. * @since 2.0.0
  348. * @example
  349. * Config.saves.slots = 4;
  350. */
  351. slots: number;
  352. /**
  353. * Determines whether saving to disk is enabled on mobile devices — i.e., smartphones, tablets, etc.
  354. *
  355. * WARNING: Mobile browsers can be fickle, so saving to disk may not work as expected in all browsers.
  356. * @default true
  357. * @since 2.34.0
  358. * @example
  359. * // To disable saving to disk on mobile devices.
  360. * Config.saves.tryDiskOnMobile = false;
  361. */
  362. tryDiskOnMobile: boolean;
  363. /**
  364. * Sets the version property of saves.
  365. *
  366. * **NOTE**: This setting is only used to set the version property of saves. Thus, it is only truly useful if you plan
  367. * to upgrade out-of-date saves via a Config.saves.onLoad callback.
  368. *
  369. * @since 2.0.0
  370. * @example
  371. * // As an integer
  372. * Config.saves.version = 3;
  373. * @example
  374. * // As a string
  375. * Config.saves.version = "v3";
  376. */
  377. version: any;
  378. };
  379. readonly ui: {
  380. /**
  381. * Determines whether the UI bar (sidebar) starts in the stowed (shut) state initially. Valid values are boolean
  382. * true/false, which causes the UI bar to always/never start in the stowed state, or an integer, which causes the UI
  383. * bar to start in the stowed state if the viewport width is less-than-or-equal-to the specified number of pixels.
  384. *
  385. * @default 800
  386. * @since 2.11.0
  387. *
  388. * @example
  389. * // As a boolean; always start stowed
  390. * Config.ui.stowBarInitially = true;
  391. *
  392. * @example
  393. * // As a boolean; never start stowed
  394. * Config.ui.stowBarInitially = false;
  395. *
  396. * @example
  397. * // As an integer; start stowed if the viewport is 800px or less
  398. * Config.ui.stowBarInitially = 800;
  399. */
  400. stowBarInitially: boolean | number;
  401. /**
  402. * Determines whether certain elements within the UI bar are updated when passages are displayed. The affected
  403. * elements are the story: banner, subtitle, author, caption, and menu.
  404. *
  405. * **NOTE**: SugarCube uses the story's title as the basis for the key used to store and load data used when playing the
  406. * story and for saves. Because of this, the story title is not included in updates and it is strongly recommended
  407. * that you do not add any kind of dynamic code to it.
  408. *
  409. * @default true
  410. * @since 2.0.0
  411. * @example
  412. * // If you don't need those elements to update
  413. * Config.ui.updateStoryElements = false;
  414. */
  415. updateStoryElements: boolean;
  416. };
  417. /**
  418. * Determines whether the link-visited class is added to internal passage links which go to previously visited
  419. * passages — i.e. the passage already exists within the story history
  420. *
  421. * **NOTE** You must provide your own styling for the `link-visited` class as none is provided by default.
  422. * @default false
  423. * @since 2.0.0
  424. * @example
  425. * Config.addVisitedLinkClass = true;
  426. * // An example style:
  427. * .link-visited {
  428. * color: purple;
  429. * }
  430. */
  431. addVisitedLinkClass: boolean;
  432. /**
  433. * Determines whether the output of the Wikifier is post-processed into more sane markup — i.e. where appropriate, it
  434. * tries to transition the plethora of <br> elements into <p> elements.
  435. * @default false
  436. * @since 2.0.0
  437. * @example
  438. * Config.cleanupWikifierOutput = true;
  439. */
  440. cleanupWikifierOutput: boolean;
  441. /**
  442. * Indicates whether SugarCube is running in test mode, which enables debug views. See Test Mode for more information.
  443. *
  444. * NOTE: This property is automatically set based on whether you're using a testing mode in a Twine compiler — i.e. Test
  445. * mode in Twine 2, Test Play From Here in Twine 1, or the test mode options (-t, --test) in Tweego. You may, however,
  446. * forcibly enable it if you need to for some reason — e.g. if you're using another compiler, which doesn't offer a way
  447. * to enable test mode.
  448. *
  449. * @default false
  450. * @since 2.2.0
  451. * @example
  452. * // Forcibly enable test mode
  453. * Config.debug = true;
  454. *
  455. * @example
  456. * // Check if test mode is enabled in JavaScript
  457. * if (Config.debug) {
  458. * // do something debug related
  459. * }
  460. *
  461. * @example
  462. * // Check if test mode is enabled via the <<if>> macro
  463. * <<if Config.debug>>
  464. * // do something debug related
  465. * <</if>>
  466. */
  467. debug: boolean;
  468. /**
  469. * Sets the integer delay (in milliseconds) before the loading screen is dismissed, once the document has signaled its
  470. * readiness. Not generally necessary, however, some browsers render slower than others and may need a little extra time
  471. * to get a media-heavy page done. This allows you to fine tune for those cases.
  472. *
  473. * @default 0
  474. * @since 2.0.0
  475. *
  476. * @example
  477. * // Delay the dismissal of the loading screen by 2000ms (2s)
  478. * Config.loadDelay = 2000;
  479. */
  480. loadDelay: number;
  481. }
  482. export {};