scene <- vl_scene(width = 6, height = 3, bg = "#faf5ea") |>
draw(rect_grob(
width = 0.9, height = 0.78,
gp = vl_gpar(fill = linear_gradient(c("#6b4f2c", "#c9a874")), col = NA)
)) |>
draw(circle_grob(
x = 0.18, y = 0.5, r = 0.22,
gp = vl_gpar(fill = "#f7c948", col = NA)
)) |>
draw(text_grob(
"vellum", x = 0.60, y = 0.5,
gp = vl_gpar(fontsize = 54, col = "white", fontface = "bold")
))One scene, three formats
This is the layer beneath the grammar. A vellum scene is described once with low-level grobs, then compiled and rendered by the Rust backend. The same scene renders to a raster (PNG), a vector (SVG), or a print-ready document (PDF) with consistent geometry and text shaping, and no per-format fiddling.
One scene value, three calls to render(). The output format follows the file extension:
render(scene, "vellum-logo.png") # raster (tiny-skia)
render(scene, "vellum-logo.svg") # vector (hand-rolled SVG writer)
render(scene, "vellum-logo.pdf") # print (krilla)Pixel-for-pixel the raster and the vector agree, because both come from one scene graph and one layout solve. Grab any of the three:
Download PNG Download SVG Download PDF
Because rendering is deterministic, the bytes are stable across platforms, which is what makes vellum graphics snapshot-testable. This retained scene graph is also what vellumplot compiles into, and what vellumwidget reads to wire up interactivity.
Back to top