AI Canvas
AI-awareDrylAiCanvas lets the AI answer with a live, clickable artifact instead of prose — and clicking inside it continues the conversation.
How it works
create_artifact streams a curated DRYL component tree — KPI stats, charts, a
region picker — that builds itself node by node into the canvas. Click a button inside the
artifact and the interaction routes back through the chat as the next turn:
update_artifact patches the canvas in place, inserting new nodes and retitling
existing ones with a staggered FLIP glide.
You hand DrylCanvasTools.All to a real agent; each tool call runs its own JSON
sub-generation on a tool-less generator agent, streaming the artifact into the canvas.
Where the innovation lies: the answer is an interface, not text — and interacting with it is a first-class conversational turn. The model builds UI, the user manipulates it, and the manipulation feeds the model's next response.
Every patch has exactly one movement. An inserted node enters, a moved node
glides, a removed node exits — and a node whose content changed pulses an accent ring, so no
update happens off-screen. Numbers in stat nodes count up to their new value,
the header carries a live element count while the artifact streams, and replacing the whole
artifact morphs the old tree into the new one instead of cutting. The expand button grows
the canvas into a fullscreen overlay through the same view transition.
// The canvas tools get their own tool-less generator agent for the JSON sub-generation.
var tools = DrylCanvasTools.Create(_run, generatorAgent);
var agent = new ChatClientAgent(chatClient, tools: tools.All);<DrylAiCanvas Run="_run" OnInteraction="HandleInteraction" />
@* A click inside the artifact becomes the next user turn: *@
@* Ask(interaction.ToPromptMessage()) — the model answers with update_artifact. *@Interactive canvas artifacts with DrylAiCanvas
The AI answers with a live, clickable artifact instead of prose. create_artifact streams a curated DRYL component tree — KPI stats, a line chart, a region picker — that builds itself node by node into DrylAiCanvas. Click a button inside the artifact and the interaction routes back through the chat as the next turn: update_artifact patches the canvas in place, inserting a bar chart and retitling the chart with a staggered FLIP glide. Fully scripted here — in your app you hand DrylCanvasTools.All to a real agent.
In your language
Every text the canvas shows or announces is a parameter with the English wording as its
default: the empty state, the fallback title and the error title, the status pill, and the
aria-live announcements a screen reader speaks while the artifact builds.
<DrylAiCanvas Run="_run"
EmptyTitle="Noch nichts gezeichnet"
EmptyText="Bitte den Assistenten, etwas zu zeigen."
FallbackTitle="Leinwand"
IdleText="Bereit" WorkingText="Denkt nach"
BuildingText="@(n => $"Baut · {n} Elemente")"
ReadyText="@(n => "Fertig")"
BuildingAnnouncement="Leinwand wird gebaut…"
ReadyAnnouncement="Leinwand fertig."
UpdatedAnnouncement="@(n => $"Leinwand aktualisiert, {n} Änderungen.")"
FailedAnnouncement="Leinwand fehlgeschlagen." />A canvas that opens on demand
If the canvas lives in a dialog or a side panel that opens only when the assistant starts
drawing, the first generation would not know how wide it is. Open the surface in
DrylCanvasTools.BeforeGenerate and wait for the canvas to measure itself with
DrylCanvasRun.WaitForSurfaceAsync — no guessed delay, and a canvas that never
mounts cannot hold the generation hostage.
var tools = DrylCanvasTools.Create(run, generator);
tools.BeforeGenerate = async ct =>
{
await OpenCanvasDialogAsync(); // your surface
await run.WaitForSurfaceAsync(TimeSpan.FromSeconds(1.5), ct); // false = no surface; generate anyway
};