How the frontend is loaded#

A K3D plot is a widget: the Python side holds the data, the drawing is done by JavaScript in the browser, and the two talk over the Jupyter comm protocol. Nothing is rendered by the kernel itself, which is why an installation can look complete on the Python side and still show no graphics.

Since 3.0.0 the widget is built on anywidget. The frontend module travels with the widget state itself: the kernel serves k3d/static/widget.mjs through the comm and the browser loads it as an ES module. There is no extension directory, nothing to register with the application, and the same mechanism works in JupyterLab, Notebook 7, Google Colab and VS Code.

The only host requirement is ipywidgets support (anywidget rides on it). If the host can show an ipywidgets.IntSlider(), it can show a K3D plot.

Note

Versions before 3.0.0 delivered the frontend as a JupyterLab federated extension plus an nbextension for Notebook 6, with all the registration failure modes those entailed (jupyter labextension list, No version of module k3d is registered and friends). None of that applies any more; stale registrations from old versions are simply ignored.

Scene objects in lazy frontends#

Every scene object (mesh, volume, points…) is a widget of its own, and a plot references them by id. Some frontends - Google Colab renders each output in its own frame - materialise widget models lazily, so the object models may not exist where the plot renders. The plot then fetches their state from the kernel over its own comm and keeps it updated (the .k3d binary encoding is used on the wire). This is automatic; the one practical difference is that hover/click callbacks and volume shadow maps need real object models and stay inactive in such frontends.

Where the errors are#

Frontend initialization errors do not appear in the server log or in the notebook. They go to the browser console (F12).

The cell prints only text. You get Plot(antialias=3, ...) followed by Output() and no drawing area. Nothing consumed the widget’s mime bundle, so display() fell back to the plain text representation of the object. Either the page has no widget support at all, or the kernel cannot open a comm. This is not a rendering failure - the JavaScript was never asked to draw.

The plot area appears but stays empty. Check the browser console for errors from widget.mjs (WebGL context, GPU blacklist) and verify WebGL2 works at all, e.g. on https://get.webgl.org/webgl2/.

Kernels other than ipykernel#

K3D uses no kernel API of its own: it neither opens comms nor imports ipykernel, and leaves all of that to ipywidgets. A kernel therefore has to support ipywidgets before it can show a plot, and K3D can do nothing about a kernel that does not.

If a plot shows only its text representation under a custom kernel, check ipywidgets on its own first:

import ipywidgets

ipywidgets.IntSlider()

If that slider does not appear either, the problem is below K3D - the kernel is not carrying comm messages to the frontend - and it has to be solved there.

Running from a source checkout#

An editable install serves the frontend straight from the checkout’s k3d/static. After changing anything under js/src:

cd js
npm run build

then restart the kernel and hard-refresh the page - the module is cached per widget state, so a stale tab keeps the old code.