# onerender docs, all pages (OneRender 1.0.0)
Every page of https://recursiveai.org/onerender/docs/ and https://recursiveai.org/onerender/cookbook/ as markdown, getting started first. Index: https://recursiveai.org/onerender/llms.txt
# Getting started with OneRender
Install OneRender for .NET 10, render an HTML invoice to a PNG and to a tagged PDF without a browser, supply its style sheet and images from your own code, read the diagnostics, and query the layout.
## Install
OneRender targets `net10.0`, so you need the .NET 10 SDK. Every package shares one version; this guide uses 1.0.0.
```shell
dotnet new console -o OneRenderStart
cd OneRenderStart
dotnet add package RecursiveAI.OneRender.Pdf --version 1.0.0
```
`RecursiveAI.OneRender.Pdf` brings in everything this guide needs: the engine (`RecursiveAI.OneRender`), the rasterizer (`RecursiveAI.OneRender.Image`) and the default fonts (`RecursiveAI.OneRender.Fonts`). If you only want images, install `RecursiveAI.OneRender.Image` instead. The libraries are NativeAOT-, trim- and WebAssembly-clean and contain no `unsafe` code.
OneRender has no JavaScript, no networking and no clock. It never fetches anything: your code hands it the HTML, and the style sheets, images and fonts the HTML refers to.
## The sample page
The steps below render `site/invoice.html`, a one-page invoice that links a style sheet and a logo:
```html
Invoice INV-1042
Invoice INV-1042
Billed to Harbor Street Books, October 14, 2026
Item
Qty
Amount
Shelf labels
400
$120.00
Reading lamps
6
$354.00
Total
$474.00
```
`site/invoice.css` sits next to it, along with `site/logo.png`:
```css
body { font: 15px/1.5 Arial, sans-serif; color: #222; margin: 32px }
header { display: flex; align-items: center; gap: 16px; margin: 0 0 20px }
h1 { font-family: Georgia, serif; font-weight: normal; margin: 0 }
.to { color: #555; margin: 0 }
table { width: 100%; border-collapse: collapse }
th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid #ddd }
td:last-child, th:last-child { text-align: right }
tfoot td { font-weight: bold; border-bottom: 0 }
```
The snippets are one program, in order. Put these `using` directives at the top of `Program.cs`:
```csharp
using OneRender;
using OneRender.Image;
using OneRender.Interaction;
using OneRender.Layout;
using OneRender.Painting;
using OneRender.Pdf;
using RecursiveAI.OneHtml;
```
## Render HTML to a PNG
`HtmlRender.ToImage` lays the page out in a viewport of the size you give, in CSS pixels, and paints it:
```csharp
string html = File.ReadAllText("site/invoice.html");
RgbaImage first = HtmlRender.ToImage(html, new HtmlRenderOptions { Width = 640, Height = 360 });
File.WriteAllBytes("first.png", first.ToPng());
Console.WriteLine($"first.png: {first.Width} x {first.Height}");
```
```text
first.png: 640 x 360
```
This first image has no styling and no logo: nothing supplied `invoice.css` or `logo.png`, and the engine won’t go looking for them. The text is set in the bundled fonts. Arial, Helvetica, Times New Roman, Courier New, Calibri and Cambria map to metric-compatible Liberation, Carlito and Caladea faces, and a family it doesn’t have, like Georgia here, falls back to the generic family you list after it. The output is the same on every machine.
## Supply style sheets and images
Give the page an address with `BaseUrl` and a `Resources` callback. The engine resolves each reference against the base address and asks the callback for the bytes. Return `null` for anything you don’t have.
```csharp
const string baseUrl = "https://billing.example/invoices/";
byte[]? Resources(string address)
{
string name = address.StartsWith(baseUrl) ? address[baseUrl.Length..] : "";
string path = Path.Combine("site", name);
Console.WriteLine($" asked for {address}");
return name.Length > 0 && File.Exists(path) ? File.ReadAllBytes(path) : null;
}
RgbaImage image = HtmlRender.ToImage(html, new HtmlRenderOptions
{
Width = 640,
Height = 360,
DevicePixelRatio = 2,
BaseUrl = baseUrl,
Resources = Resources,
});
File.WriteAllBytes("invoice.png", image.ToPng());
Console.WriteLine($"invoice.png: {image.Width} x {image.Height}");
```
```text
asked for https://billing.example/invoices/invoice.css
asked for https://billing.example/invoices/logo.png
invoice.png: 1280 x 720
```
The address is only a name: nothing is fetched from `billing.example`. Your callback decides what each address means, so it can read files, look in a database or serve embedded resources, and it never exposes anything you didn’t mean to hand over. `DevicePixelRatio = 2` renders the same 640 by 360 layout at twice the pixel density. The same callback serves fonts named in `@font-face` rules.
## Render HTML to a PDF
`HtmlPdf.ToPdf` lays the page out on pages and writes a tagged PDF, page by page, to a stream:
```csharp
using (FileStream file = File.Create("invoice.pdf"))
{
HtmlPdfResult result = HtmlPdf.ToPdf(html, file, new HtmlPdfOptions
{
Page = PdfPageSetup.Letter,
BaseUrl = baseUrl,
Resources = Resources,
});
Console.WriteLine($"invoice.pdf: {result.PageCount} page, {result.Diagnostics.Count} diagnostics");
}
```
```text
asked for https://billing.example/invoices/invoice.css
asked for https://billing.example/invoices/logo.png
invoice.pdf: 1 page, 0 diagnostics
```
- **Tagged by default.** The headings, paragraphs, table, header cells and the logo’s `alt` text become the PDF’s structure tree, and the `` and `lang` become the document title and language. Text is real text with the fonts subsetted, so it can be selected, searched and extracted.
- **Page setup.** `PdfPageSetup.Letter` and `PdfPageSetup.A4` have half-inch margins; `new PdfPageSetup(width, height, top, right, bottom, left)` takes CSS pixels (96 per inch). A `@page` rule in the document overrides it.
- **Bytes instead of a stream.** `HtmlPdf.ToPdf(html, options)` returns a `byte[]`.
## Read the diagnostics
Nothing in a document makes the renderers throw. Missing resources, unsupported features and limits become diagnostics. Here the callback supplies nothing at all:
```csharp
HtmlPdfResult missing = HtmlPdf.ToPdf(html, Stream.Null, new HtmlPdfOptions { BaseUrl = baseUrl, Resources = _ => null });
foreach (Diagnostic d in missing.Diagnostics)
Console.WriteLine($"{d.Kind}: {d.Message}");
```
```text
MissingResource: an image was not supplied by the host
```
The missing logo is reported. A style sheet your callback doesn’t supply is left out without a diagnostic, the way a browser skips a sheet that failed to load, so log what your callback misses if you need to know. Characters that no font covers are recorded on the font provider instead; [Fonts](https://recursiveai.org/onerender/cookbook/fonts/) shows how to read them and which package to add.
## Query the layout
Under the one-call renderers are public types you can use yourself. `InteractivePage` lays a page out once and answers the questions a browser’s DOM would, synchronously:
```csharp
var options = new HtmlPageOptions(FontProviders.CreateDefault())
{
ViewportWidth = 640,
ViewportHeight = 360,
BaseUrl = baseUrl,
StylesheetBytes = Resources,
};
InteractivePage page = InteractivePage.Create(html, options);
Node total = page.Page.Document.Root.QuerySelector("tfoot td:last-child");
Rect box = page.Layout.GetBoundingClientRect(total);
Console.WriteLine($"total cell: x {box.X:F1}, y {box.Y:F1}, {box.Width:F1} x {box.Height:F1}");
Console.WriteLine($"at (100, 150): <{page.ElementFromPoint(100, 150).LocalName}>");
var list = new DisplayList();
page.Page.Paint(list);
Console.WriteLine($"display list: {list.Count} items");
RgbaImage again = DisplayListRasterizer.Render(list, 640, 360);
File.WriteAllBytes("low-level.png", again.ToPng());
```
```text
asked for https://billing.example/invoices/invoice.css
total cell: x 425.8, y 225.0, 182.2 x 35.5
at (100, 150):
display list: 21 items
```
- The document is a OneHtml `Document`, so `QuerySelector` takes any CSS selector.
- `page.Layout` has the CSSOM View queries: bounding and client rectangles, offset and scroll sizes. `ElementFromPoint` is a hit test.
- Painting writes a display list: backgrounds, borders, glyph runs and images with stable ids. The rasterizer turns it into pixels, the PDF writer into pages, and a game engine can draw it with its own GPU code ([The display list](https://recursiveai.org/onerender/docs/display-list/)).
## Next steps
- [HTML to PDF](https://recursiveai.org/onerender/cookbook/html-to-pdf/) and [HTML to PNG](https://recursiveai.org/onerender/cookbook/html-to-png/) cover the options of each renderer.
- [Headers, footers and page breaks](https://recursiveai.org/onerender/cookbook/paged-media/) shows print CSS: page size, running headers, page numbers and forced breaks.
- [Render a Razor component to PDF](https://recursiveai.org/onerender/cookbook/razor-to-pdf/) does it in one call inside ASP.NET Core.
- [Replace a headless browser](https://recursiveai.org/onerender/cookbook/replace-headless-browser/) maps Puppeteer and Playwright calls to OneRender.
- [The overview](https://recursiveai.org/onerender/docs/overview/) lists every package, and [PDF output](https://recursiveai.org/onerender/docs/pdf/) has every rule of the PDF writer.
# OneRender
An HTML and CSS layout and rendering engine for .NET, written from the specifications. HTML in (or a styled tree built in C#), pixels, a tagged PDF, or a retained display list out. The same engine lays out a 200-page report and a game UI that updates every frame. It has no JavaScript, no networking and no clock: the host passes the time and supplies stylesheets, images and fonts.
## Packages
| Package | What it is | Depends on |
|---|---|---|
| `RecursiveAI.OneRender` | The engine: styled-node tree, computed values, box tree, layout, fragmentation and paged media, paint to a display list, hit testing, DOM-standard events, focus, scrolling, form controls and text editing, CSS Transitions and Animations. | OneHtml, OneFont |
| `RecursiveAI.OneRender.Image` | Display list to pixels (`HtmlRender.ToImage`, `DisplayListRasterizer`). The reference rasterizer. | OneRender, OneImage, `.Fonts` |
| `RecursiveAI.OneRender.Pdf` | Display list to tagged PDF (`HtmlPdf.ToPdf`, `DisplayListPdfWriter`). | OneRender, OnePdf (core), `.Image` |
| `RecursiveAI.OneRender.Razor` | A Razor component to a PDF or an image in one call. | OneRender, `.Image`, `.Pdf`, the ASP.NET Core shared framework |
| `RecursiveAI.OneRender.Accessibility` | Rendered page facts (boxes, paint order, text boxes, colors behind text) in OneHtml's `RenderedFacts` shape. | OneRender, OneHtml.Accessibility |
| `RecursiveAI.OneRender.Fonts` | Default fonts: Liberation Sans/Serif/Mono, Carlito, Caladea. | fonts only |
| `RecursiveAI.OneRender.Fonts.Noto.