Skip to main content

The music store, running here

Everything below the line is the example itself: the same plugin sources examples/music ships, on the same @datalayer/reactor build, assembling themselves into a store.

Starting the reactor…

What you are looking at

Nothing in that frame is drawn by this page. The application mounts four plugins and an extension and renders four empty slots; every pixel arrived as a contribution.

Try these, in this order:

  1. Add a song to the cart. The badge in the header updates — the header plugin reads a store the shop plugin owns, and neither imports the other's component.
  2. Hover the cart badge. The overlay has a Checkout button in it. The header does not know that button exists: it offers a cart-actions slot, and the checkout plugin fills it.
  3. Untick @music/checkout in the Plugins panel on the right. Both Checkout buttons go — the one in the overlay and the one under the songs — and the store carries on. Tick it back and they return.
  4. Untick @music/mood. The playlist's rule chooser empties, because disabling a plugin withdraws its contributions. The playlist plugin, which owns the point those rules were made to, is untouched.
  5. Untick the Python catalog plugin, under Backend plugins. The catalog and the shop disappear: both React plugins declare requiredBackendPlugins: ['catalog'], so a slot component gated on it stops rendering.
  6. Untick the Python playlist plugin. Nothing disappears — the frontend declared that one optional, and the card says so instead.
  7. Press View plugin graph. Sixteen nodes and thirty-two relationships, derived from what the plugins declare rather than drawn by hand: extensions delivering plugins, plugins depending on each other, the contribution points they offer and fill, and the dashed lines reaching across the wire to the Python tier. The application does not draw that button — the graph plugin contributes it, which is why unticking Graph in the list takes the button with it.

Steps 5 and 6 are the same mechanism with two different strengths declared; see Cross-tier Dependencies.

The graph in step 7 is worth a second look while switching things off: it is drawn from the platform, so a plugin leaving the list leaves the picture, and the edges that vanish with it are the ones nobody had to write down.

What is different from npm run dev

Three things, and no fourth:

  • There is no uvicorn. A documentation site is a static file, so the four Python plugins' endpoints — GET /plugins, POST /plugins/{name}/toggle, GET /api/catalog/songs, POST /api/checkout, GET /api/playlist/rules, GET /contributions — are answered in the browser by src/components/MusicDemo/backend.ts, with the same manifests and the same toggle semantics. The Python half of the panel is live rather than a screenshot, and the backend half of the graph is drawn from that same answer. Running the real backend changes nothing about what you see.
  • The graph is a button, not an address. The example gives the plugin graph its own /graph route, and pushState is its whole router. A page inside a documentation site cannot take over the URL bar, so the same state lives in a useState here. Nothing downstream changes: the slot, the button and the plugin that owns both are the example's.
  • The theme is pinned. The header contributes Datalayer's appearance controls, and running the example they repaint the whole viewport. Here the viewport is somebody else's, so the demo fixes itself to the Datalayer theme in auto color mode — following your system preference, as the page around it does — and the control is hidden rather than left visible and inert.

The plugin sources are imported unmodified — the site's webpack configuration aliases @datalayer-examples/reactor-music-* to examples/music/*/src/index.tsx, exactly as the example's own vite.config.ts does. There is no forked copy of the example in this repository, which is the only way a demo stays true.