diff --git a/pixelgl/attr.go b/pixelgl/attr.go
deleted file mode 100644
index c540bd1705ae82e4e783e60f19b04e88c2b8010a..0000000000000000000000000000000000000000
--- a/pixelgl/attr.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package pixelgl
-
-import "github.com/go-gl/mathgl/mgl32"
-
-// AttrType is the attribute's identifier
-type AttrType int
-
-// List of all possible attribute types.
-const (
-	Int AttrType = iota
-	Float
-	Vec2
-	Vec3
-	Vec4
-	Mat2
-	Mat23
-	Mat24
-	Mat3
-	Mat32
-	Mat34
-	Mat4
-	Mat42
-	Mat43
-	Intp // pointers
-	Floatp
-	Vec2p
-	Vec3p
-	Vec4p
-	Mat2p
-	Mat23p
-	Mat24p
-	Mat3p
-	Mat32p
-	Mat34p
-	Mat4p
-	Mat42p
-	Mat43p
-)
-
-// Returns the type identifier for any (supported) variable type
-func getAttrType(v interface{}) AttrType {
-	switch v.(type) {
-	case int32:
-		return Int
-	case float32:
-		return Float
-	case mgl32.Vec2:
-		return Vec2
-	case mgl32.Vec3:
-		return Vec3
-	case mgl32.Vec4:
-		return Vec4
-	case mgl32.Mat2:
-		return Mat2
-	case mgl32.Mat2x3:
-		return Mat23
-	case mgl32.Mat2x4:
-		return Mat24
-	case mgl32.Mat3:
-		return Mat3
-	case mgl32.Mat3x2:
-		return Mat32
-	case mgl32.Mat3x4:
-		return Mat34
-	case mgl32.Mat4:
-		return Mat4
-	case mgl32.Mat4x2:
-		return Mat42
-	case mgl32.Mat4x3:
-		return Mat43
-	case *mgl32.Vec2:
-		return Vec2p
-	case *mgl32.Vec3:
-		return Vec3p
-	case *mgl32.Vec4:
-		return Vec4p
-	case *mgl32.Mat2:
-		return Mat2p
-	case *mgl32.Mat2x3:
-		return Mat23p
-	case *mgl32.Mat2x4:
-		return Mat24p
-	case *mgl32.Mat3:
-		return Mat3p
-	case *mgl32.Mat3x2:
-		return Mat32p
-	case *mgl32.Mat3x4:
-		return Mat34p
-	case *mgl32.Mat4:
-		return Mat4p
-	case *mgl32.Mat4x2:
-		return Mat42p
-	case *mgl32.Mat4x3:
-		return Mat43p
-	case *int32:
-		return Intp
-	case *float32:
-		return Floatp
-	default:
-		panic("invalid AttrType")
-	}
-}
diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go
index 66c2ac4763476bdc4fc27c6e5c38428b20a79dc0..1e82feec0b36618361818191d479333316a79175 100644
--- a/pixelgl/canvas.go
+++ b/pixelgl/canvas.go
@@ -43,21 +43,21 @@ func NewCanvas(bounds pixel.Rect) *Canvas {
 	return c
 }
 
-// BindUniform will add a uniform with any supported underlying variable
-// if the uniform already exists, including defaults, they will be reassigned
-// to the new value
-func (c *Canvas) BindUniform(Name string, Value interface{}) {
+// SetUniform will update the named uniform with the value of any supported underlying
+// attribute variable. If the uniform already exists, including defaults, they will be reassigned
+// to the new value. The value can be a pointer.
+func (c *Canvas) SetUniform(Name string, Value interface{}) {
 	c.shader.AddUniform(Name, Value)
 }
 
 // UpdateShader needs to be called after any changes to the underlying GLShader
-// are made (ie, BindUniform(), SetFragmentShader()...)
+// are made, such as, SetUniform, SetFragmentShader...
 func (c *Canvas) UpdateShader() {
 	c.shader.update()
 }
 
-// SetFragmentShader allows you to define a new fragment shader on the underlying
-// GLShader. fs is the GLSL source, not a filename
+// SetFragmentShader allows you to set a new fragment shader on the underlying
+// framebuffer. Argument "fs" is the GLSL source, not a filename.
 func (c *Canvas) SetFragmentShader(fs string) {
 	c.shader.fs = fs
 }
@@ -204,7 +204,7 @@ func (c *Canvas) setUniforms(texbounds pixel.Rect) {
 	}
 
 	for loc, u := range c.shader.uniforms {
-		c.shader.s.SetUniformAttr(loc, u.Value)
+		c.shader.s.SetUniformAttr(loc, u.Value())
 	}
 }
 
@@ -336,7 +336,7 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
 		}
 
 		for loc, u := range ct.dst.shader.uniforms {
-			ct.dst.shader.s.SetUniformAttr(loc, u.Value)
+			ct.dst.shader.s.SetUniformAttr(loc, u.Value())
 		}
 
 		if tex == nil {
diff --git a/pixelgl/glshader.go b/pixelgl/glshader.go
index 9d2e8fe89d421bf7b8fccd08f2053b1cfcf58187..865c6fd8dc54997670dc5652e338a10ecca3aacc 100644
--- a/pixelgl/glshader.go
+++ b/pixelgl/glshader.go
@@ -10,28 +10,27 @@ import (
 // GLShader is a type to assist with managing a canvas's underlying
 // shader configuration. This allows for customization of shaders on
 // a per canvas basis.
-type (
-	GLShader struct {
-		s      *glhf.Shader
-		vf, uf glhf.AttrFormat
-		vs, fs string
-
-		uniforms []gsUniformAttr
-
-		uniformDefaults struct {
-			transform mgl32.Mat3
-			colormask mgl32.Vec4
-			bounds    mgl32.Vec4
-			texbounds mgl32.Vec4
-		}
-	}
+type GLShader struct {
+	s      *glhf.Shader
+	vf, uf glhf.AttrFormat
+	vs, fs string
 
-	gsUniformAttr struct {
-		Name  string
-		Type  AttrType
-		Value interface{}
+	uniforms []gsUniformAttr
+
+	uniformDefaults struct {
+		transform mgl32.Mat3
+		colormask mgl32.Vec4
+		bounds    mgl32.Vec4
+		texbounds mgl32.Vec4
 	}
-)
+}
+
+type gsUniformAttr struct {
+	Name      string
+	Type      glhf.AttrType
+	value     interface{}
+	ispointer bool
+}
 
 // reinitialize GLShader data and recompile the underlying gl shader object
 func (gs *GLShader) update() {
@@ -39,7 +38,7 @@ func (gs *GLShader) update() {
 	for _, u := range gs.uniforms {
 		gs.uf = append(gs.uf, glhf.Attr{
 			Name: u.Name,
-			Type: glhf.AttrType(u.Type),
+			Type: u.Type,
 		})
 	}
 	var shader *glhf.Shader
@@ -69,31 +68,33 @@ func (gs *GLShader) getUniform(Name string) int {
 	return -1
 }
 
-// AddUniform appends a custom uniform name and value to the shader
-//
-// To add a time uniform for example:
+// AddUniform appends a custom uniform name and value to the shader.
+// if the uniform already exists, it will simply be overwritten.
 //
-// utime := float32(time.Since(starttime)).Seconds())
-// mycanvas.shader.AddUniform("u_time", &utime)
+// example:
 //
+//   utime := float32(time.Since(starttime)).Seconds())
+//   mycanvas.shader.AddUniform("u_time", &utime)
 func (gs *GLShader) AddUniform(Name string, Value interface{}) {
-	Type := getAttrType(Value)
+	t, p := getAttrType(Value)
 	if loc := gs.getUniform(Name); loc > -1 {
 		gs.uniforms[loc].Name = Name
-		gs.uniforms[loc].Type = Type
-		gs.uniforms[loc].Value = Value
+		gs.uniforms[loc].Type = t
+		gs.uniforms[loc].ispointer = p
+		gs.uniforms[loc].value = Value
 		return
 	}
 	gs.uniforms = append(gs.uniforms, gsUniformAttr{
-		Name:  Name,
-		Type:  Type,
-		Value: Value,
+		Name:      Name,
+		Type:      t,
+		ispointer: p,
+		value:     Value,
 	})
 }
 
-// Sets up a base shader with everything needed for a pixel
+// Sets up a base shader with everything needed for a Pixel
 // canvas to render correctly. The defaults can be overridden
-// by simply using AddUniform()
+// by simply using the AddUniform function.
 func baseShader(c *Canvas) {
 	gs := &GLShader{
 		vf: defaultCanvasVertexFormat,
@@ -109,6 +110,111 @@ func baseShader(c *Canvas) {
 	c.shader = gs
 }
 
+// Value returns the attribute's concrete value. If the stored value
+// is a pointer, we return the dereferenced value.
+func (gu *gsUniformAttr) Value() interface{} {
+	if !gu.ispointer {
+		return gu.value
+	}
+	switch gu.Type {
+	case glhf.Vec2:
+		return *gu.value.(*mgl32.Vec2)
+	case glhf.Vec3:
+		return *gu.value.(*mgl32.Vec3)
+	case glhf.Vec4:
+		return *gu.value.(*mgl32.Vec4)
+	case glhf.Mat2:
+		return *gu.value.(*mgl32.Mat2)
+	case glhf.Mat23:
+		return *gu.value.(*mgl32.Mat2x3)
+	case glhf.Mat24:
+		return *gu.value.(*mgl32.Mat2x4)
+	case glhf.Mat3:
+		return *gu.value.(*mgl32.Mat3)
+	case glhf.Mat32:
+		return *gu.value.(*mgl32.Mat3x2)
+	case glhf.Mat34:
+		return *gu.value.(*mgl32.Mat3x4)
+	case glhf.Mat4:
+		return *gu.value.(*mgl32.Mat4)
+	case glhf.Mat42:
+		return *gu.value.(*mgl32.Mat4x2)
+	case glhf.Mat43:
+		return *gu.value.(*mgl32.Mat4x3)
+	case glhf.Int:
+		return *gu.value.(*int32)
+	case glhf.Float:
+		return *gu.value.(*float32)
+	default:
+		panic("invalid attrtype")
+	}
+}
+
+// Returns the type identifier for any (supported) attribute variable type
+// and whether or not it is a pointer of that type.
+func getAttrType(v interface{}) (glhf.AttrType, bool) {
+	switch v.(type) {
+	case int32:
+		return glhf.Int, false
+	case float32:
+		return glhf.Float, false
+	case mgl32.Vec2:
+		return glhf.Vec2, false
+	case mgl32.Vec3:
+		return glhf.Vec3, false
+	case mgl32.Vec4:
+		return glhf.Vec4, false
+	case mgl32.Mat2:
+		return glhf.Mat2, false
+	case mgl32.Mat2x3:
+		return glhf.Mat23, false
+	case mgl32.Mat2x4:
+		return glhf.Mat24, false
+	case mgl32.Mat3:
+		return glhf.Mat3, false
+	case mgl32.Mat3x2:
+		return glhf.Mat32, false
+	case mgl32.Mat3x4:
+		return glhf.Mat34, false
+	case mgl32.Mat4:
+		return glhf.Mat4, false
+	case mgl32.Mat4x2:
+		return glhf.Mat42, false
+	case mgl32.Mat4x3:
+		return glhf.Mat43, false
+	case *mgl32.Vec2:
+		return glhf.Vec2, true
+	case *mgl32.Vec3:
+		return glhf.Vec3, true
+	case *mgl32.Vec4:
+		return glhf.Vec4, true
+	case *mgl32.Mat2:
+		return glhf.Mat2, true
+	case *mgl32.Mat2x3:
+		return glhf.Mat23, true
+	case *mgl32.Mat2x4:
+		return glhf.Mat24, true
+	case *mgl32.Mat3:
+		return glhf.Mat3, true
+	case *mgl32.Mat3x2:
+		return glhf.Mat32, true
+	case *mgl32.Mat3x4:
+		return glhf.Mat34, true
+	case *mgl32.Mat4:
+		return glhf.Mat4, true
+	case *mgl32.Mat4x2:
+		return glhf.Mat42, true
+	case *mgl32.Mat4x3:
+		return glhf.Mat43, true
+	case *int32:
+		return glhf.Int, true
+	case *float32:
+		return glhf.Float, true
+	default:
+		panic("invalid AttrType")
+	}
+}
+
 var defaultCanvasVertexShader = `
 #version 330 core
 
diff --git a/pixelgl/window.go b/pixelgl/window.go
index de7bb0d7b7d0369bc93017a36217a38db18bcfcf..2d646c5331eb0880f969222950bdffeed0655617 100644
--- a/pixelgl/window.go
+++ b/pixelgl/window.go
@@ -425,7 +425,7 @@ func (w *Window) Color(at pixel.Vec) pixel.RGBA {
 	return w.canvas.Color(at)
 }
 
-// GetCanvas returns the window's underlying Canvas
-func (w *Window) GetCanvas() *Canvas {
+// Canvas returns the window's underlying Canvas
+func (w *Window) Canvas() *Canvas {
 	return w.canvas
 }