Takumi

Paint

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

takumi-paint lays out JSX, HTML, or a takumi node tree like takumi does. It returns the paint tree instead of pixels. The tree says what to draw, where, and in which order. Every CSS value is already resolved.

Draw the tree with Canvas, write it into slides, 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 @takumi-rs/helpers

Paint JSX

paint() lays out a node 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 device pixels. devicePixelRatio scales CSS lengths during layout.

Choose a guide

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

Reuse a painter

paint() shares one Painter. Create your own Painter to keep its fonts separate. Call free() to release its WebAssembly memory.

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

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

Last updated on

On this page