Skip to content

Releases: zshall/program-guide

TVS 6.3.0 (2026-07-31)

Choose a tag to compare

@zshall zshall released this 31 Jul 01:36
9119814

Update Notes - 6.3.0 (2026-07-30)

Components

Hot on the heels of 6.2.0, this update adds a new XMLTV integration to the program guide system.

✨ New Features

  • Added the ability to import program guide listings from an XMLTV file. This allows you to use 3rd party headends like ErsatzTV or Tunarr to display program info directly, without needing any special translation layer like we did in the past.
externalSources:
  cableListings: # key for the external source; can be anything as long as it's unique and doesn't use spaces or special characters other than dashes
    url: https://example.com/guide.xml # The URL to the XMLTV file. Can be a local file path or a remote URL.
    type: xmltv

channels:
- number: 50
  abbr: CBL
  info:
    cableListings:guide.channel.5 # This channel's guide data will be pulled from the XMLTV source named `cableListings` and the channel ID of the XMLTV `<programme>` elements would be `guide.channel.5`
  video: https://example.com/stream.m3u8 # You'll still need to pair this up with the video stream, since XMLTV doesn't provide the content itself, just metadata about what's on.

🔧 Bug Fixes

  • Fixed bug in the guide where channel ranges weren't properly showing the last channel in the range.

TVS 6.2.0 (2026-07-29)

Choose a tag to compare

@zshall zshall released this 29 Jul 22:15
9119814

Update Notes - 6.2.0 (2026-07-29)

image

This week's update expands the power of community IFrame plugins by adding multiple new capabilities to the TVS IFrame API.

✨ New Features

  • Added a new deepIntegration section to the IFrame engine that will allow configuration file authors the ability to grant permission to IFrames to access different APIs. For security, IFrames can't access these new APIs unless your config file allows it since they allow the IFrame to control TVS and read its data.
  • Added a new capabilities property in the IFrame API that tells the IFrame which APIs the config file has given it access to, so if an IFrame doesn't have all the permissions it can take advantage of it can either fall back gracefully or display an error asking for more permissions if it needs them.
  • Added a Channel Info API which allows IFrames to query listing data for all channels or the current channel and also to get a number of current or upcoming programs. This allows for plugins like a dynamic "coming up next" animation or a 3rd party program guide.
  • Added a Termination API which allows for the IFrame to signal to TVS that it's done and that we should advance to the next content if we're running in a loop engine or some other context that supports dynamic scheduled content.
  • Added two new example plugins: Listings API example and Up Next API example. You can study the source code of these and use 'em as a template to make your own plugins. The code of each is a single HTML file with no external library dependencies so you can view the source code easily.
- number: 48
  abbr: UPNEXT
  loop:
    - iframe: # This is an example of a plugin that uses the channel info API to display which listings are up next for the current channel. The plugin is hosted on a separate server and is loaded into the TV using an IFrame.
        src: https://gcpw.art/tvs/engines/up-next
        deepIntegration:
          channelInfo: current-channel # The plugin will receive updates whenever the current content changes and can request listing info for the current channel.
          canRequestTermination: true # You can grant permission for the plugin to signal that it's done and the loop should advance to the next content. The IFrame plugin must support this or it'll have no effect.
    - image: placeholders/random-placeholder.jpg
      duration: 10

- number: 49
  abbr: UPNEXT2
  iframe: # This is an example of a plugin that uses the channel info API to display program listings for different channels. The plugin is hosted on a separate server and is loaded into the TV using an IFrame.
    src: https://gcpw.art/tvs/engines/listings
    options:
      channelRange: # You can pass in options to the plugin to control how it behaves; take a look at the source code of the IFrame for how we receive and use them.
        min: 1
        max: 5
    deepIntegration:
      channelInfo: all-channels # The plugin will receive updates whenever the current content changes and can request listing info for all channels.

🔧 Bug Fixes

  • Fixed bug in bulletin editor where placeholder text was showing up in the data tab rather than the data we were trying to preview.

