/* * fee[dB]ack — manifest-declared plugin panes. * * A plugin can ship a pane by declaring it in plugin.json, with no code in * screen.js at all: * * "panes": [{ * "id": "camera_director", * "title": "Camera Director", * "icon": "🎥", * "script": "panes/camera.js", * "mirrorGlobal": "__h3dCamCtl" * }] * * The point of declaring it rather than calling panes.register() is that the * pane becomes openable — from the rail, from the tray — WITHOUT THE PLUGIN'S * SCREEN EVER HAVING BEEN VISITED. We register a stub from the manifest and * fetch the script only when the user actually opens it. A pane you can only * reach by first navigating to the screen it was supposed to replace is not * much of a pane. * * The script sets a factory global, the same shape the viz contract already uses * (`window.feedBackViz_`): * * window.feedBackPane_camera_director = { * mount(root, ctx) { ... }, * unmount(root, ctx) { ... }, * }; * * It is loaded from the sandboxed /api/plugins//src/