Fuaranfuaran

The source for generative UI

Authoring from VB

Fuaran.UI.VisualBasic lets you author Fuaran UI trees in VB using first-class XML literals – the notation closest to the mental model a VBA / VB developer already has. You write the tree as XML, translate it to a wire-faithful node, and hand the canonical JSON to any Fuaran renderer. No F# knowledge is required, and no FSharp.Core type ever appears on the surface you touch.

This guide takes you from install to a non-trivial authored tree.


1. Install

<ItemGroup>
  <PackageReference Include="Fuaran.UI.VisualBasic" />
  <!-- Optional: compile-time checking of element/attribute names. -->
  <PackageReference Include="Fuaran.UI.Analyzers" PrivateAssets="all" />
</ItemGroup>

2. Getting started

Imports Fuaran.UI.VisualBasic

Dim tree = <Card id="insights" heading="Insights">
               <Metric id="revenue" label="Revenue" value="1234.5"
                       format-currency="GBP" tone="Brand"/>
           </Card>

Dim wireJson As String = FuaranXml.Encode(tree)

FuaranXml.Translate walks the runtime XElement your XML literal produces and builds the tree; FuaranXml.Encode translates and encodes in one step. Every element name is a node kind, every attribute maps to a spec field, and nested elements become the parent's children.

3. Conventions

  • Literals and bindings. An attribute value is a literal; a value prefixed $ is a bound query the host resolves:

    <Metric id="rev" label="Revenue" value="1234.5"/>   ' static value
    <Metric id="rev" label="Revenue" value="$revenue"/>  ' bound to a query
    
  • Formats. format-currency / format-number / format-percent / format-date set the display format:

    <Metric id="rev" label="Revenue" value="$revenue" format-currency="GBP"/>
    
  • Enums are written by name (case-insensitive): tone="Brand", variant="Info", orientation="Horizontal".

  • Lists of things are child elements: <Item> for a list, <Option> for a select, <Field> for a form, <Column> for a data grid, <Marker> for a map.

4. Layout

<Dashboard id="root"> … </Dashboard>
<Stack id="col" orientation="Vertical"> … </Stack>
<Grid id="g" cols="3"> … </Grid>
<Card id="c" heading="Summary"> … </Card>
<Tabs id="t" active-index="$tab"> … </Tabs>
<Modal id="m" open="$dialogOpen" heading="Confirm"> … </Modal>
<ScrollArea id="sc" orientation="Vertical" max-height="320"> … </ScrollArea>

5. Display

<Heading id="h" text="Q4 report" level="2"/>
<Markdown id="md" text="Updated **hourly**."/>
<Badge id="b" label="Beta" variant="Info"/>
<List id="l" ordered="true"><Item>First</Item><Item>Second</Item></List>
<Divider id="hr" label="OR"/>
<Image id="img" src="/avatar.png" alt="User avatar" variant="Avatar"/>
<CodeBlock id="code" language="vbnet" line-numbers="true">Dim x = 1</CodeBlock>
<Math id="eq" display="Block">x^2 + y^2 = z^2</Math>

6. Forms

<Form id="signup" submit-label="Create account">
    <Field kind="text"     id="email" label="Email" required="true"/>
    <Field kind="number"   id="seats" label="Seats" initial="1"/>
    <Field kind="checkbox" id="terms" label="I accept the terms" required="true"/>
    <Field kind="choice"   id="plan"  label="Plan" selected="pro">
        <Option value="free" label="Free"/>
        <Option value="pro"  label="Pro"/>
    </Field>
</Form>

<Select id="region" label="Region" value="eu">
    <Option value="eu" label="Europe"/>
    <Option value="us" label="Americas"/>
</Select>

7. Data grids

The grid's columns are <Column> children; field names the row property (the host reads it at runtime – it is not part of the wire), and type picks the cell shape:

<DataGrid id="sales-grid" source="$sales">
    <Column type="text"    label="Product" field="product"/>
    <Column type="numeric" label="Amount"  field="amount"/>
</DataGrid>

8. The Node(Of Object) posture

A VB author never names a message type. The wire format carries no message payload (a Fuaran tree is data, not a program), so interactive handlers – a button's click, a form's submit – are opaque to the wire. A dispatch="…" attribute (where a future tier supports it) is author-side metadata; the bound state that drives the UI (a tab index, an open flag, a field value) is what rides the wire and round-trips. The compile-time typed source-generator tier is deferred; the runtime translator is the supported surface.

9. Accessibility – inherited by construction

The translator routes each element through the language tier's smart constructors, so a node inherits the same per-component ARIA the F# host emits – a metric announces politely, a card is a region – with no VB ARIA table to maintain. Inspect it with:

Dim aria = Accessibility.AriaJson(<Card id="c"/>)   ' {"role":"region"}

