Takumi

Paint

Lay out JSX or HTML and get the shapes, text runs, and images to draw.

takumi-paint is takumi's paint tree output, for drawing a layout with your own API. It shares one layout engine, a port of Chromium's layout, with image output and PDF output. Where those produce pixels or pages, it returns the paint tree: what to draw, where, and in which order, with every CSS value resolved.

Draw the tree on Canvas, write it into editable slides such as PPTX, or pass it to a native drawing API.

Layout places every box, paragraph, and image as a rectangle on the canvas.

Install

npm i takumi-paint

Paint JSX

paint() takes JSX, an HTML string, or a node tree, and returns a PaintTree. The demos on these pages paint this card when the site builds.

card.tsx
import {  } from "takumi-paint";

export const  = await (
  < ={{ : "flex", : 24, : "#F7F3EC" }}>
    <
      ={{
        : "flex",
        : "column",
        : 10,
        : 272,
        : 20,
        : "white",
        : "2px solid #E7E0D4",
        : 16,
        : "0 8px 20px rgba(60, 40, 20, 0.16)",
      }}
    >
      <
        ={{
          : 48,
          : 48,
          : 24,
          : "hidden",
          : "linear-gradient(135deg, #8B5CF6, #F472B6)",
        }}
      />
      < ={{ : 22 }}>Hello, paint</>
      < ={{ : 0.6, : 14 }}>Boxes, text, and steps</>
    </>
  </>,
  { : 368 },
);

Read the nodes

tree.nodes lists every node in document order.

inspect.tsx
import {  } from "takumi-paint";

const  = await (
  < ="card" ={{ : 240, : 16, : "#F7F3EC" }}>
    Hello <>world</>
  </>,
  { : 320 },
);

const  = ..(() => . === "box" && .?. === "card");
.(?.[0]); // { type: "fill", role: "background", shape: { type: "rect", … }, … }

for (const  of .) {
  if (. !== "text") continue;
  for (const  of .) .(., .?., ..); 
}
NodeHolds
boxA CSS box: its background, border, shadows, and children
textOne paragraph, as shaped runs in visual order
imageA replaced image, such as <img> or an SVG

Lengths are in device pixels. devicePixelRatio scales CSS lengths during layout.

tree.toJSON() returns the tree as plain JSON, without font files, so you can hand it to another process.

Choose a guide

NeedRead
Draw nodes in orderDrawing
Place text or lay it out againText
Check options and field typesReference

Reuse a painter

paint() uses one shared Painter. Create your own Painter to keep a separate font registry, and call free() to release its WebAssembly memory.

painter.tsx
import {  } from "takumi-paint";

const  = new ();
try {
  const  = await .(<>Hello</>, { : 320 });
  .(.);
} finally {
  .();
}

Painter also has registerFont(), unregisterFont(), and clearFonts(), and takes the same fontCacheMaxBytes option as PdfRenderer.

Runtimes

takumi-paint has the same entries as takumi-pdf, which are the default import, takumi-paint/next, and takumi-paint/no-init with takumi-paint/wasm-url. See Runtimes.

Last updated on