Skip to content

marimo not working across refresh #209

@tlambert03

Description

@tlambert03

to reproduce, copy this to example.py

# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "marimo>=0.23",
#     "rendercanvas @ git+https://github.com/pygfx/rendercanvas",
#     "pygfx",
#     "anywidget>=0.9",
#     "simplejpeg>=1.3",
# ]
# ///

import marimo

__generated_with = "0.23.0"
app = marimo.App()


@app.cell
def _():
    import pygfx
    from rendercanvas.anywidget import AnywidgetRenderCanvas

    canvas = AnywidgetRenderCanvas(size=(500, 200))
    renderer = pygfx.renderers.WgpuRenderer(canvas)
    scene = pygfx.Scene()
    camera = pygfx.OrthographicCamera(4, 2)

    geometry = pygfx.plane_geometry(4, 2)
    material = pygfx.MeshBasicMaterial(color=(0.5, 0.0, 0.5, 1.0))
    scene.add(pygfx.Mesh(geometry, material))

    def animate() -> None:
        renderer.render(scene, camera)


@app.cell
def _():
    import marimo as mo

    slider = mo.ui.slider(0, 100, value=50, label="color", show_value=True)
    slider


@app.cell
def _(animate, canvas, material, slider):
    # Drive the canvas from the slider. After a browser refresh, every call
    # to `canvas.request_draw(animate)` is a no-op in the stock anywidget
    # backend — the material color updates in Python but no new frame ever
    # reaches the browser.
    v = slider.value / 100.0
    material.color = (v, 1.0 - v, 0.5, 1.0)
    canvas.request_draw(animate)
    canvas


if __name__ == "__main__":
    app.run()

then run

marimo run --sandbox example.py

on first load it works fine, but hit refresh and the canvas no longer responds:

Screen.Recording.2026-04-16.at.3.54.48.PM.mov

according to claude:

  • canvas.request_draw(animate) sets the rendercanvas Scheduler._draw_requested
    flag, but the scheduler's async task never propagates that to the RFB layer
    (_rfb_draw_requested stays False) after the cell is re-executed.
  • RemoteFrameBuffer._rfb_maybe_draw (as re-implemented in
    AnywidgetRenderCanvas) therefore short-circuits with should_draw=False
    and no frame is rendered or pushed.
  • The visibility-triggered initial draw (intersection observer flipping
    _has_visible_views=True) still works, which is why the first frame
    after refresh renders, but every subsequent request_draw is a no-op.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions