diff --git a/examples/README.md b/examples/README.md
index 49f383e..b1528eb 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -36,6 +36,7 @@ Note that some starter examples include the creation of a `brightsign-dumps` fol
| [send-plugin-message](browser/send-plugin-message) | Plugin message communication between BrightScript and HTML/JS | 8.x, 9.x |
| [syncmanager-js](browser/syncmanager-js) | Multi-player content synchronization using SyncManager JS API | 8.x, 9.x |
| [large-file-download](browser/large-file-download) | Memory-bounded multi-GB download using Node streams in roHtmlWidget | 8.x, 9.x |
+| [seamless-video-switching](browser/seamless-video-switching) | Gap-free HTML5 video playback using dual video elements with background preloading; reads asset list via Node `fs` in roHtmlWidget | 8.x, 9.x |
### Node.js 14 Examples (`node-14/`)
diff --git a/examples/browser/seamless-video-switching/README.md b/examples/browser/seamless-video-switching/README.md
new file mode 100644
index 0000000..04c127b
--- /dev/null
+++ b/examples/browser/seamless-video-switching/README.md
@@ -0,0 +1,94 @@
+# BrightSign Dual Video Player HTML5 Application - Seamless Playback
+
+> A seamless HTML5 video player application for BrightSign that provides gap-free video transitions using dual video elements with background preloading.
+
+## 🎯 Why Use This Approach?
+
+**This dual video player provides truly seamless, gap-free video playback** - essential for advertising and professional digital signage where any visible gap between videos is unacceptable.
+
+### The Dual Player Advantage:
+- ✅ **Zero visible gaps** - No freeze frames or black screens between videos
+- ✅ **Instant transitions** - Next video is preloaded and ready to play
+- ✅ **No fade effects** - Clean cuts between videos without mixing content
+
+### How It Works:
+1. Two video elements are layered on top of each other
+2. While video 1 plays, video 2 loads the next file in the background
+3. When video 1 ends, video 2 instantly becomes visible and starts playing
+4. Video 1 (now hidden) loads the next file in the background
+5. The cycle repeats for seamless continuous playback
+
+## Configuration
+
+You can customize the following settings in `index.js` before deploying:
+
+- **`rootStoragePath`** - The root storage path on the BrightSign player (default: `/storage/sd`)
+- **`assetsFolder`** - The folder name containing your video files (default: `assets`)
+- **`MULTI_DECODER`** - Set to `true` on players with multiple hardware decode pipelines to enable near-zero-gap transitions (default: `false`). See [Multi-decoder mode](#multi-decoder-mode) below.
+- **`EARLY_START_LEAD_SECONDS`** - Multi-decoder only. How many seconds before the visible video ends to start the hidden player (default: `0.5`). Raise if the swap reveals unrendered frames; lower for a tighter cut.
+
+Example:
+```javascript
+const rootStoragePath = '/storage/sd';
+const assetsFolder = 'assets'; // Change this to use a different folder name
+const MULTI_DECODER = false; // Set to true on XT/4K series players
+const EARLY_START_LEAD_SECONDS = 0.5; // Multi-decoder only
+```
+
+If you change `assetsFolder` to a different name (e.g., `videos`), make sure to create that folder on your SD card and place your video files there instead.
+
+## Multi-decoder mode
+
+On BrightSign players with multiple hardware decode pipelines (mid-to-high-end XT and 4K series), set `MULTI_DECODER = true` in `index.js` to enable two optimizations that further reduce the transition gap:
+
+1. **Decoder pre-warming** — after the hidden player buffers (`canplay`), it plays briefly then pauses at frame 0. This initializes the hardware decode pipeline so `play()` at switch time starts near-instantly.
+2. **Early start** — the hidden player begins playing (muted, hidden) `EARLY_START_LEAD_SECONDS` before the visible video ends (default 0.5s). By the time `ended` fires, the hidden player is already producing frames and the swap is immediate.
+
+If the early start does not complete in time, the swap falls back to awaiting the `playing` event, preventing a swap onto an unrendered frame.
+
+**Do not enable `MULTI_DECODER = true` on single-decoder hardware** — pre-warming and early start will compete with the active player's decoder and may cause stuttering. Leave `MULTI_DECODER = false` for the default single-decoder behavior. Refer to the [BrightSign model and series reference](https://docs.brightsign.biz/hardware/model-and-series-reference) to check your player's capabilities.
+
+| | `MULTI_DECODER = false` (default) | `MULTI_DECODER = true` |
+|---|---|---|
+| Hardware | Any BrightSign player | Multi-decoder required (XT, 4K) |
+| Gap at transition | Small gap (decoder handoff) | Near-zero |
+| Simultaneous decoding | No | Yes |
+
+## Deployment to BrightSign Player
+
+### SD Card Structure
+
+Your BrightSign player's SD card should have the following structure:
+
+```
+SD/
+├── autorun.brs (launches index.html)
+├── index.html (loads index.js)
+├── index.js (application logic)
+└── assets/ (your video files)
+ ├── video1.mp4
+ ├── video2.mp4
+ └── video3.ts
+```
+
+### Deployment Steps
+
+1. Copy the following files to the root of your SD card:
+ - `autorun.brs`
+ - `index.html`
+ - `index.js`
+2. Create an `assets/` folder on the SD card
+3. Copy your video files into the `assets/` folder
+4. Insert the SD card into your BrightSign player and power it on
+
+The application will automatically:
+- Load video files from `/storage/sd/assets/`
+- Sort them alphabetically
+- Play them in sequence with seamless transitions
+- Loop back to the first video after the last one finishes
+
+## Notes
+
+- **Supported video formats**: See [BrightSign video formats and codecs](https://docs.brightsign.biz/advanced/video-formats-and-codecs) for the list of containers, codecs, and profiles supported by each player series.
+- **Performance**: Playback smoothness and switching behavior may vary depending on player model, OS version, video mode (resolution/framerate), and the encoding of your source files. Adjust the code (e.g., preload behavior, number of preloaded players) to fit your specific use-case.
+- **Early start threshold (multi-decoder mode)**: Adjust `EARLY_START_LEAD_SECONDS` (default `0.5`) to trade content budget against transition reliability on your specific hardware and content type.
diff --git a/examples/browser/seamless-video-switching/architecture.md b/examples/browser/seamless-video-switching/architecture.md
new file mode 100644
index 0000000..488f4b9
--- /dev/null
+++ b/examples/browser/seamless-video-switching/architecture.md
@@ -0,0 +1,61 @@
+# Architecture Diagram
+
+```mermaid
+graph TD
+ Player["BrightSign Player"]
+ Autorun["autorun.brs
(BrightScript)"]
+ HTML["index.html
(Dual Video Elements)"]
+ Bundle["index.js
(Switching Logic)"]
+ Display["HDMI Display
(Video Output)"]
+ Assets[("assets/
(Video Files
.mp4, .ts)")]
+ Player1["Video Player 1
(Visible/Hidden)"]
+ Player2["Video Player 2
(Hidden/Visible)"]
+
+ Player -->|"Boots & Launches"| Autorun
+ Autorun -->|"Creates roHtmlWidget
Loads HTML"| HTML
+ HTML -->|"Loads & Executes"| Bundle
+ Bundle -->|"Reads Video Files"| Assets
+ Bundle -->|"Controls Playback
& Visibility"| Player1
+ Bundle -->|"Controls Playback
& Visibility"| Player2
+ Player1 -->|"Renders Video"| Display
+ Player2 -->|"Renders Video"| Display
+
+ style Player fill:#4a90e2,stroke:#333,stroke-width:2px,color:#fff
+ style Autorun fill:#e67e22,stroke:#333,stroke-width:2px,color:#fff
+ style HTML fill:#9b59b6,stroke:#333,stroke-width:2px,color:#fff
+ style Bundle fill:#7b68ee,stroke:#333,stroke-width:2px,color:#fff
+ style Display fill:#34495e,stroke:#333,stroke-width:2px,color:#fff
+ style Assets fill:#50c878,stroke:#333,stroke-width:2px,color:#fff
+ style Player1 fill:#e74c3c,stroke:#333,stroke-width:2px,color:#fff
+ style Player2 fill:#e74c3c,stroke:#333,stroke-width:2px,color:#fff
+```
+
+## Seamless Video Switching Flow
+
+1. **Initial Load**: Player 1 loads and plays the first video
+2. **Preload**: While Player 1 plays, Player 2 preloads the next video (hidden)
+3. **Switch Trigger**: When Player 1 ends, the switching sequence begins
+4. **Start Hidden Player**: Player 2 starts playing (while still hidden)
+5. **Wait for Playback**: Wait until Player 2 is actually playing
+6. **Instant Transition**: Player 2 becomes visible, Player 1 becomes hidden
+7. **Background Preload**: Player 1 (now hidden) preloads the next video
+8. **Loop**: Repeat steps 3-7 indefinitely for continuous playback
+
+## Key Features
+
+- **Zero-Gap Transitions**: No black screens or freeze frames between videos
+- **Dual Player Technique**: Two HTML5 video elements layered using absolute positioning
+- **Background Preloading**: Next video is fully loaded before current video ends
+- **Instant Visibility Toggle**: CSS class switching provides immediate visual transition
+- **Alphabetical Playback**: Videos are sorted and played in alphabetical order
+- **Infinite Loop**: Playlist automatically loops back to the first video
+
+## Legend
+
+- **Blue**: BrightSign Player
+- **Orange**: BrightScript
+- **Purple**: HTML/JS Application
+- **Purple (Dark)**: JavaScript Logic
+- **Dark Gray**: External Hardware
+- **Green**: Video Files
+- **Red**: Video Player Elements
diff --git a/examples/browser/seamless-video-switching/autorun.brs b/examples/browser/seamless-video-switching/autorun.brs
new file mode 100644
index 0000000..c8da76a
--- /dev/null
+++ b/examples/browser/seamless-video-switching/autorun.brs
@@ -0,0 +1,40 @@
+function main()
+ mp = CreateObject("roMessagePort")
+
+ ' Create HTML Widget
+ widget = CreateHTMLWidget(mp)
+ widget.Show()
+
+ 'Event Loop
+ while true
+ msg = wait(0, mp)
+ print "msg received - type=";type(msg)
+ if type(msg) = "roHtmlWidgetEvent" then
+ print "msg: ";msg
+ end if
+ end while
+
+end function
+
+function CreateHTMLWidget(mp as object) as object
+ ' Get Screen Resolution
+ vidmode = CreateObject("roVideoMode")
+ width = vidmode.GetResX()
+ height = vidmode.GetResY()
+
+ r = CreateObject("roRectangle", 0, 0, width, height)
+
+ ' Create HTML Widget config
+ config = {
+ javascript_enabled: true,
+ brightsign_js_objects_enabled: true,
+ nodejs_enabled: true,
+ url: "file:///sd:/index.html",
+ port: mp
+ }
+
+ ' Create HTML Widget
+ h = CreateObject("roHtmlWidget", r, config)
+ return h
+
+end function
diff --git a/examples/browser/seamless-video-switching/index.html b/examples/browser/seamless-video-switching/index.html
new file mode 100644
index 0000000..d91b86a
--- /dev/null
+++ b/examples/browser/seamless-video-switching/index.html
@@ -0,0 +1,51 @@
+
+
+