Makie, JSServe and Observables: Can I wrap whole figures in Observables?

Hi there! Mostly a question for @sdanisch I guess, but maybe others know as well…

I’m creating interactive plots that work offline using WGLMakie and JSServe. For this, I have a custom function that takes a function with a single paramter (an Observable) and returns a Figure:

"""
Produce an interactive figure with a slider.
    Paramters:
        fig_fun: Function that takes a single argument, the Observable that the slider is controlling, and returns a Figure.
        val_range: Range of values that the slider can take.
        path: Path to save the figure to.
        pt_per_unit: Number of points per unit for plotting.
"""
function produce_interactive_figure_with_slider(fig_fun::Function, val_range::Union{AbstractVector, AbstractRange}, path::String; pt_per_unit = 1)
    
    # we neet the webgl backend for this
    WGLMakie.activate!()
    
    app = App() do session::Session
    
        _slider_range = 1:length(val_range)
        _slider = JSServe.Slider(_slider_range)

        # map slider values to actual values (should work without doing this, but seems a bit buggy)
        _value = map(_slider) do idx 
            return val_range[idx]
        end

        # create the slider div
        slider_div = DOM.div(_slider)

        # get figure
        fig = fig_fun(_value)

        # the figure div
        fig_div = DOM.div(fig)
        
        # add same styles for consistent dimensions
        width, height = size(fig.scene);
        s = Hyperscript.HTML("<style> canvas {width:$(pt_per_unit*width) pt !important; height:auto !important;} </style>")

        # record state map
        return JSServe.record_states(session, DOM.div(s, fig_div, slider_div))
    end

    # save to disk
    open(path, "w") do io
        show(io, MIME"text/html"(), Page(exportable=true, offline=true))
        show(io, MIME"text/html"(), app)
    end
    

    # TODO: output as widget for jupyter
end

This generally works really well. However, I have a number of “legacy” figures and also some figures that don’t play well with using Observable (like figures using AlgebraOfGraphics), so I would like to be able to do something like this:

fig_fun = x -> @lift my_figure($x)
produce_interactive_figure_with_slider(fig_fun, ...)

I tried passing an Observable to DOM.div(fig), which works but results in only the first state being shown and the plot disappearing after moving the slider.

Super thankful for any suggestions!