Sandbox — LSD is in active testing. All systems operational·payments are test-mode (no real charges).
Overview Use Cases News Docs Tool Store Support Community Get LSD
All docs
Docs/ Views/ A View of params and actions
Views

A View of params and actions

The base View — param() fields plus @action buttons, no kind — collects input and drives actions. Author it with @tool.view; location= only sets where it shows.

TL;DRA View with no kind is param() fields plus @action buttons — the base View, for collecting input and running actions (add a kind and it becomes a data view). There is no separate Panel type; "panel" is just the old informal word for one docked in the sidebar, and sidebar is only a location. Author it with @tool.view or a plain View subclass. An @action handler reads the fields as typed attributes (self.cutoff), and self.ctx is auto-injected on mount so it can call self.ctx.ui.notify(...). invoke("name") is the one dispatch entry — button, CLI, agent, or test — and View.show() presents it standalone (a window, or console text when headless).

The base View has no kind: it is param() fields plus @action buttons — the same declarative object the inspector uses to edit step settings. It collects input and runs actions; give it a kind and it becomes a data view instead. An @action handler reads the fields as typed attributes, so there is no values dict to keep in sync. (Where it shows — sidebar, editor, or an overlay — is location=, separate from what it is. A no-kind View docked in the sidebar is what people used to call a "panel".)

Author a View#

Subclass View, declare param() fields, and mark operations with @action:

Python
from lsdtools import View, action, param

class ClipPanel(View):
    cutoff = param(float, default=0.5, min=0.0, max=1.0, label="Cut-off")

    @action(label="Apply", style="suggested")
    def apply(self):
        return f"keeping grades ≥ {self.cutoff}"

panel = ClipPanel(cutoff=0.7)
panel.invoke("apply")          # → 'keeping grades ≥ 0.7'

invoke("apply") is the one dispatch entry for every front-end — a GUI button, the CLI, an agent, or a test all go through it. param() gives you typing, coercion, min/max validation, and the labelled field for free; @action's style is None, "suggested", or "destructive".

Dock it with @tool.view#

@tool.view decorates a function (ctx) -> View (return a View instance or class). With location="sidebar" the desktop docks the result in the sidebar. When it mounts, the runtime injects the host Context into the View's self.ctx, so an action body can reach the host — self.ctx.ui.notify(...), self.ctx.ui.show(...) — with no manual wiring:

Python
from lsdtools import Tool, Context, View, action, param

tool = Tool("grade", label="Grade tools")

class ClipPanel(View):
    cutoff = param(float, default=0.5, min=0.0, max=1.0, label="Cut-off")

    @action(label="Apply", style="suggested")
    def apply(self):
        self.ctx.ui.notify(f"cut-off set to {self.cutoff}")

@tool.view("grade.clip", title="Clip grades", location="sidebar")
def clip_panel(ctx: Context):
    return ClipPanel()
# → a "Clip grades" panel docks in the sidebar

self.ctx.ui offers notify(message, level="info"), show(view) (open a View as a modal), and confirm(message). On a standalone View you build yourself, self.ctx is None until you set it.

Show it standalone#

Any View presents itself with show() — a window when a front-end is loaded, a console rendering when headless — so you can exercise the form without the desktop:

Python
ClipPanel(cutoff=0.7).show("text")
# ── ClipPanel ──
#   Cut-off: 0.7
#   actions: Apply

show() is the View's own verb; attach it to the engine instead with engine.add(ClipPanel()) and engine.show() to present it alongside your other views.

Overlays#

@tool.view(location="overlay") is the same idea docked over the 3D viewer as a HUD: its function also returns a View (typically an action-only one), and the desktop reads the dock / view_kind hints to place it. Everything on this page applies — an overlay is just a View shown in a different spot.

LearnEverything you show is a View · Data views · Commands & actions

StartHow an LSD package fits together · Naming: which is which

ExamplesA dockable panel · A complete package </content>

Frequently asked questions

How does an action get at the host (notify, show a dialog)?

Through self.ctx. When a @tool.view is mounted, the runtime injects the host Context into self.ctx, so an @action body can call self.ctx.ui.notify(...) or self.ctx.ui.show(...) with no wiring. On a standalone View you construct yourself, self.ctx is None until you set it.

Is there still a Panel or Field class?

No. The old JSON ui()/Panel/Field builder was removed, and there is no Panel class or @tool.panel decorator. A View with no kind is just a View — param() for fields, @action for buttons — the same object the desktop inspector already edits. "Panel" is only the old informal word for one docked in the sidebar; where it shows is location= (sidebar / editor / overlay), separate from what it is.

By LSD Team · Last updated Jul 18, 2026 Ask on Discord View as Markdown