Every watchable channel in Television Simulator ‘99 plays a background video sourced from YouTube. This approach lets the simulator reuse publicly available archival footage — such as the 90s commercial compilation on Channel 12 — without bundling large video files. The YouTube IFrame Player API manages playback; a thinDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/zshall/program-guide/llms.txt
Use this file to discover all available pages before exploring further.
YouTubeApi helper class wraps its methods; and the TV class ties mute state to the on-screen overlay so the viewer always knows when audio is silenced.
Loading Sequence
The YouTube IFrame API must be ready before the guide can load, because the default channel’s player is instantiated as soon as the channel class is created. The loading chain is:TV.startUp() calls YouTubeApi.loadYouTubeAPI()
loadYouTubeAPI() is an async method that calls Helpers.loadScript with the IFrame API URL. Helpers.loadScript creates a <script> tag, appends it to <head>, and returns a Promise that resolves on script.onload.YouTube fires onYouTubeIframeAPIReady
Once the injected script downloads and initialises, YouTube’s API calls the globally defined
onYouTubeIframeAPIReady function. The implementation in youtube-ctrl.js dispatches a custom DOM event instead of coupling directly to the TV class:TV listens for the youtubeReady event
Inside
TV.startUp(), a document event listener waiting on youtubeReady fires. It performs the AJAX fetch of guide.xml, parses the response, and calls showChannel for the default channel — guaranteeing the YT global is available before any channel tries to instantiate a player.YT.Player Instantiation in Channel12
Inside Channel12.show(), a YT.Player is created targeting the #ytplayer div that was injected by layout.html. The video starts automatically, native controls are hidden, and related-video suggestions are suppressed:
onPlayerReady calls event.target.playVideo() to ensure playback begins even if autoplay is blocked by the browser. onPlayerStateChange logs when the video enters the playing state and can be extended to handle end-of-video looping.
The player instance must be assigned to
this.player on the channel object. TV.toggleMute() accesses this.channel.player directly — if player is not exposed, mute operations will silently fail.YouTubeApi Static Methods
The YouTubeApi class in youtube-ctrl.js is a thin wrapper around the YT.Player instance API. All methods are static and accept a player reference as their first argument.
loadYouTubeAPI()
Async. Injects the
https://www.youtube.com/iframe_api script tag using Helpers.loadScript. Returns a Promise that resolves when the script finishes loading.restartVideo(player)
Stops the current video then immediately calls
playVideo(). Useful for looping back to the beginning of a clip.stopVideo(player)
Calls
player.stopVideo(), which halts playback and resets the playhead to the beginning of the video.toggleMuteVideo(player)
Checks the current mute state with
player.isMuted(). If muted, calls player.unMute(); otherwise calls player.mute(). Returns !player.isMuted() evaluated immediately after the mute/unmute call. TV.toggleMute() stores this value as this.muted and shows the MUTING overlay when it is true.muteVideo(player)
Unconditionally mutes the player.
unmuteVideo(player)
Unconditionally unmutes the player.
Mute State Integration
TV.toggleMute() calls YouTubeApi.toggleMuteVideo with the current channel’s player, stores the resulting boolean, and then updates the on-screen overlay via afterMute():
this.muted is true, the text MUTING appears in the #tvm-bottom-left div overlaid on the TV screen (bottom-left corner). When the viewer unmutes, the text is cleared.
The #tv-mute element in index.html is an invisible clickable region styled to overlap the physical mute button area of the TV image:
TV.startUp():
Player Reference Pattern
WhenTV.showChannel switches channels it calls teardown() on the old channel. The base Channel.teardown() checks for this.player and calls YouTubeApi.stopVideo if it exists:
YT.Player must store it as this.player to get automatic cleanup — and to allow TV’s mute controls to reach it. A channel that stores its player under any other property name (e.g. this.ytPlayer) will not be stopped on channel change and will not respond to mute.