SoneSone
Getting started

Quick start

Render your first document in 30 seconds.

This is the smallest useful Sone program — a hero "Hello, World" headline rendered to a JPG.

import { Column, Span, sone, Text } from "sone";
import fs from "node:fs/promises";

function Document() {
  return Column(
    Text("Hello, ", Span("World").color("white").weight("bold"))
      .size(44)
      .color("white"),
  )
    .padding(24)
    .bg("black");
}

const buffer = await sone(Document()).jpg();
await fs.writeFile("image.jpg", buffer);

Three things to notice:

  1. Builders return values, not JSX. Column(...) and Text(...) are plain functions. .padding(24) returns the same node, so calls chain fluently.
  2. Children come first, props chain after. Text("Hello, ", Span("World")...) declares the content; .size(44) configures it.
  3. sone(node).jpg() is the render call. Everything before it is layout description; this line actually paints to a Canvas and returns a buffer.

Other output formats

The same node tree can render to any format Sone supports:

const root = Document();

await sone(root).png();      // PNG buffer
await sone(root).jpg(0.9);   // JPG buffer (quality 0–1)
await sone(root).webp();     // WebP buffer
await sone(root).pdf();      // PDF buffer
await sone(root).svg();      // SVG buffer
await sone(root).canvas();   // raw skia-canvas Canvas

See Output formats for the full list.

Sizing

By default, Sone auto-sizes the canvas to fit content. Pass width / height to fix it:

await sone(root, { width: 1200, height: 630 }).png(); // perfect for OG images

What now?