Embedding some canvas notebook cells shows nothing

When using the Embed code feature, some canvas cells don’t seem to render anything, I only get an empty <canvas> element.

The two cells that give this behavior are viewof gl here :

And the canvas cell here :

Am I doing something wrong, or maybe there is something specific with canvas cells ?

Many thanks in advance.

1 Like

Just a message to confirm that I am seeing the same empty cells when copying out the embed code.

1 Like

Here’s the code to embed the first one:

<div id="observablehq-420d7eb3">
  <div class="observablehq-viewof-gl"></div>
  <div class="observablehq-draw"></div>
</div>
<script type="module">
  import {Runtime, Inspector} from "https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js";
  import define from "https://api.observablehq.com/@mbostock/clifford-attractor-iii.js?v=3";
  (new Runtime).module(define, name => {
    if (name === "viewof gl") return Inspector.into("#observablehq-420d7eb3 .observablehq-viewof-gl")();
    if (name === "draw") return Inspector.into("#observablehq-420d7eb3 .observablehq-draw")();
  });
</script>

For whatever reason, you have to render both the draw and viewof gl cells to see the visualization.


Similar thing for the second one:

<div id="observablehq-6826a06f">
  <div class="observablehq-canvas"></div>
  <div class="observablehq-mouse"></div>
</div>
<script type="module">
  import {Runtime, Inspector} from "https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js";
  import define from "https://api.observablehq.com/@mbostock/eyes.js?v=3";
  (new Runtime).module(define, name => {
    if (name === "canvas") return Inspector.into("#observablehq-6826a06f .observablehq-canvas")();
    if (name === "mouse") return Inspector.into("#observablehq-6826a06f .observablehq-mouse")();
  });
</script>
4 Likes

You’re absolutely right, I can confirm that it works when rendering both cells for these two notebooks. Thanks a lot.

1 Like

Note that viewof gl does not depend explicitly on draw so I suppose the bundler has no way of knowing to include the latter. The code in draw does modify viewof gl so that it renders, though, so you’ve got to indlude draw to see viewof gl.

I suppose the idea is to be able to continually modify viewof gl, without re-rendering the whole thing. I’ve seen similar sorts of things when working with X3Dom.

4 Likes

Exactly. And that’s because of side-effects: the draw cell is mutating the WebGL context created by the viewof gl cell.

In general, we try to avoid side-effects in Observable: the value of a cell should only depend on the other cells it references, and cells shouldn’t mutate values defined by other cells (with the exception of the mutable operator).

But certain web APIs, including WebGL, are inherently mutable APIs: the only way to draw to a WebGL context is to call methods that change the state of the context and the contents of the buffers etc.

For side-effects to work when importing or embedding, the side-effect cells must be named (as draw is here) and embedded for them to run.

2 Likes