aframevr / aframe-inspector

:mag: Visual inspector tool for A-Frame. Hit *<ctrl> + <alt> + i* on any A-Frame scene.
https://aframe.io/aframe-inspector/examples/
MIT License
654 stars 201 forks source link

Consider supporting user inspector plugins? #523

Open donmccurdy opened 6 years ago

donmccurdy commented 6 years ago

Hi @fernandojsg —

What do you think about letting developers write plugins for the inspector, by having a simple API for attaching their DOM element to a tab?

Some example use cases:

These all seem like interesting use cases for the inspector, but not necessarily something we'd build and support ourselves. But maybe we could have an API like this?

var el = document.createElement('div');
var btnEl = document.createElement('button');
btnEl.textContent = 'Export Scene';
btnEl.addEventListener('click', () => ...);
el.appendChild(btnEl);

AFRAME.inspector.registerPanel(el, {position: 'bottom'});
dmarcos commented 6 years ago

In order for plugins to not be disruptive to the current UI I would probably give them their own panel to render themselves. That panel would be invoked by the user. Idea:

donmccurdy commented 6 years ago

Yeah, I think the location is not too critical unless it becomes used for a bunch of fancy stuff. Which would be a good problem to have. Could be a third, new panel that pops up from the bottom of the page as well.

fernandojsg commented 6 years ago

Actually I started with something called modules a while back when I wanted to create a VR editor mode for the inspector. Basically you register the modules and they can be activated or deactivated. As I didn't continue with the VR editor I've just the dummy module there, but we could use it just as a starting point for something like you propose. https://github.com/aframevr/aframe-inspector/blob/d3e0a32dfe0a9100386c1e6ec561f3003c48d526/src/lib/modules/dummy/index.js

fernandojsg commented 6 years ago

@donmccurdy @dmarcos do you have any idea that could be simple enough to use it as an example and as a proof of concept of the plugin system?

Utopiah commented 6 years ago

I'm sure there are quite a few more examples out there so definitely eager to see this.

donmccurdy commented 6 years ago

I think a couple of the ideas in my OP would be simple enough. Namely,

fernandojsg commented 6 years ago

@donmccurdy I had already added the gltf exporter to the inspector (https://blog.mozvr.com/gltf-exporter-in-three-js-and-a-frame/) but maybe I could just remove it from the main code and use it as a simple use case for the plugin. I was working also in the inVR inspector mode as a plugin, but it didn't include any panel or UI, just a shortcut to enable/disable it.

I'm not sure how to deal with plugins that will need to include UI as they should be using react instead of plain javascript so it's not something straightforward.

Proposals for implementation welcome :)

fernandojsg commented 6 years ago

Ok, I'll start checking the @tomas-polach as it seems that it's the only one that it's really implemented without modifying the core (https://github.com/archilogic-com/3dio-inspector-plugins)

fernandojsg commented 6 years ago

One question, should we have types of plugins and let the editor have a specific behaviour for it? Let's say:

Just some quick thoughts about it:

donmccurdy commented 6 years ago

I had already added the gltf exporter to the inspector

oh, nice! might as well keep it in the main code then.

I'm not sure how to deal with plugins that will need to include UI as they should be using react instead of plain javascript so it's not something straightforward.

IMO that's the only important case; if plugins did not need a UI they wouldn't need to integrate with the inspector.

One question, should we have types of plugins and let the editor have a specific behaviour for it?

My vote would be, all plugins are tab plugins (or some sort of UI panel), and there should be an API so that the plugin can listen for events when the selected entity changes. But I don't think there should be separate types of plugins for entities/components/no-ui.

So really this requires

  1. A DOM element that won't be overwritten by React.
  2. Events when selected entity changes, inspector opens/closes, tab opens/closes, etc.
tomas-polach commented 6 years ago

sry for joining late. this would be a great step forward!! all major editors thrive on community driven plugins. i'm fine with all the proposals as mentioned above and i am looking forward to adapt the 3d.io inspector plugins to fit into the new structure. based on the proposals above, here is my two cents:

Using Plugins

Writing Plugins

});

donmccurdy commented 6 years ago

What's the minimum API we can introduce that would let people start experimenting with interesting plugins? I think search/discovery and keybindings might be best left until there are some examples in the wild and plugin authors can perhaps help contribute then.

Suggested:

  1. Fire events on scene when inspector is shown/hidden. (see inspector.js).
  2. Fire events when entity is selected in the LHS sidebar. (perhaps pass the inspector's own events to the scene object?)
  3. Hook to create a persistent DOM element in the inspector's UI. A new bottom panel, perhaps with a named tab for plugins, seems like the easiest place to start.
plugin-mock
donmccurdy commented 6 years ago

Another quick note, more to just keep this in one place... if my plugin needs to scan the scene, filtering the inspector's objects out is a bit of guesswork:

    const content = new THREE.Scene();
    this.sceneEl.object3D.updateMatrixWorld();
    this.sceneEl.object3D.traverse((node) => {
      if (!node.isMesh || node.name.match(/^[XYZE]+|picker$/)) return;
      const clone = node.clone();
      clone.matrix.copy(node.matrixWorld);
      content.add(clone);
    });

... another nice-to-have would be markings (userData, say?) to identify these objects, or a more predictable prefix on the object names.

donmccurdy commented 6 years ago

Also, I'm using a helper component to get around the lack of inspector open/close events, and that's working reasonably well:

AFRAME.registerComponent('inspector-plugin-mything', {
  init: function () {
    const tmpEl = document.createElement('div');
    tmpEl.innerHTML = panelTpl;
    const panelEl = tmpEl.children[0];
    document.body.appendChild(panelEl);
    this.plugin = new MyPlugin(panelEl, this.el);
  },
  pause: function () {
    this.plugin.setVisible(true);
  },
  play: function () {
    this.plugin.setVisible(false);
  }
});