labkit.app is the MATLAB App SDK above LabKit's GUI-free domain libraries.
Apps own scientific workflow, calculations, units, wording, plots, and exports.
The SDK owns semantic layout, transactions, project documents, portable
sources, dialogs, resources, results, and native component lifecycle.
| Goal | Documentation |
|---|---|
| Build or refactor an App | Build a Complete App |
| Understand ownership boundaries | Architecture |
| Declare compatible LabKit modules | Compatibility contracts |
| Look up exact MATLAB syntax | Public API reference |
| Browse the App SDK API by capability | App SDK API |
| Validate framework or GUI changes | Testing |
The required path has three concepts:
| API | Purpose |
|---|---|
labkit.app.Definition |
App identity, lifecycle callbacks, layout, and launch |
labkit.app.layout.* |
Semantic inputs, displays, containers, and workbench structure |
labkit.app.view.Snapshot |
Derived visible state and App-owned rendering |
Read an App in this order: definition.m shows its complete contract,
+workbench/buildLayout.m shows the user workflow, and its capability
packages show the controls, state transitions, presentation, and rendering
owned by each feature. Open projectSpec.m or createSession.m only when the
definition names those optional capabilities.
Layout controls bind directly to named App callbacks, and plot areas bind
directly to their renderer. Apps do not maintain handler, renderer, or
capability registries. Runtime-injected values are
labkit.app.CallbackContext and typed labkit.app.event.* payloads.
Callbacks name those boundary values explicitly and delegate domain work
through narrow inputs.
Optional capabilities are grouped by purpose:
| Package | Purpose |
|---|---|
labkit.app.event.* |
Typed callback payloads |
labkit.app.interaction.* |
Managed plot gestures with direct callbacks |
labkit.app.plot.* |
Domain-neutral axes redraw, message, fit, and annotation mechanics |
labkit.app.project.* |
Durable project schema and migration |
labkit.app.result.* |
Exported files and result packages |
labkit.app.dialog.* |
Explicit dialog outcomes |
labkit.app.CallbackContext |
Runtime operations available inside callbacks |
function app = definition()
workbench = labkit.app.layout.workbench({ ...
labkit.app.layout.field("gain", Label="Gain", ...
Kind="numeric", Bind="project.parameters.gain"), ...
labkit.app.layout.button("run", "Run", @runAnalysis, ...
Tooltip="Compute the result from the current gain.")});
app = labkit.app.Definition( ...
Entrypoint="labkit_Example_app", AppId="example", ...
Title="Example", Family="Examples", ...
AppVersion="1.0.0", Updated="2026-07-19", ...
Requirements=labkit.contract.requirements("app", ">=2 <3"), ...
Workbench=workbench);
endThe entrypoint calls definition().launch(...). Definition compiles the
immutable semantic graph before creating a figure, validates direct callback
and renderer signatures, and builds one private native platform plan.
- Bind ordinary state with
Bind="project..."orBind="session...". - Use
labkit.app.layout.fileListfor portable file records and selection. SetAllowDuplicatePaths=trueonly when separate workflow tasks may share one resolved path, and present row-level workflow state withSnapshot.fileItemStatuses. Source changes rebuild the transient session; Apps do not mirror choose, remove, clear, or selection UI events. - Give every scientific or workflow action an App-owned
Tooltip. The framework guarantees a nonempty label-based fallback, while repository guardrails require tracked Apps to explain the action instead of repeating its visible label. File-list choose/folder/remove/clear controls expose dedicated tooltip options and domain-neutral label defaults. - Rebuild transient data with
session = createSession(project,context)and resolve opaque source records withcontext.resolveSourcePaths. - Return only derived view state from
labkit.app.view.Snapshot; runtime supplies layout defaults, bindings, file state, log text, and status text. - Give short
statusPanelsummaries an explicitLineshint so the native layout reserves detail height only for genuinely multiline content. - Use
labkit.app.layout.dataTablewithlabkit.app.event.TableCellEditandlabkit.app.event.TableCellSelection; Apps never decode native events. - Use
labkit.app.layout.plotAreaand a fixedrenderer(axesById,model)callback.axesByIdis always a named struct, even when the plot area declares only one axis. - Pass a transient
ViewRevisiontoSnapshot.renderPlotwhen an App exposes an explicit reset-view action. The adapter preserves user zoom while the revision is unchanged and accepts renderer-fitted limits once when it changes. - Pass one workspace node or a row cell array of vertically arranged nodes to
workspace.page; growable tables and plots share the available page height without an App-authored wrapper section. - Use
layout.group(..., Title="...")for a nested reader-facing control boundary inside a section; leaveTitleblank for arrangement-only groups. - A control tab containing one growable file list, table, log, status, or plot surface fills the available tab height. Tabs with longer mixed content remain scrollable.
- Declare editable overlays with
labkit.app.interaction.*on the plot area; supply their current values with same-named Snapshot methods. - For a managed rectangle with
OnBackgroundPressed, an un-dragged click anywhere on its plot—including inside the rectangle—uses that point callback; dragging the rectangle still uses its change callback. - Use
labkit.app.plot.clearAxes,showMessage, andfitAxesToGraphicsfor renderer mechanics;EqualDataUnits=truemakes a one-time fitted equal-scale view from the settled native axes allocation without dispatching pending UI callbacks, without changing the allocation or locking later zoom. Apps still decide message wording and viewport policy. - Use
labkit.app.project.Schema,labkit.app.result.File, andlabkit.app.result.Packageonly when those optional capabilities exist. - Use
labkit.app.project.sourceRecordonly in pure project creation or migration code that must turn a legacy path into a portable source value; runtime callbacks still resolve paths throughCallbackContext.
Runtime validates candidate state and the complete view snapshot before publishing either. The private MATLAB adapter maps semantic IDs to native components, skips unchanged native property writes, reuses direct associations between controls and their labels, preserves plot viewports, normalizes native event differences, and never exposes component registries to Apps.
Normal App launches show the completed native window. Official GUI validation
uses the same launch path with a framework-owned visibility policy: hidden
keeps the final window off screen and minimized minimizes it after startup.
Tests therefore exercise real controls without individual Apps or test methods
having to hide the window after launch.
The native runtime installs one top-level Tools menu so framework-owned utilities do not compete with the App's workflow controls:
- Plots opens, copies, or saves the App's plot surfaces.
- Screenshot copies the complete App surface to the system clipboard or saves it to an image file.
- Project State saves or loads the current project document when the App declares a project schema.
These actions are framework-owned native behavior. Apps do not declare menu items, implement clipboard integration, or duplicate project persistence callbacks.
Framework concepts and source names are versionless. Compatibility belongs to
labkit.app.version; saved-data versions belong to
labkit.app.project.Schema.