⚙️ Other Changes

  • For those participating in the Television Simulator Studio alpha I've made some breaking changes regarding how guide data is delivered: the info.series property has been removed and in its place we've added a new property: info.subtitle. This is because in XMLTV and other systems, TV Shows use title to mean series and sub-title to mean the episode title. In movies however they use title to mean the movie title and might use sub-title to be a movie tagline or something else but series isn't used.

TVS 6.1.0 (2026-07-22)

Choose a tag to compare

@zshall zshall released this 23 Jul 02:41
9119814

6.1.0 (2026-07-22)

image

This update is all about program guides; we've got a new guide theme available, a few new guide features and a bit of performance optimization.

✨ New Features

  • Added new 1997 theme to the program guide engine which is modeled after the PC Prevue guide.
  • Guides now refresh with current listings dynamically instead of needing to change channels to get the listings to update.
  • Added timezone option to the guide engine which allows you to specify a timezone for the program guide, which will let you display the current guide listings but in a different time zone than what you're currently in. This doesn't change what's currently on as there can only be one program airing per channel at a time, but will affect the current date and time display and the timeslot labels in the guide.
  • Added currentTimeFormat, currentDateFormat, and currentTimeslotTimeFormat which allow you to customize how the time and date are displayed in program guides. They accept the same formatting strings as the character generator.
- number: 166
  abbr: G97
  name: Guide 1997
  guide:
    logo:  placeholders/guide-header-1997.png # Logo to show at the top of the guide
    theme: "1997"
    # themeOptions:
      # borderColor: blue # Optional. The border color of the guide in the guide header
      # clockColor: red # Optional. The background color of the clock in the guide header

- number: 167
  abbr: GTIMES
  name: Guide timezones and time formatting example
  guide:
    timezone: America/Los_Angeles # Optional. You can specify a timezone for the guide to use. If not specified, the browser's timezone will be used. Use IANA timezones (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
    currentTimeFormat: "hh:mm:ss 'PT'" # Optional. You can specify a time format for the current time in the guide header. If not specified, the default format will be used.
    currentTimeslotTimeFormat: "hh:mm a" # Optional. You can specify a time format for the current timeslot in the guide header. If not specified, the default format will be used.

