Files
LEDMatrix/docs
ChuckandClaude Opus 5.5 56947298d6 a plugin API for content that changes while it scrolls (#696)
* perf(timing): say which render-thread work a late frame followed

The soak already says how often a moving frame reached the panel late, but
not what the render thread was doing just before it. Vegas does two kinds of
work there between frames -- building its strip (compose, extend) and, with
live elements, patching changed pixels into it -- and deciding whether either
is affordable needs their own numbers.

- FrameTimingRecorder.note_op(kind, nbytes) tags the next presented frame.
  Totals gain op_frames, late_op_frames, op_freezes and op_bytes per kind;
  aggregate() still takes frames without ops. The file schema is unchanged.
- Vegas tags compose and every strip extension (with the bytes it copied).
- frame_soak prints an "after work" table: frames, late %, freezes and MB
  moved per kind, only when something tagged its work.
- render_bench gains --strip-screens (Vegas-sized strips), --patch-bytes /
  --patch-every / --patch-where (in-place column writes, as a live element
  update does) and --extend-every-screens / --extend-width (append + trim on
  a fixed cadence that holds the strip's width).

No runtime behaviour changes: this is the measurement gate for live Vegas
elements.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(changelog): note the frame-op attribution and bench modes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(scroll): build the strip's PIL image only when something reads it

Every Vegas strip extension rebuilt ScrollHelper.cached_image from
cached_array in full, twice (append, then trim), on the render thread:
Image.fromarray is 1.7ms for an 8,000px strip and 3.8ms for 20,000px on a
Pi 4 (measured on ledpi), about two thirds of an extension's render-thread
cost. Nothing on the frame path reads the image's pixels; every frame is cut
from the array.

cached_image is now a property. append_content and drop_scrolled_prefix
defer it; the first read builds it from the array it started with and keeps
it only if the strip has not changed meanwhile, so a sync push racing an
extension cannot leave a stale image cached. Assigning cached_image stores
exactly what was assigned, as before. has_strip() says whether there is a
strip without building its image; the helper's frame path, Vegas and the
adapter's scroll-cache invalidation use it. The strip is also no longer held
in memory twice.

In Vegas the image is now built only by a multi-display sync push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(vegas): live elements -- a plugin API for content that changes while it scrolls

Vegas bakes each plugin's pictures into one strip, so a card already on its
way across the panel keeps what it showed when it was drawn. This adds the
API and bookkeeping for content that can be updated in place; the worker
that redraws and swaps it follows separately. No shipped plugin implements
the hook yet, so nothing changes for users.

Plugin API (core 3.8.0), all no-ops by default:
- BasePlugin.get_vegas_elements() -> [VegasElement(key, image, version,
  live, refresh_hz)]: named, fixed-width pieces of Vegas content.
- BasePlugin.redraw_vegas_element(key, width, height, at): a lock-free
  redraw for content that changes with time.
- BasePlugin.notify_vegas_data_changed(): data that lands outside update().
- src/plugin_system/vegas_elements.py (VegasElement, re-exported from
  base_plugin).

Core:
- PluginAdapter asks a plugin that implements the hook for elements on the
  background fetch only (under its lock, on its own canvas); every other
  path keeps get_vegas_content(). Live elements are pinned (padded with
  content_padding, never trimmed), tagged with their key, digest and data
  epoch in Image.info so the existing cache and group plumbing carry them
  unchanged, and untagged if a width budget crops them.
- RenderPipeline records where each live element lands (ElementRecord), in
  absolute strip columns a trim does not move; the block-start arithmetic
  is shared with the STATIC markers.
- PluginManager update listeners (add/remove_update_listener,
  notify_data_changed): told the moment update() completes, not at the
  next ~4s Vegas poll. The coordinator uses one to move each plugin's data
  epoch on.
- vegas_scroll.live_refresh (kill switch), live_max_hz, live_min_interval,
  live_lead_screens; per-plugin core-owned vegas_live. Live elements are
  off under multi-display sync, in swap mode and with offscreen_prefetch off.
- scripts/check_plugin.py checks the element contract
  (src/plugin_system/testing/vegas.py); test/fixtures/plugins/vegas-live-stub
  is a working example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:59:16 -04:00
..

LEDMatrix Documentation

This directory contains guides, references, and architectural notes for the LEDMatrix project. If you are setting up a Pi for the first time, start with the project root README — it covers hardware, OS imaging, and the one-shot installer. The pages here go deeper.

I'm a new user

  1. GETTING_STARTED.md — first-time setup walkthrough
  2. WEB_INTERFACE_GUIDE.md — using the web UI
  3. PLUGIN_STORE_GUIDE.md — installing and managing plugins
  4. WIFI_NETWORK_SETUP.md — WiFi and AP-mode setup
  5. TROUBLESHOOTING.md — common issues and fixes (PERMISSIONS.md for "Permission denied")
  6. SSH_UNAVAILABLE_AFTER_INSTALL.md — recovering SSH after install
  7. CONFIG_DEBUGGING.md — diagnosing config problems
  8. LOW_MEMORY_BOARDS.md — Pi Zero 2 W / 3B+ / 1GB Pi 4 memory limits

I want to write a plugin

Start here:

  1. PLUGIN_DEVELOPMENT_GUIDE.md — end-to-end workflow
  2. PLUGIN_QUICK_REFERENCE.md — cheat sheet
  3. PLUGIN_API_REFERENCE.md — display, cache, and plugin-manager APIs
  4. PLUGIN_ERROR_HANDLING.md — error-handling patterns
  5. DEV_PREVIEW.md — preview plugins on your dev machine without a Pi
  6. EMULATOR_SETUP_GUIDE.md — running the matrix emulator

Going deeper:

Configuring plugins

Advanced features

Reference

Contributing to LEDMatrix itself

Audits

Contributing to the docs

  • Markdown only, professional tone, minimal emoji.
  • Prefer adding to an existing page over creating a new one. If you add a new page, link it from this index in the section it belongs to.
  • If a page becomes obsolete, delete it (it stays in the repository history) and fix the links to it; test/test_doc_links.py fails on broken relative links.
  • Keep examples runnable — paths, commands, and config keys here should match what's actually in the repo.