Skip to content

Conversation

@leszko
Copy link
Collaborator

@leszko leszko commented Jan 16, 2026

Add support for defining parts of the frontend in plugins.

Demo

demo_dynamic.mp4

Sample plugin

It's simplest to understand how it works by looking at a sample plugin: https://github.com/leszko/scope-plugin-ui

  1. Look at schema.py, it introduces custom UI fields, e.g.
    config_slider: int = Field(
        default=50,
        ge=0,
        le=100,
        description="Integer 0–100 in Settings",
        json_schema_extra=ui_field_config(
            order=3, is_load_param=True, label="Slider"
        ),
    )
  1. Install the plugin with DAYDREAM_SCOPE_PREVIEW=1 uv run daydream-scope install git+https://github.com/leszko/scope-plugin-ui
  2. Look the fields rendered in UI
image

What and how to define

Any field in schema.py that includes json_schema_extra will be rendered in the UI.
You can define the following keys inside json_schema_extra to control how the field is displayed:

  • order (int) — Controls the rendering order in the UI (lower numbers appear first).
  • category (str) — Determines where the field is displayed. Possible values:
    • input
    • configuration (default)
  • component (str) — The name of a custom or complex UI component to use for this field.
  • label (str) — The label shown in the UI. If not provided, the field’s description is used.
  • modes (list[str]) — Specifies which modes the field is visible in.
    Defaults to ["text", "video"].

Resources:

Non-Goals

  • Complex components can be improved, but I'll leave it for now, better to send a separate PR for that; the intention of this PR is to have support for primitive fields for plugins
  • Complex components and their usage in SettingsPanel, I also leave it as a separate PR
  • UI Schema JSON returned from the Server API endpoint (for now let's just use the same schema endpoint)

@leszko leszko force-pushed the rafal/dynamic-parameters branch 6 times, most recently from 08ff0f2 to f805f4c Compare January 27, 2026 17:09
@leszko leszko marked this pull request as ready for review January 27, 2026 17:09
@leszko leszko requested a review from yondonfu January 27, 2026 17:21
Copy link
Contributor

@yondonfu yondonfu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good! I tested install of the sample plugin and confirmed that the schema driven fields show up in InputAndControls + Settings panel and that updating the fields in the former trigger parameter update sends across the WebRTC data channel during runtime.

Image

There seems to be a stray box by default when I open up the app and look at the default LongLive settings.

(str | None); the UI renders an image picker like first_frame_image.
Omit for primitive widgets.
modes: Restrict to input modes, e.g. ["video"]. Omit to show in all modes.
is_load_param: If True, this field is a load param (passed when loading the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this belong here? The distinction between runtime vs. load params seems like a data level distinction as opposed to a UI level distinction?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to decide if the UI elements are disabled when the stream is active. E.g. you cannot modify height/width when the stream is ongoing.

Some other options:

  • Rename to enabled_when_stream_active or something similar to clarify the intention
  • Do not allow load params at all to define by plugins. So, all plugin-defined UI elements are always active

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right that's why the UI needs to know if it is a load param. I'm wondering if it makes sense to just make that distinction outside of json_extra_schema since this is just being used for UI logic and whether something is a load vs runtime param affects whether it should be passed in the pipeline init or the call which is not just a UI concern. The immediate thought is having some way to mark a field as runtime vs load eg separate load/runtime config. I don't have a strong pref here so just making a note. If you think this can be considered separately no problem.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s keep things as they are for now.

I agree that the backend could eventually use is_load_param to decide whether params should be passed to __init__() or __call__(). However, at this stage, I think the simplest and safest approach is to pass all params to both.

The main reason I don’t want to introduce that separation yet is that some params will likely apply to both cases, which requires more careful design. For now, filtering this in the UI feels like the best and least complex solution.

@leszko
Copy link
Collaborator Author

leszko commented Jan 28, 2026

This looks pretty good! I tested install of the sample plugin and confirmed that the schema driven fields show up in InputAndControls + Settings panel and that updating the fields in the former trigger parameter update sends across the WebRTC data channel during runtime.

Image There seems to be a stray box by default when I open up the app and look at the default LongLive settings.

Ahh, sorry, my bad I haven't removed this part form the PR after testing. Removed now.
image

Signed-off-by: Rafal Leszko <rafal@livepeer.org>
@leszko leszko force-pushed the rafal/dynamic-parameters branch from f805f4c to c9fb517 Compare January 28, 2026 07:43
@leszko leszko requested a review from yondonfu January 28, 2026 07:43
@leszko leszko force-pushed the rafal/dynamic-parameters branch 3 times, most recently from 4f33260 to 901fa07 Compare January 28, 2026 09:02
Copy link
Contributor

@yondonfu yondonfu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need to happen immediately, but for my own understanding will we be able to slim down BasePipelineConfig too? It seems to have a lot of stuff.

</div>

{/* Schema-driven input fields (category "input"), below app-defined sections */}
{configSchema &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we be able to in a separate PR remove the app-defined sections if this is here?

Copy link
Collaborator Author

@leszko leszko Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, let's maybe do it in separate refactoring PR, try to convert every part of the Input & Settings section into Complex Components. For now, it's ok, these code should be applied to each pipeline (though it may be hidden for some), so it's mainly about refactoring it into Complex Components.

@leszko
Copy link
Collaborator Author

leszko commented Jan 29, 2026

Doesn't need to happen immediately, but for my own understanding will we be able to slim down BasePipelineConfig too? It seems to have a lot of stuff.

Yes, agree. The same actually with some parts of the frontend, like StreamPage.tsx, schemaSettings.tsx, and SettingsPanel.tsx. I have a feeling there is too much happening there. But let's keep it as a separate PR. This is only have a lot of changes, I don't want to introduce additional refactor here.

Signed-off-by: Rafal Leszko <rafal@livepeer.org>
@leszko leszko force-pushed the rafal/dynamic-parameters branch from 65270d8 to 5964d39 Compare January 29, 2026 09:10
@leszko leszko requested a review from yondonfu January 29, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants