Your First App
This page shows the smallest real Tessera app worth building. It uses the configured startup path because that is the public lane most teams will actually keep.
If you have not run a quickstart yet, do that first:
Paste this into Program.cs
csharp.cs
using Tessera;
using Tessera.Controls;
using Tessera.Layout;
var app = TesseraApplication.CreateBuilder()
.UseApp<OrdersApp>()
.ConfigureRuntime(static runtime =>
{
runtime.PointerActivationPolicy = PointerActivationPolicy.SingleClick;
runtime.Screen = new ScreenOptions
{
AltScreen = true,
WindowTitle = "Orders",
EnableFocusReporting = true,
EnableBracketedPaste = true,
MouseTracking = MouseTrackingMode.AllMotion
};
})
.Build();
await app.RunAsync();
internal sealed class OrdersApp : TesseraApp
{
private readonly StatusBar _status = new();
private readonly Button _refreshButton = new() { Text = "Refresh orders" };
private int _orderCount = 12;
public OrdersApp()
{
_refreshButton.Activated += (_, _) => _orderCount++;
}
public override TesseraEffect? Update(Message message)
{
return message is KeyPressed key && key.IsCharacter('q', ModifierKeys.Ctrl)
? TesseraEffects.Quit
: null;
}
public override Screen Build(ScreenContext context)
{
_status.LeftText = $"Orders: {_orderCount}";
_status.RightText = "Enter refreshes Ctrl+Q quits";
return Screen.Build(window =>
{
window.Padding(1);
window.Footer(1, _status);
window.Body(body => body.Center(_refreshButton, width: 24, height: 3));
});
}
}Run it
bash.sh
dotnet runVerify before moving on
- the app launches without terminal corruption
- pressing
Enteron the button updates the count - pressing
Ctrl+Qexits immediately - rerunning
dotnet runstarts clean again
What each part does
TesseraApplication.CreateBuilder()- starts the configuration-first startup path
.UseApp<OrdersApp>()- tells the builder which
TesseraAppto create
- tells the builder which
.ConfigureRuntime(...)- applies runtime-loop and screen options such as pointer policy and alternate screen behavior
OrdersApp : TesseraApp- is the application contract you implement
Update(Message)- handles global messages and returns effects such as
TesseraEffects.Quit
- handles global messages and returns effects such as
Build(ScreenContext)- returns the next screen tree
Screen.Build(...)- uses the default imperative window builder for shell-style screens
Minimal startup still exists
If you want the absolute smallest entry point, Tessera still supports:
csharp.cs
await TesseraApplication.RunAsync(new OrdersApp());That is fine for tiny demos. The builder path is usually better once you need runtime configuration.
What to do next
- Run the starter ladder in examples.
- Read app-model to understand
Initialize,Update,Build,Post, and effects. - Read layout-and-screen-composition to understand
Screen.Build(...).