diff --git a/vector/glow-extras/vector/graphics2D.hh b/vector/glow-extras/vector/graphics2D.hh
index 824e5ce83eb9935f7db47e9b8f758bfc017d314a..24be5d02ecc762e8a2cf04877b201e45ae7dd6b1 100644
--- a/vector/glow-extras/vector/graphics2D.hh
+++ b/vector/glow-extras/vector/graphics2D.hh
@@ -17,6 +17,7 @@ struct stroke2D
     stroke2D() = default;
     stroke2D(tg::color3 const& c) : color(c, 1.0f), width(1.0f) {}
     stroke2D(tg::color4 const& c, float w = 1.0f) : color(c), width(w) {}
+    stroke2D(float r, float g, float b, float a = 1.0f) : color(r, g, b, a), width(1.0f) {}
 };
 struct fill2D
 {
@@ -25,6 +26,7 @@ struct fill2D
     fill2D() = default;
     fill2D(tg::color4 const& c) : color(c) {}
     fill2D(tg::color3 const& c) : color(c) {}
+    fill2D(float r, float g, float b, float a = 1.0f) : color(r, g, b, a) {}
 };
 
 /// High-level API for writing to images
@@ -38,6 +40,11 @@ struct fill2D
 /// Example:
 ///   g.draw(tg::pos3{...}, {1, 0, 0}); // 1px red dot
 ///   g.draw(tg::segment3{...}, {tg::color3::blue, 5.0f}); // 5px blue segment
+///
+/// TODO:
+///   - infinite types like ray and line
+///   - vectors
+///   - think about customization points
 struct graphics2D
 {
     explicit graphics2D(image2D& img) : img(img) {}
@@ -66,6 +73,30 @@ public:
         perform_draw(stroke);
     }
 
+    void draw(tg::triangle2 const& t, stroke2D const& stroke)
+    {
+        img.begin_path();
+        img.move_to(t.pos0);
+        img.line_to(t.pos1);
+        img.line_to(t.pos2);
+        img.line_to(t.pos0);
+        perform_draw(stroke);
+    }
+
+    void draw(tg::circle2 const& c, stroke2D const& stroke)
+    {
+        img.begin_path();
+        img.circle(c.center, c.radius);
+        perform_draw(stroke);
+    }
+
+    void draw(tg::sphere2 const& s, stroke2D const& stroke)
+    {
+        img.begin_path();
+        img.circle(s.center, s.radius);
+        perform_draw(stroke);
+    }
+
     // filling
 public:
     void fill(tg::aabb2 const& r, fill2D const& fill)
@@ -75,6 +106,33 @@ public:
         perform_fill(fill);
     }
 
+    void fill(tg::triangle2 const& t, fill2D const& fill)
+    {
+        img.begin_path();
+        img.move_to(t.pos0);
+        img.line_to(t.pos1);
+        img.line_to(t.pos2);
+        img.line_to(t.pos0);
+        perform_fill(fill);
+    }
+
+    void fill(tg::circle2 const& c, fill2D const& fill)
+    {
+        img.begin_path();
+        img.circle(c.center, c.radius);
+        perform_fill(fill);
+    }
+
+    void fill(tg::sphere2 const& s, fill2D const& fill)
+    {
+        img.begin_path();
+        img.circle(s.center, s.radius);
+        perform_fill(fill);
+    }
+
+public:
+    image2D_low_level_api& low_level_api() { return img; }
+
 private:
     void perform_draw(stroke2D const& s)
     {