defnotmid

Projects / 01

ovg

Odin vector graphics. A 2D vector canvas that started as a port of femtovg (the nanovg lineage) and grew well beyond it.

  • Odin
  • MIT
  • software rasterizer
  • SDL_GPU · Vulkan / Metal / D3D12
  • no deps beyond Odin vendor
Source on GitHub ↗
28 seconds of ovg, music included. Every frame is an onimite script drawn by ovg: dashes, SVG, filters, masks, ligatures and Arabic shaping, and the GPU/software parity scene.

By the numbers

of the resvg test suite
88.5%
1037 files; the curated 53 all pass
GPU vs software parity
1–2/255
every parity scene, RX 9070 XT, Vulkan (RADV)
to lay out a 42-character line
1.1 µs
cached; 4.8 µs shaped from scratch
CSS blend modes
16
plus patterns, masks and clip paths

All figures from the ovg README (tools/svg_suite, tools/sdlgpu_parity, text layout).

What's in it

  1. 01The femtovg core

    Paths, strokes, gradients, image paints, scissoring, compositing, render-to-image and antialiased fills, recorded as commands for a backend.

  2. 02Layers

    Group opacity, clip paths, alpha and luminance masks, 16 blend modes and patterns, each sized to its content.

  3. 03SVG filters

    Blur, drop shadow, offset, flood, composite, merge, blend and colour matrix, with filter regions and linearRGB.

  4. 04SVG import

    svg_parse / svg_draw with CSS styling, <use>, gradients, patterns, masks, filters and text, plus per-element overrides for animation.

  5. 05Lottie import

    After Effects (Bodymovin) animations: precomps, mattes, masks, trim paths and eased keyframes.

  6. 06Real text

    Shaping with kb_text_shape (ligatures, kerning, Arabic and Indic scripts, bidi), per-glyph font fallback and multi-style layout, drawn as vector outlines.

  7. 07Dashes

    Dash arrays, offsets and pathLength, enough to draw shapes on stroke by stroke.

  8. 08Custom shaders

    Register compiled SkSL (from oksl) and run it as a layer, with image, video or group children.

  9. 09Record anywhere, play on the GPU

    A recording canvas builds a frame's commands on any thread; the GPU thread plays them back, so frames build in parallel.

Two backends, one picture

The software backend is the pixel reference. It evaluates the fragment shader's formulas, replays the stencil passes and samples textures exactly like the GPU, so the SDL_GPU backend (Vulkan on Linux, Metal on macOS) can be diffed against it scene by scene. The only dependencies are Odin's own vendor packages: stb for fonts and images, kb_text_shape for shaping, and SDL3 for the GPU path.

Use it

import vg "ovg"        // e.g. -collection:libs=.. then "libs:ovg"

sw: vg.Software_Backend
vg.software_backend_init(&sw)
c: vg.Canvas
vg.canvas_init(&c, vg.software_backend(&sw))

vg.set_size(&c, 640, 360)
vg.clear_rect(&c, 0, 0, 640, 360, vg.WHITE)

p: vg.Path
vg.path_rounded_rect(&p, 40, 40, 200, 120, 16)
vg.fill_path(&c, &p, vg.paint_linear_gradient(40, 40, 240, 160, vg.rgb(255, 80, 0), vg.rgb(0, 60, 255)))
stroke := vg.paint_color(vg.BLACK)
stroke.stroke.line_width = 3
vg.stroke_path(&c, &p, stroke)

vg.flush(&c)
vg.write_png("out.png", sw.pixels, sw.width, sw.height)

The family