All docs
Naming: which is which
A few LSD words carry more than one meaning — View, panel, table, workspace, entity. This page pins each to its exact meaning.
Why this page exists#
A handful of LSD words are overloaded. The meaning is always clear from context in the code, but the words alone can be ambiguous when you are new or reading an error. Here is each one, pinned.
"View"#
| Term | What it is | Where you meet it |
|---|---|---|
View (the class) |
The one UI class — param() fields, @action buttons, and optional data (feed / to_text / to_image). Has the show() verb; engine.add(a_view) then engine.show(). |
from lsdtools import View |
@tool.view |
A decorator; the factory it wraps returns a View. The desktop mounts it as a sidebar panel, an overlay, or an editor tab (per location=). |
authoring a package |
ViewContribution |
The internal object a @tool.view becomes at mount time. You rarely name it (it lives in lsdtools.advanced). |
escape hatch only |
A @tool.view factory returns a View — the same class you subclass yourself or get from the
views façade. There is no separate wrapper: a view is the object you show().
"Panel"#
@tool.view(..., location="sidebar")— a decorator whose factory returns aView(params@action, nokind). The desktop docks it in the sidebar.
- The word "panel" in the desktop UI is just where that
Viewis shown — there is no separate Panel class in the authoring API. (location="overlay"is the same idea, docked over the 3D viewer.)
So: a panel is a View with no kind. If you are authoring one, you write a View subclass.
"Table" vs "pa.Table" vs "views.table"#
Table— the one class and constructor: an immutable, zero-copy wrapper around one Arrow table with a small verb list (with_column,filter,join,group_by,sort,print…). Build one withTable({...}),Table([{...}, …]),Table(df), orTable(pa_table); read files withTable.read_csv/Table.read_parquet.- There is no lowercase
table(...)factory — the constructor absorbed it. Two look-alikes remain and are not the LSD class:pa.table(...)is pyarrow's own constructor, andviews.table(...)is the data-view façade that wraps aTablefor display. pa.Table— raw pyarrow..arrowon aTableis the zero-copy escape hatch out to it (andTable(pa_table)brings one back in). A step parameter annotatedTableorpa.Tableis an input port.
"Workspace"#
engine.workspace is the engine's run / cache directory — where step outputs land. It is a
Workspace object that is a path string (so os.path.join(engine.workspace, ...) still works) but
also answers .exists, .size(), .dir_for(entity), and .clean(). Engine() with no argument
makes a throwaway temp one; Engine("project.lsd") puts it beside the project file.
(The desktop's "project" and the hub "workspace" are different, product-level concepts — not the one an SDK author meets.)
"Entity"#
Entity— the base class: a node that owns an ordered list of steps. You subclass it (or use@tool.entity) to define a domain type.@tool.entity— registers a creatable entity type (a builder function, or a hand-writtenEntitysubclass).@tool.template(anEntityTemplate) — a recipe that turns dropped file(s) into a ready-wired entity in the import wizard.
Configurable → View#
A short inheritance chain underlies the authoring surface, which is why params behave the same everywhere:
Configurable— anything withparam()fields (steps, entities, the engine — all of them).View— aConfigurablethat also has@actionbuttons and optional data (feed/to_text/to_image). With nokindit renders as a form (a panel); with akind(table/chart/flowchart/custom) it represents data.
Steps are Configurables, not Views — they have parameters but no @action. That they render
in the same inspector as a View is because both are Configurable.
"watch" — the View↔Entity verb#
view.watch(entity) is the one verb that links a view to an entity: the
view holds that entity's output and refreshes on every re-run. It is the symmetry partner of an
entity's run — engine.add
plus run_all() moves data, engine.add plus show() presents it, and watch is the wire between
them.
- It takes an
Entityor an entity name (a name with no entity yet stays pending and resolves when one is added). Any order works — watch before or after either the view or the entity is added to the engine. - The framework does the bus wiring — you never call
bus.on(...)to feed a view. - Watching an entity that has already run pulls its output immediately (what makes drag-and-drop and a reopened project feel instant).
- It returns the view, so
views.table(title=...).watch(entity)reads as one phrase.
The desktop's drag-drop, the 3-D checkbox, and right-click "Show in ▸" are all sugar over this one
verb. (Do not confuse it with on_view_event — a view-local UI observer — or the low-level event bus.)
"ViewerPayload" — what a deliver returns#
A ViewerPayload is the object a @tool.deliver step returns to
show a result (symmetric to how a @tool.load step takes a src: Source). The framework writes any
tables to Parquet, persists a
*_payload.json sidecar, stamps entity_id / step_id, and emits the payload's topic — routing it
to every view that watches the entity. You never hand-roll ctx.emit("viewer/...").
| Payload | Topic | Shows |
|---|---|---|
LayerPayload |
viewer/layer/set |
3-D geometry — LayerPayload(kind=..., tables=..., style=...) |
ChartPayload |
viewer/chart/set |
a chart (usually spec-only) — ChartPayload(kind=..., title=..., series=...) |
LegendPayload |
viewer/legend/set |
a colour legend (spec-only) — LegendPayload(title=..., colormap=...) |
ViewerPayload |
your topic |
the base class — subclass it and register_payload it for a custom viewer topic |
A payload return is for the terminal deliver artifact. Live, mid-run signals (progress, a training
epoch) stay ctx.emit custom events. See Rendering & payloads and
Deliver steps for the full story.
Related#
Learn — The Tool object · Tables & data flow · Contributing UI
Start — How an LSD package fits together
Frequently asked questions
`@tool.view` or the `View` class — which do I use?
Both name the same thing from two sides. `View` is the class — `param()` fields + `@action` + optional data — that you subclass or get from the `views` façade. `@tool.view` is the decorator whose factory returns a `View`; the desktop mounts it (a sidebar panel, an overlay, or an editor tab, per `location=`). You call `show()` on the View itself, or attach it with `engine.add(a_view)`.
Is `table` the same as `Table`?
`Table` (capital T) is the one class and constructor — the zero-copy wrapper over one Arrow table; build one with `Table({...})`, `Table([...])`, or `Table.read_csv(...)`. There is no lowercase `table` factory. `pa.table` is raw pyarrow's constructor and `views.table(...)` is the data-view façade — different things; `.arrow` on a `Table` gets you to pyarrow and back.