diff --git a/canvas.go b/pixelgl/canvas.go
similarity index 82%
rename from canvas.go
rename to pixelgl/canvas.go
index b2860fa2e7dc34842bc9b04217605230416e32e3..84c12d3f16e8301aec39754095a743cdbb7a000e 100644
--- a/canvas.go
+++ b/pixelgl/canvas.go
@@ -1,10 +1,11 @@
-package pixel
+package pixelgl
 
 import (
 	"image/color"
 
 	"github.com/faiface/glhf"
 	"github.com/faiface/mainthread"
+	"github.com/faiface/pixel"
 	"github.com/go-gl/mathgl/mgl32"
 	"github.com/pkg/errors"
 )
@@ -19,9 +20,9 @@ type Canvas struct {
 	copyVs *glhf.VertexSlice
 	smooth bool
 
-	drawTd TrianglesDrawer
+	drawTd pixel.TrianglesDrawer
 
-	pic *Picture
+	pic *pixel.Picture
 	mat mgl32.Mat3
 	col mgl32.Vec4
 	bnd mgl32.Vec4
@@ -56,13 +57,14 @@ func NewCanvas(width, height float64, smooth bool) *Canvas {
 		c.copyVs.End()
 	})
 
-	c.drawTd = TrianglesDrawer{Triangles: &TrianglesData{
-		{Position: V(-1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 0)},
-		{Position: V(1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 0)},
-		{Position: V(1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 1)},
-		{Position: V(-1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 0)},
-		{Position: V(1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 1)},
-		{Position: V(-1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 1)},
+	white := pixel.NRGBA{R: 1, G: 1, B: 1, A: 1}
+	c.drawTd = pixel.TrianglesDrawer{Triangles: &pixel.TrianglesData{
+		{Position: pixel.V(-1, -1), Color: white, Texture: pixel.V(0, 0)},
+		{Position: pixel.V(1, -1), Color: white, Texture: pixel.V(1, 0)},
+		{Position: pixel.V(1, 1), Color: white, Texture: pixel.V(1, 1)},
+		{Position: pixel.V(-1, -1), Color: white, Texture: pixel.V(0, 0)},
+		{Position: pixel.V(1, 1), Color: white, Texture: pixel.V(1, 1)},
+		{Position: pixel.V(-1, 1), Color: white, Texture: pixel.V(0, 1)},
 	}}
 
 	c.pic = nil
@@ -74,7 +76,7 @@ func NewCanvas(width, height float64, smooth bool) *Canvas {
 
 // SetSize resizes the Canvas. The original content will be stretched to fit the new size.
 func (c *Canvas) SetSize(width, height float64) {
-	if V(width, height) == V(c.Size()) {
+	if pixel.V(width, height) == pixel.V(c.Size()) {
 		return
 	}
 	mainthread.Call(func() {
@@ -107,15 +109,15 @@ func (c *Canvas) Size() (width, height float64) {
 // Content returns a Picture that contains the content of this Canvas. The returned Picture changes
 // as you draw onto the Canvas, so there is no real need to call this method more than once (but it
 // might be beneficial to your code to do so).
-func (c *Canvas) Content() *Picture {
-	return PictureFromTexture(c.f.Texture())
+func (c *Canvas) Content() *pixel.Picture {
+	return pixel.PictureFromTexture(c.f.Texture())
 }
 
 // Clear fills the whole Canvas with one specified color.
 func (c *Canvas) Clear(col color.Color) {
 	mainthread.CallNonBlock(func() {
 		c.f.Begin()
-		col := NRGBAModel.Convert(col).(NRGBA)
+		col := pixel.NRGBAModel.Convert(col).(pixel.NRGBA)
 		glhf.Clear(float32(col.R), float32(col.G), float32(col.B), float32(col.A))
 		c.f.End()
 	})
@@ -123,13 +125,13 @@ func (c *Canvas) Clear(col color.Color) {
 
 // Draw draws the content of the Canvas onto another Target. If no transform is applied, the content
 // is fully stretched to fit the Target.
-func (c *Canvas) Draw(t Target) {
+func (c *Canvas) Draw(t pixel.Target) {
 	t.SetPicture(c.Content())
 	c.drawTd.Draw(t)
 }
 
 // MakeTriangles returns Triangles that draw onto this Canvas.
-func (c *Canvas) MakeTriangles(t Triangles) TargetTriangles {
+func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
 	gt := NewGLTriangles(c.s, t).(*glTriangles)
 	return &canvasTriangles{
 		c:           c,
@@ -140,10 +142,10 @@ func (c *Canvas) MakeTriangles(t Triangles) TargetTriangles {
 // SetPicture sets a Picture that will be used in further draw operations.
 //
 // This does not set the Picture that this Canvas draws onto, don't confuse it.
-func (c *Canvas) SetPicture(p *Picture) {
+func (c *Canvas) SetPicture(p *pixel.Picture) {
 	if p != nil {
-		min := pictureBounds(p, V(0, 0))
-		max := pictureBounds(p, V(1, 1))
+		min := pictureBounds(p, pixel.V(0, 0))
+		max := pictureBounds(p, pixel.V(1, 1))
 		c.bnd = mgl32.Vec4{
 			float32(min.X()), float32(min.Y()),
 			float32(max.X()), float32(max.Y()),
@@ -153,16 +155,16 @@ func (c *Canvas) SetPicture(p *Picture) {
 }
 
 // SetTransform sets the transformations used in further draw operations.
-func (c *Canvas) SetTransform(t ...Transform) {
+func (c *Canvas) SetTransform(t ...pixel.Transform) {
 	c.mat = transformToMat(t...)
 }
 
 // SetMaskColor sets the mask color used in further draw operations.
 func (c *Canvas) SetMaskColor(col color.Color) {
 	if col == nil {
-		col = NRGBA{1, 1, 1, 1}
+		col = pixel.NRGBA{R: 1, G: 1, B: 1, A: 1}
 	}
-	nrgba := NRGBAModel.Convert(col).(NRGBA)
+	nrgba := pixel.NRGBAModel.Convert(col).(pixel.NRGBA)
 	r := float32(nrgba.R)
 	g := float32(nrgba.G)
 	b := float32(nrgba.B)
diff --git a/gltriangles.go b/pixelgl/gltriangles.go
similarity index 81%
rename from gltriangles.go
rename to pixelgl/gltriangles.go
index b2648a324b687b46f89ec8aabe0acf94303733fe..a0b39390fc910d27343d9ad7a7c73ecba03398ec 100644
--- a/gltriangles.go
+++ b/pixelgl/gltriangles.go
@@ -1,10 +1,11 @@
-package pixel
+package pixelgl
 
 import (
 	"fmt"
 
 	"github.com/faiface/glhf"
 	"github.com/faiface/mainthread"
+	"github.com/faiface/pixel"
 )
 
 // NewGLTriangles returns OpenGL triangles implemented using glhf.VertexSlice. A few notes.
@@ -15,7 +16,7 @@ import (
 // Draw method simply draws the underlying glhf.VertexSlice. It needs to be called in the main
 // thread manually. Also, you need to take care of additional Target initialization or setting of
 // uniform attributes.
-func NewGLTriangles(shader *glhf.Shader, t Triangles) TargetTriangles {
+func NewGLTriangles(shader *glhf.Shader, t pixel.Triangles) pixel.TargetTriangles {
 	var gt *glTriangles
 	mainthread.Call(func() {
 		gt = &glTriangles{
@@ -54,7 +55,7 @@ func (gt *glTriangles) SetLen(len int) {
 	}
 }
 
-func (gt *glTriangles) Slice(i, j int) Triangles {
+func (gt *glTriangles) Slice(i, j int) pixel.Triangles {
 	return &glTriangles{
 		vs:     gt.vs.Slice(i, j),
 		data:   gt.data[i*gt.vs.Stride() : j*gt.vs.Stride()],
@@ -62,7 +63,7 @@ func (gt *glTriangles) Slice(i, j int) Triangles {
 	}
 }
 
-func (gt *glTriangles) updateData(t Triangles) {
+func (gt *glTriangles) updateData(t pixel.Triangles) {
 	// glTriangles short path
 	if t, ok := t.(*glTriangles); ok {
 		copy(gt.data, t.data)
@@ -70,7 +71,7 @@ func (gt *glTriangles) updateData(t Triangles) {
 	}
 
 	// TrianglesData short path
-	if t, ok := t.(*TrianglesData); ok {
+	if t, ok := t.(*pixel.TrianglesData); ok {
 		for i := 0; i < gt.Len(); i++ {
 			var (
 				px, py = (*t)[i].Position.XY()
@@ -89,14 +90,14 @@ func (gt *glTriangles) updateData(t Triangles) {
 		return
 	}
 
-	if t, ok := t.(TrianglesPosition); ok {
+	if t, ok := t.(pixel.TrianglesPosition); ok {
 		for i := 0; i < gt.Len(); i++ {
 			px, py := t.Position(i).XY()
 			gt.data[i*gt.vs.Stride()+0] = float32(px)
 			gt.data[i*gt.vs.Stride()+1] = float32(py)
 		}
 	}
-	if t, ok := t.(TrianglesColor); ok {
+	if t, ok := t.(pixel.TrianglesColor); ok {
 		for i := 0; i < gt.Len(); i++ {
 			col := t.Color(i)
 			gt.data[i*gt.vs.Stride()+2] = float32(col.R)
@@ -105,7 +106,7 @@ func (gt *glTriangles) updateData(t Triangles) {
 			gt.data[i*gt.vs.Stride()+5] = float32(col.A)
 		}
 	}
-	if t, ok := t.(TrianglesTexture); ok {
+	if t, ok := t.(pixel.TrianglesTexture); ok {
 		for i := 0; i < gt.Len(); i++ {
 			tx, ty := t.Texture(i).XY()
 			gt.data[i*gt.vs.Stride()+6] = float32(tx)
@@ -125,7 +126,7 @@ func (gt *glTriangles) submitData() {
 	})
 }
 
-func (gt *glTriangles) Update(t Triangles) {
+func (gt *glTriangles) Update(t pixel.Triangles) {
 	if gt.Len() != t.Len() {
 		panic(fmt.Errorf("%T.Update: invalid triangles len", gt))
 	}
@@ -133,7 +134,7 @@ func (gt *glTriangles) Update(t Triangles) {
 	gt.submitData()
 }
 
-func (gt *glTriangles) Copy() Triangles {
+func (gt *glTriangles) Copy() pixel.Triangles {
 	return NewGLTriangles(gt.shader, gt)
 }
 
@@ -143,18 +144,18 @@ func (gt *glTriangles) Draw() {
 	gt.vs.End()
 }
 
-func (gt *glTriangles) Position(i int) Vec {
+func (gt *glTriangles) Position(i int) pixel.Vec {
 	px := gt.data[i*gt.vs.Stride()+0]
 	py := gt.data[i*gt.vs.Stride()+1]
-	return V(float64(px), float64(py))
+	return pixel.V(float64(px), float64(py))
 }
 
-func (gt *glTriangles) Color(i int) NRGBA {
+func (gt *glTriangles) Color(i int) pixel.NRGBA {
 	r := gt.data[i*gt.vs.Stride()+2]
 	g := gt.data[i*gt.vs.Stride()+3]
 	b := gt.data[i*gt.vs.Stride()+4]
 	a := gt.data[i*gt.vs.Stride()+5]
-	return NRGBA{
+	return pixel.NRGBA{
 		R: float64(r),
 		G: float64(g),
 		B: float64(b),
@@ -162,8 +163,8 @@ func (gt *glTriangles) Color(i int) NRGBA {
 	}
 }
 
-func (gt *glTriangles) Texture(i int) Vec {
+func (gt *glTriangles) Texture(i int) pixel.Vec {
 	tx := gt.data[i*gt.vs.Stride()+6]
 	ty := gt.data[i*gt.vs.Stride()+7]
-	return V(float64(tx), float64(ty))
+	return pixel.V(float64(tx), float64(ty))
 }
diff --git a/input.go b/pixelgl/input.go
similarity index 98%
rename from input.go
rename to pixelgl/input.go
index afa903b9a061fc856991ee4f0727ddc4b1ff6fe5..f2ba4c0722dbd78d5e1a4fa3b864f4dadd7f3ac7 100644
--- a/input.go
+++ b/pixelgl/input.go
@@ -1,7 +1,8 @@
-package pixel
+package pixelgl
 
 import (
 	"github.com/faiface/mainthread"
+	"github.com/faiface/pixel"
 	"github.com/go-gl/glfw/v3.2/glfw"
 )
 
@@ -21,7 +22,7 @@ func (w *Window) JustReleased(button Button) bool {
 }
 
 // MousePosition returns the current mouse position relative to the window.
-func (w *Window) MousePosition() Vec {
+func (w *Window) MousePosition() pixel.Vec {
 	var x, y, width, height float64
 	mainthread.Call(func() {
 		x, y = w.window.GetCursorPos()
@@ -33,11 +34,11 @@ func (w *Window) MousePosition() Vec {
 	x = (x - width/2) / (width / 2)
 	y = (height/2 - y) / (height / 2)
 
-	return V(x, y)
+	return pixel.V(x, y)
 }
 
 // MouseScroll returns the scroll amount (in both axis) since the last call to Window.Update.
-func (w *Window) MouseScroll() Vec {
+func (w *Window) MouseScroll() pixel.Vec {
 	return w.currInp.scroll
 }
 
@@ -348,7 +349,7 @@ func (w *Window) initInput() {
 		})
 
 		w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) {
-			w.currInp.scroll += V(xoff, yoff)
+			w.currInp.scroll += pixel.V(xoff, yoff)
 		})
 	})
 }
diff --git a/monitor.go b/pixelgl/monitor.go
similarity index 99%
rename from monitor.go
rename to pixelgl/monitor.go
index c2ad61cf9d68020991529255db753c83ef4d580b..a5f5861334448cd089c5881e7bcef42b53459ad6 100644
--- a/monitor.go
+++ b/pixelgl/monitor.go
@@ -1,4 +1,4 @@
-package pixel
+package pixelgl
 
 import (
 	"github.com/faiface/mainthread"
diff --git a/run.go b/pixelgl/run.go
similarity index 98%
rename from run.go
rename to pixelgl/run.go
index bf46261a13b95813da8ea921cec5788187d3f0fc..599c4ab7aa89d05613f46b8af0a8697e7d2ec940 100644
--- a/run.go
+++ b/pixelgl/run.go
@@ -1,4 +1,4 @@
-package pixel
+package pixelgl
 
 import (
 	"github.com/faiface/mainthread"
diff --git a/pixelgl/util.go b/pixelgl/util.go
new file mode 100644
index 0000000000000000000000000000000000000000..af30bf8ddedda48521d929efa5c5f7984817ac8b
--- /dev/null
+++ b/pixelgl/util.go
@@ -0,0 +1,43 @@
+package pixelgl
+
+import (
+	"github.com/faiface/pixel"
+	"github.com/go-gl/mathgl/mgl32"
+)
+
+func clamp(x, low, high float64) float64 {
+	if x < low {
+		return low
+	}
+	if x > high {
+		return high
+	}
+	return x
+}
+
+func lerp(x float64, a, b pixel.Vec) pixel.Vec {
+	return a.Scaled(1-x) + b.Scaled(x)
+}
+
+func lerp2d(x, a, b pixel.Vec) pixel.Vec {
+	return pixel.V(
+		lerp(x.X(), a, b).X(),
+		lerp(x.Y(), a, b).Y(),
+	)
+}
+
+func transformToMat(t ...pixel.Transform) mgl32.Mat3 {
+	mat := mgl32.Ident3()
+	for i := range t {
+		mat = mat.Mul3(t[i].Mat())
+	}
+	return mat
+}
+
+func pictureBounds(p *pixel.Picture, v pixel.Vec) pixel.Vec {
+	w, h := float64(p.Texture().Width()), float64(p.Texture().Height())
+	a := p.Bounds().Pos
+	b := p.Bounds().Pos + p.Bounds().Size
+	u := lerp2d(v, a, b)
+	return pixel.V(u.X()/w, u.Y()/h)
+}
diff --git a/window.go b/pixelgl/window.go
similarity index 97%
rename from window.go
rename to pixelgl/window.go
index 5600f253de00601528f635dc8943ef3a15c05b2c..cf5ce992128782c33d862b80901d2e8ad6439b08 100644
--- a/window.go
+++ b/pixelgl/window.go
@@ -1,4 +1,4 @@
-package pixel
+package pixelgl
 
 import (
 	"image/color"
@@ -7,6 +7,7 @@ import (
 
 	"github.com/faiface/glhf"
 	"github.com/faiface/mainthread"
+	"github.com/faiface/pixel"
 	"github.com/go-gl/glfw/v3.2/glfw"
 	"github.com/pkg/errors"
 )
@@ -70,7 +71,7 @@ type Window struct {
 
 	prevInp, tempInp, currInp struct {
 		buttons [KeyLast + 1]bool
-		scroll  Vec
+		scroll  pixel.Vec
 	}
 }
 
@@ -368,19 +369,19 @@ func (w *Window) end() {
 // Window.
 //
 // Window supports TrianglesPosition, TrianglesColor and TrianglesTexture.
-func (w *Window) MakeTriangles(t Triangles) TargetTriangles {
+func (w *Window) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
 	return w.canvas.MakeTriangles(t)
 }
 
 // SetPicture sets a Picture that will be used in subsequent drawings onto the Window.
-func (w *Window) SetPicture(p *Picture) {
+func (w *Window) SetPicture(p *pixel.Picture) {
 	w.canvas.SetPicture(p)
 }
 
 // SetTransform sets a global transformation matrix for the Window.
 //
 // Transforms are applied right-to-left.
-func (w *Window) SetTransform(t ...Transform) {
+func (w *Window) SetTransform(t ...pixel.Transform) {
 	w.canvas.SetTransform(t...)
 }