diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts
index 982a0284b71e9f41f0606af4fe00d8e287d6ba7a..097c967759cb612993c907a6edaeb6ae5ffcdeaa 100644
--- a/src/apps/render-test/state.ts
+++ b/src/apps/render-test/state.ts
@@ -15,18 +15,41 @@ import { createTransformAttributes } from 'mol-gl/renderable/util';
 import { calculateTextureInfo } from 'mol-gl/util';
 import Icosahedron from 'mol-geo/primitive/icosahedron'
 import Box from 'mol-geo/primitive/box'
+import Spacefill from 'mol-geo/representation/structure/spacefill'
+
+import CIF from 'mol-io/reader/cif'
+import Computation from 'mol-util/computation'
+import { AtomSet, Structure } from 'mol-model/structure'
+import { UnitRepresentation } from 'mol-geo/representation/structure';
+
+async function parseCif(data: string|Uint8Array) {
+    const comp = CIF.parse(data)
+    const ctx = Computation.observable({
+        updateRateMs: 250
+    })
+    const parsed = await comp(ctx);
+    if (parsed.isError) throw parsed;
+    return parsed
+}
+
+async function getPdb(pdb: string) {
+    const data = await fetch(`https://files.rcsb.org/download/${pdb}.cif`)
+    const parsed = await parseCif(await data.text())
+    const structure = Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
+    return structure
+}
 
 export default class State {
     regl: REGL.Regl
 
-    initRegl (container: HTMLDivElement) {
+    async initRegl (container: HTMLDivElement) {
         const regl = glContext.create({
             container,
             extensions: [
                 'OES_texture_float',
                 'OES_texture_float_linear',
                 'OES_element_index_uint',
-                // 'ext_disjoint_timer_query',
+                // 'EXT_disjoint_timer_query',
                 'EXT_blend_minmax',
                 'ANGLE_instanced_arrays'
             ],
@@ -34,7 +57,9 @@ export default class State {
         })
 
         const camera = Camera.create(regl, container, {
-            center: Vec3.create(0, 0, 0)
+            center: Vec3.create(0, 0, 0),
+            near: 0.01,
+            far: 1000
         })
 
         const p1 = Vec3.create(0, 4, 0)
@@ -57,8 +82,6 @@ export default class State {
         Mat4.setTranslation(m4, p2)
         Mat4.toArray(m4, transformArray2, 32)
 
-
-
         const colorTexInfo = calculateTextureInfo(3, 3)
         const color = new Uint8Array(colorTexInfo.length)
         color.set([
@@ -110,22 +133,44 @@ export default class State {
 
         const mesh2 = MeshRenderable.create(regl,
             {
-                position: Attribute.create(regl, new Float32Array(box.vertices), { size: 3 }),
-                normal: Attribute.create(regl, new Float32Array(box.normals), { size: 3 }),
+                position: Attribute.create(regl, new Float32Array(sphere.vertices), { size: 3 }),
+                normal: Attribute.create(regl, new Float32Array(sphere.normals), { size: 3 }),
                 ...createTransformAttributes(regl, transformArray2)
             },
             {
                 colorTex,
                 colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
-                'light.position': Vec3.create(0, 0, -20),
+                'light.position': Vec3.create(0, 0, -100),
                 'light.color': Vec3.create(1.0, 1.0, 1.0),
                 'light.ambient': Vec3.create(0.5, 0.5, 0.5),
                 'light.falloff': 0,
                 'light.radius': 500
             },
-            box.indices
+            // box.indices
         )
 
+        function createSpacefills (structure: Structure) {
+            const spacefills: UnitRepresentation[] = []
+            const { atoms, units } = structure;
+            const unitIds = AtomSet.unitIds(atoms);
+            for (let i = 0, _i = unitIds.length; i < _i; i++) {
+                const unitId = unitIds[i];
+                const unit = units[unitId];
+                const atomGroup = AtomSet.unitGetByIndex(atoms, i);
+
+                const spacefill = Spacefill(regl)
+                spacefill.create(unit, atomGroup, {})
+                console.log('spacefill', spacefill)
+                spacefills.push(spacefill)
+            }
+            return spacefills
+        }
+
+        const structures = await getPdb('1crn')
+        const spacefills = createSpacefills(structures[0])
+
+        structures[0]
+
         const baseContext = regl({
             context: {
                 model: Mat4.identity(),
@@ -143,6 +188,7 @@ export default class State {
                 baseContext(() => {
                     // console.log(ctx)
                     regl.clear({color: [0, 0, 0, 1]})
+                    spacefills.forEach(r => r.draw())
                     position.update(array => { array[0] = Math.random() })
                     // points.update(a => { a.position[0] = Math.random() })
                     // mesh.draw()
diff --git a/src/apps/render-test/ui.tsx b/src/apps/render-test/ui.tsx
index fd88f2f5f1473ab7ef998391be930a4e89ad6a03..ed518d906ce262bfe999d10f22f8cbb944f64c71 100644
--- a/src/apps/render-test/ui.tsx
+++ b/src/apps/render-test/ui.tsx
@@ -7,16 +7,16 @@
 import * as React from 'react'
 import State from './state'
 
-export default class Root extends React.Component<{ state: State }, { }> {
+export default class Root extends React.Component<{ state: State }, { initialized: boolean }> {
     private canvasContainer: HTMLDivElement | null = null;
+    state = { initialized: false }
 
     componentDidMount() {
-        if (this.canvasContainer) this.props.state.initRegl(this.canvasContainer)
+        if (this.canvasContainer) this.props.state.initRegl(this.canvasContainer).then(() => this.setState({ initialized: true }))
     }
 
     render() {
         return <div ref={elm => this.canvasContainer = elm} style={{ position: 'absolute', top: 0, right: 0, left: 0, bottom: 0, overflow: 'hidden' }}>
-
         </div>
     }
 }
\ No newline at end of file
diff --git a/src/mol-geo/primitive/polyhedron.ts b/src/mol-geo/primitive/polyhedron.ts
index 11c2f9798541386cc755b2acba987b684901704c..db17d24242941bd782118e1770027c4a81288b6a 100644
--- a/src/mol-geo/primitive/polyhedron.ts
+++ b/src/mol-geo/primitive/polyhedron.ts
@@ -88,7 +88,5 @@ export default function Polyhedron(_vertices: Helpers.NumberArray, _indices: Hel
                 }
             }
         }
-
-        console.log(v)
     }
 }
\ No newline at end of file
diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4d66ed595134b44b8d963d3de9338cca5f05b41
--- /dev/null
+++ b/src/mol-geo/representation/structure/index.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 { AtomGroup, AtomSet, Structure, Unit } from 'mol-model/structure';
+
+export interface RepresentationProps {
+
+}
+
+export interface UnitRepresentation {
+    create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => boolean,
+    update: (props: RepresentationProps) => boolean,
+    draw: () => void
+}
+
+// export interface StructureRepresentation {
+//     create: (structure: Structure, props: RepresentationProps) => boolean,
+//     update: (props: RepresentationProps) => boolean
+// }
+
+export class StructureRepresentation {
+    constructor () {
+
+    }
+    create (structure: Structure, props: RepresentationProps) {
+        const { atoms, units } = structure;
+        const unitIds = AtomSet.unitIds(atoms);
+        for (let i = 0, _i = unitIds.length; i < _i; i++) {
+            const unitId = unitIds[i];
+            const unit = units[unitId];
+            const atomGroup = AtomSet.unitGetByIndex(atoms, i);
+
+        }
+
+        return true
+    }
+    update: (props: RepresentationProps) => false
+}
\ No newline at end of file
diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f609e878e1d93f1b4a0a0b479bcff9b85cee719 100644
--- a/src/mol-geo/representation/structure/spacefill.ts
+++ b/src/mol-geo/representation/structure/spacefill.ts
@@ -0,0 +1,106 @@
+/**
+ * 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 { MeshRenderable, Renderable } from 'mol-gl/renderable'
+import { createTransformAttributes } from 'mol-gl/renderable/util';
+import Attribute from 'mol-gl/attribute';
+import { calculateTextureInfo } from 'mol-gl/util';
+import Icosahedron from 'mol-geo/primitive/icosahedron'
+import { Vec3, Mat4 } from 'mol-math/linear-algebra'
+import { OrderedSet } from 'mol-data/int'
+import { Atom, AtomGroup, Unit } from 'mol-model/structure';
+import P from 'mol-model/structure/query/properties';
+import { RepresentationProps, UnitRepresentation } from './index';
+
+export default function Spacefill(regl: REGL.Regl): UnitRepresentation {
+    let vertices: Float32Array
+    let normals: Float32Array
+
+    const renderables: Renderable<any>[] = []
+
+    return {
+        create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => {
+            const atomCount = OrderedSet.size(atomGroup.atoms)
+
+            const l = Atom.Location();
+            l.unit = unit;
+
+            const sphere = Icosahedron(1, 0)
+            const vertexCount = sphere.vertices.length / 3
+
+            vertices = new Float32Array(atomCount * vertexCount * 3)
+            normals = new Float32Array(atomCount * vertexCount * 3)
+
+            const v = Vec3.zero()
+            const m = Mat4.identity()
+
+            for (let i = 0; i < atomCount; i++) {
+                l.atom = OrderedSet.getAt(atomGroup.atoms, i)
+
+                v[0] = P.atom.x(l)
+                v[1] = P.atom.y(l)
+                v[2] = P.atom.z(l)
+                Mat4.setTranslation(m, v)
+
+                for (let j = 0; j < vertexCount; ++j) {
+                    Vec3.fromArray(v, sphere.vertices, j * 3)
+                    Vec3.transformMat4(v, v, m)
+                    Vec3.toArray(v, vertices, i * vertexCount * 3 + j * 3)
+                }
+
+                normals.set(sphere.normals, i * vertexCount * 3)
+            }
+
+            const transformArray = new Float32Array(16)
+            const m4 = Mat4.identity()
+            Mat4.toArray(m4, transformArray, 0)
+
+            const colorTexInfo = calculateTextureInfo(3, 3)
+            const color = new Uint8Array(colorTexInfo.length)
+            color.set([
+                0, 0, 255,
+                0, 255, 0,
+                255, 0, 0
+            ])
+            // console.log(color, colorTexInfo)
+            const colorTex = regl.texture({
+                width: colorTexInfo.width,
+                height: colorTexInfo.height,
+                format: 'rgb',
+                type: 'uint8',
+                wrapS: 'clamp',
+                wrapT: 'clamp',
+                data: color
+            })
+
+            const spheres = MeshRenderable.create(regl,
+                {
+                    position: Attribute.create(regl, new Float32Array(vertices), { size: 3 }),
+                    normal: Attribute.create(regl, new Float32Array(normals), { size: 3 }),
+                    ...createTransformAttributes(regl, transformArray)
+                },
+                {
+                    colorTex,
+                    colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
+                    'light.position': Vec3.create(0, 0, -100),
+                    'light.color': Vec3.create(1.0, 1.0, 1.0),
+                    'light.ambient': Vec3.create(0.5, 0.5, 0.5),
+                    'light.falloff': 0,
+                    'light.radius': 500
+                }
+            )
+
+            // console.log({ vertices, normals, vertexCount, atomCount })
+
+            renderables.push(spheres)
+
+            return true
+        },
+        update: (props: RepresentationProps) => false,
+        draw: () => renderables.forEach(r => r.draw())
+    }
+}
diff --git a/src/mol-gl/attribute.ts b/src/mol-gl/attribute.ts
index 1133d5e7b57adf73c649c132112d0e7a47433408..c2fc73eb2b37a22dcdf0e502660fd7c5c6d4e30e 100644
--- a/src/mol-gl/attribute.ts
+++ b/src/mol-gl/attribute.ts
@@ -46,6 +46,7 @@ interface Attribute<T extends Helpers.TypedArray> {
     set(index: number, ...values: number[]): void
     update(mutator: Attribute.Mutator<T>): void
     reload(): void
+    destroy(): void
 }
 
 interface AttributeProps {
@@ -58,6 +59,8 @@ interface AttributeProps {
 namespace Attribute {
     export type Mutator<T extends Helpers.TypedArray> = (data: T) => (UpdateInfo | void)
     export type UpdateInfo = boolean | { offset: number, count: number }
+    export type ArrayCell<T> = { array: ReferenceCell<T> }
+    export type ReferenceCell<T> = { readonly version: number, readonly value: T }
 
     export function create<T extends Helpers.TypedArray>(regl: REGL.Regl, array: T, props: AttributeProps): Attribute<T> {
         const itemSize = props.size
@@ -94,7 +97,8 @@ namespace Attribute {
                 mutator(_array)
                 buffer(_array)
             },
-            reload: () => buffer(_array)
+            reload: () => buffer(_array),
+            destroy: () => buffer.destroy()
         }
     }
 }
diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts
index e0caa9da7a40c50fe5543db7585885ca2ad67c6d..91fa3ffd70fe17b1082fe290b3abe65cc2a90f5d 100644
--- a/src/mol-gl/renderable/mesh.ts
+++ b/src/mol-gl/renderable/mesh.ts
@@ -34,15 +34,15 @@ namespace Mesh {
     export type Attributes = { [K in keyof Data]: Attribute<Data[K]> }
 
     export function create(regl: REGL.Regl, attributes: Attributes, uniforms: Uniforms, elements?: Helpers.UintArray): Renderable<Data> {
-        console.log('mesh', {
-            count: attributes.position.getCount(),
-            instances: attributes.transformColumn0.getCount(),
-            attributes,
-            uniforms
-        })
+        // console.log('mesh', {
+        //     count: attributes.position.getCount(),
+        //     instances: attributes.transformColumn0.getCount(),
+        //     attributes,
+        //     uniforms
+        // })
         const instanceCount = attributes.transformColumn0.getCount()
         const instanceId = fillSerial(new Float32Array(instanceCount))
-        console.log(instanceId)
+        // console.log(instanceId)
         const command = regl({
             ...MeshShaders,
             uniforms: {
diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag
index 4a224d852dcf63e0c5f033f95b6d9997b8c0c87f..c542564e3e23c17c478218fde4e895fb556f130e 100644
--- a/src/mol-gl/shader/mesh.frag
+++ b/src/mol-gl/shader/mesh.frag
@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-precision mediump float;
+precision highp float;
 
 struct Light {
     vec3 position;
diff --git a/src/mol-gl/shader/mesh.vert b/src/mol-gl/shader/mesh.vert
index 3c760d523329804a185ff3a0af346911afbed687..7396279ec1b08e5d51e9b49d856e343727fac928 100644
--- a/src/mol-gl/shader/mesh.vert
+++ b/src/mol-gl/shader/mesh.vert
@@ -6,7 +6,7 @@
 
 #define INSTANCE_COLOR
 
-precision mediump float;
+precision highp float;
 
 uniform mat4 projection, model, view;
 
diff --git a/src/mol-math/linear-algebra/3d.ts b/src/mol-math/linear-algebra/3d.ts
index 727ef49ee3d61f75372de38bd44c84aafee1066c..fb76874a102916e6ac63dfe08038746f91757352 100644
--- a/src/mol-math/linear-algebra/3d.ts
+++ b/src/mol-math/linear-algebra/3d.ts
@@ -897,6 +897,9 @@ export namespace Vec3 {
         return out;
     }
 
+    /**
+     * Performs a linear interpolation between two Vec3's
+     */
     export function lerp(out: Vec3, a: Vec3, b: Vec3, t: number) {
         const ax = a[0],
             ay = a[1],
@@ -907,12 +910,65 @@ export namespace Vec3 {
         return out;
     }
 
+    /**
+     * Performs a hermite interpolation with two control points
+     */
+    export function hermite(out: Vec3, a: Vec3, b: Vec3, c: Vec3, d: Vec3, t: number) {
+        const factorTimes2 = t * t;
+        const factor1 = factorTimes2 * (2 * t - 3) + 1;
+        const factor2 = factorTimes2 * (t - 2) + t;
+        const factor3 = factorTimes2 * (t - 1);
+        const factor4 = factorTimes2 * (3 - 2 * t);
+
+        out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+        out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+        out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+        return out;
+    }
+
+    /**
+     * Performs a bezier interpolation with two control points
+     */
+    export function bezier(out: Vec3, a: Vec3, b: Vec3, c: Vec3, d: Vec3, t: number) {
+        const inverseFactor = 1 - t;
+        const inverseFactorTimesTwo = inverseFactor * inverseFactor;
+        const factorTimes2 = t * t;
+        const factor1 = inverseFactorTimesTwo * inverseFactor;
+        const factor2 = 3 * t * inverseFactorTimesTwo;
+        const factor3 = 3 * factorTimes2 * inverseFactor;
+        const factor4 = factorTimes2 * t;
+
+        out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
+        out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
+        out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
+
+        return out;
+    }
+
+    /**
+     * Generates a random vector with the given scale
+     */
+    export function random(out: Vec3, scale: number) {
+        const r = Math.random() * 2.0 * Math.PI;
+        const z = (Math.random() * 2.0) - 1.0;
+        const zScale = Math.sqrt(1.0-z*z) * scale;
+
+        out[0] = Math.cos(r) * zScale;
+        out[1] = Math.sin(r) * zScale;
+        out[2] = z * scale;
+        return out;
+    }
+
+    /**
+     * Transforms the Vec3 with a Mat4. 4th vector component is implicitly '1'
+     */
     export function transformMat4(out: Vec3, a: Vec3, m: Mat4) {
         const x = a[0], y = a[1], z = a[2],
-            w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
-        out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
-        out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
-        out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+            w = 1 / ((m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0);
+        out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) * w;
+        out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) * w;
+        out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) * w;
         return out;
     }