diff --git a/README.md b/README.md
index 62d07d33..550f0b3c 100644
--- a/README.md
+++ b/README.md
@@ -188,7 +188,7 @@ curl -X POST http://your-pi-ip:5000/api/v3/plugins/install \
| Plugin | Description | Preview |
|--------|-------------|---------|
-| [Web UI Info](./plugins/web-ui-info/) | Displays web UI URL for device access | |
+| [Web UI Info](./plugins/web-ui-info/) | Displays web UI URL for device access |
|
### Development (1)
diff --git a/docs/assets/web-ui-info/hero.png b/docs/assets/web-ui-info/hero.png
new file mode 100644
index 00000000..fc6a6977
Binary files /dev/null and b/docs/assets/web-ui-info/hero.png differ
diff --git a/docs/assets/web-ui-info/hostname-length.png b/docs/assets/web-ui-info/hostname-length.png
new file mode 100644
index 00000000..e52f4a82
Binary files /dev/null and b/docs/assets/web-ui-info/hostname-length.png differ
diff --git a/docs/assets/web-ui-info/narrow-wrap.png b/docs/assets/web-ui-info/narrow-wrap.png
new file mode 100644
index 00000000..4296231f
Binary files /dev/null and b/docs/assets/web-ui-info/narrow-wrap.png differ
diff --git a/docs/assets/web-ui-info/panel-sizes.png b/docs/assets/web-ui-info/panel-sizes.png
new file mode 100644
index 00000000..49290dd7
Binary files /dev/null and b/docs/assets/web-ui-info/panel-sizes.png differ
diff --git a/docs/assets/web-ui-info/shots.json b/docs/assets/web-ui-info/shots.json
new file mode 100644
index 00000000..a2aa7983
--- /dev/null
+++ b/docs/assets/web-ui-info/shots.json
@@ -0,0 +1,121 @@
+{
+ "plugin": "web-ui-info",
+ "defaults": {
+ "width": 128,
+ "height": 32,
+ "scale": 6,
+ "hostname": "ledmatrix",
+ "config": {
+ "enabled": true
+ }
+ },
+ "shots": [
+ {
+ "name": "hero",
+ "width": 128,
+ "height": 32
+ },
+ {
+ "name": "size-64x32",
+ "width": 64,
+ "height": 32,
+ "scale": 6,
+ "standalone": false
+ },
+ {
+ "name": "size-128x32",
+ "width": 128,
+ "height": 32,
+ "scale": 6,
+ "standalone": false
+ },
+ {
+ "name": "size-256x32",
+ "width": 256,
+ "height": 32,
+ "scale": 6,
+ "standalone": false
+ },
+ {
+ "name": "size-128x64",
+ "width": 128,
+ "height": 64,
+ "scale": 6,
+ "standalone": false
+ },
+ {
+ "name": "host-short",
+ "hostname": "pi",
+ "standalone": false
+ },
+ {
+ "name": "host-long",
+ "hostname": "raspberrypi-livingroom",
+ "standalone": false
+ },
+ {
+ "name": "host-long-64",
+ "width": 64,
+ "height": 32,
+ "scale": 6,
+ "hostname": "raspberrypi-livingroom",
+ "standalone": false
+ }
+ ],
+ "composites": [
+ {
+ "name": "panel-sizes",
+ "columns": 2,
+ "cells": [
+ {
+ "shot": "size-64x32",
+ "label": "64 x 32"
+ },
+ {
+ "shot": "size-128x32",
+ "label": "128 x 32"
+ },
+ {
+ "shot": "size-256x32",
+ "label": "256 x 32"
+ },
+ {
+ "shot": "size-128x64",
+ "label": "128 x 64"
+ }
+ ]
+ },
+ {
+ "name": "hostname-length",
+ "columns": 1,
+ "cells": [
+ {
+ "shot": "host-short",
+ "label": "\"pi\" - \"at\" prefix fits"
+ },
+ {
+ "shot": "hero",
+ "label": "\"ledmatrix\" - \"at\" prefix fits"
+ },
+ {
+ "shot": "host-long",
+ "label": "\"raspberrypi-livingroom\" - prefix dropped"
+ }
+ ]
+ },
+ {
+ "name": "narrow-wrap",
+ "columns": 1,
+ "cells": [
+ {
+ "shot": "size-64x32",
+ "label": "\"ledmatrix\" on 64x32"
+ },
+ {
+ "shot": "host-long-64",
+ "label": "long hostname wraps"
+ }
+ ]
+ }
+ ]
+}
diff --git a/plugins.json b/plugins.json
index f8240000..fd023c79 100644
--- a/plugins.json
+++ b/plugins.json
@@ -952,10 +952,10 @@
"plugin_path": "plugins/web-ui-info",
"stars": 0,
"downloads": 0,
- "last_updated": "2026-07-31",
+ "last_updated": "2026-09-02",
"verified": true,
"screenshot": "",
- "latest_version": "1.0.2"
+ "latest_version": "1.1.0"
},
{
"id": "youtube-stats",
diff --git a/plugins/web-ui-info/README.md b/plugins/web-ui-info/README.md
index 414864fc..8aef87d1 100644
--- a/plugins/web-ui-info/README.md
+++ b/plugins/web-ui-info/README.md
@@ -1,64 +1,228 @@
-# Web UI Info Plugin
+# Web UI Info
-A simple built-in plugin for LEDMatrix that displays the web UI URL for easy access.
+A one-screen reminder of the address your LEDMatrix web interface is on.
+It alternates between the device's hostname and its IP address, so you can
+read the URL off the panel instead of hunting for the Pi on your network.
-## Features
+
-- Displays "visit web ui at http://[deviceID]:5000" on the LED matrix
-- Automatically detects device hostname
-- Easily enabled/disabled via web interface
-- Configurable display duration
+No network access, no API key, no dependencies beyond what LEDMatrix already
+ships — the plugin only reads local system information.
+
+---
+
+## What it shows
+
+Two centred lines of white text:
+
+```text
+visit web ui
+at ledmatrix:5000
+```
+
+The address on the second line **alternates every 10 seconds** between:
+
+| Mode | Second line | Source |
+|---|---|---|
+| Hostname | `at ledmatrix:5000` | `socket.gethostname()` |
+| IP address | `at 192.168.1.42:5000` | the first interface address that is not loopback |
+
+Both modes are laid out identically — only the address text differs. The port
+is always `5000`, the port the LEDMatrix web interface listens on; it is not
+configurable from this plugin.
+
+---
+
+## Installation
+
+Web UI Info ships with the default Plugin Store:
+
+1. Open the web interface (`http://your-pi-ip:5000`)
+2. Go to the **Plugin Manager** tab
+3. Find **Web UI Info** under **Plugin Store** and click **Install**
+4. Toggle it on, then click **Restart Display Service** on the **Overview** tab
+
+To install from source instead, copy the directory into your LEDMatrix
+plugins directory (default `plugin-repos/`):
+
+```bash
+cp -r plugins/web-ui-info ~/LEDMatrix/plugin-repos/
+sudo systemctl restart ledmatrix
+```
+
+---
## Configuration
-The plugin can be configured in `config/config.json`:
+Settings live in the plugin's tab in the web UI, and are stored in
+`config/config.json` under the `web-ui-info` key. The full schema is
+[`config_schema.json`](config_schema.json).
+
+| Option | Type | Default | Description |
+|---|---|---|---|
+| `enabled` | boolean | `true` | Master switch. When off, the plugin is skipped in the rotation. |
+| `display_duration` | number | `10` | Seconds the panel holds the screen before the display rotates on (1–300). |
+| `transition.enabled` | boolean | `true` | **Not implemented** — see below. |
+| `transition.type` | string | `"redraw"` | **Not implemented** — see below. |
+| `transition.speed` | integer | `2` | **Not implemented** — see below. |
+
+That is the whole surface: this plugin has no colours, fonts, or layout
+options. The text is always white, always centred.
```json
{
"web-ui-info": {
"enabled": true,
- "display_duration": 10,
- "transition": {
- "type": "redraw",
- "speed": 2,
- "enabled": true
- }
+ "display_duration": 10
}
}
```
-### Configuration Options
+### `display_duration` and the 10-second alternation
+
+The swap is driven by a wall clock, not by a per-turn counter: the plugin
+changes address whenever 10 seconds have passed since the last change. Two
+things follow from that.
+
+**Between turns.** The gap between one appearance in the rotation and the next
+is almost always longer than 10 seconds, so the plugin swaps as it comes back
+on screen. Consecutive turns alternate hostname, then IP, then hostname again —
+even at the default `display_duration`.
+
+**Within a turn.** A screen held longer than 10 seconds swaps again while you
+are looking at it.
+
+| `display_duration` | What you see |
+|---|---|
+| `5` – `10` (default) | One address per turn, alternating from turn to turn |
+| `20` | One swap part way through the screen |
+| `30` or more | A swap roughly every 10 seconds |
+
+The default is fine for most setups. Raise it to `20` if you want both
+addresses in a single turn rather than across two.
+
+### The `transition` settings do nothing
+
+`transition.enabled`, `transition.type`, and `transition.speed` appear in the
+configuration form, but `manager.py` never reads them and the LEDMatrix core
+implements no display transitions. Changing them has no effect. They are
+tracked for removal in
+[issue #381](https://github.com/ChuckBuilds/ledmatrix-plugins/issues/381) —
+four other plugins declare the same dead block.
+
+---
+
+## How the address is found
-- `enabled` (boolean): Enable or disable the plugin (default: `true`)
-- `display_duration` (number): How long to display the message in seconds (default: `10`, range: 1-300)
-- `transition` (object): Transition settings for switching to/from this display
+### Hostname
-## Usage
+`socket.gethostname()`, read once when the plugin loads. If that raises, the
+plugin falls back to `localhost`.
-The plugin will automatically be discovered and loaded when the LEDMatrix system starts. It will display the web UI URL during the normal rotation cycle.
+### IP address
-To enable/disable the plugin:
-1. Open the web UI at `http://[your-device]:5000`
-2. Open the **Plugin Manager** tab
-3. Find **Web UI Info** in the **Installed Plugins** list and toggle it
- on or off
-4. Restart the display service from the **Overview** tab
+Re-read every 30 seconds, so unplugging Ethernet or switching networks is
+picked up without a restart. The plugin tries these in order and takes the
+first answer that is neither loopback (`127.x`) nor the AP-mode address:
-## Device ID
+1. **AP mode check.** If `hostapd` is active, or `wlan0` already holds
+ `192.168.4.1`, the plugin reports `192.168.4.1` — the address the web UI is
+ on when the Pi is running as its own access point.
+2. **`hostname -I`** — the fastest path, and the one that normally answers on
+ a Raspberry Pi.
+3. **`ip -4 addr show`** — preferring wired interfaces (`eth*`, `enp*`), then
+ `wlan0`.
+4. **A UDP socket to `8.8.8.8`** — no packet is actually sent; this just asks
+ the kernel which local address it would route from. Needs a default route.
+5. **`socket.gethostbyname()`** on the hostname.
-The plugin uses `socket.gethostname()` to determine the device hostname. If the hostname cannot be determined, it falls back to "localhost".
+If every step fails, the second line reads `at localhost:5000`.
-## Display
+---
-The plugin displays two lines of text:
-- Line 1: "visit web ui"
-- Line 2: "at [deviceID]:5000"
+## Panel sizes
-Text is centered horizontally on the display and rendered in white.
+The text is drawn in the 4x6 bitmap font at a fixed size, so what changes
+across panels is how much room the two lines have, not how big they are.
+
+
+
+The block is centred both horizontally and vertically, so it sits in the
+middle of a tall panel rather than against the top edge.
+
+---
+
+## Long hostnames
+
+A hostname long enough to overflow the panel used to be silently sliced off at
+both ends. The plugin now shortens the line in stages instead:
+
+
+
+1. `at