Remote framebuffer in a notebook (anywidget)¶
pdum.rfb renders in Python and views in the browser over a plain WebSocket — not
the Jupyter kernel comm, so frames never touch the notebook protocol. This works the
same in Jupyter and marimo (mo.ui.anywidget(RfbViewer(...))). Install the extra:
uv add 'habemus-papadum-rfb[anywidget]'.
One widget = one Web Worker + one WebSocket; the server multiplexes many streams on
one port. See docs/notebook.md.
In [ ]:
Copied!
import itertools
import numpy as np
import pdum.rfb as rfb
from pdum.rfb.notebook import publish_loop
# `await` works at the top level in Jupyter/marimo (a loop is already running).
display = await rfb.serve(320, 240, port=0)
frames = itertools.count()
def render():
t = next(frames) % 256
img = np.zeros((240, 320, 3), dtype=np.uint8)
img[:, :, 2] = t # animate the blue channel
img[100:140, :] = (240, 120, 40) # a static orange band
return img
# Non-blocking background task on the notebook's loop.
task = publish_loop(display, render, fps=10)
print("serving at", display.ws_url)
import itertools
import numpy as np
import pdum.rfb as rfb
from pdum.rfb.notebook import publish_loop
# `await` works at the top level in Jupyter/marimo (a loop is already running).
display = await rfb.serve(320, 240, port=0)
frames = itertools.count()
def render():
t = next(frames) % 256
img = np.zeros((240, 320, 3), dtype=np.uint8)
img[:, :, 2] = t # animate the blue channel
img[100:140, :] = (240, 120, 40) # a static orange band
return img
# Non-blocking background task on the notebook's loop.
task = publish_loop(display, render, fps=10)
print("serving at", display.ws_url)
Render the batteries viewer right in the cell (status pill, HUD toggle, toolbar):
In [ ]:
Copied!
display.widget()
display.widget()
Or a bare canvas on the same stream — you supply the chrome/styling:
In [ ]:
Copied!
display.widget(batteries=False)
display.widget(batteries=False)
Tear down when done:
In [ ]:
Copied!
task.cancel()
await display.aclose()
task.cancel()
await display.aclose()