Tea dispatches custom DOM events at specific points during story operation to let your JavaScript code react to what’s happening — dialog state changes, passage transitions, audio playback, engine lifecycle, and typewriter-effect macro activity. All events are fired onDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/pompom454/tea/llms.txt
Use this file to discover all available pages before exploring further.
document unless noted otherwise.
Events are represented as objects. Tea events added in v2.37.0+ carry their custom data in an event.detail object rather than directly on the event.
For standard browser/DOM events (click, input, etc.) see the MDN Event reference.
Dialog events
These events fire during the opening and closing lifecycle of Tea’s built-in dialog system. All four events fire from the dialog’s body element (#ui-dialog-body), so event.target refers to that element.
:dialogopening
:dialogopening
Fired as the first step when
Dialog.open() is called — before the dialog becomes visible. The dialog is still populated with its content at this point, so you can inspect or modify it.Event data: none (but event.target is #ui-dialog-body):dialogopened
:dialogopened
Fired as the last step when
Dialog.open() is called — after the dialog is fully visible.Event data: none:dialogclosing
:dialogclosing
Fired as the first step when
Dialog.close() is called — while the dialog is still open and its content is intact. Use this event if you need to read the dialog’s title or class list before it is torn down.Event data: none:dialogclosed
:dialogclosed
Fired as the last step when
Dialog.close() is called — after the dialog has already been closed and reset.Event data: noneNavigation events
Navigation events fire at each stage of passage transition. They are processed in the following order each time the player moves to a new passage::passageinit— before the history state is modified:passagestart— before the passage content is rendered (afterPassageReady):passagerender— after rendering (afterPassageFooter):passagedisplay— after the passage is shown on screen (afterPassageDone):uiupdate— UI sidebar/banner update (also updatesStoryMenu,StoryCaption, etc.):passageend— at the very end of navigation
detail objects carry a passage property that is a Passage API object. Events from step 2 onward also carry a content property that is the rendered passage HTMLElement.
:passageinit
:passageinit
Fired before the modification of the state history. At this point the new passage exists but the history has not yet advanced.
event.detail properties:passage(Passage) — The incoming passage object.
:passagestart
:passagestart
Fired before the incoming passage is rendered, after
PassageReady has run. The content element exists but is still empty — you can use .wiki() to prepend content.event.detail properties:content(HTMLElement) — The (currently empty) element that will hold rendered content.passage(Passage) — The incoming passage object.
:passagerender
:passagerender
Fired after the incoming passage has been fully rendered (TwineScript processed, macros executed), after
PassageFooter has run. The content element holds the complete rendered passage DOM.event.detail properties:content(HTMLElement) — The fully rendered passage element.passage(Passage) — The incoming passage object.
:passagedisplay
:passagedisplay
Fired after the rendered passage has been displayed (output to the screen) and after
PassageDone has run.event.detail properties:content(HTMLElement) — The displayed passage element.passage(Passage) — The incoming passage object.
:passageend
:passageend
Fired at the very end of passage navigation, after all other navigation events and UI updates have completed.
event.detail properties:content(HTMLElement) — The passage element.passage(Passage) — The incoming passage object.
SimpleAudio events
These events fire on audio track elements and are intended to be listened to viaAudioTrack.on(), AudioTrack.one(), or AudioRunner.on() rather than directly on document. They have no custom data on the event object.
:fading
:fading
Fired on a track element when a fade starts.Event data: none
:faded
:faded
Fired on a track element when a fade completes normally (i.e., was not interrupted by
fadeStop()).Event data: none:stopped
:stopped
Fired on a track element when playback is stopped via
.stop(), either called directly or as part of another operation (e.g., SimpleAudio.stop()).Event data: noneThis is distinct from the native
ended event (which fires when a track plays to completion) and the native pause event. See MDN for those events.System events
System events fire once (or at most a few times) during story startup and teardown.:storyready
:storyready
Fired once just before the loading screen is dismissed at story startup. Use this to perform any initialization that must happen after the engine is fully ready but before the player sees the first passage.Event data: none
:enginerestart
:enginerestart
Fired once just before the page is reloaded when
Engine.restart() is called. Use this to perform any cleanup needed before the page refreshes.Event data: none:uiupdate
:uiupdate
Fired each time the built-in UI is updated by
UI.update(). This happens as step 5 of every passage navigation, after the passage has been displayed. Use this to update custom sidebar elements or other persistent UI.Event data: none<<type>> macro events
These events fire during typewriter-effect typing sequences created by the <<type>> macro.
:typingstart
:typingstart
Local event fired on the typing wrapper element when the typing of a section starts. Bubbles up the DOM tree.Event data: none
:typingstop
:typingstop
Local event fired on the typing wrapper element when the typing of a section stops (including when skipped by the player). Bubbles up the DOM tree.Event data: none
:typingcomplete
:typingcomplete
Global event fired on Event data: none
document when all <<type>> macro invocations within the current passage have finished typing.If additional
<<type>> macros are injected into the passage after :typingcomplete has fired, a new sequence begins and a new :typingcomplete event will eventually fire for that sequence.