⚙️ Other Changes

  • Changed the way that the internal marquee component works under the hood to allow for partial CSS-driven animations for the guide table instead of scrolling one pixel per tick, which allows us to use hardware acceleration and have smoother animations. To make sure that the guide headers still do the push animation that the program guides are known for, we've got a second track for guide headers that are animated separately so that the sticky positioning still works as it did before, but with much less repainting. I've tested this on a Raspberry Pi 4 and things look smoother now (even on high-end machines we'd see a lot of stuttering before.)

TVS 6.0.1 (2026-07-18)

Choose a tag to compare

@zshall zshall released this 18 Jul 15:54
9119814
Update-6 0 1

🔧 Bug Fixes

  • Fixed bug with feed-reader engine where text would overrun the screen horizontally if preformatted text was being displayed.

⚙️ Other Changes

  • This is the first public release to be built using a new Gitea actions workflow as opposed to manually. I'm slowly incorporating more automation steps so that we can get things built and released more reliably and faster; a typical done-by-hand release would take an hour or two sometimes because I had to coordinate Docker, GitHub, the documentation site, Discord announcements and the demo site manually. This new build process takes care of Docker and GitHub so far.

TVS 6.0.0 (2026-07-14)

Choose a tag to compare

@zshall zshall released this 15 Jul 01:07
9119814

Update Notes - 6.0.0 (2026-07-14)

image

✨ New Features

Audio Routing

Component-level audio routing now lives under _component.audio.

  • Add src to play a dedicated audio file or stream while the component is mounted.
  • Omit src if the component already has its own audio and you only want it to duck or mute other managed audio.
  • Use group, priority, and interrupts to control which lower-priority audio groups are muted or ducked.
backgroundAudio: placeholders/bgm-3.mp3
backgroundAudioOptions:
  group: music

video:
  provider: youtube
  src: yXkIHyBfns8
  _component:
    audio:
      group: voice
      priority: 10
      interrupts:
      - groups:
        - music
        behavior: mute

Power-On Channel

Added the ability to revert to a default channel whenever the TV's power state changes.

startup:
  powerOnChannel: 1 # any time the power is turned off and back on again, jump to this channel.

Hidden Channels

Added the ability to hide a channel. Hidden channels won't be displayed in guides and channel lists, but can be accessed directly via number inputs.

- number: 280
  name: Hidden Channel
  abbr: HIDE
  hidden: true # Set a channel as `hidden` and it won't show up in the guide or channel lists.
  color: red

Subchannels

Added the ability to have subchannels; e.g. channels like 2.1 or 4.10. Subchannels are required to be in quotes when defined in the channel guide:

- number: "3.14"
  name: Pi Channel
  abbr: PI
  image: placeholders/apple-pie.jpg

Subchannels are not decimals. 1.1, 1.10 and 1.100 are three different channels:

  • Channel 1, subchannel 1
  • Channel 1, subchannel 10
  • Channel 1, subchannel 100

Negative subchannels and subchannels on channel zero are not allowed. Subchannels are shown in the guide and channel listings after their primary channels.

Layout updates

The mix layout has been reworked to accept an array of components stacked on top of each other rather than just a and b components, and per-component options like mixMode and opacity are now in a _mix section instead of in the top level. Read the upgrade guide below to learn how to migrate. h-split and v-split also accept arrays now and you can specify a weight for each component now rather than one splitPercentage.

‼️ Breaking Changes

  • The external listings feature of the program guide has been replaced with a new info system. The guide.externalListings option has been removed.
  • Channel title and description have been removed in favor of the info system.
  • The video-game engine has been moved out of TVS and into its own open source project
  • mix layout uses an array rather than a and b components. Options for mixMode and opacity are now under _mix.mode and _mix.opacity.
  • h-split and v-split layouts use an array rather than a and b components.

🚚 Backwards Compatibility

To help ease the transition to the new version, limited backwards compatibility has been added. If your configuration file has a 5.x schema like this at the top:

# yaml-language-server: $schema=https://gcpw.art/tvs/schemas/5.11.0.json

We'll load your config file in compatibility mode, which will translate your config file on-the-fly to work around breaking changes. Some things like removed / moved engines (basic-text and video-game) will not load but channels that can be loaded with modifications will load.

When you're ready to upgrade from 5.x to 6.x you can follow the steps below:

Upgrade Guide 5.x -> 6.0

  1. Change the schema line to the 6.0 schema:
# yaml-language-server: $schema=https://gcpw.art/tvs/schemas/6.0.0.json
  1. Replace any basic-text engine usage with character-generator. I've prepared a template that looks the same as basic-text's defaults that you can drop in:
- number: 1
  name: Basic Text backwards compatibility
  abbr: TEXT
  character-generator:
    src: placeholders/config-examples/bulletins/basic-text.json
    lines:
      line:
        - text: First line of text # put your text here
        - text: Second line of text
  1. Replace any video-game engine usage with the new iframe version. You can self-host it or use the hosted version:
- number: -1
  iframe:
    src: http://gcpw.art/tvs/engines/video-game # replace with your own server if self-hosting
    options:
      game: flappybird.nes # Required. The game library by default is from `retrobrews.github.io`. You can specify a game from there directly. Set to false to use a core that doesn't require a game.
      core: fceumm # Required. The system to emulate.
      # The video game engine doesn't support granular volume adjustment right now, but mute and unmute work.
      # BREAKING CHANGE since v6.0.0: Only game controller inputs are accepted to free up reserved keyboard keys for future use.
  1. Change usage of mix from the old to new syntax:
  • Use a list rather than a and b
  • mixMode: becomes _mix.mode
  • opacity: becomes _mix.opacity

Old syntax:

- number: 133
  name: Mix Layout
  mix:
    a:
      opacity: 0.6
      image: placeholders/example-program.webp
    b:
      mixMode: difference
      generator: test-pattern

New syntax:

- number: 133
  name: Mix Layout
  mix:
    - image: placeholders/example-program.webp
      _mix: 
        opacity: 0.6
    - generator: test-pattern
      _mix:
        mode: difference
  1. Change usage of v-split and h-split from the old to new syntax:

Old syntax:

- number: 139
  name: V-Split
  v-split:
    a:
      color: red
    b:
      color: blue

New syntax:

- number: 139
  name: V-Split
  v-split:
    - color: red
    - color: blue

splitPercentage can continue to be used but only if you have two components. The new equivalent is _split.weight:

- number: 139
  name: V-Split
  v-split:
    - color: red
    - color: blue
      _split:
        weight: 2 # This component will take up two units of weight compared to the others. The default is to distribute each component equally (1 weight per component)
    - color: green
  1. Move channel title and description to info section

Anywhere where you have a channel with title and description attributes, move these to the info section and replace description with summary.

Old syntax:

- number: 2
  name: Welcome
  abbr: WELCOME
  title: Thanks for testing Television Simulator!
  description: Welcome to TVS 6.0!

New syntax:

- number: 2
  name: Welcome
  abbr: WELCOME
  info:
    title: Thanks for testing Television Simulator!
    summary: Welcome to TVS 6.0!

Thanks to all users and supporters!

Television Simulator 6.0 has been in development for about 9 months and has undergone 188 commits, 253 files changed, +26,049, -15,436 code lines changed, and 28 prereleases. Lots of features that haven't been documented previously are now documented and there's a new video tutorial on custom themes. Whether you are new to TVS or a long-time user, thanks for checking it out!

TVS 5.11.0-beta (2026-05-10)

Choose a tag to compare

@zshall zshall released this 11 May 02:48
9119814

Update Notes - 5.11.0 (2026-05-10)

5 11

✨ New Features

Added a new virtual video signal feature that works with all components. Think of it as the ability to define a resolution that all inner components will use.
Added a new _component property, present on all content engines, that allows you to define properties that can apply to any component. Currently we only use one property: dimensions (the virtual video signal).

- number: 270
  name: Virtual Video Signals
  abbr: VVS
  generator:
    type: test-pattern
    _component:
      dimensions:
        width: 1280
        height: 720
        aspectRatioBehavior: contain

🔧 Bug Fixes

  • Fixed a bug with the validation schema where volume was incorrectly set as a required property for the generator engine.
  • Fixed validation schema bug where loop didn't correctly inherit from the base component.

❗ Deprecation Notice

In version 6.0.0, interruptsBackgroundAudio will change; either being moved to _component or restructured in another way. That way all properties that apply to all components will be under _component.

TVS 5.10.0-beta (2026-04-24)

Choose a tag to compare

@zshall zshall released this 25 Apr 03:21
9119814

Update Notes - 5.10.0 (2026-04-24)

about

✨ New Features

This update has added a new Character Generator engine that can be used in many scenarios:

  • Displaying news bulletins, weather and text ads
  • Overlaying text over videos or images
  • Adding a crawl / ticker to a channel
  • Integrating with live data (given you supply it in the right format)

TVS 5.10 ships with a built-in character generator template editor which you can also try on the demo site.

This update also adds two new weather providers that work worldwide: wttr.in and weatherapi.com which requires an API key.

- number: 150
  name: Weather demo
  abbr: WX1
  weather:
    logo: placeholders/weather.png
    provider: wttr.in
    units: imperial

- number: 151
  name: Weather demo
  abbr: WX2
  weather:
    logo: placeholders/weather.png
    provider: weatherapi.com
    apiKey: "YOUR-API-KEY"
    units: metric

❗ Deprecation Notice

The basic-text engine has been deprecated and will be removed in TVS 6.0. All example usages of it have been updated to use character-generator instead.

TVS 5.9.2-beta (2026-03-16)

Choose a tag to compare

@zshall zshall released this 17 Mar 03:49
9119814

Update Notes - 5.9.2 (2026-03-16)

image

🔧 Bug Fixes

  • Fixed #115 which was a problem I traced back to a Svelte framework issue. Svelte 5.53.7 exhibited this issue but Svelte 5.53.12 has fixed it. The issue manifested itself in TVS as a problem when changing channels too quickly; we would unload a channel rapidly while it's still loading and this would cause multiple channels to be loaded at the same time despite using a {#key} block to prevent this. The zombie channels would never unload and would stick around until we refreshed the page.

  • Added a 200ms throttle on channel change operations to help prevent any future issues with changing channels too fast. If you hold down the channel up / down button we no longer change channels as fast as possible; we'll change channels about 5 channels per second instead. If you mash channel up and down buttons rapidly we'll ignore any button presses shorter than 200ms apart.

  • Fixed an issue with the YouTube playlist engine where if you use it inside a h-split or v-split layout the player would take up 100% of the screen rather than 100% of its container meaning that we were losing half the image. YouTube playlists resize to fit their container properly now.

TVS 5.9.1-beta (2026-03-15)

Choose a tag to compare

@zshall zshall released this 15 Mar 21:59
9119814

Update Notes - 5.9.1 (2026-03-15)

image

🔧 Bug Fixes

  • Fixed #113; the <marquee> tag is broken in Chrome 146, so I switched to a custom implementation. This runs at 60 FPS and behaves similarly to the real marquee tag. Currently it is only available in the 1989 program guide theme, but it'll be used in upcoming engines as well.

TVS 5.9.0-beta (2026-03-09)

Choose a tag to compare

@zshall zshall released this 10 Mar 00:31
9119814

Update Notes - 5.9.0 (2026-03-09)

✨ New Features

  • Added new sat1992 OSD theme based on C-Band satellite TV from the early 90's. This theme brings with it some interesting customization options; true to the way the real receivers work, we simulate a satellite dish on a motorized base. You can optionally define a list of known satellites with positions based on motor pulses (these values can be any arbitrary number). You can then define themeOptions in individual channels to specify the satellite that the picture would be received from. When you go to a channel that uses a different satellite than the one that you were on previously, the simulated motor will display progress saying it's turning to the position that you specified.
osd:
  theme: sat1992 # 1990's analog C-band satellite receiver theme
  themeOptions:
    # showChannelInterference: false # by default, we display overlays of 
    satellite: C1 # the default satellite for all channels to be on. If unset, only channels with a satellite option set will display one.
    satellites: # you can define a list of different satellites; they'll be a letter and number combination followed by a 4-digit number representing the location in the sky
      C1: 3600 # these are all arbitrary numbers
      C3: 4100
      C4: 4300
      C5: 4550
      G1: 4550
      G2: 4700
      G3: 5100
      G4: 6200
      T3: 6900

channels:
- number: 1
  name: Test Channel
  color: blue
  themeOptions: # optional section for theme-specific metadata
    satellite: C3 # you can designate a channel as being on a particular satellite; choose from the list you defined in the OSD themes

- number: 2
  name: Test Channel 2
  color: red
  themeOptions:
    satellite: G2

- number: 3
  name: Test Channel 3
  color: green # if a channel doesn't specify a satellite, it defaults to the one specified in the OSD options, or no satellite if one isn't specified there either
  • Added a new abstract-background engine, which can currently apply two different visual effects to an image of your choice; wave1 and wave2.
- number: 143
  name: Abstract background 1
  abstract-background:
    type: wave1

- number: 144
  name: Abstract background 2
  abstract-background:
    type: wave2

- number: 145
  name: Abstract background with custom image
  abstract-background:
    src: placeholders/example-program.webp
    type: wave2
    width: 400
    height: 300