gzuidhof / starboard-notebook

In-browser literate notebooks
Mozilla Public License 2.0
1.22k stars 97 forks source link

Reactive math notebook #21

Closed stefnotch closed 3 years ago

stefnotch commented 3 years ago

Starboard notebooks look super interesting! If things go nicely, I might end up contributing to this project, since it seems like it could be pretty useful for some of my university course tools.

I wanted to ask if you're open to the idea of "reactive" notebooks. Basically, a notebook where cells can depend on other cells and auto-update. (Preferably running the entire user-code in a worker that can easily be killed) This would be extremely useful for more math-oriented notebooks.

Furthermore, I noticed your pull request to pyodide, which I find pretty cool. Since you're already have pyodide, loading sympy is pretty easy. Thus, I wanted to ask if you're also open to adding a mathematical formula editor (probably mathlive) and a fair bit of magic along those lines. Maybe the mathematical formula editor should be done as a plugin or something.

I do have a bit of experience with the math stuff, since I hacked together this.

gzuidhof commented 3 years ago

Hi stefnotch,

I'm definitely open to reactive notebooks, they are super cool! Starboard Notebook is generic enough that you should be able to implement a reactive environment just as a new cell type (i.e. without any changes to Starboard's own core).

Here is an example of a somewhat complete new cell type: CoffeeScript cell-type loaded dynamically.

A cell type is defined by this interface:

export interface CellHandler {
    cell: Cell;
    runtime: Runtime;  // contains the "guts" of the notebook, e.g. pre-built modules such as a text editor

    attach(param: CellHandlerAttachParameters): void;
    run(): Promise<any>;
    dispose(): Promise<void>;
    focusEditor(): void;
}

When you register it you would create a definition like this:

const COFFEESCRIPT_CELL_TYPE_DEFINITION = {
    name: "CoffeeScript",
    cellType: ["coffeescript"],
    createHandler: (cell, runtime) => new CoffeeScriptCellHandler(cell, runtime),
}

This definition is all the information the notebook runtime needs to be able to offer it to the user. The cell contains the data that contains that describes the serialized cell completely.


Of course a reactive environment won't have a "run" per say, or more accurately it will re-evaluate after any change. The CSS cell type definition is perhaps a useful example.

Quantum sheet is super cool!

Kreijstal commented 3 years ago

hey uh, I heard observable runtime is open source, (the runtime not the editor)

Maybe is there a way to import an observablehq notebook? This would be so cool, because you wouldn't have to depend on observablehq anymore.

gzuidhof commented 3 years ago

I don't see why not. You could create a "Observable" cell type that uses this runtime, and translate from an observable source file to a Starboard file as long as you can express the cells in plaintext (I don't see why not!).

Looking at the Observable runtime package it is not immediately obvious how the runtime works. As Observable isn't plain Javascript, I imagine we will need the parser too. This then returns a tree/structure, how do I turn that into a Module/Variable? Is that part open source? I think that's the missing link, maybe it's missing on purpose? Or perhaps more likely I'm just not seeing it.

Kreijstal commented 3 years ago

Maybe you can take a look at these notebooks https://observablehq.com/@jashkenas/ouroboros-a-notebook-embeds-itself https://ashkenas.com/breakout/

gzuidhof commented 3 years ago

Thank you for the links, they help get me a step closer, but there is still the missing link: how do we go from a bunch of cells containing some text like:

// Cell 1
md`# My Neat Notebook`

// Cell 2
md`This notebook is an example notebook to demonstrate installing Observable notebooks as npm modules.`

to

// https://observablehq.com/@jashkenas/my-neat-notebook@9
export default function define(runtime, observer) {
  const main = runtime.module();
  main.variable(observer("title")).define("title", ["md"], function(md){return(
md`# My Neat Notebook`
)});
  main.variable(observer("text")).define("text", ["md"], function(md){return(
md`This notebook is an example notebook to demonstrate installing Observable notebooks as npm modules.`
)});
  return main;
}

And really that's not the only step, as it would need to "live-update" these modules using define or something as you develop, so just a simple singular "build" step would not work. That part doesn't appear to be open source.

The above example looks trivial enough as it's just Markdown, but what if we use some of the non-standard code features like viewof. It looks like there's an unofficial compiler available. This thread has some interesting notes about its capabilities.

@mbostock is there any chance the compiler will be open-sourced in the (near) future?

gzuidhof commented 3 years ago

@Kreijstal it's in the works: https://github.com/asg017/dataflow/issues/4

gzuidhof commented 3 years ago

I made a post about it here (HN discussion)