diff --git a/pd/nw/todo.txt b/pd/nw/todo.txt
index 7c705eeeb7075b1c8fa1065cbfbe3d19f6e192af..ea5c6b5a46396c43244e8b220ffaad5fdce42049 100644
--- a/pd/nw/todo.txt
+++ b/pd/nw/todo.txt
@@ -143,6 +143,8 @@ Everything else: (A [*] means we've fixed it)
     glist_getcanvas(x) as its first parameter
 [x] get rid of the old tcl specific sys_get_audio_apis
 [ ] have a single function to set t_svg_attr
+[ ] change x_x1..y2 to simple x_bbox[4], and change current x_bbox to
+    x_cachebbox (or something like that)
 
 Crashers
 --------
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 3e4ec9af41690eaa316bf924f0349d46c34cf393..8a1c19e13de64def06460d84a14c11491d38e339 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -1100,17 +1100,23 @@ typedef struct _svg
     t_svg_attr x_strokemiterlimit;
     t_svg_attr x_strokeopacity;
     t_svg_attr x_strokewidth;
-    t_svg_attr x_rx; /* for rounded rectangles */
-    t_svg_attr x_ry;
+    t_svg_attr x_rx; /* for rounded rectangles, ellipse,
+                        and abused for
+                        circle (aka 'r')
+                        line (aka 'x2') */
+    t_svg_attr x_ry; /* abused for line (aka 'y2') */
     int x_transform_n;
     t_fielddesc *x_transform;
-    t_fielddesc x_width;
+    t_svg_attr x_x; /* doubles as 'cx' and 'x1' */
+    t_svg_attr x_y; /* doubles as 'cy' and 'y1' */
+    t_svg_attr x_width;
+    t_svg_attr x_height;
     t_svg_attr x_vis;
     t_fielddesc x_bbox; /* turn bbox calculation on or off */
     int x_pathrect_cache; /* 0 to recalc on next draw_getrect call
                              1 for cached
                             -1 to turn off caching */
-    int x_x1; /* use these for caching path bbox */
+    int x_x1; /* for cached bbox */
     int x_y1;
     int x_x2;
     int x_y2;
@@ -1185,19 +1191,55 @@ static int path_ncmds(int argc, t_atom *argv)
     return j;
 }
 
+void svg_attr_setfloatarg(t_svg_attr *a, int argc, t_atom *argv)
+{
+    fielddesc_setfloatarg(&a->a_attr, argc, argv);
+    a->a_flag = 1;
+}
+
+void svg_attr_setfloat_const(t_svg_attr *a, float n)
+{
+    fielddesc_setfloat_const(&a->a_attr, 0);
+    a->a_flag = 0;
+}
+
 void *svg_new(t_pd *parent, t_symbol *s, int argc, t_atom *argv)
 {
     t_fielddesc *fd;
     int i, flags = 0;
     t_svg *x = (t_svg *)pd_new(svg_class);
+    t_symbol *type = x->x_type = s;
     x->x_flags = flags;
-    x->x_type = s;
     x->x_parent = (void *)parent;
     fielddesc_setfloat_const(&x->x_vis.a_attr, 1);
     /* let it inherit visibility from parent group, if present */
     x->x_vis.a_flag = 0;
     /* the following should be set in method space */
     /* flags |= NOMOUSE; */
+    if (type == gensym("rect") ||
+        type == gensym("circle") ||
+        type == gensym("ellipse") ||
+        type == gensym("line"))
+    {
+        if (argc) svg_attr_setfloatarg(&x->x_x, argc--, argv++);
+        else svg_attr_setfloat_const(&x->x_x, 0);
+        if (argc) svg_attr_setfloatarg(&x->x_y, argc--, argv++);
+        else svg_attr_setfloat_const(&x->x_x, 0);
+        if (type == gensym("rect"))
+        {
+            if (argc) svg_attr_setfloatarg(&x->x_width, argc--, argv++);
+            else svg_attr_setfloat_const(&x->x_width, 0);
+            if (argc) svg_attr_setfloatarg(&x->x_height, argc--, argv++);
+            else svg_attr_setfloat_const(&x->x_height, 0);
+        }
+        else
+        {
+            if (argc) svg_attr_setfloatarg(&x->x_rx, argc--, argv++);
+            else svg_attr_setfloat_const(&x->x_rx, 0);
+            if (argc) svg_attr_setfloatarg(&x->x_ry, argc--, argv++);
+            else svg_attr_setfloat_const(&x->x_ry, 0);
+        }
+    }
     if (x->x_type == gensym("path"))
     {
         int ncmds = x->x_npathcmds = path_ncmds(argc, argv);
@@ -1556,56 +1598,26 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s,
                 &x->x_strokewidth.a_attr, template, data, 1));
         *predraw_bbox = 1;
     }
