building a plugin that uses the observable runtime in

Hi All

New to observable, but have fallen in love with what it can do.

Like how this is so easy to change and modify and fork, coming from a long time no-coder that is learning to code. (old dog, new tricks, etc).

I plan on learning D3 so I can replicate some of what I see here in a plugin environment in, but in the interim, I am wondering if everytime you “download code” if the package follows the exact same format. My thought is in Bubble dot io, you have a javascript plugin execution environment, that would allow you to make a page element out of any JS code, so I am hoping that we could create a plugin that is always running the runtime, with parameterized and uploaded source files from the download code package.

Essentially I want to create a javasript plugin for bubble that could take the package.json information, upload the .js and various files (bubble dot io stores all upload files in aws S3) and then you could run that observable item on the bubble page.

I realize this will not let me integrate with bubble data sources easily, but it is a great interim step until I can create D3 based charts and solutions that I package up as their own plugin in traditional ECMAscript or vanilla javascript (I think is coffeescript).

Thanks for any advice.


Hi Craig, welcome to Observable!

I would recommend embedding your notebooks over repackaging your downloaded code. We don’t make guarantees about the structure of the downloaded code, so it’s possible it could change in the future; the goal of that feature is to allow you to export your notebook to work outside of Observable, not to present a stable API for running your Observable notebooks in other contexts. But that is what embedding is for! You can even pass data into the runtime and see your embedded cells update.

I’m not familiar with plugin development though, so I might be missing something here. If you can load external JavaScript files dynamically, then embedding should work.

Hi Thomas,

Thank you for the information.

My main purpose for embedding was to bring visualization to bubble data. It is a long way around but the short version is, it is an object database that makes it very easy to integrate if you have a javascript source file to bring most any functionality to the app.

So in our case, we wanted to move to D3 for visualizations of nutrition and logging data over time, coming out of the bubble database.

So it sounds like to get that tighter connectivity, we could user observable to sketch what we want to build and then migrate that functionality to a D3 plugin we develop down the road. I understand now that the observable code is not javascript and that going from an observable notebook to a standalone D3 element is not an “automatic path”.

I believe we can package up and deliver node modules via the plugin editor, so I want to explore that as well. If I get it working I will post it and explain.


Absolutely, a lot of folks find Observable a great place for prototyping D3.

But do look at the embedding: you might not have to rewrite anything if you embed Observable in this JavaScript runtime! If it can run JavaScript and it’s in a browser, it can probably embed Observable cells.


I really like this visualization:

However I really need to have this in D3 rather in a notebook to consider a way to use the selection of a state for an input to the rest of my application. Is there a logical approach to making a D3 standalone version of a map and data like this?



In order to use the selection of a state as an input to the rest of your application, you might try code like the examples in the embedding notebook in the section “Reading values from JavaScript” of
You can set a callback on Observable cells that will be called each time a value changes by returning an object with a “fulfilled” property to the module call:

new Runtime().module(notebook, name => {
  switch (name) {
    case "viewof selection": return new Inspector(container);
    case "selection": return {fulfilled(value) { setSelection(value); }};
1 Like

Thanks - I will check it out!