First stable release of the feedBack plugin specification. Marks the normative spec and its
companion best-practices guide (54 rules, ground-truthed against the app) as stable, consolidating
everything accumulated since the 0.1.0 draft. The version string moves 0.1.0 → 1.0.0 and the
document status changes from Draft to Stable.
Changed
-
§8 (Capabilities) and
schemas/plugin.schema.jsonnow document the real capability-declaration
vocabulary, ground-truthed against every bundled plugin: the domain keys and fields are an
open set defined by the declared standard (e.g.capability-pipelines.v1), and a declaration
may carryoperations/requests(alongsidecommands),emits/observes(alongside
events), pluskindanddescription. Thecompatibilityfield is no longer a hard schema
enum (its values are an open set); the observed values are documented instead. Purely additive
and clarifying — every existing manifest still validates. -
§6 (Client surface) rewritten to document the client screen contract, ground-truthed against the
Host. Adds the mount lifecycle (§6.1 — Host-created container,screen-sourced markup,
self-executingscriptwith no Host-invoked entry point, and a normative idempotent
re-hydration MUST), screen activation/visibility (§6.2), and a description of the
Host-provided, Host-versioned runtime surface (§6.3 — event bus, contribution registries, and
the forward-stable capability control plane; raw window globals documented as supported-but-legacy).
New §6.4 "Performance and the shared main thread" makes the hot-path rules normative
(SHOULD NOT do per-frame DOM/layout/IO; don't observe/mutate the shell — use contribution
registries; suspend work when hidden; keep state per-instance). Replaces the previous "client
runtime API is out of scope" placeholder. Settings/Styles/Static-assets renumbered to §6.5–6.7. -
Best-practices guide: added a "Client screen & the shared main thread" section grounded in
real feedBack performance regressions — no DOM/layout work on a per-frame path, don't
DOM-observe or mutate the app shell (use registration APIs instead of injecting into song/library
cards), no synchronous storage/network on hot or gameplay-event paths, idempotent re-hydration
(plugin-runtime-idempotent.v1), stop work when hidden, stay per-instance, and talk to other
plugins through the capabilityclaim/dispatch/releaseflow rather than their globals.
Regrouped the guide (Getting started / Server routes / Client screen / Shipping) and expanded the
pre-publish checklist with a client-performance block. Docs only. -
Best-practices guide: added a "Visualizations" section for
type: "visualization"plugins,
ground-truthed against the Host's renderer contract and recent splitscreen/settings fixes. Covers
the factory pattern (window.feedBackViz_<id>returns a fresh renderer per call — required for
splitscreen's N simultaneous panels), the renderer interface (draw/init/resize/destroy/
contextType), per-instance resource ownership anddestroy()cleanup, treating the per-frame
bundle as read-only, self-detecting canvas size drift, and communicating settings via
applySetting(key, value)per instance (declaresettingson thevisualizationcapability;
the Host applies each change to the specific per-panel instance) — including the concrete failure
modes recent fixes addressed (apply-live-not-reload, no cross-setting leakage, deliberate
per-panel vs global key scoping, fan-out to all panels, settings panel loads before the renderer),
and persistence guidance (Host owns persistence — don't hand-rolllocalStorage; if self-managed,
stage an in-memory fallback before the quota-falliblesetItemand keep it off the per-frame path),
plus the fail-safe auto-revert. Expanded the checklist with a Visualizations block. Docs only. -
Best-practices guide: expanded the
id/naming rule (rule 2) with the collision and namespacing
gotchas, ground-truthed against the loader. Explains how far theidreaches (routes module
plugin_<id>_routes, screen containerplugin-<id>, viz globalwindow.feedBackViz_<id>,
diagnostics path,localStorageprefix), the exact-case folder rule and why the charset matters
(it becomes a Python module + DOM/JS identifiers), the collision resolution (a bundledid
always wins — a user plugin reusing it is silently ignored; between two non-bundled plugins the
first discovered wins), reserved ids (capability_inspector,app_tour_*are always-enabled),
and namespacing shared-space names (localStorage,windowglobals, routes, CSS) byid. Added
matching checklist items. Docs only. -
Best-practices guide: added a "Minigames" section for plugins that register into the bundled
minigameshost, ground-truthed against the host + SDK. Covers late-binding registration (the
host loads after your plugin — queue viawindow.__feedBackMinigamesPendingand/or the
feedBack-minigames-readyevent), theminigamemanifest block withspec.id=== pluginid,
thestart/stoplifecycle where the game must release everything it opens (rAF loops,
AudioContext,getUserMedia, timers, listeners — the host only cancels its own), supersede-safe
start(double-tap / navigate-away races), standalone-by-default vsusesPlayer, and host-owned
scoring/persistence (report via the SDK; single active session). Added a Minigames checklist block.
Docs only. -
Best-practices guide: added an "Organizing client code across files" section for splitting a
plugin's client JS instead of shipping one monolithicscreen.js, ground-truthed against how the
Host loads and serves plugin JS. Covers bundling to onescreen.jsas the simplest path;
the constraint thatscreen.jsis a classic script (noimport/export/import.meta— split
files share state viawindow); serving extra files fromassets/(the plugin root isn't
servable) referenced by absolute/api/plugins/<id>/…URLs (relative resolves against the
document, not the script); and idempotent runtime loading so re-hydration doesn't double-load.
Added a matching checklist block. Docs only. -
Best-practices guide: added an "Integrating with the app" section, ground-truthed against the
window.feedBackruntime surface. Adds the event-bus catalog (screen:changed,song:*,
library:changed,viz:*,highway:*with theirevent.detailpayloads), the rule to drive
the app through thefeedBackAPI (navigate/getNavParams/playSong/seek/setLoop/
currentSong/playQueue) rather than its DOM controls, wrapper discipline for hooking
Host globals (call andawaitthe original, install once, clean up, no load-order assumptions),
and the v2/v3 player-chrome mount contract. Added a matching checklist block. Docs only. -
Best-practices guide: added a "Server-side robustness" section for
routes-shipping plugins,
ground-truthed against the loader. Covers declaring Python deps inrequirements.txt(no
manifest field; installs are hash-keyed, sequential, and delay later plugins — keep them minimal
and pinned; a failed install is non-fatal so guard heavy/optional imports), not blocking the
event loop (a fastsetup()killed at a ~60s timeout; a blockingasync defhandler freezes the
server — use non-blocking I/O or a plaindefthat runs in the threadpool), splitting server
code viacontext["load_sibling"]rather than bare imports that collide across plugins in
sys.modules, and logging throughcontext["log"](neverprint()) plus route namespacing.
Added a matching checklist block. Docs only. -
Best-practices guide: added a "Styling" section. A plugin can't rely on the app's compiled
stylesheet (it only contains classes the bundled code uses), so a runtime-installed plugin renders
unstyled unless it ships its own compiled stylesheet viastyles. Covers building it to
coexist — base/preflight reset off, selectors scoped, no Tailwind Play CDN / runtime CSS
engine (slow, offline-hostile), and bumpversionto cache-bust the sheet. Added a matching
checklist block. Docs only. -
Best-practices guide: added a "Diagnostics" section. Covers contributing plugin state to the
user-exportable diagnostics bundle — client viawindow.feedBack.diagnostics.contribute(id, payload)(idempotent; last snapshot before export wins) and server viadiagnostics.server_files
/diagnostics.callable("module:function"returning dict/list/bytes/str; the Host catches exceptions
so a broken function never crashes the export) — and the rule that a bundle is effectively public,
so it MUST NOT contain secrets, credentials, absolute paths, usernames, or raw user content and
should stay small with aschemafield. Added a matching checklist block. Docs only. -
Best-practices guide: added an "Extending the app's shared surfaces" section — the
registration APIs rule 10 points authors to but never named. Covers song/library card actions
(window.feedBack.libraryCardActions.register(spec)withapplies/enabled/run), nav entries
(the manifestnavkey), keyboard shortcuts (window.registerShortcutwith scoped lifetimes,
cleaned up on teardown), and audio faders (window.feedBack.audio.registerFader, gated on
feedBack:audio:ready, plugin owns persistence). Added a matching checklist block. Docs only. -
Best-practices guide: added "Onboarding tours" and "Library providers" sections, the
last of the extension points a completeness sweep found. Tours: any plugin can ship a guided tour
as a declarativetour.json(atourmanifest key; steps are centeredbubbles or element
spotlights withselector/waitFor), with the clientwindow.feedBackTour.register(...)API
reserved for dynamic steps and offering the tour once. Library providers: add song sources via
context["register_library_provider"](unregister on teardown; the Host enforces owner attribution
and the built-inlocalprovider can't be removed; declare thelibrarycapability and page large
sources). Added matching checklist items. Docs only. -
Best-practices guide: added a "Highway overlays and note-state providers" section for
plugins that participate in the note-highway without replacing its renderer. Covers overlays
(a layer on top of whatever renderer is active — own your rAF + canvas, re-read state each frame,
respect lefty/invert, gate the built-inproject/fretXgeometry helpers on
highway.isDefaultRenderer(), track thehighway:visibilityevent for sibling DOM, clean up on
toggle-off; nottype: "visualization", not in the picker), and the note-state provider
(highway.setNoteStateProvider(fn)— a scorer lights the note gem itself on a correct hit; a single
global surface, cleared on stop). Added matching checklist items. Docs only.