diff --git a/src/apps/canvas/assembly-symmetry.ts b/src/apps/canvas/assembly-symmetry.ts
index 4ee64f1c908095c8dda12a1f421be919d3b50468..69fee7dd07fd6acfb60c87a354f719dd556a2493 100644
--- a/src/apps/canvas/assembly-symmetry.ts
+++ b/src/apps/canvas/assembly-symmetry.ts
@@ -66,10 +66,10 @@ export function getClusterColorTheme(featureId: number, assemblySymmetry: Assemb
     const DefaultColor = Color(0xCCCCCC)
     const f = assemblySymmetry.db.rcsb_assembly_symmetry_feature
     const feature = Table.pickRow(f, i => f.id.value(i) === featureId)
-    if (!feature) return { kind: 'uniform', color: () => DefaultColor }
+    if (!feature) return { granularity: 'uniform', color: () => DefaultColor }
 
     const clusters = assemblySymmetry.getClusters(featureId)
-    if (!clusters._rowCount) return { kind: 'uniform', color: () => DefaultColor }
+    if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor }
 
     const clusterByMember = new Map<string, number>()
     for (let i = 0, il = clusters._rowCount; i < il; ++i) {
@@ -84,7 +84,7 @@ export function getClusterColorTheme(featureId: number, assemblySymmetry: Assemb
     const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] })
 
     return {
-        kind: 'instance',
+        granularity: 'instance',
         color: (location: Location): Color => {
             if (StructureElement.isLocation(location)) {
                 const ns = location.unit.conformation.operator.name.split('-')
diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts
index 4490697d596f412d8d95292714c44984959091b1..30c3607cab182be5124ebd8b59b2035a7683b228 100644
--- a/src/apps/canvas/structure-view.ts
+++ b/src/apps/canvas/structure-view.ts
@@ -157,7 +157,7 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
         if (structure) {
             console.log('createStructureRepr')
             await cartoon.createOrUpdate({
-                colorTheme: { name: 'unit-index' },
+                colorTheme: { name: 'chain-id' },
                 sizeTheme: { name: 'uniform', value: 0.2 },
                 useFog: false // TODO fog not working properly
             }, structure).run()
@@ -169,7 +169,7 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
             // }, structure).run()
 
             await ballAndStick.createOrUpdate({
-                colorTheme: { name: 'unit-index' },
+                colorTheme: { name: 'chain-id' },
                 sizeTheme: { name: 'uniform', value: 0.1 },
                 useFog: false // TODO fog not working properly
             }, structure).run()
diff --git a/src/mol-geo/representation/structure/complex-visual.ts b/src/mol-geo/representation/structure/complex-visual.ts
index 343a6082d9a9af562cd7a7a63834301a46e0331c..b53af777d0746e80387a8eb4e8f6eb06fec9da04 100644
--- a/src/mol-geo/representation/structure/complex-visual.ts
+++ b/src/mol-geo/representation/structure/complex-visual.ts
@@ -55,7 +55,6 @@ export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMe
 
         locationIt = createLocationIterator(structure)
         renderObject = await createComplexMeshRenderObject(ctx, structure, mesh, locationIt, currentProps)
-        console.log(renderObject.values)
     }
 
     async function update(ctx: RuntimeContext, props: Partial<P>) {
diff --git a/src/mol-geo/representation/structure/visual/util/common.ts b/src/mol-geo/representation/structure/visual/util/common.ts
index 6e5a74848abd82bc342c42f866e1132731aaf275..d77396d737c2763f39876841d02c49e507de8a7e 100644
--- a/src/mol-geo/representation/structure/visual/util/common.ts
+++ b/src/mol-geo/representation/structure/visual/util/common.ts
@@ -27,7 +27,7 @@ import { TransformData, createIdentityTransform, createTransforms } from '../../
 export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, props: ColorThemeProps, colorData?: ColorData): Promise<ColorData> {
     const colorTheme = ColorTheme(props)
     // Always use 'group' kind for 'complex' location iterators, i.e. an instance may include multiple units
-    const kind = colorTheme.kind === 'instance' && locationIt.isComplex ? 'group' : colorTheme.kind
+    const kind = colorTheme.granularity === 'instance' && locationIt.isComplex ? 'group' : colorTheme.granularity
     switch (kind) {
         case 'uniform': return createUniformColor(ctx, locationIt, colorTheme.color, colorData)
         case 'group': return createGroupColor(ctx, locationIt, colorTheme.color, colorData)
@@ -52,7 +52,10 @@ type StructureMeshProps = Required<MeshProps & StructureProps>
 
 async function _createMeshValues(ctx: RuntimeContext, transforms: TransformData, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): Promise<MeshValues> {
     const { instanceCount, groupCount } = locationIt
+    console.time('createColors')
     const color = await createColors(ctx, locationIt, props.colorTheme)
+    console.timeEnd('createColors')
+    console.log(locationIt.groupCount)
     const marker = createMarkers(instanceCount * groupCount)
 
     const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount }
diff --git a/src/mol-view/theme/color.ts b/src/mol-view/theme/color.ts
index 8ea3047f9c9c1bb7711402a9a668128454105bbc..29387093247ceeed0618e0e577c8a125dff66c5c 100644
--- a/src/mol-view/theme/color.ts
+++ b/src/mol-view/theme/color.ts
@@ -22,7 +22,7 @@ export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance'
 export type LocationColor = (location: Location, isSecondary: boolean) => Color
 
 export interface ColorTheme {
-    kind: ColorType
+    granularity: ColorType
     color: LocationColor
 }
 
diff --git a/src/mol-view/theme/color/carbohydrate-symbol.ts b/src/mol-view/theme/color/carbohydrate-symbol.ts
index edd870e95d240654617acbc18c2540d8f8cdd4e5..dd900029669f2742e6788bbf96c9bedecf5ae649 100644
--- a/src/mol-view/theme/color/carbohydrate-symbol.ts
+++ b/src/mol-view/theme/color/carbohydrate-symbol.ts
@@ -45,5 +45,5 @@ export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme
         color = () => DefaultColor
     }
 
-    return { kind: 'group', color: color }
+    return { granularity: 'group', color: color }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/chain-id.ts b/src/mol-view/theme/color/chain-id.ts
index 917c6fcfa43132706393495c1b0d38ffc4f128ee..fa8e7b57da5ccb9a70f5123fb954896839ac7d65 100644
--- a/src/mol-view/theme/color/chain-id.ts
+++ b/src/mol-view/theme/color/chain-id.ts
@@ -25,15 +25,25 @@ function getAsymId(unit: Unit): StructureElement.Property<string> {
 export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme {
     const l = StructureElement.create()
 
+    const scaleMap = new Map<number, ColorScale>()
+    function getScale(size: number) {
+        let scale = scaleMap.get(size)
+        if (!scale) {
+            scale = ColorScale.create({ domain: [ 0, size - 1 ] })
+            scaleMap.set(size, scale)
+        }
+        return scale
+    }
+
     function color(location: Location): Color {
         if (StructureElement.isLocation(location)) {
             const map = location.unit.model.properties.asymIdSerialMap
-            const scale = ColorScale.create({ domain: [ 0, map.size - 1 ] })
+            const scale = getScale(map.size)
             const asym_id = getAsymId(location.unit)
             return scale.color(map.get(asym_id(location)) || 0)
         } else if (Link.isLocation(location)) {
             const map = location.aUnit.model.properties.asymIdSerialMap
-            const scale = ColorScale.create({ domain: [ 0, map.size - 1 ] })
+            const scale = getScale(map.size)
             const asym_id = getAsymId(location.aUnit)
             l.unit = location.aUnit
             l.element = location.aUnit.elements[location.aIndex]
@@ -42,5 +52,5 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme {
         return DefaultColor
     }
 
-    return { kind: 'group', color }
+    return { granularity: 'group', color }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/cross-link.ts b/src/mol-view/theme/color/cross-link.ts
index 54e03924464045d4fef55ab0e7483c71dcd4ef93..b869b3f5d25275c3c5f65618fc3d1360c30cba53 100644
--- a/src/mol-view/theme/color/cross-link.ts
+++ b/src/mol-view/theme/color/cross-link.ts
@@ -40,5 +40,5 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme {
         color = () => DefaultColor
     }
 
-    return { kind: 'group', color }
+    return { granularity: 'group', color }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/custom.ts b/src/mol-view/theme/color/custom.ts
index 2eaaf72d183e4a9e51e6b6d64b0a1328acd64395..eb3d93bc0fe43b58b1b57f1e00d27c5522c34a78 100644
--- a/src/mol-view/theme/color/custom.ts
+++ b/src/mol-view/theme/color/custom.ts
@@ -13,7 +13,7 @@ const DefaultColor = Color(0xCCCCCC)
 export function CustomColorTheme(props: ColorThemeProps): ColorTheme {
     const value = defaults(props.value, DefaultColor)
     return {
-        kind: defaults(props.kind, 'uniform'),
+        granularity: defaults(props.kind, 'uniform'),
         color: defaults(props.color, () => value)
     }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/element-index.ts b/src/mol-view/theme/color/element-index.ts
index 290b466f608bad8876dff37adae8a8f6d0101e61..104d294de2b176c5d822ed48fa3f4885a64e0a41 100644
--- a/src/mol-view/theme/color/element-index.ts
+++ b/src/mol-view/theme/color/element-index.ts
@@ -42,5 +42,5 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme {
         color = () => DefaultColor
     }
 
-    return { kind: 'groupInstance', color }
+    return { granularity: 'groupInstance', color }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/element-symbol.ts b/src/mol-view/theme/color/element-symbol.ts
index 44845edfd944e5d4e9297b236ee8bf5ae434fc1b..1922afc99bc22af1ba54ec323fd9c291fc62ea61 100644
--- a/src/mol-view/theme/color/element-symbol.ts
+++ b/src/mol-view/theme/color/element-symbol.ts
@@ -38,5 +38,5 @@ export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme {
         return DefaultElementSymbolColor
     }
 
-    return { kind: 'group', color }
+    return { granularity: 'group', color }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/shape-group.ts b/src/mol-view/theme/color/shape-group.ts
index ba27b7c7016d39502721b3982ce188b63e6d9ccd..0615daa35f0c797761b4393053014288b44e71a9 100644
--- a/src/mol-view/theme/color/shape-group.ts
+++ b/src/mol-view/theme/color/shape-group.ts
@@ -13,7 +13,7 @@ const DefaultColor = Color(0xCCCCCC)
 
 export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme {
     return {
-        kind: 'group',
+        granularity: 'group',
         color: (location: Location): Color => {
             if (Shape.isLocation(location)) {
                 return location.shape.colors.ref.value[location.group]
diff --git a/src/mol-view/theme/color/uniform.ts b/src/mol-view/theme/color/uniform.ts
index 44f705dbb6ffe7aa072314311b288abef372a820..a516c6e6dbcc340888db02574676325e2a34cf0f 100644
--- a/src/mol-view/theme/color/uniform.ts
+++ b/src/mol-view/theme/color/uniform.ts
@@ -13,7 +13,7 @@ export function UniformColorTheme(props: ColorThemeProps): ColorTheme {
     const color = props.value || DefaultColor
 
     return {
-        kind: 'uniform',
+        granularity: 'uniform',
         color: () => color
     }
 }
\ No newline at end of file
diff --git a/src/mol-view/theme/color/unit-index.ts b/src/mol-view/theme/color/unit-index.ts
index 4b55b16dd09622a931deac5da509d707ba594841..42786deda6072ad2d0149fb1ab03e91c023d23fc 100644
--- a/src/mol-view/theme/color/unit-index.ts
+++ b/src/mol-view/theme/color/unit-index.ts
@@ -34,5 +34,5 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme {
         color = () => DefaultColor
     }
 
-    return { kind: 'instance', color }
+    return { granularity: 'instance', color }
 }
\ No newline at end of file