Curiosity

Front-end recipes

The curiosity-ai/frontend-recipes repository is a library of self-contained, runnable examples for building custom front-ends on top of a Curiosity Workspace using the Mosaik front-end framework, the Tesserae UI library, and the h5 C# → JavaScript compiler.

Where the Connector Recipes cover ingesting data into a workspace, these recipes cover putting a custom UI on top of one.

All ten recipes live inside a single front-end project — FrontEnd.Recipes — so they build together and can be deployed as a single bundle.

Recipes are a developer-onboarding tool

Every recipe targets the same shape: a single C# view returned from a registered route, wrapped in a HubStack + HubTitle so it inherits the workspace's standard chrome. The skeleton is identical — only the body changes.


Project layout

FrontEnd.Recipes/
├── FrontEnd.Recipes.csproj
├── h5.json
├── h5.Release.json
└── src/
    ├── App.cs                    ← entry: routes + sidebar + HomeView replacement
    ├── Recipes.cs                ← catalog used by App.cs and the landing page
    ├── RecipesHomeView.cs        ← replaces the workspace's default home view
    ├── API/
    │   └── Endpoints.cs          ← Mosaik.API.Endpoints.CallAsync wrappers (currently mocked)
    ├── Schema/
    │   └── DTOs.cs               ← [ObjectLiteral] DTOs returned by Endpoints.cs
    └── Recipes/
        ├── 01_HelloWorld/
        ├── 02_SearchArea/
        ├── 03_Pivot/
        ├── 04_SegmentedPivot/
        ├── 05_NodeRenderer/
        ├── 06_NeighborsGraph/
        ├── 07_Dashboard/
        ├── 08_CustomChat/
        ├── 09_Sidebar/
        └── 10_UserPreferences/

Each recipe folder is self-contained — a README.md explaining the idea and a single (or small handful of) .cs files showing the smallest amount of code that makes the feature work.


The shape of a recipe

flowchart LR Route["Router.Register(#/recipe/xyz)"] --> Factory["ViewFactory(state)"] Factory --> View["XyzView : IComponent"] View --> Hub["HubStack(HubTitle(...))"] Hub --> Body["BuildBody(state)"] Body -->|optional| API["RecipeEndpoints.GetXAsync()"] API -.->|prod| Endpoint["Mosaik.API.Endpoints.CallAsync"]

Every recipe shares the same skeleton:

public sealed class XyzView : IComponent
{
    private readonly IComponent _container;

    public XyzView(Parameters state)
    {
        _container = HubStack(HubTitle("Title", "#/recipe/xyz"), DefaultRoutes.Home)
                        .Section(BuildBody(state), grow: true);
    }

    private IComponent BuildBody(Parameters state) { /* ... */ }

    public HTMLElement Render() => _container.Render();
}

App.cs registers it as a route and adds a SidebarButton for it — both driven from Recipes.cs, so adding an eleventh recipe is a matter of dropping a new entry into RecipeCatalog.All and creating a folder under src/Recipes/.


Prerequisites

  • A .NET SDK that matches the h5 toolchain bundled in the .csproj.

  • The h5 compiler as a global dotnet tool:

    dotnet tool update --global h5-compiler
    
  • The Curiosity CLI if you want to push the front-end to a workspace from the command line:

    dotnet tool update --global Curiosity.CLI
    
  • A Curiosity workspace to connect to. Local workspaces typically run at http://localhost:8080/.


Running locally

From the repo root:

cd FrontEnd.Recipes
dotnet build

# Serve the compiled bundle against a workspace
curiosity-cli serve \
    -s    http://localhost:8080 \
    -p    bin/Debug/netstandard2.0/h5 \
    -port 5000

Add the serving URL to the workspace's CORS allow-list:

export MSK_CORS=http://localhost:5000

Then open http://localhost:5000 in a browser. The first thing you should see is the recipe catalog landing page (the replaced HomeView).


Deploying to a workspace

Zip the h5 output folder and upload it via Manage → Interface → Upload Front End, or push it directly with the CLI:

curiosity-cli upload-front-end \
    -s http://localhost:8080/ \
    -t $CURIOSITY_INTERFACE_TOKEN \
    -p bin/Release/netstandard2.0/h5/

Browse recipes

Each card links to a dedicated page with the recipe's purpose, an example excerpt, and the files to copy.

UI building blocks

Hello World

The minimum page — routing, HubStack, HubTitle, basic Tesserae components.

Pivot

Tabbed navigation — cached vs lazy, justified, centered, overflow.

SegmentedPivot

Compact segmented-control toggles for filters and views.

Search, nodes, and the graph

SearchArea

Wire the workspace search box, facet filters, and custom result renderers.

INodeRenderer

Custom node schema + cards / previews / detail pages, with admin-side schema bootstrap.

Neighbors & Graph

Traverse with Mosaik.API.Query, the Neighbors list component, and the GraphExplorerView.

Dashboards and chat

Dashboards

Stat cards, Plotly line / bar charts, and a top-categories card, driven by endpoints.

Custom Chat

Replace PostMessage, customize the chat header, examples, and per-message actions.

Sidebar

Add custom buttons to the default sidebar and react to the active route.

User Preferences

Custom preferences page surfaced under the UserPreferences sidebar mode.


Talking to the workspace

Anywhere a recipe would hit a custom workspace endpoint, the call goes through src/API/Endpoints.cs. Each method has the production-style call commented out and returns hard-coded data so the repo runs without any backend:

public static async Task<DashboardSeriesResponse> GetDashboardSeriesAsync()
{
    // return await Mosaik.API.Endpoints.CallAsync<DashboardSeriesResponse>("recipes/dashboard-series");

    return new DashboardSeriesResponse { /* canned data */ };
}

DTOs returned by those endpoints live in src/Schema/DTOs.cs and use [ObjectLiteral] so they round-trip cleanly through h5.


Reusing a recipe

1

Copy the folder

Pick the recipe whose pattern matches what you need; copy the folder under src/Recipes/ to your own project (or to a new folder here).

2

Rename the view class

Adjust its namespace to your project.

3

Register the route

Add it in your App.cs — or add an entry to RecipeCatalog.All if you're staying inside this project — the route, sidebar entry, and home-page card all light up automatically.

4

Wire the data

Replace any call into RecipeEndpoints with a real Mosaik.API.Endpoints.CallAsync<T> to your workspace endpoint.


See also

  • Custom Front-Ends — the reference docs for building Tesserae-based UIs on top of Curiosity Workspace.
  • Tesserae — the C# component toolkit the recipes use for layout, search, charts, and chat.
  • h5 — the C# → JavaScript transpiler that turns the recipes into the bundle the workspace serves.
  • Connector Recipes — the data-ingestion counterpart of these recipes.
© 2026 Curiosity. All rights reserved.