-    else if (s == gensym("r"))
+    else if (s == gensym("rx") || s == gensym("r"))
     {
-        //sys_vgui(".x%lx.c itemconfigure %s -rx %g -ry %g\n",
-        //glist_getcanvas(c), tag,
-        //fielddesc_getcoord(x->x_vec+2, template, data, 1),
-        //fielddesc_getcoord(x->x_vec+2, template, data, 1));
+        //sys_vgui(".x%lx.c itemconfigure %s -rx %g\n",
+        //    glist_getcanvas(c), tag, fielddesc_getcoord(
+        //    x->x_vec+2, template, data, 1));
         gui_vmess("gui_draw_configure", "sssf",
-            canvas_tag(glist_getcanvas(c)), tag, s->s_name,
-            fielddesc_getcoord(x->x_vec+2, template, data, 1));
-        *predraw_bbox = 1;
-    }
-    else if (s == gensym("rx"))
-    {
-        if (x->x_type == gensym("rect"))
-            //sys_vgui(".x%lx.c itemconfigure %s -rx %d\n",
-            //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
-            //        &x->x_rx.a_attr, template, data, 1));
-            gui_vmess("gui_draw_configure", "sssi",
-                canvas_tag(glist_getcanvas(c)), tag, s->s_name, (int)fielddesc_getcoord(
+            canvas_tag(glist_getcanvas(c)), tag,
+                s == gensym("r") ? "r" : "rx", fielddesc_getcoord(
                     &x->x_rx.a_attr, template, data, 1));
-        else
-        {
-            //sys_vgui(".x%lx.c itemconfigure %s -rx %g\n",
-            //    glist_getcanvas(c), tag, fielddesc_getcoord(
-            //    x->x_vec+2, template, data, 1));
-            gui_vmess("gui_draw_configure", "sssf",
-                canvas_tag(glist_getcanvas(c)), tag, s->s_name, fielddesc_getcoord(
-                    x->x_vec+2, template, data, 1));
-            *predraw_bbox = 1;
-        }
+        *predraw_bbox = 1;
     }
     else if (s == gensym("ry"))
     {
-        if (x->x_type == gensym("rect"))
-            //sys_vgui(".x%lx.c itemconfigure %s -ry %d\n",
-            //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
-            //    &x->x_ry.a_attr, template, data, 1));
-            gui_vmess("gui_draw_configure", "sssi",
-                canvas_tag(glist_getcanvas(c)), tag, s->s_name, (int)fielddesc_getcoord(
-                    &x->x_ry.a_attr, template, data, 1));
-        else
-        {
-            //sys_vgui(".x%lx.c itemconfigure %s -ry %g\n",
-            //    glist_getcanvas(c), tag, fielddesc_getcoord(
-            //    x->x_vec+3, template, data, 1));
-            gui_vmess("gui_draw_configure", "sssf",
-                canvas_tag(glist_getcanvas(c)), tag, fielddesc_getcoord(
-                    x->x_vec+3, template, data, 1));
-            *predraw_bbox = 1;
-        }
+        //sys_vgui(".x%lx.c itemconfigure %s -ry %g\n",
+        //    glist_getcanvas(c), tag, fielddesc_getcoord(
+        //    x->x_vec+3, template, data, 1));
+        gui_vmess("gui_draw_configure", "sssf",
+            canvas_tag(glist_getcanvas(c)), tag, s->s_name, fielddesc_getcoord(
+                &x->x_ry.a_attr, template, data, 1));
+        *predraw_bbox = 1;
     }
     else if (s == gensym("transform"))
     {
@@ -1644,6 +1656,52 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s,
             &x->x_vis.a_attr, template, data, 1) ? "visible" : "hidden");
         *predraw_bbox = 1;
     }