The canonical fixture corpus is authored bare (no ARIA), so a tree you author carries ARIA the bare fixtures omit – the intended, documented posture (see the C# authoring guide's accessibility section for the shared cross-host decision), not a divergence.

10. Compile-time safety

The XML-literal surface is translated at runtime, so a typo'd element or attribute is otherwise a runtime error. Reference Fuaran.UI.Analyzers to get compile-time diagnostics – Roslyn parses VB XML literals into syntax trees, so the analyzer flags an unknown element (<Metrik> → "did you mean <Metric>?"), a duplicate id, and a source="$…" that doesn't resolve against your manifest, as IDE squiggles + build errors, before you run.

11. Prefer fluent? The same factories, without XML

The XML-literal surface is a veneer: FuaranXml.Translate drives the C# factory surface (Fuaran.UI.CSharp) for you. That surface is plain .NET – no C#-only construct appears on any public signature – so a VB author can also drive it directly, in the same fluent options-record style the C# guide documents. VB's With { } object initializers set the C# init-only records, the facade's implicit conversions widen a bare "Revenue" / 1234.5 to Text / Binding(Of Double) exactly as they do in C#, and C#'s required-member enforcement carries over: omit a required field (an Id, a metric's Label) and VB fails the build with BC37321, the same compile-time guarantee C# callers get.

Imports Csharp = Fuaran.UI.CSharp

Dim tree = Csharp.Fuaran.Card(New Csharp.CardOptions With {
    .Id = "insights",
    .Heading = "Insights",
    .Children = {
        Csharp.Fuaran.Metric(New Csharp.MetricOptions With {
            .Id = "revenue",
            .Label = "Revenue",
            .Value = 1234.5,
            .Format = Csharp.CellFormat.Currency("GBP"),
            .Tone = Csharp.Tone.Brand})}})

Dim wireJson As String = tree.Encode()

VB's Imports can also name the factory type itself – the moral equivalent of C#'s using static – so the factory calls bind unqualified:

Imports Csharp = Fuaran.UI.CSharp   ' the options + facade types
Imports Fuaran.UI.CSharp.Fuaran     ' the factory class — Card(…), Metric(…) unqualified

Dim tree = Card(New Csharp.CardOptions With { .Id = "insights", … })

Both spellings produce byte-identical wire JSON to the §2 XML literal – all three notations drive the same factories and encode through the same canonical F# codec. The conformance suite pins this (FluentAuthoring.vb byte-compares the fluent tree against its XML-literal equivalent), so the parity is a regression check, not a doc claim.

When to reach for which. The XML literals stay the recommended idiom: closest to the VBA mental model, and lighter per node – fluent VB is wordier than fluent C# (VB has no target-typed New(), so every options record is spelled out). The fluent surface earns its place when a tree is assembled programmatically (loops and conditionals compose more naturally as expressions than as spliced XML), when your team already writes C#-style builders, or when you're porting authoring code from the C# guide line-for-line. Mixing is fine in one direction – FuaranXml.Translate returns the same FuaranNode the factories do, so a literal-authored fragment can sit inside a fluent-built tree's Children (the reverse – splicing a factory-built node into an XML literal – is not supported; the translator walks XML only).

12. The runtime tier – apply, validate, op-streams (through the veneer)

Authoring is only half the story: the same runtime tier the C# guide describes – the tree-op apply engine, a runtime validate self-check, and the op-stream hash chain – is available to VB through the C# veneer, which VB already references (Imports Csharp = Fuaran.UI.CSharp). This is the established layering: the VB XML-literal translator drives the C# factories, and the C# package carries the runtime surface, so VB reaches the single shared F# engine with no extra dependency and no F# of its own.

FuaranXml.Translate returns a Csharp.FuaranNode – exactly the handle the C# runtime API takes:

Imports Csharp = Fuaran.UI.CSharp

Dim card = FuaranXml.Translate(<Card id="insights">
                                   <Metric id="rev" label="Revenue" value="1234.5" tone="Brand"/>
                               </Card>)

' Validate (runtime wire-shape self-check).
If Not Csharp.Fuaran.IsValid(card) Then ' inspect Csharp.Fuaran.Validate(card)
End If

' Apply a tree-op through the shared engine.
Dim m2 = FuaranXml.Translate(<Metric id="cost" label="Cost" value="500" tone="Default"/>)
Dim result = Csharp.Fuaran.Apply(card, Csharp.Ops.InsertChild("insights", 1, m2))
If result.IsOk Then Dim wire = result.Value.Encode()

' Record ops in a hash chain (corruption detection - see CRYPTO.md).
Dim chain = New Csharp.OpStreamChain("insights-stream")
Dim actor = Csharp.FuaranActor.Agent("claude", "opus-4", "agent-1")
chain.Append(Csharp.Ops.RemoveNode("cost"), actor)
If Not chain.Verify().IsIntact Then ' provenance broken
End If

The semantics – one engine, no re-implementation, structured ApplyErrorCode errors, hash pre-image shared across hosts – are identical to the C# surface; see the C# authoring guide §§12–15 for the full model. As there, rendering is not on this surface: a conformant renderer (Fable/React, TypeScript, or the Rust host) paints the wire tree; VB authors, validates, applies, and notarises it.

13. Wire fidelity

FuaranXml.Encode calls the language tier's canonical encoder directly – there is no VB codec. A VB-authored tree therefore produces the exact same bytes as its equivalent in any other Fuaran host, by construction.


See also

  • WIRE_FORMAT.md – the canonical wire-format specification.
  • csharp-authoring.md – the C# fluent surface (the same wire contract, different notation).
  • Fuaran.UI.VisualBasic package README – a quick-start summary.