diff --git a/.vscode/settings.json b/.vscode/settings.json
index 00ad71fba1a3d0ed26f404f386e5966e082327cd..55712c19f1dffd66d4fed7a406a354f215c43a14 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
 {
-    "typescript.tsdk": "node_modules\\typescript\\lib"
+    "typescript.tsdk": "node_modules/typescript/lib"
 }
\ No newline at end of file
diff --git a/package.json b/package.json
index 8cf7a5c1afd0cb59266d874eb7e81acec2fb0cda..03c7cac9732118e293b1bd8ab4913208bae3b6a3 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,8 @@
     "watch": "tsc -watch",
     "test": "jest",
     "script": "node build/node_modules/script.js",
-    "app-render-test": "webpack build/node_modules/apps/render-test/index.js --mode development -o web/render-test/index.js"
+    "app-render-test": "webpack build/node_modules/apps/render-test/index.js --mode development -o web/render-test/index.js",
+    "app-render-test-watch": "webpack build/node_modules/apps/render-test/index.js -w --mode development -o web/render-test/index.js"
   },
   "jest": {
     "moduleFileExtensions": [
diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts
index b5d995ae342ffbc9b1f63c60896e95e1906d93e4..6286734446e253c3511255abb7798ccf8f630e64 100644
--- a/src/apps/render-test/state.ts
+++ b/src/apps/render-test/state.ts
@@ -8,9 +8,7 @@ import REGL = require('regl');
 import * as glContext from 'mol-gl/context'
 import { Camera } from 'mol-gl/camera'
 import { Vec3 } from 'mol-math/linear-algebra'
-
-const pointVert = require('mol-gl/shader/point.vert')
-const pointFrag = require('mol-gl/shader/point.frag')
+import Point from 'mol-gl/renderable/point'
 
 export default class State {
     regl: REGL.Regl
@@ -31,21 +29,16 @@ export default class State {
             center: Vec3.create(0, 0, 0)
         })
 
-        const drawPoints = regl({
-            vert: pointVert,
-            frag: pointFrag,
-            attributes: {
-                position: [[0, -1, 0], [-1, 0, 0], [1, 1, 0]]
-            },
-            count: 3,
-            primitive: 'points'
+        const points = Point.create(regl, {
+            position: new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0])
         })
 
         regl.frame(() => {
             camera.update((state: any) => {
                 if (!camera.isDirty()) return
                 regl.clear({color: [0, 0, 0, 1]})
-                drawPoints()
+                points.update(a => { a.position[0] = Math.random() })
+                points.draw()
             }, undefined)
         })
 
diff --git a/src/helpers.d.ts b/src/helpers.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b82c6a8c259923f095e10b0813c88f9df9b5c6c
--- /dev/null
+++ b/src/helpers.d.ts
@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+declare module Helpers {
+    export type Mutable<T> = {
+        -readonly [P in keyof T]: T[P]
+    }
+    export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array
+}
\ No newline at end of file
diff --git a/src/mol-gl/attribute.ts b/src/mol-gl/attribute.ts
new file mode 100644
index 0000000000000000000000000000000000000000..852640ce309576230a9ca684c5be746b708c85c8
--- /dev/null
+++ b/src/mol-gl/attribute.ts
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import REGL = require('regl');
+
+interface Attribute<T extends Helpers.TypedArray> {
+    readonly buffer: REGL.Buffer
+    readonly length: number
+    readonly data: T
+    set(value: number, index: number): void
+    growIfNeeded(size: number): void
+    update(mutator: Attribute.Mutator<T>): void
+    reload(): void
+}
+
+namespace Attribute {
+    export type Mutator<T extends Helpers.TypedArray> = (data: T) => (boolean | void)
+
+    export function create<T extends Helpers.TypedArray>(regl: REGL.Regl, data: T): Attribute<T> {
+        let _data = data
+        let _length = _data.length
+        const buffer = regl.buffer(_data)
+        const growIfNeeded = function(length: number) {
+            if (length > _data.length) {
+                _data = new (_data as any).constructor(_data)
+                _length = _data.length
+                buffer(_data)
+            }
+        }
+        return {
+            buffer,
+            get length() { return _length },
+            get data() { return _data },
+            set: (value: number, index: number) => {
+                growIfNeeded(index)
+                _data[index] = value
+                buffer.subdata([value], index * data.BYTES_PER_ELEMENT)
+            },
+            growIfNeeded(size: number) {
+                growIfNeeded(size)
+            },
+            update: (mutator: Mutator<T>) => {
+                mutator(_data)
+                buffer(_data)
+            },
+            reload: () => {
+                buffer(_data)
+            }
+        }
+    }
+}
+
+export default Attribute
\ No newline at end of file
diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts
new file mode 100644
index 0000000000000000000000000000000000000000..395762c592584646c90781b771f580d502a41c47
--- /dev/null
+++ b/src/mol-gl/renderable.ts
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import REGL = require('regl');
+import Attribute from './attribute'
+import Point from './renderable/point'
+
+export type AttributesMutator<T extends AttributesData> = (data: T) => (boolean | void)
+export type AttributesData = { [k: string]: Helpers.TypedArray }
+export type Attributes<T extends AttributesData> = { [K in keyof T]: Attribute<T[K]> }
+export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL.Buffer }
+
+export interface Renderable<T extends AttributesData> {
+    draw(): void,
+    update(mutator: AttributesMutator<T>): void
+}
+
+export { Point }
\ No newline at end of file
diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts
new file mode 100644
index 0000000000000000000000000000000000000000..946af4f6a4f3d4277bc5cae3b6ed27042e8ebd74
--- /dev/null
+++ b/src/mol-gl/renderable/point.ts
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import REGL = require('regl');
+import { Renderable, AttributesMutator, AttributesData } from '../renderable'
+import { createAttributes, getBuffers, getData } from './util'
+
+const pointVert = require('mol-gl/shader/point.vert')
+const pointFrag = require('mol-gl/shader/point.frag')
+
+type Point = 'point'
+
+namespace Point {
+    export interface Data extends AttributesData {
+        position: Float32Array
+    }
+    export function create(regl: REGL.Regl, data: Data): Renderable<Data> {
+        const attributes = createAttributes(regl, data)
+        const command = regl({
+            vert: pointVert,
+            frag: pointFrag,
+            attributes: getBuffers(attributes),
+            count: data.position.length / 3,
+            primitive: 'points'
+        })
+        return {
+            draw: () => command(),
+            update: (mutator: AttributesMutator<Data>) => {
+                mutator(getData(attributes))
+                for (const k of Object.keys(attributes)) {
+                    attributes[k].reload()
+                }
+            }
+        }
+    }
+}
+
+export default Point
\ No newline at end of file
diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c6801722c8426b0c01a6f9f71641ba54bab22c58
--- /dev/null
+++ b/src/mol-gl/renderable/util.ts
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import REGL = require('regl');
+
+import Attribute from '../attribute'
+import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
+
+export function getData<T extends AttributesData>(attributes: Attributes<T>): T {
+    const data: AttributesData = {}
+    for (const k of Object.keys(attributes)) {
+        data[k] = attributes[k].data
+    }
+    return data as T
+}
+
+export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
+    const buffers: AttributesBuffers<any> = {}
+    for (const k of Object.keys(attributes)) {
+        buffers[k] = attributes[k].buffer
+    }
+    return buffers as AttributesBuffers<T>
+}
+
+export function createAttributes<T extends AttributesData>(regl: REGL.Regl, data: T): Attributes<T> {
+    const attributes: Attributes<any> = {}
+    for (const k of Object.keys(data)) {
+        attributes[k] = Attribute.create(regl, data[k])
+    }
+    return attributes as Attributes<T>
+}
\ No newline at end of file