+    else if (s == gensym("width"))
+    {
+        //sys_vgui(".x%lx.c itemconfigure %s -state %s\n",
+        //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
+        //    &x->x_vis.a_attr, template, data, 1) ? "normal" : "hidden");
+        gui_vmess("gui_draw_configure", "sssf",
+            canvas_tag(glist_getcanvas(c)), tag, "width", fielddesc_getcoord(
+            &x->x_width.a_attr, template, data, 1));
+        *predraw_bbox = 1;
+    }
+    else if (s == gensym("x") || s == gensym("cx"))
+    {
+        //sys_vgui(".x%lx.c itemconfigure %s -state %s\n",
+        //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
+        //    &x->x_vis.a_attr, template, data, 1) ? "normal" : "hidden");
+        gui_vmess("gui_draw_configure", "sssf",
+            canvas_tag(glist_getcanvas(c)), tag,
+                s == gensym("x") ? "x" : "cx", fielddesc_getcoord(
+                    &x->x_x.a_attr, template, data, 1));
+        *predraw_bbox = 1;
+    }
+
+    else if (s == gensym("y") || s == gensym("cy"))
+    {
+        //sys_vgui(".x%lx.c itemconfigure %s -state %s\n",
+        //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
+        //    &x->x_vis.a_attr, template, data, 1) ? "normal" : "hidden");
+        gui_vmess("gui_draw_configure", "sssf",
+            canvas_tag(glist_getcanvas(c)), tag,
+                s == gensym("y") ? "y" : "cy", fielddesc_getcoord(
+                    &x->x_y.a_attr, template, data, 1));
+        *predraw_bbox = 1;
+    }
+
+    else if (s == gensym("height"))
+    {
+        //sys_vgui(".x%lx.c itemconfigure %s -state %s\n",
+        //    glist_getcanvas(c), tag, (int)fielddesc_getcoord(
+        //    &x->x_vis.a_attr, template, data, 1) ? "normal" : "hidden");
+        gui_vmess("gui_draw_configure", "sssf",
+            canvas_tag(glist_getcanvas(c)), tag, "height", fielddesc_getcoord(
+            &x->x_height.a_attr, template, data, 1));
+        *predraw_bbox = 1;
+    }
+
+
     else if (s == gensym("stroke-dasharray"))
     {
         // not ready yet... need a gui interface for variable size attrs
@@ -1881,9 +1939,10 @@ t_svg_attr *svg_getattr(t_svg *x, t_symbol *s)
 {
     if (s == gensym("fill-opacity")) return &x->x_fillopacity;
     else if (s == gensym("fill-rule")) return &x->x_fillrule;
+    else if (s == gensym("height")) return &x->x_height;
     else if (s == gensym("opacity")) return &x->x_opacity;
     else if (s == gensym("pointer-events")) return &x->x_pointerevents;
-    else if (s == gensym("rx")) return &x->x_rx;
+    else if (s == gensym("rx") || s == gensym("r")) return &x->x_rx;
     else if (s == gensym("ry")) return &x->x_ry;
     else if (s == gensym("stroke-opacity")) return &x->x_strokeopacity;
     else if (s == gensym("stroke-dashoffset")) return &x->x_strokedashoffset;
@@ -1892,7 +1951,10 @@ t_svg_attr *svg_getattr(t_svg *x, t_symbol *s)
     else if (s == gensym("stroke-miterlimit")) return &x->x_strokemiterlimit;
     else if (s == gensym("stroke-width")) return &x->x_strokewidth;
     else if (s == gensym("vis")) return &x->x_vis;
-    else return 0;
+    else if (s == gensym("width")) return &x->x_width;
+    else if (s == gensym("x") || s == gensym("cx")) return &x->x_x;
+    else if (s == gensym("y") || s == gensym("cy")) return &x->x_y;
+    return 0;
 }
 
 void svg_setattr(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
@@ -3247,7 +3309,9 @@ static void draw_getrect(t_gobj *z, t_glist *glist,
         for (i = 0, f = sa->x_vec; i < n; i+=2, f+=2)
         {
             t_float xloc = fielddesc_getcoord(f, template, data, 0);
-            t_float yloc = fielddesc_getcoord(f+1, template, data, 0);
+            /* 0 for y coordinate if user forgot to supply one */
+            t_float yloc = 
+                i+1 < n ? fielddesc_getcoord(f+1, template, data, 0) : 0;
 
             mset(mtx2, xloc, yloc, 0, 0, 0, 0);
             mtx2[2][0] = 1;
@@ -3277,11 +3341,11 @@ static void draw_getrect(t_gobj *z, t_glist *glist,
         t_float tx1, ty1, tx2, ty2, t5, t6; /* transformed points */
         if (sa->x_type == gensym("rect"))
         {
-            xx1 = fielddesc_getcoord(sa->x_vec, template, data, 0);
-            yy1 = fielddesc_getcoord(sa->x_vec+1, template, data, 0);
-            t_float rwidth = fielddesc_getcoord(sa->x_vec+2,
+            xx1 = fielddesc_getcoord(&sa->x_x.a_attr, template, data, 0);
+            yy1 = fielddesc_getcoord(&sa->x_y.a_attr, template, data, 0);
+            t_float rwidth = fielddesc_getcoord(&sa->x_width.a_attr,
                 template, data, 0);
-            t_float rheight = fielddesc_getcoord(sa->x_vec+3,
+            t_float rheight = fielddesc_getcoord(&sa->x_height.a_attr,
                 template, data, 0);
             xx2 = xx1 + rwidth;
             yy2 = yy1 + rheight;
@@ -3291,18 +3355,20 @@ static void draw_getrect(t_gobj *z, t_glist *glist,
             /* Yes, I realize this isn't a correct bbox but it's
                late and I'm losing steam... Need to just port Raphael's
                path bbox method to c, then convert ellipses to paths... */
-            t_float cx = fielddesc_getcoord(sa->x_vec,
+            t_float cx = fielddesc_getcoord(&sa->x_x.a_attr,
                 template, data, 0);
-            t_float cy = fielddesc_getcoord(sa->x_vec+1, template, data, 0);
-            t_float rx = fielddesc_getcoord(sa->x_vec+2, template, data, 0);
-            t_float ry = fielddesc_getcoord(sa->x_vec +
-                (sa->x_type == gensym("ellipse")? 3 : 2), template,
-                data, 0);
+            t_float cy = fielddesc_getcoord(&sa->x_y.a_attr, template, data, 0);
+            t_float rx = fielddesc_getcoord(&sa->x_rx.a_attr, template, data, 0);
+            t_float ry;
+            if (sa->x_type == gensym("circle"))
+                ry = rx;
+            else
+                ry = fielddesc_getcoord(&sa->x_ry.a_attr, template,
+                    data, 0);
             xx1 = cx;
             yy1 = cy;
             xx2 = rx;
             yy2 = ry;
- 
         }
         svg_parsetransform(sa, template, data, &m1, &m2, &m3, &m4, &m5, &m6);
         mset(mtx2, m1, m2, m3, m4, m5, m6);
@@ -3476,69 +3542,35 @@ static void svg_togui(t_svg *x, t_template *template, t_word *data)
         gui_s("stroke-width");
         gui_f(fielddesc_getfloat(&x->x_strokewidth.a_attr, template, data, 1));
     }
-    if (x->x_type == gensym("circle"))
+    if (x->x_rx.a_flag)
     {
-        if (x->x_nargs > 0)
-        {
-            gui_s("cx");
-            gui_f(fielddesc_getfloat(&x->x_vec[0], template, data, 1));
-        }
-        if (x->x_nargs > 1)
-        {
-            gui_s("cy");
-            gui_f(fielddesc_getfloat(&x->x_vec[1], template, data, 1));
-        }
-        if (x->x_nargs > 2)
-        {
-            gui_s("r");
-            gui_f(fielddesc_getfloat(&x->x_vec[2], template, data, 1));
-        }
+        gui_s(x->x_type == gensym("circle") ? "r" : "rx");
+        gui_f(fielddesc_getfloat(&x->x_rx.a_attr, template, data, 1));
     }
-    if (x->x_type == gensym("ellipse"))
-    {
-        if (x->x_nargs > 0)
-        {
-            gui_s("cx");
-            gui_f(fielddesc_getfloat(&x->x_vec[0], template, data, 1));
-        }
-        if (x->x_nargs > 1)
-        {
-            gui_s("cy");
-            gui_f(fielddesc_getfloat(&x->x_vec[1], template, data, 1));
-        }
-        if (x->x_nargs > 2)
-        {
-            gui_s("rx");
-            gui_f(fielddesc_getfloat(&x->x_vec[2], template, data, 1));
-        }
-        if (x->x_nargs > 3)
+    if (x->x_ry.a_flag)
         {
             gui_s("ry");
-            gui_f(fielddesc_getfloat(&x->x_vec[3], template, data, 1));
+            gui_f(fielddesc_getfloat(&x->x_ry.a_attr, template, data, 1));
         }
+    if (x->x_x.a_flag)
+    {
+        gui_s(x->x_type == gensym("rect") ? "x" : "cx");
+        gui_f(fielddesc_getfloat(&x->x_x.a_attr, template, data, 1));
     }
-    if (x->x_type == gensym("rect"))
+    if (x->x_y.a_flag)
     {
-        if (x->x_nargs > 0)
-        {
-            gui_s("x");
-            gui_f(fielddesc_getfloat(&x->x_vec[0], template, data, 1));
-        }
-        if (x->x_nargs > 1)
-        {
-            gui_s("y");
-            gui_f(fielddesc_getfloat(&x->x_vec[1], template, data, 1));
-        }
-        if (x->x_nargs > 2)
-        {
-            gui_s("width");
-            gui_f(fielddesc_getfloat(&x->x_vec[2], template, data, 1));
-        }
-        if (x->x_nargs > 3)
-        {
-            gui_s("height");
-            gui_f(fielddesc_getfloat(&x->x_vec[3], template, data, 1));
-        }
+        gui_s(x->x_type == gensym("rect") ? "y" : "cy");
+        gui_f(fielddesc_getfloat(&x->x_y.a_attr, template, data, 1));
+    }
+    if (x->x_width.a_flag)
+    {
+        gui_s("width");
+        gui_f(fielddesc_getfloat(&x->x_width.a_attr, template, data, 1));
+    }
+    if (x->x_height.a_flag)
+    {
+        gui_s("height");
+        gui_f(fielddesc_getfloat(&x->x_height.a_attr, template, data, 1));
     }
     if (x->x_type == gensym("line"))
     {
@@ -4111,7 +4143,6 @@ t_parentwidgetbehavior draw_widgetbehavior =
 
 static void svg_free(t_svg *x)
 {
-
     /* [group] has no pts in x_attr->a_vec, but it looks like
        t_freebytes allocates a single byte so freeing it
        should be fine */
@@ -4159,9 +4190,9 @@ static void draw_setup(void)
        "bbox" method for this */
     class_addmethod(svg_class, (t_method)svg_bbox,
         gensym("bbox"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_ellipsepoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("cx"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_ellipsepoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("cy"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_data,
         gensym("data"), A_GIMME, 0);
@@ -4173,7 +4204,7 @@ static void draw_setup(void)
         gensym("fill-opacity"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("fill-rule"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_rectpoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("height"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_event,
         gensym("mousedown"), A_GIMME, 0);
@@ -4183,7 +4214,7 @@ static void draw_setup(void)
         gensym("pointer-events"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_data,
         gensym("points"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_r,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("r"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("rx"), A_GIMME, 0);
@@ -4209,15 +4240,15 @@ static void draw_setup(void)
         gensym("transform"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("vis"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_rectpoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("width"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_rectpoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("x"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_linepoints,
         gensym("x1"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_linepoints,
         gensym("x2"), A_GIMME, 0);
-    class_addmethod(svg_class, (t_method)svg_rectpoints,
+    class_addmethod(svg_class, (t_method)svg_setattr,
         gensym("y"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_linepoints,
         gensym("y1"), A_GIMME, 0);