Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Paper/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you from a blank .NET project to a running Prowl.Paper UI in four steps. By the end you will have Paper installed, a renderer wired up, a working frame loop, and a clickable button on screen.
1
Install the NuGet Package
2
Add Prowl.Paper to your project with the .NET CLI:
3
dotnet add package Prowl.Paper
4
That single package brings in the layout engine, the animation system, the text renderer, and all core APIs. The only transitive dependency is Prowl.Quill, which is pulled in automatically.
5
A renderer backend is not included in the NuGet package — you must supply one. See Step 2 below, or read the full Installation guide for backend details.
6
Pick and Initialise a Renderer
7
Paper draws everything through the ICanvasRenderer interface, so it is completely decoupled from any specific graphics API. You must pass a concrete renderer to the Paper constructor:
8
// Constructor signature (Paper.Core.cs)
public Paper(ICanvasRenderer renderer, float width, float height, FontAtlasSettings fontAtlas)
9
The repository ships ready-to-use reference implementations under Samples/:
10
BackendLocationOpenTK (OpenGL)Samples/OpenTK/PaperRenderer.csRaylibSamples/RaylibSample/RaylibCanvasRenderer.csWebGL / WASMSamples/WasmExample/
11
Here is how the Raylib sample constructs Paper:
12
// From Samples/RaylibSample/Program.cs
_renderer = new RaylibCanvasRenderer();
P = new Paper(_renderer, width, height, new Prowl.Quill.FontAtlasSettings());
13
And the equivalent for OpenTK:
14
// From Samples/OpenTK/Program.cs
var nativeWindowSettings = new NativeWindowSettings()
{
    ClientSize = new Vector2i(1080, 850),
    Title = "Paper OpenTK Example",
    Flags = OpenTK.Windowing.Common.ContextFlags.ForwardCompatible
};

using var app = new PaperTKWindow(GameWindowSettings.Default, nativeWindowSettings);
app.Run();
15
Copy the renderer file that matches your graphics backend from Samples/ into your own project as a starting point. Each renderer is self-contained and under 500 lines.
16
Load a Font
17
Paper uses FontAtlasSettings for atlas configuration and AddFallbackFont to register typefaces. Load a font file before your frame loop starts:
18
// Load a TTF font file from a stream and register it as the fallback font
using var stream = File.OpenRead("path/to/font.ttf");
var fontFile = new FontFile(stream);
P.AddFallbackFont(fontFile);
19
Run the Frame Loop
20
Paper’s API is structured around three calls per frame: BeginFrame, your UI declarations, and EndFrame. Wrap these inside whatever loop your host framework provides.
21
// In your main loop:
void RenderUI()
{
    // Begin the UI frame
    P.BeginFrame(deltaTime);

    // Define your UI
    using (P.Column("MainContainer")
        .BackgroundColor(240, 240, 240)
        .Enter())
    {
        // A header
        using (P.Box("Header")
            .Height(60)
            .BackgroundColor(50, 120, 200)
            .Text(Text.Center("My Application", myFont, Color.White))
            .Enter()) { }

        // Content area
        using (P.Row("Content").Enter())
        {
            // Sidebar
            P.Box("Sidebar")
                .Width(200)
                .BackgroundColor(220, 220, 220);

            // Main content
            P.Box("MainContent");
        }
    }

    // End the UI frame
    P.EndFrame();
}
22
The layout above produces a full-window column with a 60 px header bar, a 200 px sidebar, and a main content area that stretches to fill the remaining space — all without a single size calculation on your part.
23
using (...Element().Enter()) is the pattern for entering a container element’s scope. Children declared inside the using block are automatically parented to that container. Leaf elements (those with no children) do not need .Enter().
24
When the window is resized, call SetResolution so the layout engine knows the new dimensions:
25
// From Samples/RaylibSample/Program.cs
if (width != GetScreenWidth() || height != GetScreenHeight())
{
    width = GetScreenWidth();
    height = GetScreenHeight();
    P.SetResolution(width, height);
}

Building a Clickable Button

Interactive elements use the same fluent API as static ones — just chain an event handler:
P.Box("MyButton")
    .Size(100)
    .BackgroundColor(Color.ForestGreen)
    .Rounded(8)
    .Text(Text.Center("Click Me", myFont, Color.White))
    .OnClick((rect) => Console.WriteLine("Button clicked!"));
You can layer in hover and active states with animated transitions:
P.Box("AnimatedButton")
    .Width(120).Height(40)
    .BackgroundColor(Color.ForestGreen)
    .Rounded(8)
    .Hovered
        .BackgroundColor(Color.DarkGreen)
        .End()
    .Active
        .BackgroundColor(Color.DarkOliveGreen)
        .End()
    .Transition(GuiProp.BackgroundColor, 0.2, Easing.SineInOut)
    .Text(Text.Center("Click Me", myFont, Color.White))
    .OnClick((rect) => Console.WriteLine("Clicked!"));
Style blocks are applied in declaration order. If you place .If(someCondition) after .Hovered, the condition takes priority over the hover state when it is true — a deliberate design choice that makes precedence explicit and predictable.

Forwarding Input

Paper does not poll input itself; you must forward events from your host framework each frame before calling BeginFrame:
// Minimal input forwarding (Raylib example)
void UpdateInput()
{
    Vector2 mousePos = GetMousePosition();
    P.SetPointerState(PaperMouseBtn.Unknown, mousePos.X, mousePos.Y, false, true);

    if (IsMouseButtonPressed(MouseButton.Left))
        P.SetPointerState(PaperMouseBtn.Left, mousePos.X, mousePos.Y, true, false);
    if (IsMouseButtonReleased(MouseButton.Left))
        P.SetPointerState(PaperMouseBtn.Left, mousePos.X, mousePos.Y, false, false);

    float wheelDelta = GetMouseWheelMove();
    if (wheelDelta != 0)
        P.SetPointerWheel(wheelDelta);

    int key = GetCharPressed();
    while (key > 0)
    {
        P.AddInputCharacter(((char)key).ToString());
        key = GetCharPressed();
    }
}
The full key-mapping logic for each backend can be found in the respective sample Program.cs files.

Next Steps

Installation

Detailed setup for all three renderer backends, HiDPI configuration, font loading, and a version compatibility table.

Immediate-Mode Concepts

Learn the principles behind the immediate-mode paradigm and how Prowl.Paper applies them.

Build docs developers (and LLMs) love