diff --git a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts
index b1852e23a216c80e5eac7ca424898f61ee63bc48..fa76a9e30682fb81d21be816edc22eb1c5f830ea 100644
--- a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts
+++ b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts
@@ -31,25 +31,20 @@ async function createInterUnitLinkCylinderMesh(ctx: RuntimeContext, structure: S
 
     if (!bondCount) return Mesh.createEmpty(mesh)
 
-    function referencePosition(edgeIndex: number): Vec3 | null {
-        // TODO
-        return null
-    }
-
-    function position(posA: Vec3, posB: Vec3, edgeIndex: number): void {
-        const b = bonds[edgeIndex]
-        const uA = b.unitA, uB = b.unitB
-        uA.conformation.position(uA.elements[b.indexA], posA)
-        uB.conformation.position(uB.elements[b.indexB], posB)
-    }
-
-    function order(edgeIndex: number): number {
-        return bonds[edgeIndex].order
+    const builderProps = {
+        linkCount: bondCount,
+        referencePosition: (edgeIndex: number) => null, // TODO
+        position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
+            const b = bonds[edgeIndex]
+            const uA = b.unitA, uB = b.unitB
+            uA.conformation.position(uA.elements[b.indexA], posA)
+            uB.conformation.position(uB.elements[b.indexB], posB)
+        },
+        order: (edgeIndex: number) => bonds[edgeIndex].order,
+        flags: (edgeIndex: number) => bonds[edgeIndex].flag
     }
 
-    const linkBuilder = { linkCount: bondCount, referencePosition, position, order }
-
-    return createLinkCylinderMesh(ctx, linkBuilder, props, mesh)
+    return createLinkCylinderMesh(ctx, builderProps, props, mesh)
 }
 
 export const DefaultInterUnitLinkProps = {
diff --git a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts
index 8d8b2f199b875a85dce6845ce3483654d075a632..15564c2cf637ee2879c72bb557fa48e7bd8fcab7 100644
--- a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts
+++ b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts
@@ -32,38 +32,35 @@ async function createIntraUnitLinkCylinderMesh(ctx: RuntimeContext, unit: Unit,
     const elements = unit.elements;
     const links = unit.links
     const { edgeCount, a, b, edgeProps, offset } = links
-    const { order: _order } = edgeProps
+    const { order: _order, flags: _flags } = edgeProps
 
     if (!edgeCount) return Mesh.createEmpty(mesh)
 
     const vRef = Vec3.zero()
-
     const pos = unit.conformation.invariantPosition
 
-    function referencePosition(edgeIndex: number): Vec3 | null {
-        let aI = a[edgeIndex], bI = b[edgeIndex];
-        if (aI > bI) [aI, bI] = [bI, aI]
-        for (let i = offset[aI], il = offset[aI + 1]; i < il; ++i) {
-            if (b[i] !== bI) return pos(elements[b[i]], vRef)
-        }
-        for (let i = offset[bI], il = offset[bI + 1]; i < il; ++i) {
-            if (a[i] !== aI) return pos(elements[a[i]], vRef)
-        }
-        return null
-    }
-
-    function position(posA: Vec3, posB: Vec3, edgeIndex: number): void {
-        pos(elements[a[edgeIndex]], posA)
-        pos(elements[b[edgeIndex]], posB)
-    }
-
-    function order(edgeIndex: number): number {
-        return _order[edgeIndex]
+    const builderProps = {
+        linkCount: edgeCount * 2,
+        referencePosition: (edgeIndex: number) => {
+            let aI = a[edgeIndex], bI = b[edgeIndex];
+            if (aI > bI) [aI, bI] = [bI, aI]
+            for (let i = offset[aI], il = offset[aI + 1]; i < il; ++i) {
+                if (b[i] !== bI) return pos(elements[b[i]], vRef)
+            }
+            for (let i = offset[bI], il = offset[bI + 1]; i < il; ++i) {
+                if (a[i] !== aI) return pos(elements[a[i]], vRef)
+            }
+            return null
+        },
+        position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
+            pos(elements[a[edgeIndex]], posA)
+            pos(elements[b[edgeIndex]], posB)
+        },
+        order: (edgeIndex: number) => _order[edgeIndex],
+        flags: (edgeIndex: number) => _flags[edgeIndex]
     }
 
-    const builder = { linkCount: edgeCount * 2, referencePosition, position, order }
-
-    return createLinkCylinderMesh(ctx, builder, props, mesh)
+    return createLinkCylinderMesh(ctx, builderProps, props, mesh)
 }
 
 export const DefaultIntraUnitLinkProps = {
diff --git a/src/mol-geo/representation/structure/visual/util/link.ts b/src/mol-geo/representation/structure/visual/util/link.ts
index 52079675792df5de3f4f06a971e963d7e08e2523..4d23190b207f3cea2ca31bd5df6256758d01f6c3 100644
--- a/src/mol-geo/representation/structure/visual/util/link.ts
+++ b/src/mol-geo/representation/structure/visual/util/link.ts
@@ -8,6 +8,7 @@ import { Vec3 } from 'mol-math/linear-algebra';
 import { RuntimeContext } from 'mol-task';
 import { Mesh } from '../../../../shape/mesh';
 import { MeshBuilder } from '../../../../shape/mesh-builder';
+import { LinkType } from 'mol-model/structure/model/types';
 
 export const DefaultLinkCylinderProps = {
     linkScale: 0.4,
@@ -52,6 +53,7 @@ export interface LinkCylinderMeshBuilderProps {
     referencePosition(edgeIndex: number): Vec3 | null
     position(posA: Vec3, posB: Vec3, edgeIndex: number): void
     order(edgeIndex: number): number
+    flags(edgeIndex: number): LinkType.Flag
 }
 
 /**
@@ -59,12 +61,13 @@ export interface LinkCylinderMeshBuilderProps {
  * the half closer to the first vertex, i.e. vertex a.
  */
 export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: LinkCylinderMeshBuilderProps, props: LinkCylinderProps, mesh?: Mesh) {
-    const { linkCount, referencePosition, position, order } = linkBuilder
+    const { linkCount, referencePosition, position, order, flags } = linkBuilder
 
     if (!linkCount) return Mesh.createEmpty(mesh)
 
-    // approximate vertextCount, exact calculation would need to take link orders into account
-    const vertexCount = 32 * linkCount
+    // approximate vertextCount (* 2), exact calculation would need to take
+    // multiple cylinders for bond orders and metall coordinations into account
+    const vertexCount = props.radialSegments * 2 * linkCount * 2
     const meshBuilder = MeshBuilder.create(vertexCount, vertexCount / 2, mesh)
 
     const va = Vec3.zero()
@@ -84,9 +87,15 @@ export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: L
         position(va, vb, edgeIndex)
 
         const o = order(edgeIndex)
+        const f = flags(edgeIndex) as any as LinkType // TODO
         meshBuilder.setId(edgeIndex)
 
-        if (o === 2 || o === 3) {
+        if (LinkType.is(f, LinkType.Flag.MetallicCoordination)) {
+            // show metall coordinations with dashed cylinders
+            cylinderParams.radiusTop = cylinderParams.radiusBottom = linkRadius / 3
+            meshBuilder.addFixedCountDashedCylinder(va, vb, 0.5, 7, cylinderParams)
+        } else if (o === 2 || o === 3) {
+            // show bonds with order 2 or 3 using 2 or 3 parallel cylinders
             const multiRadius = linkRadius * (linkScale / (0.5 * o))
             const absOffset = (linkRadius - multiRadius) * linkSpacing
 
diff --git a/src/mol-geo/shape/mesh-builder.ts b/src/mol-geo/shape/mesh-builder.ts
index cb72406c13ab18e2a5607c40ac055d72a97c5cfa..6eed0f441cc4772eb606763c1f731e67880c964c 100644
--- a/src/mol-geo/shape/mesh-builder.ts
+++ b/src/mol-geo/shape/mesh-builder.ts
@@ -21,12 +21,12 @@ type Primitive = {
 }
 
 export interface MeshBuilder {
-    add(t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array): number
-    addBox(t: Mat4, props?: BoxProps): number
-    addCylinder(start: Vec3, end: Vec3, scale: number, props: CylinderProps): number
-    addDoubleCylinder(start: Vec3, end: Vec3, scale: number, shift: Vec3, props: CylinderProps): number
-    // addFixedCountDashedCylinder(t: Mat4, props?: CylinderProps): number
-    addIcosahedron(center: Vec3, radius: number, detail: number): number
+    add(t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices?: Uint32Array): void
+    addBox(t: Mat4, props?: BoxProps): void
+    addCylinder(start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps): void
+    addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void
+    addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void
+    addIcosahedron(center: Vec3, radius: number, detail: number): void
     setId(id: number): void
     getMesh(): Mesh
 }
@@ -43,7 +43,7 @@ const tmpCylinderMatDir = Vec3.zero()
 const tmpCylinderCenter = Vec3.zero()
 const tmpCylinderMat = Mat4.zero()
 // const tmpCylinderMatTrans = Mat4.zero()
-const tmpShiftedCylinderStart = Vec3.zero()
+const tmpCylinderStart = Vec3.zero()
 
 function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) {
     Vec3.setMagnitude(tmpCylinderMatDir, dir, length / 2)
@@ -99,7 +99,7 @@ export namespace MeshBuilder {
         let currentId = -1
 
         function add(t: Mat4, _vertices: Float32Array, _normals: Float32Array, _indices: Uint32Array) {
-            const { elementCount, elementSize } = vertices
+            const { elementCount } = vertices
             const n = getNormalMatrix(tmpMat3, t)
             for (let i = 0, il = _vertices.length; i < il; i += 3) {
                 // position
@@ -116,41 +116,64 @@ export namespace MeshBuilder {
             for (let i = 0, il = _indices.length; i < il; i += 3) {
                 ChunkedArray.add3(indices, _indices[i] + elementCount, _indices[i + 1] + elementCount, _indices[i + 2] + elementCount);
             }
-            return elementCount * elementSize
         }
 
         return {
             add,
             addBox: (t: Mat4, props?: BoxProps) => {
                 const box = Box(props)
-                return add(t, box.vertices, box.normals, box.indices)
+                add(t, box.vertices, box.normals, box.indices)
             },
-            addCylinder: (start: Vec3, end: Vec3, scale: number, props: CylinderProps) => {
-                const d = Vec3.distance(start, end) * scale
+            addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => {
+                const d = Vec3.distance(start, end) * lengthScale
                 props.height = d
                 const { vertices, normals, indices } = getCylinder(props)
                 Vec3.sub(tmpCylinderDir, end, start)
                 setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d)
-                return add(tmpCylinderMat, vertices, normals, indices)
+                add(tmpCylinderMat, vertices, normals, indices)
             },
-            addDoubleCylinder: (start: Vec3, end: Vec3, scale: number, shift: Vec3, props: CylinderProps) => {
-                const d = Vec3.distance(start, end) * scale
+            addDoubleCylinder: (start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) => {
+                const d = Vec3.distance(start, end) * lengthScale
                 props.height = d
                 const { vertices, normals, indices } = getCylinder(props)
                 Vec3.sub(tmpCylinderDir, end, start)
                 // positivly shifted cylinder
-                Vec3.add(tmpShiftedCylinderStart, start, shift)
-                setCylinderMat(tmpCylinderMat, tmpShiftedCylinderStart, tmpCylinderDir, d)
+                Vec3.add(tmpCylinderStart, start, shift)
+                setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d)
                 add(tmpCylinderMat, vertices, normals, indices)
                 // negativly shifted cylinder
-                Vec3.sub(tmpShiftedCylinderStart, start, shift)
-                setCylinderMat(tmpCylinderMat, tmpShiftedCylinderStart, tmpCylinderDir, d)
-                return add(tmpCylinderMat, vertices, normals, indices)
+                Vec3.sub(tmpCylinderStart, start, shift)
+                setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d)
+                add(tmpCylinderMat, vertices, normals, indices)
+            },
+            addFixedCountDashedCylinder: (start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) => {
+                const s = Math.floor(segmentCount / 2)
+                const step = 1 / segmentCount
+
+                // automatically adjust length so links/bonds that are rendered as two half cylinders
+                // have evenly spaced dashed cylinders
+                if (lengthScale < 1) {
+                    const bias = lengthScale / 2 / segmentCount
+                    lengthScale += segmentCount % 2 === 1 ? bias : -bias
+                }
+
+                const d = Vec3.distance(start, end) * lengthScale
+                props.height = d * step
+                const { vertices, normals, indices } = getCylinder(props)
+                Vec3.sub(tmpCylinderDir, end, start)
+
+                for (let j = 0; j < s; ++j) {
+                    const f = step * (j * 2 + 1)
+                    Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f)
+                    Vec3.add(tmpCylinderStart, start, tmpCylinderDir)
+                    setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step)
+                    add(tmpCylinderMat, vertices, normals, indices)
+                }
             },
             addIcosahedron: (center: Vec3, radius: number, detail: number) => {
                 const { vertices, normals, indices } = getIcosahedron({ radius, detail })
                 setIcosahedronMat(tmpIcosahedronMat, center)
-                return add(tmpIcosahedronMat, vertices, normals, indices)
+                add(tmpIcosahedronMat, vertices, normals, indices)
             },
             setId: (id: number) => {
                 if (currentId !== id) {
diff --git a/src/mol-util/bit-flags.ts b/src/mol-util/bit-flags.ts
index 8143eb160bcbc0a1268cb3ddb9ef56d094d2d6e8..7f0bb8870771381b93be9e199f14e8bd52a4394e 100644
--- a/src/mol-util/bit-flags.ts
+++ b/src/mol-util/bit-flags.ts
@@ -10,7 +10,7 @@ namespace BitFlags {
     export function create<F>(flags: F): BitFlags<F> { return flags as any; }
 
     export function has<F>(flags: BitFlags<F>, flag: F) { return ((flags as any) & (flag as any)) !== 0; }
-    // toCheck must be non-zero
+    /** toCheck must be non-zero */
     export function hasAll<F>(flags: BitFlags<F>, toCheck: BitFlags<F>) { return !!toCheck && ((flags as any) & (toCheck as any)) === (toCheck as any); }
 }
 
diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts
index 25d2ae1914a12d0de4d450ac7a5029380ff3c546..b9afd01aaf4d647893092389258bbd3b35f3dc75 100644
--- a/src/mol-view/stage.ts
+++ b/src/mol-view/stage.ts
@@ -42,9 +42,10 @@ export class Stage {
 
         // this.loadPdbid('1jj2')
         // this.loadPdbid('4umt') // ligand has bond with order 3
-        // this.loadPdbid('1crn')
-        this.loadPdbid('3pqr')
-        // this.loadPdbid('4v5a')
+        // this.loadPdbid('1crn') // small
+        this.loadPdbid('1blu') // metal coordination
+        // this.loadPdbid('3pqr') // inter unit bonds
+        // this.loadPdbid('4v5a') // ribosome
         // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`)
     }