# Changelog Notable changes to the LEDMatrix core. The version below is the value of `src.__version__`, which the plugin loader reports to compatibility checks and which plugin manifests reference via `ledmatrix_min_version`. **Why this file exists:** the plugin monorepo bundles fallback copies of several core modules (see `docs/plugin-development/08-shared-sports-code.md` in [ledmatrix-plugins](https://github.com/ChuckBuilds/ledmatrix-plugins)). A plugin may delete its bundled copy only when its manifest floors on the first core release that ships the module — which requires module additions to be recorded here, against a version number. When you add a module plugins will import via `src.*`, note it in the Unreleased section and bump `src/__init__.py` in the release that ships it. **Use `ledmatrix_min_version` in manifests, not `ledmatrix_min`.** The loader accepts both, but the store flags the old spelling as deprecated (`store_manager.py`) and only the new one is in `schema/manifest_schema.json`. ## Unreleased ### Web UI: the Display tab is an ES-module page, with a page-visibility service (stage 4) - New `static/v3/js/core/visibility.js`: each page module gets `ctx.visibility` with `whileVisible(start, stop)`, `every(ms, fn)` and `isVisible()`. Work registered there runs only while the page's tab is the active tab and the browser tab is visible, and ends when the page is swapped out, with no teardown code in the page. It reads the active tab from `window.LEDVisibility`, so it agrees with the classic partials that still use that directly. The page registry gained a `mountContext` option for services bound to one mounted page. - The Display tab's inline scripts are now `static/v3/js/pages/display.js`. The partial has no inline script, `onclick` or `onchange` any more. The multi-display sync status poll (every 5 s) runs through `ctx.visibility.every`; the status and scroll-speed hint requests go through `core/api.js` with the page's abort signal, and so does the Vegas order widget's plugin-list request. - Behaviour differences: with sync on, opening the tab asks for the status once instead of twice, and a Display tab loaded while not on screen waits until it is. A login redirect during a poll no longer flashes "Sync status unavailable". The `window.syncStatusInterval` timer id is gone (nothing read it). A pending scroll-hint request or widget retry is dropped when the partial is swapped out. - `window.updateSyncUI` keeps working as a deprecated alias through `window.LEDMatrix` (one console warning). - New suites `test/js/dom/test_visibility_service.js` and `dom/test_display_page.js`; `unit/test_display_partial_ids.js` imports the module instead of slicing the template. ### Plugins ask for the screen in-process: `request_on_demand()` / `end_on_demand()` The in-process way in that stage 5 of the control socket needed (`docs/IPC_CONTROL_SOCKET.md`, "Plugins in the display process"). - **`BasePlugin.request_on_demand(mode=None, duration=None, pinned=False)`** shows the plugin now, and **`BasePlugin.end_on_demand()`** gives the screen back. Both are safe from any thread (an MQTT callback, a timer thread): `PluginManager.request_on_demand()` / `end_on_demand()` hand the request to `DisplayController.submit_plugin_on_demand()`, which only queues it (at most 32) and wakes the render thread through the control socket's flag (`ControlServer.wake()`). The render thread applies it with the socket's commands, through the same handler as a web on-demand request, so it lands within a frame rather than on the mailbox's once-a-second look. Both return the request id, or `None` when no display runs in the process (the web interface, `scripts/check_plugin.py`) or the queue is full. - **A plugin's stop ends only its own session.** A mailbox stop still ends any session, whoever started it. - **Older cores.** Plugins detect the methods with `hasattr` and write the `display_on_demand_request` mailbox when they are missing or answer `None`; the pattern is in `docs/PLUGIN_API_REFERENCE.md` ("On-demand display"). The display still reads the mailbox for plugins that write it. ### Web UI: Schedule and General are ES-module pages (stage 3) - The Schedule and General tabs follow stage 2 (#727): their inline `