DrylCanvasWorkspace
AI-awareDrylCanvasWorkspace and DrylCanvasDock turn the canvas into an application surface: named views instead of a single sheet, and a command bar in the corner instead of a chat column.
How it works
A line-of-business page is a workspace holding named views, plus a dock in the corner.
The workspace shows exactly one view at full size; the others stay one chip
away in the bar. The open_view tool lets the model open a view and build
into it — the previous artifact stays where it was instead of being overwritten.
Switching is a movement, not a jump. It runs through the same
view-transition layer as the canvas's own fullscreen morph, and the bar carries the
gliding gradient indicator DrylTabs uses. A single view gets no bar at
all — one artifact needs no chrome.
The dock is a command bar, not a chat. An input plus one line
of live status ("Building · 7 elements"); the full transcript unfolds on demand, and
your app supplies its content through the <Log> slot. The dock lives
in the browser's top layer, so it anchors to the viewport rather than to the nearest
glass card.
// One workspace, one run: the run always writes into the view the user is looking at.
private readonly CanvasWorkspace _ws = new();
private readonly DrylCanvasRun _run = new();
protected override void OnInitialized() => _run.UseWorkspace(_ws);
// The workspace argument is what adds open_view to the tool set.
var tools = DrylCanvasTools.Create(_run, generatorAgent, workspace: _ws);
var agent = new ChatClientAgent(chatClient, tools: tools.All);<DrylCanvasWorkspace Workspace="_ws">
<View><DrylAiCanvas Run="_run" AllowExpand="false" /></View>
</DrylCanvasWorkspace>
<DrylCanvasDock Run="_run" Busy="Busy" OnSend="Send" Corner="DockCorner.BottomRight">
<Log>@* your own DrylMessages — the dock brings no second message model *@</Log>
</DrylCanvasDock>Workspace and dock
Ask the dock below for a view — "Overview", "Order 4711" or "Returns". Every request runs through open_view: the view is opened, activated, and the artifact streams into it node by node. The previous view stays as a chip in the bar; clicking it morphs back. Fully scripted — in your app you hand DrylCanvasTools.All to a real model.
Documents and history
A workspace that only lives in memory is a demo, not an application. A
CanvasDocument serializes the whole workspace — every named view, its
artifact, and which one was open — with a schema version, so a dashboard survives a
reload, a user switch and a deployment. Data bindings travel with it; the numbers do
not, so a restored document asks your sources for fresh values.
Persistence is your call. DRYL ships the
ICanvasDocumentStore contract and an in-memory implementation and no
database code at all. On WebAssembly the same interface goes over HTTP or
localStorage.
Undo is a movement. Each settled revision is a snapshot; the bar offers undo, redo and "back to version N", and every step morphs through the same view-transition layer a view switch uses — the artifact changes, it never blinks.
// The contract, plus the implementation DRYL ships. Register your own instead and it wins.
builder.Services.AddDrylCanvasDocumentStore();
// Save the whole workspace …
var doc = CanvasDocument.Capture(_ws, "Sales dashboard");
var id = await store.SaveAsync(doc);
// … and bring it back, views, active view and all.
var loaded = await store.LoadAsync(id);
loaded?.Restore(_ws);
// A saved document as the starting point of a new one.
var fresh = loaded!.AsTemplate("Q3 dashboard");<DrylCanvasWorkspace Workspace="_ws"
ShowHistory
Revision="_run.Round"
RevisionLabel="@_lastPrompt"
AutoSave
@bind-DocumentId="_documentId"
DocumentTitle="Sales dashboard" />Document and history
Add a metric a few times — each change is committed as a version. Step back with undo, jump to any version through the history popover, then save the workspace, change it again and load it back. "New from template" turns the saved document into the starting point of a new one. Everything runs against the in-memory store; no model involved.
Direct manipulation
Describing a change is not always the shortest way to make one. Hand the canvas a
CanvasSelection and its elements become pickable — by click or by
keyboard. The selected element carries a small toolbar: prompt about it, pin it,
duplicate it, remove it, drag it into another slot.
A pin is an instruction to the AI, not a freeze. A node marked
"locked": true is refused by the patcher on every AI op — and the model
gets a sentence in its receipt saying why, so the next turn works around it instead
of retrying. What you trigger still goes through: a data refresh keeps
refreshing, an action result keeps landing, and the toolbar itself keeps working.
The dock knows what you pointed at. Share one selection between
canvas and dock and the chip above the input names the element; the prompt you send
is prefixed with its id, type and label, so "make it a bar chart" patches the right
node. And because a reorder is a plain move op, the siblings glide into
their new slots on the FLIP layer that was already there — one op, one movement.
// One selection, shared by the canvas and the dock. Handing it over is the opt-in —
// there is no second flag, and a canvas without one renders exactly as before.
private readonly CanvasSelection _selection = new();
// A user edit is a version like an AI round is.
private void HandleEdit(CanvasEdit edit)
{
_revisionLabel = edit.Label; // e.g. "Removed Revenue per month"
_revision++;
}<DrylCanvasWorkspace Workspace="_ws" ShowHistory
Revision="_revision" RevisionLabel="@_revisionLabel">
<View>
<DrylAiCanvas Run="_run" AllowExpand="false"
Selection="_selection" OnEdit="HandleEdit" />
</View>
</DrylCanvasWorkspace>
<DrylCanvasDock Run="_run" Busy="Busy" OnSend="Send" Selection="_selection" />Direct manipulation
Ask for "Overview", then click an element. Pin it and watch the toolbar disable what a pin forbids; duplicate it and the copy glides in with fresh ids; drag the handle or press Alt+Arrow to reorder. With something selected, the dock prefixes your prompt with that element — send anything and the scripted update round updates the free stats while bouncing off the pinned one. Every edit is committed as a version, so undo covers your changes as well as the model's.
Click an element to select it — then prompt about it, pin, duplicate or remove it. Arrow keys walk the artifact, Alt + ↑/↓ reorders, Enter asks the dock about the selected element.