diff --git a/gltriangles.go b/gltriangles.go
index ca022fa98373b4c7252ef66e1a3d9e534184a7c3..2665aed22005b32636d7fae662ccee6c5897b422 100644
--- a/gltriangles.go
+++ b/gltriangles.go
@@ -119,12 +119,7 @@ func (gt *glTriangles) submitData() {
 	mainthread.CallNonBlock(func() {
 		gt.vs.Begin()
 		dataLen := len(data) / gt.vs.Stride()
-		if dataLen > gt.vs.Len() {
-			gt.vs.Append(make([]float32, (dataLen-gt.vs.Len())*gt.vs.Stride()))
-		}
-		if dataLen < gt.vs.Len() {
-			gt.vs = gt.vs.Slice(0, dataLen)
-		}
+		gt.vs.SetLen(dataLen)
 		gt.vs.SetVertexData(gt.data)
 		gt.vs.End()
 	})
diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go
index e7b75b657fb97302968bc6118e3ad2ce416bae00..a1d70e1f93d9edc13e15b4a0c10fd46e947405b3 100644
--- a/pixelgl/vertex.go
+++ b/pixelgl/vertex.go
@@ -50,7 +50,7 @@ func (vs *VertexSlice) Stride() int {
 	return vs.va.stride / 4
 }
 
-// Len returns the length of the VertexSlice.
+// Len returns the length of the VertexSlice (number of vertices).
 func (vs *VertexSlice) Len() int {
 	return vs.j - vs.i
 }
@@ -60,20 +60,11 @@ func (vs *VertexSlice) Cap() int {
 	return vs.va.cap - vs.i
 }
 
-// Slice returns a sub-slice of this VertexSlice covering the range [i, j) (relative to this
-// VertexSlice).
-//
-// Note, that the returned VertexSlice shares an underlying vertex array with the original
-// VertexSlice. Modifying the contents of one modifies corresponding contents of the other.
-func (vs *VertexSlice) Slice(i, j int) *VertexSlice {
-	if i < 0 || j < i || j > vs.va.cap {
-		panic("failed to slice vertex slice: index out of range")
-	}
-	return &VertexSlice{
-		va: vs.va,
-		i:  vs.i + i,
-		j:  vs.i + j,
-	}
+// SetLen resizes the VertexSlice to length len.
+func (vs *VertexSlice) SetLen(len int) {
+	vs.End() // vs must have been Begin-ed before calling this method
+	*vs = vs.grow(len)
+	vs.Begin()
 }
 
 // grow returns supplied vs with length changed to len. Allocates new underlying vertex array if
@@ -110,18 +101,20 @@ func (vs VertexSlice) grow(len int) VertexSlice {
 	return newVs
 }
 
-// Append adds supplied vertices to the end of the VertexSlice. If the capacity of the VertexSlice
-// is not sufficient, a new, larger underlying vertex array will be allocated. The content of the
-// original VertexSlice will be copied to the new underlying vertex array.
-//
-// The data is in the same format as with SetVertexData.
+// Slice returns a sub-slice of this VertexSlice covering the range [i, j) (relative to this
+// VertexSlice).
 //
-// The VertexSlice is appended 'in-place', contrary Go's builtin slices.
-func (vs *VertexSlice) Append(data []float32) {
-	vs.End() // vs must have been Begin-ed before calling this method
-	*vs = vs.grow(vs.Len() + len(data)/vs.Stride())
-	vs.Begin()
-	vs.Slice(vs.Len()-len(data)/vs.Stride(), vs.Len()).SetVertexData(data)
+// Note, that the returned VertexSlice shares an underlying vertex array with the original
+// VertexSlice. Modifying the contents of one modifies corresponding contents of the other.
+func (vs *VertexSlice) Slice(i, j int) *VertexSlice {
+	if i < 0 || j < i || j > vs.va.cap {
+		panic("failed to slice vertex slice: index out of range")
+	}
+	return &VertexSlice{
+		va: vs.va,
+		i:  vs.i + i,
+		j:  vs.i + j,
+	}
 }
 
 // SetVertexData sets the contents of the VertexSlice.