diff --git a/package-lock.json b/package-lock.json
index a6e919d8410914b5d76a52a8e4ad3b668941885d..539aec393ef4a81fe88c46bb79781f76eeceaac4 100644
Binary files a/package-lock.json and b/package-lock.json differ
diff --git a/package.json b/package.json
index 2a8e33f0618a18dee2d3a64009f085d4f5e82f8b..eede657509d5f0454525f990cd395429c99582ee 100644
--- a/package.json
+++ b/package.json
@@ -88,6 +88,7 @@
     "@types/react-dom": "^16.0.9",
     "@types/webgl2": "0.0.4",
     "benchmark": "^2.1.4",
+    "circular-dependency-plugin": "^5.0.2",
     "cpx": "^1.5.0",
     "css-loader": "^1.0.1",
     "extra-watch-webpack-plugin": "^1.0.3",
diff --git a/src/apps/canvas/app.ts b/src/apps/canvas/app.ts
index 25b2b5aeba30cd47ab92d99e7fb7d5fcdb46b391..fc8e304edd25da52c0e3bbe3f34432e4f4b62356 100644
--- a/src/apps/canvas/app.ts
+++ b/src/apps/canvas/app.ts
@@ -12,6 +12,10 @@ import { CifBlock } from 'mol-io/reader/cif';
 import { VolumeView } from './volume-view';
 import { Ccp4File } from 'mol-io/reader/ccp4/schema';
 import { Progress } from 'mol-task';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
+import { StructureRepresentationRegistry } from 'mol-repr/structure/registry';
+import { VolumeRepresentationRegistry } from 'mol-repr/volume/registry';
 
 export class App {
     canvas3d: Canvas3D
@@ -23,6 +27,11 @@ export class App {
     structureLoaded: BehaviorSubject<StructureView | null> = new BehaviorSubject<StructureView | null>(null)
     volumeLoaded: BehaviorSubject<VolumeView | null> = new BehaviorSubject<VolumeView | null>(null)
 
+    colorThemeRegistry = new ColorTheme.Registry()
+    sizeThemeRegistry = new SizeTheme.Registry()
+    structureRepresentationRegistry = new StructureRepresentationRegistry()
+    volumeRepresentationRegistry = new VolumeRepresentationRegistry()
+
     initViewer(_canvas: HTMLCanvasElement, _container: HTMLDivElement) {
         this.canvas = _canvas
         this.container = _container
@@ -64,6 +73,14 @@ export class App {
         console.log(Progress.format(progress))
     }
 
+    get reprCtx () {
+        return {
+            webgl: this.canvas3d.webgl,
+            colorThemeRegistry: this.colorThemeRegistry,
+            sizeThemeRegistry: this.sizeThemeRegistry
+        }
+    }
+
     //
 
     async loadMmcif(cif: CifBlock, assemblyId?: string) {
diff --git a/src/apps/canvas/assembly-symmetry.ts b/src/apps/canvas/assembly-symmetry.ts
index f4cdb2888466a56c6f9babcc311ea010249714db..e43357c196bd3f16120d60250bd10f502ce5f4e0 100644
--- a/src/apps/canvas/assembly-symmetry.ts
+++ b/src/apps/canvas/assembly-symmetry.ts
@@ -66,10 +66,10 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem
     const DefaultColor = Color(0xCCCCCC)
     const s = assemblySymmetry.db.rcsb_assembly_symmetry
     const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId)
-    if (!symmetry) return { features: {}, granularity: 'uniform', color: () => DefaultColor }
+    if (!symmetry) return { granularity: 'uniform', color: () => DefaultColor, props: {} }
 
     const clusters = assemblySymmetry.getClusters(symmetryId)
-    if (!clusters._rowCount) return { features: {}, granularity: 'uniform', color: () => DefaultColor }
+    if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor, props: {} }
 
     const clusterByMember = new Map<string, number>()
     for (let i = 0, il = clusters._rowCount; i < il; ++i) {
@@ -83,7 +83,6 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem
     const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] })
 
     return {
-        features: {},
         granularity: 'instance',
         color: (location: Location): Color => {
             if (StructureElement.isLocation(location)) {
@@ -94,6 +93,7 @@ export function getClusterColorTheme(symmetryId: number, assemblySymmetry: Assem
                 return cluster !== undefined ? scale.color(cluster) : DefaultColor
             }
             return DefaultColor
-        }
+        },
+        props: {}
     }
 }
\ No newline at end of file
diff --git a/src/apps/canvas/component/representation.tsx b/src/apps/canvas/component/representation.tsx
index 8bbdf8bae91586a7dd784220c1230b24e3b838d8..ab7e997086e69cd5131b3785f29ad547c3d48530 100644
--- a/src/apps/canvas/component/representation.tsx
+++ b/src/apps/canvas/component/representation.tsx
@@ -8,16 +8,14 @@ import * as React from 'react'
 import Canvas3D from 'mol-canvas3d/canvas3d';
 import { App } from '../app';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { Representation } from 'mol-repr';
+import { Representation } from 'mol-repr/representation';
 import { ParametersComponent } from 'mol-app/component/parameters';
-import { ColorTheme } from 'mol-theme/color';
-import { getColorThemeProps } from 'mol-geo/geometry/color-data';
-import { ColorThemeComponent } from 'mol-app/component/color-theme';
 
-export interface RepresentationComponentProps {
+export interface RepresentationComponentProps<P extends PD.Params> {
     app: App
     canvas3d: Canvas3D
-    repr: Representation<PD.Params>
+    repr: Representation<P>
+    params: P
 }
 
 export interface RepresentationComponentState {
@@ -26,13 +24,13 @@ export interface RepresentationComponentState {
     reprProps: Readonly<{}>
 }
 
-export class RepresentationComponent extends React.Component<RepresentationComponentProps, RepresentationComponentState> {
+export class RepresentationComponent<P extends PD.Params> extends React.Component<RepresentationComponentProps<P>, RepresentationComponentState> {
 
-    private stateFromRepr(repr: Representation<PD.Params>) {
+    private stateFromRepr(repr: Representation<P>) {
         return {
-            label: this.props.repr.label,
-            reprParams: this.props.repr.params,
-            reprProps: this.props.repr.props
+            label: repr.label,
+            reprParams: this.props.params,
+            reprProps: repr.props
         }
     }
 
@@ -41,8 +39,7 @@ export class RepresentationComponent extends React.Component<RepresentationCompo
     }
 
     async onChange(k: string, v: any) {
-        const ctx = { webgl: this.props.canvas3d.webgl }
-        await this.props.app.runTask(this.props.repr.createOrUpdate(ctx, { [k]: v }).run(
+        await this.props.app.runTask(this.props.repr.createOrUpdate(this.props.app.reprCtx, { [k]: v }).run(
             progress => this.props.app.log(progress)
         ), 'Representation Update')
         this.props.canvas3d.add(this.props.repr)
@@ -52,10 +49,10 @@ export class RepresentationComponent extends React.Component<RepresentationCompo
 
     render() {
         const { label, reprParams, reprProps } = this.state
-        let colorTheme: ColorTheme | undefined = undefined
-        if ('colorTheme' in reprProps) {
-            colorTheme = ColorTheme(getColorThemeProps(reprProps))
-        }
+        // let colorTheme: ColorTheme | undefined = undefined
+        // if ('colorTheme' in reprProps) {
+        //     colorTheme = ColorTheme(getColorThemeProps(reprProps))
+        // }
 
         return <div>
             <div>
@@ -68,7 +65,7 @@ export class RepresentationComponent extends React.Component<RepresentationCompo
                     onChange={(k, v) => this.onChange(k as string, v)}
                 />
             </div>
-            { colorTheme !== undefined ? <ColorThemeComponent colorTheme={colorTheme} /> : '' }
+            {/* { colorTheme !== undefined ? <ColorThemeComponent colorTheme={colorTheme} /> : '' } */}
         </div>;
     }
 }
\ No newline at end of file
diff --git a/src/apps/canvas/component/structure-view.tsx b/src/apps/canvas/component/structure-view.tsx
index 9b8fd7d785b34911588028d951b22b6224668994..3bfd625633ef9a6999b8ef87589486270581b6c1 100644
--- a/src/apps/canvas/component/structure-view.tsx
+++ b/src/apps/canvas/component/structure-view.tsx
@@ -7,8 +7,8 @@
 import * as React from 'react'
 import { StructureView } from '../structure-view';
 import { RepresentationComponent } from './representation';
-import { Representation } from 'mol-repr';
-import { StructureRepresentation } from 'mol-repr/structure/index';
+import { Representation } from 'mol-repr/representation';
+import { StructureRepresentation } from 'mol-repr/structure/representation';
 
 export interface StructureViewComponentProps {
     structureView: StructureView
@@ -37,6 +37,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
             structureView: sv,
 
             label: sv.label,
+            structure: sv.structure,
             modelId: sv.modelId,
             modelIds: sv.getModelIds(),
             assemblyId: sv.assemblyId,
@@ -84,7 +85,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
     }
 
     render() {
-        const { structureView, label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state
+        const { structureView, label, structure, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state
 
         const modelIdOptions = modelIds.map(m => {
             return <option key={m.id} value={m.id}>{m.label}</option>
@@ -174,6 +175,9 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
                             return <div key={i}>
                                 <RepresentationComponent
                                     repr={structureRepresentations[k] as Representation<any>}
+                                    params={
+                                        structureView.app.structureRepresentationRegistry.get(k)!.params(structureView.app.reprCtx, structure!)
+                                    }
                                     canvas3d={structureView.canvas3d}
                                     app={structureView.app}
                                 />
diff --git a/src/apps/canvas/component/volume-view.tsx b/src/apps/canvas/component/volume-view.tsx
index 159a0d2176dc108377d34cfa1147038d75bbb852..bf351b4dc38f9782f086df4353f48761bf83c400 100644
--- a/src/apps/canvas/component/volume-view.tsx
+++ b/src/apps/canvas/component/volume-view.tsx
@@ -6,9 +6,9 @@
 
 import * as React from 'react'
 import { RepresentationComponent } from './representation';
-import { Representation } from 'mol-repr';
+import { Representation } from 'mol-repr/representation';
 import { VolumeView } from '../volume-view';
-import { VolumeRepresentation } from 'mol-repr/volume/index';
+import { VolumeRepresentation } from 'mol-repr/volume/representation';
 
 export interface VolumeViewComponentProps {
     volumeView: VolumeView
@@ -28,6 +28,7 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp
         return {
             volumeView: vv,
             label: vv.label,
+            volume: vv.volume,
             active: vv.active,
             volumeRepresentations: vv.volumeRepresentations
         }
@@ -61,7 +62,7 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp
     // }
 
     render() {
-        const { volumeView, label, active, volumeRepresentations } = this.state
+        const { volumeView, label, volume, active, volumeRepresentations } = this.state
 
         return <div>
             <div>
@@ -89,6 +90,9 @@ export class VolumeViewComponent extends React.Component<VolumeViewComponentProp
                             return <div key={i}>
                                 <RepresentationComponent
                                     repr={volumeRepresentations[k] as Representation<any>}
+                                    params={
+                                        volumeView.app.volumeRepresentationRegistry.get(k)!.params(volumeView.app.reprCtx, volume!)
+                                    }
                                     canvas3d={volumeView.viewer}
                                     app={volumeView.app}
                                 />
diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts
index eeff5581a4cb6d4dcc4e95fe1055642be4122aee..5f80091c05466fc21c26c6140c49d86bcc837ec0 100644
--- a/src/apps/canvas/structure-view.ts
+++ b/src/apps/canvas/structure-view.ts
@@ -17,15 +17,8 @@ import Canvas3D from 'mol-canvas3d/canvas3d';
 // import { addBoundingBox } from 'mol-geo/mesh/builder/bounding-box';
 import { BehaviorSubject } from 'rxjs';
 import { App } from './app';
-import { StructureRepresentation } from 'mol-repr/structure/index';
-import { ShapeRepresentation, ShapeProps } from 'mol-repr/shape/index';
-import { CartoonRepresentation } from 'mol-repr/structure/representation/cartoon';
-import { MolecularSurfaceRepresentation } from 'mol-repr/structure/representation/molecular-surface';
-import { PointRepresentation } from 'mol-repr/structure/representation/point';
-import { BallAndStickRepresentation } from 'mol-repr/structure/representation/ball-and-stick';
-import { CarbohydrateRepresentation } from 'mol-repr/structure/representation/carbohydrate';
-import { SpacefillRepresentation } from 'mol-repr/structure/representation/spacefill';
-import { DistanceRestraintRepresentation } from 'mol-repr/structure/representation/distance-restraint';
+import { StructureRepresentation } from 'mol-repr/structure/representation';
+import { ShapeRepresentation, ShapeProps } from 'mol-repr/shape/representation';
 
 export interface StructureView {
     readonly app: App
@@ -66,25 +59,17 @@ interface StructureViewProps {
 export async function StructureView(app: App, canvas3d: Canvas3D, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> {
     const active: { [k: string]: boolean } = {
         cartoon: true,
-        point: false,
-        surface: false,
-        ballAndStick: false,
-        carbohydrate: false,
-        spacefill: false,
-        distanceRestraint: false,
-        symmetryAxes: true,
+        // point: false,
+        // surface: false,
+        // ballAndStick: false,
+        // carbohydrate: false,
+        // spacefill: false,
+        // distanceRestraint: false,
+        // symmetryAxes: true,
         // polymerSphere: false,
     }
 
-    const structureRepresentations: { [k: string]: StructureRepresentation<any> } = {
-        cartoon: CartoonRepresentation(),
-        surface: MolecularSurfaceRepresentation(),
-        point: PointRepresentation(),
-        ballAndStick: BallAndStickRepresentation(),
-        carbohydrate: CarbohydrateRepresentation(),
-        spacefill: SpacefillRepresentation(),
-        distanceRestraint: DistanceRestraintRepresentation(),
-    }
+    const structureRepresentations: { [k: string]: StructureRepresentation<any> } = {}
 
     const symmetryAxes = ShapeRepresentation()
     const polymerSphere = ShapeRepresentation()
@@ -206,14 +191,25 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon
     async function createStructureRepr() {
         if (structure) {
             console.log('createStructureRepr')
-            for (const k in structureRepresentations) {
+            for (const k in active) {
                 if (active[k]) {
-                    await app.runTask(structureRepresentations[k].createOrUpdate({ webgl: canvas3d.webgl }, {}, structure).run(
+                    let repr: StructureRepresentation
+                    if (structureRepresentations[k]) {
+                        repr = structureRepresentations[k]
+                    } else {
+                        repr = app.structureRepresentationRegistry.create('cartoon', app.reprCtx, structure)
+                        structureRepresentations[k] = repr
+                    }
+                    await app.runTask(repr.createOrUpdate(app.reprCtx, {}, {}, structure).run(
                         progress => app.log(progress)
                     ), 'Create/update representation')
-                    canvas3d.add(structureRepresentations[k])
+                    canvas3d.add(repr)
                 } else {
-                    canvas3d.remove(structureRepresentations[k])
+                    if (structureRepresentations[k]) {
+                        canvas3d.remove(structureRepresentations[k])
+                        structureRepresentations[k].destroy()
+                        delete structureRepresentations[k]
+                    }
                 }
             }
 
@@ -264,7 +260,7 @@ export async function StructureView(app: App, canvas3d: Canvas3D, models: Readon
                     //     colorFunction: colorTheme.color,
                     //     colorGranularity: colorTheme.granularity,
                     // }).run()
-                    await symmetryAxes.createOrUpdate({ webgl: canvas3d.webgl }, {}, axesShape).run()
+                    await symmetryAxes.createOrUpdate(app.reprCtx, {}, {}, axesShape).run()
                     canvas3d.add(symmetryAxes)
                 } else {
                     canvas3d.remove(symmetryAxes)
diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts
index 6c05559ef90422c25527822337f72f7e0e602d02..023f16fec99ffc3be3bdee4b09139dac1f43e65c 100644
--- a/src/apps/canvas/volume-view.ts
+++ b/src/apps/canvas/volume-view.ts
@@ -8,7 +8,7 @@ import Canvas3D from 'mol-canvas3d/canvas3d';
 import { BehaviorSubject } from 'rxjs';
 import { App } from './app';
 import { VolumeData } from 'mol-model/volume';
-import { VolumeRepresentation } from 'mol-repr/volume/index';
+import { VolumeRepresentation } from 'mol-repr/volume/representation';
 import { IsosurfaceRepresentation } from 'mol-repr/volume/isosurface-mesh';
 import { DirectVolumeRepresentation } from 'mol-repr/volume/direct-volume';
 
@@ -54,7 +54,7 @@ export async function VolumeView(app: App, viewer: Canvas3D, volume: VolumeData,
     async function createVolumeRepr() {
         for (const k in volumeRepresentations) {
             if (active[k]) {
-                await app.runTask(volumeRepresentations[k].createOrUpdate({ webgl: viewer.webgl }, {}, volume).run(
+                await app.runTask(volumeRepresentations[k].createOrUpdate(app.reprCtx, {}, {}, volume).run(
                     progress => app.log(progress)
                 ), 'Create/update representation')
                 viewer.add(volumeRepresentations[k])
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index 2f6bd0b460136e3c653cdbf485b70044475b8fbd..576e0d68ce2d079ff4c0f0198c78af661d66bd85 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -16,7 +16,7 @@ import TrackballControls from './controls/trackball'
 import { Viewport } from './camera/util'
 import { resizeCanvas } from './util';
 import { createContext, getGLContext, WebGLContext } from 'mol-gl/webgl/context';
-import { Representation } from 'mol-repr';
+import { Representation } from 'mol-repr/representation';
 import { createRenderTarget } from 'mol-gl/webgl/render-target';
 import Scene from 'mol-gl/scene';
 import { RenderVariant } from 'mol-gl/webgl/render-item';
diff --git a/src/mol-geo/geometry/color-data.ts b/src/mol-geo/geometry/color-data.ts
index d9d798acc569fbbace36806b517015e0690e11fd..fe85ae1bc6e206d2a03a0c57aaf68830d3446894 100644
--- a/src/mol-geo/geometry/color-data.ts
+++ b/src/mol-geo/geometry/color-data.ts
@@ -6,14 +6,13 @@
 
 import { ValueCell } from 'mol-util';
 import { TextureImage, createTextureImage } from 'mol-gl/renderable/util';
-import { Color, ColorMap } from 'mol-util/color';
+import { Color } from 'mol-util/color';
 import { Vec2, Vec3 } from 'mol-math/linear-algebra';
 import { LocationIterator } from '../util/location-iterator';
 import { NullLocation } from 'mol-model/location';
-import { LocationColor, ColorThemeProps, ColorTheme, ColorThemeName, ScaleLegend, TableLegend, ColorScaleName, getColorScaleFromName } from 'mol-theme/color';
+import { LocationColor, ColorTheme } from 'mol-theme/color';
 import { RuntimeContext } from 'mol-task';
 import { getGranularity } from './geometry';
-import { Structure } from 'mol-model/structure';
 
 export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance'
 
@@ -25,37 +24,6 @@ export type ColorData = {
     dColorType: ValueCell<string>,
 }
 
-export interface ColorProps {
-    colorTheme: ColorThemeName
-    colorList?: Color[] | ColorScaleName
-    colorMap?: ColorMap<any>
-    colorDomain?: [number, number]
-    colorValue?: Color
-    colorFunction?: LocationColor,
-    colorGranularity?: ColorType,
-    colorDescription?: string,
-    colorLegend?: ScaleLegend | TableLegend
-    structure?: Structure
-}
-
-export function getColorThemeProps(props: ColorProps): ColorThemeProps {
-    const p: ColorThemeProps = {
-        name: props.colorTheme
-    }
-    if (props.colorDomain !== undefined) p.domain = props.colorDomain
-    if (props.colorList !== undefined) {
-        p.list = typeof props.colorList === 'string' ? getColorScaleFromName(props.colorList) : props.colorList
-    }
-    if (props.colorMap !== undefined) p.map = props.colorMap
-    if (props.colorValue !== undefined) p.value = props.colorValue
-    if (props.structure !== undefined) p.structure = props.structure
-    if (props.colorFunction !== undefined) p.color = props.colorFunction
-    if (props.colorGranularity !== undefined) p.granularity = props.colorGranularity
-    if (props.colorDescription !== undefined) p.description = props.colorDescription
-    if (props.colorLegend !== undefined) p.legend = props.colorLegend
-    return p
-}
-
 export function createColors(ctx: RuntimeContext, locationIt: LocationIterator, colorTheme: ColorTheme, colorData?: ColorData): Promise<ColorData> {
     switch (getGranularity(locationIt, colorTheme.granularity)) {
         case 'uniform': return createUniformColor(ctx, locationIt, colorTheme.color, colorData)
diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts
index 1e6575fbf7ea4bab48105808a5e02b754bf1f0c9..50dfc577d7e0cca54bd64994313d39bdc6d0d0af 100644
--- a/src/mol-geo/geometry/direct-volume/direct-volume.ts
+++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts
@@ -17,9 +17,10 @@ import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { TransformData } from '../transform-data';
 import { createColors } from '../color-data';
 import { createMarkers } from '../marker-data';
-import { Geometry, Theme } from '../geometry';
+import { Geometry } from '../geometry';
 import { transformPositionArray } from 'mol-geo/util';
 import { calculateBoundingSphere } from 'mol-gl/renderable/util';
+import { Theme } from 'mol-theme/theme';
 
 const VolumeBox = Box()
 const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][]
diff --git a/src/mol-geo/geometry/direct-volume/transfer-function.ts b/src/mol-geo/geometry/direct-volume/transfer-function.ts
index 1679daa27fe7867c4e128141509e5bdd362f4a41..e93515f9c3e814445f6701078fb4dddcb13a83e2 100644
--- a/src/mol-geo/geometry/direct-volume/transfer-function.ts
+++ b/src/mol-geo/geometry/direct-volume/transfer-function.ts
@@ -29,7 +29,7 @@ export function createTransferFunctionTexture(controlPoints: ControlPoint[], tex
     ]
     const scale = ColorScale.create({
         domain: [0, 1],
-        list: ColorMatplotlib.viridis
+        listOrName: ColorMatplotlib.viridis
     })
 
     const n = 256
diff --git a/src/mol-geo/geometry/geometry.ts b/src/mol-geo/geometry/geometry.ts
index 2bf275c6a9590a367dcbdf54fcb75e886fa87985..c2c082d3150d260ccf45bfb5f31fa9324f32c174 100644
--- a/src/mol-geo/geometry/geometry.ts
+++ b/src/mol-geo/geometry/geometry.ts
@@ -9,15 +9,14 @@ import { Points } from './points/points';
 import { RenderableState } from 'mol-gl/renderable';
 import { ValueCell } from 'mol-util';
 import { BaseValues } from 'mol-gl/renderable/schema';
-import { Color } from 'mol-util/color';
-import { ColorThemeOptions, ColorThemeName, ColorScaleOptions, ColorScaleName, ColorTheme } from 'mol-theme/color';
 import { LocationIterator } from '../util/location-iterator';
-import { ColorType, getColorThemeProps } from './color-data';
-import { SizeType, getSizeThemeProps } from './size-data';
+import { ColorType } from './color-data';
+import { SizeType } from './size-data';
 import { Lines } from './lines/lines';
 import { ParamDefinition as PD } from 'mol-util/param-definition'
 import { DirectVolume } from './direct-volume/direct-volume';
-import { SizeTheme, SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
+import { BuiltInSizeThemeOptions, BuiltInSizeThemeName } from 'mol-theme/size';
+import { BuiltInColorThemeName, BuiltInColorThemeOptions } from 'mol-theme/color';
 
 //
 
@@ -36,18 +35,6 @@ export type VisualQuality = keyof typeof VisualQualityInfo
 export const VisualQualityNames = Object.keys(VisualQualityInfo)
 export const VisualQualityOptions = VisualQualityNames.map(n => [n, n] as [VisualQuality, string])
 
-export interface Theme {
-    color: ColorTheme
-    size: SizeTheme
-}
-
-export function createTheme(props: Geometry.Props) {
-    return {
-        color: ColorTheme(getColorThemeProps(props)),
-        size: SizeTheme(getSizeThemeProps(props))
-    }
-}
-
 //
 
 export type GeometryKindType = {
@@ -76,15 +63,11 @@ export namespace Geometry {
         visible: PD.Boolean('Visible', '', true),
         depthMask: PD.Boolean('Depth Mask', '', true),
         useFog: PD.Boolean('Use Fog', '', false),
-        quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions),
 
-        colorTheme: PD.Select<ColorThemeName>('Color Name', '', 'uniform', ColorThemeOptions),
-        colorList: PD.Select<ColorScaleName>('Color Scale', '', 'default', ColorScaleOptions),
-        colorValue: PD.Color('Color Value', '', Color(0xCCCCCC)),
+        quality: PD.Select<VisualQuality>('Quality', '', 'auto', VisualQualityOptions),
 
-        sizeTheme: PD.Select<SizeThemeName>('Size Name', '', 'uniform', SizeThemeOptions),
-        sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
-        sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
+        colorTheme: PD.Select<BuiltInColorThemeName>('Color Name', '', 'uniform', BuiltInColorThemeOptions),
+        sizeTheme: PD.Select<BuiltInSizeThemeName>('Size Name', '', 'uniform', BuiltInSizeThemeOptions),
     }
     export const DefaultProps = PD.getDefaultValues(Params)
     export type Props = typeof DefaultProps
diff --git a/src/mol-geo/geometry/lines/lines.ts b/src/mol-geo/geometry/lines/lines.ts
index 54954156927bbeeed26faf7d6b57115a64ad1256..4c5a48a7313b0a431ba858066795b32a77a2d1e5 100644
--- a/src/mol-geo/geometry/lines/lines.ts
+++ b/src/mol-geo/geometry/lines/lines.ts
@@ -7,7 +7,7 @@
 import { ValueCell } from 'mol-util'
 import { Mat4 } from 'mol-math/linear-algebra'
 import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
-import { Geometry, Theme } from '../geometry';
+import { Geometry } from '../geometry';
 import { RuntimeContext } from 'mol-task';
 import { createColors } from '../color-data';
 import { createMarkers } from '../marker-data';
@@ -20,6 +20,7 @@ import { LinesBuilder } from './lines-builder';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { calculateBoundingSphere } from 'mol-gl/renderable/util';
 import { Sphere3D } from 'mol-math/geometry';
+import { Theme } from 'mol-theme/theme';
 
 /** Wide line */
 export interface Lines {
diff --git a/src/mol-geo/geometry/mesh/mesh.ts b/src/mol-geo/geometry/mesh/mesh.ts
index 9d4ca0deba32cafc054e75dce3b86452c416eba7..0c1a8f5cf5556010e58731ced5275e18481845ed 100644
--- a/src/mol-geo/geometry/mesh/mesh.ts
+++ b/src/mol-geo/geometry/mesh/mesh.ts
@@ -9,8 +9,7 @@ import { ValueCell } from 'mol-util'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Sphere3D } from 'mol-math/geometry'
 import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
-import { MeshValues } from 'mol-gl/renderable';
-import { Geometry, Theme } from '../geometry';
+import { Geometry } from '../geometry';
 import { createMarkers } from '../marker-data';
 import { TransformData } from '../transform-data';
 import { LocationIterator } from '../../util/location-iterator';
@@ -18,6 +17,8 @@ import { createColors } from '../color-data';
 import { ChunkedArray } from 'mol-data/util';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { calculateBoundingSphere } from 'mol-gl/renderable/util';
+import { Theme } from 'mol-theme/theme';
+import { MeshValues } from 'mol-gl/renderable/mesh';
 
 export interface Mesh {
     readonly kind: 'mesh',
diff --git a/src/mol-geo/geometry/points/points.ts b/src/mol-geo/geometry/points/points.ts
index 84a191bf7559f158dc926384f9d44200c4902270..616e7e057ed2e98404bb6185d41e127ba2fc08c9 100644
--- a/src/mol-geo/geometry/points/points.ts
+++ b/src/mol-geo/geometry/points/points.ts
@@ -7,8 +7,7 @@
 import { ValueCell } from 'mol-util'
 import { Mat4 } from 'mol-math/linear-algebra'
 import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
-import { Geometry, Theme } from '../geometry';
-import { PointsValues } from 'mol-gl/renderable';
+import { Geometry } from '../geometry';
 import { RuntimeContext } from 'mol-task';
 import { createColors } from '../color-data';
 import { createMarkers } from '../marker-data';
@@ -18,6 +17,8 @@ import { LocationIterator } from '../../util/location-iterator';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { calculateBoundingSphere } from 'mol-gl/renderable/util';
 import { Sphere3D } from 'mol-math/geometry';
+import { Theme } from 'mol-theme/theme';
+import { PointsValues } from 'mol-gl/renderable/points';
 
 /** Point cloud */
 export interface Points {
diff --git a/src/mol-geo/geometry/size-data.ts b/src/mol-geo/geometry/size-data.ts
index 06cdcef0c6d48ef6d47a333bf9fc58edb3eb14c1..6b791ed0f5839d00c4c10ccdcaa8f7aff90b6840 100644
--- a/src/mol-geo/geometry/size-data.ts
+++ b/src/mol-geo/geometry/size-data.ts
@@ -10,9 +10,8 @@ import { TextureImage, createTextureImage } from 'mol-gl/renderable/util';
 import { LocationIterator } from '../util/location-iterator';
 import { Location, NullLocation } from 'mol-model/location';
 import { RuntimeContext } from 'mol-task';
-import { SizeThemeProps, SizeTheme, SizeThemeName } from 'mol-theme/size';
+import { SizeTheme } from 'mol-theme/size';
 import { getGranularity } from './geometry';
-import { Structure } from 'mol-model/structure';
 
 export type SizeType = 'uniform' | 'instance' | 'group' | 'groupInstance'
 
@@ -24,22 +23,6 @@ export type SizeData = {
     dSizeType: ValueCell<string>,
 }
 
-export interface SizeProps {
-    sizeTheme: SizeThemeName
-    sizeValue?: number
-    sizeFactor?: number
-    structure?: Structure
-}
-
-export function getSizeThemeProps(props: SizeProps): SizeThemeProps {
-    return {
-        name: props.sizeTheme,
-        value: props.sizeValue,
-        factor: props.sizeFactor,
-        structure: props.structure,
-    }
-}
-
 export async function createSizes(ctx: RuntimeContext, locationIt: LocationIterator, sizeTheme: SizeTheme, sizeData?: SizeData): Promise<SizeData> {
     switch (getGranularity(locationIt, sizeTheme.granularity)) {
         case 'uniform': return createUniformSize(ctx, locationIt, sizeTheme.size, sizeData)
diff --git a/src/mol-gl/render-object.ts b/src/mol-gl/render-object.ts
index 84e892862ffb3bb336c6ed7b716a124cb106a0d3..f4761dea481de4ed1278c44b68947e64d6eb31e1 100644
--- a/src/mol-gl/render-object.ts
+++ b/src/mol-gl/render-object.ts
@@ -4,12 +4,15 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { PointsRenderable, MeshRenderable, RenderableState, MeshValues, PointsValues, LinesValues, LinesRenderable, Renderable } from './renderable'
+import { RenderableState, Renderable } from './renderable'
 import { RenderableValues } from './renderable/schema';
 import { idFactory } from 'mol-util/id-factory';
 import { WebGLContext } from './webgl/context';
 import { GaussianDensityValues, GaussianDensityRenderable } from './renderable/gaussian-density';
 import { DirectVolumeValues, DirectVolumeRenderable } from './renderable/direct-volume';
+import { MeshValues, MeshRenderable } from './renderable/mesh';
+import { PointsValues, PointsRenderable } from './renderable/points';
+import { LinesValues, LinesRenderable } from './renderable/lines';
 
 const getNextId = idFactory(0, 0x7FFFFFFF)
 
diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts
index 8512933e0d78e1beea97d2ba39da357f7bdf8322..370437898cfee60a0df4e37d155640412c21a6fb 100644
--- a/src/mol-gl/renderable.ts
+++ b/src/mol-gl/renderable.ts
@@ -46,8 +46,4 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
         update: () => renderItem.update(),
         dispose: () => renderItem.destroy()
     }
-}
-
-export { MeshRenderable, MeshSchema, MeshValues } from './renderable/mesh'
-export { PointsRenderable, PointsSchema, PointsValues } from './renderable/points'
-export { LinesRenderable, LinesSchema, LinesValues } from './renderable/lines'
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/mol-model/structure/structure/unit/gaussian-density.ts b/src/mol-model/structure/structure/unit/gaussian-density.ts
index 9e63a7ee5e2d3600260e94dd18c7388438aa7725..0acfa52fdea9448162cfda3b52fd94aeb2367424 100644
--- a/src/mol-model/structure/structure/unit/gaussian-density.ts
+++ b/src/mol-model/structure/structure/unit/gaussian-density.ts
@@ -5,7 +5,6 @@
  */
 
 import { Unit, StructureElement, ElementIndex } from 'mol-model/structure';
-import { SizeTheme } from 'mol-theme/size';
 import { GaussianDensity } from 'mol-math/geometry/gaussian-density';
 import { Task, RuntimeContext } from 'mol-task';
 import { DensityData } from 'mol-math/geometry';
@@ -13,6 +12,7 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { GaussianDensityTexture } from 'mol-math/geometry/gaussian-density/gpu';
 import { Texture } from 'mol-gl/webgl/texture';
 import { WebGLContext } from 'mol-gl/webgl/context';
+import { PhysicalSizeTheme } from 'mol-theme/size/physical';
 
 export const GaussianDensityParams = {
     resolution: PD.Numeric('Resolution', '', 1, 0.1, 10, 0.1),
@@ -43,7 +43,7 @@ function getConformationAndRadius(unit: Unit) {
     }
 
     const l = StructureElement.create(unit)
-    const sizeTheme = SizeTheme({ name: 'physical' })
+    const sizeTheme = PhysicalSizeTheme({}, {})
     const radius = (index: number) => {
         l.element = index as ElementIndex
         return sizeTheme.size(l)
diff --git a/src/mol-plugin/state/objects.ts b/src/mol-plugin/state/objects.ts
index cb2cf337c0014d2a58f957595bce61982c4b9b3b..93b8aa819498e9030408fb4a46e6a6b87fb24515 100644
--- a/src/mol-plugin/state/objects.ts
+++ b/src/mol-plugin/state/objects.ts
@@ -7,7 +7,7 @@
 import { PluginStateObject } from './base';
 import { CifFile } from 'mol-io/reader/cif';
 import { Model as _Model, Structure as _Structure } from 'mol-model/structure'
-import { StructureRepresentation } from 'mol-repr/structure/index';
+import { StructureRepresentation } from 'mol-repr/structure/representation';
 
 const _create = PluginStateObject.Create
 
diff --git a/src/mol-plugin/state/transforms/visuals.ts b/src/mol-plugin/state/transforms/visuals.ts
index 3dbb0a621f161399802b8184f55767f729aa3dc6..dc7a49f265798d5d11476f06cc2591312e153ae2 100644
--- a/src/mol-plugin/state/transforms/visuals.ts
+++ b/src/mol-plugin/state/transforms/visuals.ts
@@ -8,9 +8,16 @@ import { Transformer } from 'mol-state';
 import { Task } from 'mol-task';
 import { PluginStateTransform } from '../base';
 import { PluginStateObjects as SO } from '../objects';
-//import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon';
-import { BallAndStickRepresentation, DefaultBallAndStickProps } from 'mol-repr/structure/representation/ball-and-stick';
+// import { CartoonRepresentation, DefaultCartoonProps } from 'mol-repr/structure/representation/cartoon';
+// import { BallAndStickRepresentation } from 'mol-repr/structure/representation/ball-and-stick';
 import { PluginContext } from 'mol-plugin/context';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
+import { RepresentationRegistry } from 'mol-repr/representation';
+
+const colorThemeRegistry = new ColorTheme.Registry()
+const sizeThemeRegistry = new SizeTheme.Registry()
+const representationRegistry = new RepresentationRegistry()
 
 export { CreateStructureRepresentation }
 namespace CreateStructureRepresentation { export interface Params { } }
@@ -21,14 +28,15 @@ const CreateStructureRepresentation = PluginStateTransform.Create<SO.Structure,
     to: [SO.StructureRepresentation3D],
     apply({ a, params }, plugin: PluginContext) {
         return Task.create('Structure Representation', async ctx => {
-            const repr = BallAndStickRepresentation(); // CartoonRepresentation();
-            await repr.createOrUpdate({ webgl: plugin.canvas3d.webgl }, DefaultBallAndStickProps, a.data).runInContext(ctx);
+            const repr = representationRegistry.create('cartoon', { colorThemeRegistry, sizeThemeRegistry }, a.data)
+            // const repr = BallAndStickRepresentation(); // CartoonRepresentation();
+            await repr.createOrUpdate({ webgl: plugin.canvas3d.webgl, colorThemeRegistry, sizeThemeRegistry }, {}, {}, a.data).runInContext(ctx);
             return new SO.StructureRepresentation3D({ label: 'Visual Repr.' }, repr);
         });
     },
     update({ a, b }, plugin: PluginContext) {
         return Task.create('Structure Representation', async ctx => {
-            await b.data.createOrUpdate({ webgl: plugin.canvas3d.webgl }, b.data.props, a.data).runInContext(ctx);
+            await b.data.createOrUpdate({ webgl: plugin.canvas3d.webgl, colorThemeRegistry, sizeThemeRegistry }, b.data.props, {}, a.data).runInContext(ctx);
             return Transformer.UpdateResult.Updated;
         });
     }
diff --git a/src/mol-repr/index.ts b/src/mol-repr/representation.ts
similarity index 58%
rename from src/mol-repr/index.ts
rename to src/mol-repr/representation.ts
index 2ebfe22338168d79a89269562d1033fd98045b11..a0868ba3cc0532cebc2297f733dd97af5bdd0e23 100644
--- a/src/mol-repr/index.ts
+++ b/src/mol-repr/representation.ts
@@ -12,61 +12,95 @@ import { MarkerAction } from '../mol-geo/geometry/marker-data';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { WebGLContext } from 'mol-gl/webgl/context';
 import { getQualityProps } from './util';
-import { Theme } from 'mol-geo/geometry/geometry';
-// import { ColorTheme } from 'mol-theme/color';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
+import { ThemeProps, Theme, ThemeRegistryContext } from 'mol-theme/theme';
 
 // export interface RepresentationProps {
 //     visuals?: string[]
 // }
 export type RepresentationProps = { [k: string]: any }
 
+//
+
+export interface RepresentationProvider<D, P extends PD.Params> {
+    readonly factory: (defaultProps: PD.DefaultValues<P>) => Representation<D, PD.DefaultValues<P>>
+    readonly params: (ctx: ThemeRegistryContext, data: D) => P
+}
+
+export class RepresentationRegistry<D> {
+    private _list: { name: string, provider: RepresentationProvider<D, any> }[] = []
+    private _map = new Map<string, RepresentationProvider<D, any>>()
+
+    constructor() {};
+
+    add<P extends PD.Params>(name: string, factory: RepresentationProvider<D, P>['factory'], params: RepresentationProvider<D, P>['params']) {
+        const provider = { factory, params } as RepresentationProvider<D, P>
+        this._list.push({ name, provider })
+        this._map.set(name, provider)
+    }
+
+    get(id: string) {
+        return this._map.get(id)
+    }
+
+    create(id: string, ctx: ThemeRegistryContext, data: D, props = {}): Representation<D, any> {
+        const provider = this.get(id)
+        return provider ? provider.factory({ ...PD.getDefaultValues(provider.params(ctx, data)), ...props }) : Representation.Empty
+    }
+
+    get list() {
+        return this._list
+    }
+}
+
+//
+
 export interface RepresentationContext {
     webgl?: WebGLContext
+    colorThemeRegistry: ColorTheme.Registry
+    sizeThemeRegistry: SizeTheme.Registry
 }
 
-export interface Representation<D, P extends RepresentationProps = {}> {
+export { Representation }
+interface Representation<D, P extends RepresentationProps = {}> {
     readonly label: string
-    readonly params: PD.Params
     readonly renderObjects: ReadonlyArray<RenderObject>
     readonly props: Readonly<P>
-    createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, data?: D) => Task<void>
+    createOrUpdate: (ctx: RepresentationContext, props?: Partial<P>, themeProps?: ThemeProps, data?: D) => Task<void>
     getLoci: (pickingId: PickingId) => Loci
     mark: (loci: Loci, action: MarkerAction) => boolean
     destroy: () => void
 }
-
-export namespace Representation {
+namespace Representation {
     export type Any = Representation<any>
-    export const Empty: Representation<undefined> = {
-        label: '', params: {}, renderObjects: [], props: {},
+    export const Empty: Representation<any> = {
+        label: '', renderObjects: [], props: {},
         createOrUpdate: () => Task.constant('', undefined),
         getLoci: () => EmptyLoci,
         mark: () => false,
         destroy: () => {}
     }
 
-    export function createMulti<D, P extends RepresentationProps = {}>(label: string, params: PD.Params, defaultProps: P, reprList: Representation<D, P>[]): Representation<D, P> {
-        let currentProps: P
+    export type Def<P extends RepresentationProps = {}> = { [k: string]: (defaultProps: P) => Representation<any, P> }
+
+    export function createMulti<D, P extends RepresentationProps = {}>(label: string, defaultProps: P, reprDefs: Def<P>): Representation<D, P> {
+        let currentProps: P = Object.assign({}, defaultProps)
         let currentData: D
 
-        const visualsOptions: [string, string][] = []
-        for (let i = 0, il = reprList.length; i < il; ++i) {
-            visualsOptions.push([ i.toString(), reprList[i].label ])
-        }
-        params['visuals'] = PD.MultiSelect<string>('Visuals', '', ['surface'], visualsOptions)
-
-        if (!defaultProps.visuals) {
-            defaultProps.visuals = reprList.map((r, i) => i.toString())
-        }
+        const reprMap: { [k: number]: string } = {}
+        const reprList: Representation<D, P>[] = Object.keys(reprDefs).map((name, i) => {
+            reprMap[i] = name
+            return reprDefs[name](defaultProps)
+        })
 
         return {
             label,
-            params,
             get renderObjects() {
                 const { visuals } = currentProps
                 const renderObjects: RenderObject[] = []
                 for (let i = 0, il = reprList.length; i < il; ++i) {
-                    if (!visuals || visuals.includes(i.toString())) {
+                    if (!visuals || visuals.includes(reprMap[i])) {
                         renderObjects.push(...reprList[i].renderObjects)
                     }
                 }
@@ -77,16 +111,16 @@ export namespace Representation {
                 reprList.forEach(r => Object.assign(props, r.props))
                 return props as P
             },
-            createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, data?: D) => {
+            createOrUpdate: (ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, data?: D) => {
                 if (data) currentData = data
-                const qualityProps = getQualityProps(Object.assign({}, currentProps, props), data)
-                currentProps = Object.assign({}, defaultProps, currentProps, props, qualityProps)
+                const qualityProps = getQualityProps(Object.assign({}, currentProps, props), currentData)
+                Object.assign(currentProps, props, qualityProps)
 
                 const { visuals } = currentProps
                 return Task.create(`Creating '${label}' representation`, async runtime => {
                     for (let i = 0, il = reprList.length; i < il; ++i) {
-                        if (!visuals || visuals.includes(i.toString())) {
-                            await reprList[i].createOrUpdate(ctx, currentProps, currentData).runInContext(runtime)
+                        if (!visuals || visuals.includes(reprMap[i])) {
+                            await reprList[i].createOrUpdate(ctx, currentProps, themeProps, currentData).runInContext(runtime)
                         }
                     }
                 })
@@ -116,7 +150,8 @@ export namespace Representation {
 
 //
 
-export interface VisualContext extends RepresentationContext {
+export interface VisualContext {
+    webgl?: WebGLContext
     runtime: RuntimeContext,
 }
 
diff --git a/src/mol-repr/shape/index.ts b/src/mol-repr/shape/representation.ts
similarity index 91%
rename from src/mol-repr/shape/index.ts
rename to src/mol-repr/shape/representation.ts
index 632458983dd63be0c085552b95fa36daae7cfeaf..718f68ce30e76ccee8487d969e53f7b234de776e 100644
--- a/src/mol-repr/shape/index.ts
+++ b/src/mol-repr/shape/representation.ts
@@ -6,25 +6,26 @@
 
 import { Task } from 'mol-task'
 import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object';
-import { RepresentationProps, Representation, RepresentationContext } from '..';
+import { RepresentationProps, Representation, RepresentationContext } from '../representation';
 import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
 import { ValueCell } from 'mol-util';
-import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color';
 import { Shape } from 'mol-model/shape';
 import { OrderedSet, Interval } from 'mol-data/int';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
-import { createRenderableState, createTheme } from 'mol-geo/geometry/geometry';
+import { createRenderableState } from 'mol-geo/geometry/geometry';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
+import { ThemeProps, createTheme } from 'mol-theme/theme';
 
 export interface ShapeRepresentation<P extends RepresentationProps = {}> extends Representation<Shape, P> { }
 
 export const ShapeParams = {
     ...Mesh.Params,
-    colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions)
+    // TODO
+    // colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'shape-group', ColorThemeOptions)
 }
 export const DefaultShapeProps = PD.getDefaultValues(ShapeParams)
 export type ShapeProps = typeof DefaultShapeProps
@@ -38,7 +39,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation
     let _shape: Shape
     let currentProps: P
 
-    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, shape?: Shape) {
+    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, shape?: Shape) {
         currentProps = Object.assign({}, DefaultShapeProps, currentProps, props)
         if (shape) _shape = shape
 
@@ -49,7 +50,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation
 
             const mesh = _shape.mesh
             const locationIt = ShapeGroupIterator.fromShape(_shape)
-            const theme = createTheme(currentProps)
+            const theme = createTheme(ctx, currentProps, themeProps, {})
             const transform = createIdentityTransform()
 
             const values = await Mesh.createValues(runtime, mesh, transform, locationIt, theme, currentProps)
@@ -62,7 +63,6 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation
 
     return {
         label: 'Shape mesh',
-        params: ShapeParams,
         get renderObjects () { return renderObjects },
         get props () { return currentProps },
         createOrUpdate,
diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts
index 58529f5dd1b6c43a45a5ace7b7f01a0544052ea2..607a1047b87f479f60330c241132239f88548098 100644
--- a/src/mol-repr/structure/complex-representation.ts
+++ b/src/mol-repr/structure/complex-representation.ts
@@ -8,23 +8,24 @@
 import { Structure } from 'mol-model/structure';
 import { Task } from 'mol-task'
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { StructureProps, StructureRepresentation, StructureParams } from './index';
+import { StructureProps, StructureRepresentation } from './representation';
 import { ComplexVisual } from './complex-visual';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
-import { RepresentationContext } from 'mol-repr';
-import { createTheme, Theme } from 'mol-geo/geometry/geometry';
+import { RepresentationContext } from 'mol-repr/representation';
+import { Theme, ThemeProps, createTheme } from 'mol-theme/theme';
 
-export function ComplexRepresentation<P extends StructureProps>(label: string, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> {
+export function ComplexRepresentation<P extends StructureProps>(label: string, defaultProps: P, visualCtor: () => ComplexVisual<P>): StructureRepresentation<P> {
     let visual: ComplexVisual<P> | undefined
+
     let _structure: Structure
-    let _props: P
+    let _props: P = Object.assign({}, defaultProps)
     let _theme: Theme
 
-    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) {
+    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, structure?: Structure) {
         if (structure) _structure = structure
-        _props = Object.assign({}, _props, props, { structure: _structure })
-        _theme = createTheme(_props)
+        _props = Object.assign({}, _props, props)
+        _theme = createTheme(ctx, { structure: _structure }, props, themeProps, _theme)
 
         return Task.create('Creating or updating ComplexRepresentation', async runtime => {
             if (!visual) visual = visualCtor()
@@ -46,7 +47,6 @@ export function ComplexRepresentation<P extends StructureProps>(label: string, v
 
     return {
         label,
-        params: StructureParams, // TODO
         get renderObjects() {
             return visual && visual.renderObject ? [ visual.renderObject ] : []
         },
diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts
index 4440129f999ebde9726e73d8ada58117e3db3743..75363b93f38601606a1af658ce5def7b62845969 100644
--- a/src/mol-repr/structure/complex-visual.ts
+++ b/src/mol-repr/structure/complex-visual.ts
@@ -5,23 +5,26 @@
  */
 
 import { Structure } from 'mol-model/structure';
-import { Visual, VisualContext } from '..';
+import { Visual, VisualContext } from '../representation';
 import { MeshRenderObject, LinesRenderObject, PointsRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object';
 import { createComplexMeshRenderObject, UnitKind, UnitKindOptions } from './visual/util/common';
-import { StructureProps, StructureMeshParams, StructureParams } from './index';
+import { StructureProps, StructureMeshParams, StructureParams } from './representation';
 import { deepEqual, ValueCell } from 'mol-util';
 import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
 import { Interval } from 'mol-data/int';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { RenderableValues } from 'mol-gl/renderable/schema';
 import { createSizes } from 'mol-geo/geometry/size-data';
-import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry';
+import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { createColors } from 'mol-geo/geometry/color-data';
 import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
-import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util';
+import { VisualUpdateState } from 'mol-repr/util';
+import { Theme } from 'mol-theme/theme';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
 
 export interface  ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { }
 
@@ -40,7 +43,7 @@ interface ComplexVisualBuilder<P extends ComplexProps, G extends Geometry> {
     createLocationIterator(structure: Structure): LocationIterator
     getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
     mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean,
-    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
+    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme): void
 }
 
 interface ComplexVisualGeometryBuilder<P extends ComplexProps, G extends Geometry> extends ComplexVisualBuilder<P, G> {
@@ -56,6 +59,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
 
     let renderObject: ComplexRenderObject | undefined
     let currentProps: P
+    let currentTheme: Theme
     let geometry: Geometry
     let currentStructure: Structure
     let locationIt: LocationIterator
@@ -63,6 +67,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
 
     async function create(ctx: VisualContext, structure: Structure, theme: Theme, props: Partial<P> = {}) {
         currentProps = Object.assign({}, defaultProps, props)
+        currentTheme = theme
         currentStructure = structure
 
         conformationHash = Structure.conformationHash(currentStructure)
@@ -79,7 +84,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
 
         locationIt.reset()
         VisualUpdateState.reset(updateState)
-        setUpdateState(updateState, newProps, currentProps)
+        setUpdateState(updateState, newProps, currentProps, theme, currentTheme)
 
         const newConformationHash = Structure.conformationHash(currentStructure)
         if (newConformationHash !== conformationHash) {
@@ -87,7 +92,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
             updateState.createGeometry = true
         }
 
-        if (colorChanged(currentProps, newProps)) updateState.updateColor = true
+        if (ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true
         if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
 
         //
@@ -113,6 +118,7 @@ export function ComplexVisual<P extends ComplexMeshProps>(builder: ComplexVisual
         updateRenderableState(renderObject.state, newProps)
 
         currentProps = newProps
+        currentTheme = theme
         return true
     }
 
@@ -178,9 +184,9 @@ export interface ComplexMeshVisualBuilder<P extends ComplexMeshProps> extends Co
 export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> {
     return ComplexVisual({
         ...builder,
-        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
-            builder.setUpdateState(state, newProps, currentProps)
-            if (sizeChanged(currentProps, newProps)) state.createGeometry = true
+        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => {
+            builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme)
+            if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         createEmptyGeometry: Mesh.createEmpty,
         createRenderObject: createComplexMeshRenderObject,
diff --git a/src/mol-repr/structure/registry.ts b/src/mol-repr/structure/registry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90822d785f74c2f767e613df604f01718231a643
--- /dev/null
+++ b/src/mol-repr/structure/registry.ts
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Structure } from 'mol-model/structure';
+import { RepresentationProvider, RepresentationRegistry } from '../representation';
+import { CartoonRepresentationProvider } from './representation/cartoon';
+
+export class StructureRepresentationRegistry extends RepresentationRegistry<Structure> {
+    constructor() {
+        super()
+        Object.keys(BuiltInStructureRepresentations).forEach(name => {
+            const p = (BuiltInStructureRepresentations as { [k: string]: RepresentationProvider<Structure, any> })[name]
+            this.add(name, p.factory, p.params)
+        })
+    }
+}
+
+export const BuiltInStructureRepresentations = {
+    'cartoon': CartoonRepresentationProvider,
+}
+export type BuiltInStructureRepresentationsName = keyof typeof BuiltInStructureRepresentations
+export const BuiltInStructureRepresentationsNames = Object.keys(BuiltInStructureRepresentations)
+export const BuiltInStructureRepresentationsOptions = BuiltInStructureRepresentationsNames.map(n => [n, n] as [BuiltInStructureRepresentationsName, string])
\ No newline at end of file
diff --git a/src/mol-repr/structure/index.ts b/src/mol-repr/structure/representation.ts
similarity index 81%
rename from src/mol-repr/structure/index.ts
rename to src/mol-repr/structure/representation.ts
index a0fb183ab0af993ff82b53c30450c6c08635bc00..80a6116037aac73908e19e7a39ab7692a2266b6f 100644
--- a/src/mol-repr/structure/index.ts
+++ b/src/mol-repr/structure/representation.ts
@@ -6,9 +6,7 @@
  */
 
 import { Structure } from 'mol-model/structure';
-import { ColorThemeName, ColorThemeOptions } from 'mol-theme/color';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { Representation, RepresentationProps } from '..';
+import { Representation, RepresentationProps, RepresentationProvider } from '../representation';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Geometry } from 'mol-geo/geometry/geometry';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -17,12 +15,13 @@ import { Lines } from 'mol-geo/geometry/lines/lines';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
 
 export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { }
-// export interface  StructureVisual<P extends RepresentationProps = {}> extends Visual<Structure, P> { }
+
+export type StructureRepresentationProvider<P extends PD.Params> = RepresentationProvider<Structure, P>
+
+//
 
 export const StructureParams = {
     ...Geometry.Params,
-    colorTheme: PD.Select<ColorThemeName>('Color Theme', '', 'polymer-index', ColorThemeOptions),
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
 }
 export const DefaultStructureProps = PD.getDefaultValues(StructureParams)
 export type StructureProps = typeof DefaultStructureProps
diff --git a/src/mol-repr/structure/representation/backbone.ts b/src/mol-repr/structure/representation/backbone.ts
index 33731218d0a9387e5bc7aaa6594ca5807f93f3df..0105026f30b8f29a1e5212a38805aa6d50c6b1f8 100644
--- a/src/mol-repr/structure/representation/backbone.ts
+++ b/src/mol-repr/structure/representation/backbone.ts
@@ -1,25 +1,29 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { PolymerBackboneVisual, PolymerBackboneParams } from '../visual/polymer-backbone-cylinder';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { UnitsRepresentation } from '../units-representation';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { PolymerBackboneVisual, PolymerBackboneParams } from '../visual/polymer-backbone-cylinder';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { UnitsRepresentation } from '../units-representation';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const BackboneParams = {
-    ...PolymerBackboneParams
-}
-export const DefaultBackboneProps = PD.getDefaultValues(BackboneParams)
-export type BackboneProps = typeof DefaultBackboneProps
+// export const BackboneParams = {
+//     ...PolymerBackboneParams,
+// }
+// export function getBackboneParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return BackboneParams // TODO return copy
+// }
+// export type BackboneProps = PD.DefaultValues<typeof BackboneParams>
 
-export type BackboneRepresentation = StructureRepresentation<BackboneProps>
+// export type BackboneRepresentation = StructureRepresentation<BackboneProps>
 
-export function BackboneRepresentation(): BackboneRepresentation {
-    return Representation.createMulti('Backbone', BackboneParams, DefaultBackboneProps, [
-        UnitsRepresentation('Polymer backbone cylinder', PolymerBackboneVisual)
-    ] as StructureRepresentation<BackboneProps>[])
-}
\ No newline at end of file
+// export function BackboneRepresentation(defaultProps: BackboneProps): BackboneRepresentation {
+//     return Representation.createMulti('Backbone', defaultProps, [
+//         UnitsRepresentation('Polymer backbone cylinder', defaultProps, PolymerBackboneVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/ball-and-stick.ts b/src/mol-repr/structure/representation/ball-and-stick.ts
index 7f94d0bf8be200c636df1461daa11fcacd889986..e8efe097138b194a47823d1b92fefa5a1e095fe7 100644
--- a/src/mol-repr/structure/representation/ball-and-stick.ts
+++ b/src/mol-repr/structure/representation/ball-and-stick.ts
@@ -1,38 +1,38 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
-import { IntraUnitLinkVisual, IntraUnitLinkParams } from '../visual/intra-unit-link-cylinder';
-import { InterUnitLinkVisual, InterUnitLinkParams } from '../visual/inter-unit-link-cylinder';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { UnitKind, UnitKindOptions } from '../visual/util/common';
-import { UnitsRepresentation } from '../units-representation';
-import { ComplexRepresentation } from '../complex-representation';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
+// import { IntraUnitLinkVisual, IntraUnitLinkParams } from '../visual/intra-unit-link-cylinder';
+// import { InterUnitLinkVisual, InterUnitLinkParams } from '../visual/inter-unit-link-cylinder';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { UnitsRepresentation } from '../units-representation';
+// import { ComplexRepresentation } from '../complex-representation';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const BallAndStickParams = {
-    ...ElementSphereParams,
-    ...IntraUnitLinkParams,
-    ...InterUnitLinkParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
-    unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions),
-}
-export const DefaultBallAndStickProps = PD.getDefaultValues(BallAndStickParams)
-export type BallAndStickProps = typeof DefaultBallAndStickProps
+// export const BallAndStickParams = {
+//     ...ElementSphereParams,
+//     ...IntraUnitLinkParams,
+//     ...InterUnitLinkParams,
+//     // TODO
+//     // unitKinds: PD.MultiSelect<UnitKind>('Unit Kind', '', ['atomic'], UnitKindOptions),
+// }
+// export function getBallAndStickParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return BallAndStickParams // TODO return copy
+// }
+// export type BallAndStickProps = PD.DefaultValues<typeof BallAndStickParams>
 
-export type BallAndStickRepresentation = StructureRepresentation<BallAndStickProps>
+// export type BallAndStickRepresentation = StructureRepresentation<BallAndStickProps>
 
-export function BallAndStickRepresentation(): BallAndStickRepresentation {
-    return Representation.createMulti('Ball & Stick', BallAndStickParams, DefaultBallAndStickProps, [
-        UnitsRepresentation('Element sphere mesh', ElementSphereVisual),
-        UnitsRepresentation('Intra-unit link cylinder', IntraUnitLinkVisual),
-        ComplexRepresentation('Inter-unit link cylinder', InterUnitLinkVisual)
-    ] as unknown as StructureRepresentation<BallAndStickProps>[]) // TODO avoid cast to unknown
-}
\ No newline at end of file
+// export function BallAndStickRepresentation(defaultProps: BallAndStickProps): BallAndStickRepresentation {
+//     return Representation.createMulti('Ball & Stick', defaultProps, [
+//         UnitsRepresentation('Element sphere mesh', defaultProps, ElementSphereVisual),
+//         UnitsRepresentation('Intra-unit link cylinder', defaultProps, IntraUnitLinkVisual),
+//         ComplexRepresentation('Inter-unit link cylinder', defaultProps, InterUnitLinkVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/carbohydrate.ts b/src/mol-repr/structure/representation/carbohydrate.ts
index 3a0c79e9ad004992b88dcfc125ee2343c186fdbd..6493be0aeaaf44ebb3372d507ee41f7e074efbb7 100644
--- a/src/mol-repr/structure/representation/carbohydrate.ts
+++ b/src/mol-repr/structure/representation/carbohydrate.ts
@@ -1,32 +1,32 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { CarbohydrateSymbolVisual, CarbohydrateSymbolParams } from '../visual/carbohydrate-symbol-mesh';
-import { CarbohydrateLinkVisual, CarbohydrateLinkParams } from '../visual/carbohydrate-link-cylinder';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { ComplexRepresentation } from '../complex-representation';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { CarbohydrateSymbolVisual, CarbohydrateSymbolParams } from '../visual/carbohydrate-symbol-mesh';
+// import { CarbohydrateLinkVisual, CarbohydrateLinkParams } from '../visual/carbohydrate-link-cylinder';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { ComplexRepresentation } from '../complex-representation';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const CarbohydrateParams = {
-    ...CarbohydrateSymbolParams,
-    ...CarbohydrateLinkParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 0.1, 20),
-    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
-}
-export const DefaultCarbohydrateProps = PD.getDefaultValues(CarbohydrateParams)
-export type CarbohydrateProps = typeof DefaultCarbohydrateProps
+// export const CarbohydrateParams = {
+//     ...CarbohydrateSymbolParams,
+//     ...CarbohydrateLinkParams,
+// }
+// export function getCarbohydrateParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return CarbohydrateParams // TODO return copy
+// }
+// export type CarbohydrateProps = PD.DefaultValues<typeof CarbohydrateParams>
 
-export type CarbohydrateRepresentation = StructureRepresentation<CarbohydrateProps>
+// export type CarbohydrateRepresentation = StructureRepresentation<CarbohydrateProps>
 
-export function CarbohydrateRepresentation(): CarbohydrateRepresentation {
-    return Representation.createMulti('Carbohydrate', CarbohydrateParams, DefaultCarbohydrateProps, [
-        ComplexRepresentation('Carbohydrate symbol mesh', CarbohydrateSymbolVisual),
-        ComplexRepresentation('Carbohydrate link cylinder', CarbohydrateLinkVisual)
-    ] as StructureRepresentation<CarbohydrateProps>[])
-}
\ No newline at end of file
+// export function CarbohydrateRepresentation(defaultProps: CarbohydrateProps): CarbohydrateRepresentation {
+//     return Representation.createMulti('Carbohydrate', defaultProps, [
+//         ComplexRepresentation('Carbohydrate symbol mesh', defaultProps, CarbohydrateSymbolVisual),
+//         ComplexRepresentation('Carbohydrate link cylinder', defaultProps, CarbohydrateLinkVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/cartoon.ts b/src/mol-repr/structure/representation/cartoon.ts
index 59e0639758375d2600943412da45f82a8ef3a2e2..da2483be5107b99964329c1542ca7de7bb97f0c0 100644
--- a/src/mol-repr/structure/representation/cartoon.ts
+++ b/src/mol-repr/structure/representation/cartoon.ts
@@ -4,34 +4,48 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { PolymerTraceVisual,  PolymerTraceParams } from '../visual/polymer-trace-mesh';
-import { PolymerGapVisual, PolymerGapParams } from '../visual/polymer-gap-cylinder';
-import { NucleotideBlockVisual, NucleotideBlockParams } from '../visual/nucleotide-block-mesh';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
+import { PolymerTraceVisual,  PolymerTraceParams, PolymerTraceProps } from '../visual/polymer-trace-mesh';
+import { PolymerGapVisual, PolymerGapParams, PolymerGapProps } from '../visual/polymer-gap-cylinder';
+import { NucleotideBlockVisual, NucleotideBlockParams, NucleotideBlockProps } from '../visual/nucleotide-block-mesh';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { UnitsRepresentation } from '../units-representation';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
-import { PolymerDirectionVisual, PolymerDirectionParams } from '../visual/polymer-direction-wedge';
+import { StructureRepresentation, StructureRepresentationProvider } from '../representation';
+import { Representation } from 'mol-repr/representation';
+import { PolymerDirectionVisual, PolymerDirectionParams, PolymerDirectionProps } from '../visual/polymer-direction-wedge';
+import { Structure } from 'mol-model/structure';
+import { ThemeRegistryContext } from 'mol-theme/theme';
+import { BuiltInSizeThemeName, BuiltInSizeThemeOptions } from 'mol-theme/size';
+import { BuiltInColorThemeOptions, BuiltInColorThemeName } from 'mol-theme/color';
+
+const CartoonVisuals = {
+    'polymer-trace': (defaultProps: PolymerTraceProps) => UnitsRepresentation('Polymer trace mesh', defaultProps, PolymerTraceVisual),
+    'polymer-gap': (defaultProps: PolymerGapProps) => UnitsRepresentation('Polymer gap cylinder', defaultProps, PolymerGapVisual),
+    'nucleotide-block': (defaultProps: NucleotideBlockProps) => UnitsRepresentation('Nucleotide block mesh', defaultProps, NucleotideBlockVisual),
+    'direction-wedge': (defaultProps: PolymerDirectionProps) => UnitsRepresentation('Polymer direction wedge', defaultProps, PolymerDirectionVisual)
+}
+type CartoonVisualName = keyof typeof CartoonVisuals
+const CartoonVisualOptions = Object.keys(CartoonVisuals).map(name => [name, name] as [CartoonVisualName, string])
 
 export const CartoonParams = {
     ...PolymerTraceParams,
     ...PolymerGapParams,
     ...NucleotideBlockParams,
     ...PolymerDirectionParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01),
+    sizeTheme: PD.Select<BuiltInSizeThemeName>('Size Theme', '', 'uniform', BuiltInSizeThemeOptions),
+    colorTheme: PD.Select<BuiltInColorThemeName>('Color Theme', '', 'polymer-index', BuiltInColorThemeOptions),
+    visuals: PD.MultiSelect<CartoonVisualName>('Visuals', '', ['polymer-trace', 'polymer-gap', 'nucleotide-block'], CartoonVisualOptions),
 }
-export const DefaultCartoonProps = { ...PD.getDefaultValues(CartoonParams), visuals: [ '0', '1', '2' ] }
-export type CartoonProps = typeof DefaultCartoonProps
+export function getCartoonParams(ctx: ThemeRegistryContext, structure: Structure) {
+    return CartoonParams // TODO return copy
+}
+export type CartoonProps = PD.DefaultValues<typeof CartoonParams>
 
 export type CartoonRepresentation = StructureRepresentation<CartoonProps>
+export function CartoonRepresentation(defaultProps: CartoonProps): CartoonRepresentation {
+    return Representation.createMulti('Cartoon', defaultProps, CartoonVisuals as unknown as Representation.Def<CartoonProps>)
+}
 
-export function CartoonRepresentation(): CartoonRepresentation {
-    return Representation.createMulti('Cartoon', CartoonParams, DefaultCartoonProps, [
-        UnitsRepresentation('Polymer trace mesh', PolymerTraceVisual),
-        UnitsRepresentation('Polymer gap cylinder', PolymerGapVisual),
-        UnitsRepresentation('Nucleotide block mesh', NucleotideBlockVisual),
-        UnitsRepresentation('Polymer direction wedge', PolymerDirectionVisual)
-    ] as unknown as StructureRepresentation<CartoonProps>[]) // TODO avoid cast to unknown
+export const CartoonRepresentationProvider: StructureRepresentationProvider<typeof CartoonParams> = {
+    factory: CartoonRepresentation, params: getCartoonParams
 }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/distance-restraint.ts b/src/mol-repr/structure/representation/distance-restraint.ts
index 08ed872669f2632e0d3c9ba64acaeeb7ffc67063..94edde13a8cb99ff0ec108ef8f90f4018a4e99c3 100644
--- a/src/mol-repr/structure/representation/distance-restraint.ts
+++ b/src/mol-repr/structure/representation/distance-restraint.ts
@@ -1,28 +1,29 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { CrossLinkRestraintVisual, CrossLinkRestraintParams } from '../visual/cross-link-restraint-cylinder';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { ComplexRepresentation } from '../complex-representation';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { CrossLinkRestraintVisual, CrossLinkRestraintParams } from '../visual/cross-link-restraint-cylinder';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { ComplexRepresentation } from '../complex-representation';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const DistanceRestraintParams = {
-    ...CrossLinkRestraintParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 0.25, 0, 0.05, 20),
-}
-export const DefaultDistanceRestraintProps = PD.getDefaultValues(DistanceRestraintParams)
-export type DistanceRestraintProps = typeof DefaultDistanceRestraintProps
+// export const DistanceRestraintParams = {
+//     ...CrossLinkRestraintParams,
+// }
+// export function getDistanceRestraintParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return DistanceRestraintParams // TODO return copy
+// }
+// export type DistanceRestraintProps = PD.DefaultValues<typeof DistanceRestraintParams>
 
-export type DistanceRestraintRepresentation = StructureRepresentation<DistanceRestraintProps>
+// export type DistanceRestraintRepresentation = StructureRepresentation<DistanceRestraintProps>
 
-export function DistanceRestraintRepresentation(): DistanceRestraintRepresentation {
-    return Representation.createMulti('Distance restraint', DistanceRestraintParams, DefaultDistanceRestraintProps, [
-        ComplexRepresentation('Cross-link restraint', CrossLinkRestraintVisual)
-    ] as StructureRepresentation<DistanceRestraintProps>[])
-}
\ No newline at end of file
+// export function DistanceRestraintRepresentation(defaultProps: DistanceRestraintProps): DistanceRestraintRepresentation {
+//     return Representation.createMulti('Distance restraint', defaultProps, [
+//         ComplexRepresentation('Cross-link restraint', defaultProps, CrossLinkRestraintVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/molecular-surface.ts b/src/mol-repr/structure/representation/molecular-surface.ts
index 0e8fa626b5c7a151ccd1a6a54c5dd347d2cd13dd..b55aa5faedede552c07c3d9aa8aa7e0a671fb2a7 100644
--- a/src/mol-repr/structure/representation/molecular-surface.ts
+++ b/src/mol-repr/structure/representation/molecular-surface.ts
@@ -1,33 +1,35 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { GaussianSurfaceVisual, GaussianSurfaceParams } from '../visual/gaussian-surface-mesh';
-import { UnitsRepresentation } from '../units-representation';
-import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { GaussianDensityVolumeParams, GaussianDensityVolumeVisual } from '../visual/gaussian-density-volume';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { GaussianSurfaceVisual, GaussianSurfaceParams } from '../visual/gaussian-surface-mesh';
+// import { UnitsRepresentation } from '../units-representation';
+// import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { GaussianDensityVolumeParams, GaussianDensityVolumeVisual } from '../visual/gaussian-density-volume';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const MolecularSurfaceParams = {
-    ...GaussianSurfaceParams,
-    ...GaussianWireframeParams,
-    ...GaussianDensityVolumeParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-}
-export const DefaultMolecularSurfaceProps = { ...PD.getDefaultValues(MolecularSurfaceParams), visuals: [ '0' ] }
-export type MolecularSurfaceProps = typeof DefaultMolecularSurfaceProps
+// export const MolecularSurfaceParams = {
+//     ...GaussianSurfaceParams,
+//     ...GaussianWireframeParams,
+//     ...GaussianDensityVolumeParams,
+// }
+// export function getMolecularSurfaceParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return MolecularSurfaceParams // TODO return copy
+// }
+// export type MolecularSurfaceProps = PD.DefaultValues<typeof MolecularSurfaceParams>
 
-export type MolecularSurfaceRepresentation = StructureRepresentation<MolecularSurfaceProps>
+// export type MolecularSurfaceRepresentation = StructureRepresentation<MolecularSurfaceProps>
 
-export function MolecularSurfaceRepresentation(): MolecularSurfaceRepresentation {
-    return Representation.createMulti('Molecular Surface', MolecularSurfaceParams, DefaultMolecularSurfaceProps, [
-        UnitsRepresentation('Gaussian surface', GaussianSurfaceVisual),
-        UnitsRepresentation('Gaussian wireframe', GaussianWireframeVisual),
-        UnitsRepresentation('Gaussian volume', GaussianDensityVolumeVisual)
-    ] as unknown as StructureRepresentation<MolecularSurfaceProps>[]) // TODO avoid cast to unknown
-}
\ No newline at end of file
+// export function MolecularSurfaceRepresentation(defaultProps: MolecularSurfaceProps): MolecularSurfaceRepresentation {
+//     return Representation.createMulti('Molecular Surface', defaultProps, [
+//         UnitsRepresentation('Gaussian surface', defaultProps, GaussianSurfaceVisual),
+//         UnitsRepresentation('Gaussian wireframe', defaultProps, GaussianWireframeVisual),
+//         UnitsRepresentation('Gaussian volume', defaultProps, GaussianDensityVolumeVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/point.ts b/src/mol-repr/structure/representation/point.ts
index 0e483ee9e0c8e2e8fff096f68a7289365eb7ce8d..efc91f8df4b9d209ffd7cba231bb777863c8e3fe 100644
--- a/src/mol-repr/structure/representation/point.ts
+++ b/src/mol-repr/structure/representation/point.ts
@@ -1,25 +1,29 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { ElementPointVisual, ElementPointParams } from '../visual/element-point';
-import { UnitsRepresentation } from '../units-representation';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { ElementPointVisual, ElementPointParams } from '../visual/element-point';
+// import { UnitsRepresentation } from '../units-representation';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const PointParams = {
-    ...ElementPointParams,
-}
-export const DefaultPointProps = PD.getDefaultValues(PointParams)
-export type PointProps = typeof DefaultPointProps
+// export const PointParams = {
+//     ...ElementPointParams,
+// }
+// export function getPointParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return PointParams // TODO return copy
+// }
+// export type PointProps = PD.DefaultValues<typeof PointParams>
 
-export type PointRepresentation = StructureRepresentation<PointProps>
+// export type PointRepresentation = StructureRepresentation<PointProps>
 
-export function PointRepresentation(): PointRepresentation {
-    return Representation.createMulti('Point', PointParams, DefaultPointProps, [
-        UnitsRepresentation('Point', ElementPointVisual)
-    ] as StructureRepresentation<PointProps>[])
-}
\ No newline at end of file
+// export function PointRepresentation(defaultProps: PointProps): PointRepresentation {
+//     return Representation.createMulti('Point', defaultProps, [
+//         UnitsRepresentation('Point', defaultProps, ElementPointVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/representation/spacefill.ts b/src/mol-repr/structure/representation/spacefill.ts
index 46a8a3e64d37ced19b1ad30bd09aabc95c83b9b3..42f35ae58b1ed7f670570809e92c1753d01cbb26 100644
--- a/src/mol-repr/structure/representation/spacefill.ts
+++ b/src/mol-repr/structure/representation/spacefill.ts
@@ -1,25 +1,29 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
+// /**
+//  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author Alexander Rose <alexander.rose@weirdbyte.de>
+//  */
 
-import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
-import { UnitsRepresentation } from '../units-representation';
-import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { StructureRepresentation } from '../index';
-import { Representation } from 'mol-repr';
+// import { ElementSphereVisual, ElementSphereParams } from '../visual/element-sphere';
+// import { UnitsRepresentation } from '../units-representation';
+// import { ParamDefinition as PD } from 'mol-util/param-definition';
+// import { StructureRepresentation } from '../representation';
+// import { Representation } from 'mol-repr/representation';
+// import { ThemeRegistryContext } from 'mol-theme/theme';
+// import { Structure } from 'mol-model/structure';
 
-export const SpacefillParams = {
-    ...ElementSphereParams
-}
-export const DefaultSpacefillProps = PD.getDefaultValues(SpacefillParams)
-export type SpacefillProps = typeof DefaultSpacefillProps
+// export const SpacefillParams = {
+//     ...ElementSphereParams,
+// }
+// export function getSpacefillParams(ctx: ThemeRegistryContext, structure: Structure) {
+//     return SpacefillParams // TODO return copy
+// }
+// export type SpacefillProps = PD.DefaultValues<typeof SpacefillParams>
 
-export type SpacefillRepresentation = StructureRepresentation<SpacefillProps>
+// export type SpacefillRepresentation = StructureRepresentation<SpacefillProps>
 
-export function SpacefillRepresentation(): SpacefillRepresentation {
-    return Representation.createMulti('Spacefill', SpacefillParams, DefaultSpacefillProps, [
-        UnitsRepresentation('Sphere mesh', ElementSphereVisual)
-    ] as StructureRepresentation<SpacefillProps>[])
-}
\ No newline at end of file
+// export function SpacefillRepresentation(defaultProps: SpacefillProps): SpacefillRepresentation {
+//     return Representation.createMulti('Spacefill', defaultProps, [
+//         UnitsRepresentation('Sphere mesh', defaultProps, ElementSphereVisual)
+//     ])
+// }
\ No newline at end of file
diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts
index 0b419bc140e3a411bbc0c24c4aa5617ce4e4aaba..3f1b1026dfbd7f9f8504b61fe2bc3a9bd8f6b101 100644
--- a/src/mol-repr/structure/units-representation.ts
+++ b/src/mol-repr/structure/units-representation.ts
@@ -8,27 +8,27 @@
 import { Structure, Unit } from 'mol-model/structure';
 import { Task } from 'mol-task'
 import { RenderObject } from 'mol-gl/render-object';
-import { RepresentationProps, Visual, RepresentationContext } from '..';
+import { RepresentationProps, Visual, RepresentationContext } from '../representation';
 import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci';
 import { StructureGroup } from './units-visual';
-import { StructureProps, StructureParams, StructureRepresentation } from './index';
+import { StructureProps, StructureRepresentation } from './representation';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
-import { Theme, createTheme } from 'mol-geo/geometry/geometry';
+import { Theme, ThemeProps, createTheme } from 'mol-theme/theme';
 
 export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<StructureGroup, P> { }
 
-export function UnitsRepresentation<P extends StructureProps>(label: string, visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> {
+export function UnitsRepresentation<P extends StructureProps>(label: string, defaultProps: P, visualCtor: () => UnitsVisual<P>): StructureRepresentation<P> {
     let visuals = new Map<number, { group: Unit.SymmetryGroup, visual: UnitsVisual<P> }>()
 
-    let _props: P
-    let _theme: Theme
     let _structure: Structure
     let _groups: ReadonlyArray<Unit.SymmetryGroup>
+    let _props: P = Object.assign({}, defaultProps)
+    let _theme: Theme
 
-    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, structure?: Structure) {
-        _props = Object.assign({}, _props, props, { structure: structure || _structure })
-        _theme = createTheme(_props)
+    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, structure?: Structure) {
+        _props = Object.assign({}, _props, props)
+        _theme = createTheme(ctx, { structure: structure || _structure }, props, themeProps, _theme)
 
         return Task.create('Creating or updating UnitsRepresentation', async runtime => {
             if (!_structure && !structure) {
@@ -132,7 +132,6 @@ export function UnitsRepresentation<P extends StructureProps>(label: string, vis
 
     return {
         label,
-        params: StructureParams, // TODO
         get renderObjects() {
             const renderObjects: RenderObject[] = []
             visuals.forEach(({ visual }) => {
diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts
index 29a00fc88bb991cf23f2c88a0fa9b921bea4d1c1..5ce13b5dc01dfc7e12e5716bfb173a6757f735bc 100644
--- a/src/mol-repr/structure/units-visual.ts
+++ b/src/mol-repr/structure/units-visual.ts
@@ -5,8 +5,8 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { RepresentationProps, Visual, VisualContext } from '../';
-import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './index';
+import { RepresentationProps, Visual, VisualContext } from '../representation';
+import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams, StructureParams } from './representation';
 import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
 import { MeshRenderObject, PointsRenderObject, LinesRenderObject, DirectVolumeRenderObject } from 'mol-gl/render-object';
 import { createUnitsMeshRenderObject, createUnitsPointsRenderObject, createUnitsTransform, createUnitsLinesRenderObject, createUnitsDirectVolumeRenderObject, UnitKind, UnitKindOptions, includesUnitKind } from './visual/util/common';
@@ -14,7 +14,7 @@ import { deepEqual, ValueCell, UUID } from 'mol-util';
 import { Interval } from 'mol-data/int';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { RenderableValues } from 'mol-gl/renderable/schema';
-import { Geometry, updateRenderableState, Theme } from 'mol-geo/geometry/geometry';
+import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { createMarkers, MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
@@ -24,7 +24,10 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { Points } from 'mol-geo/geometry/points/points';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
-import { VisualUpdateState, colorChanged, sizeChanged } from 'mol-repr/util';
+import { VisualUpdateState } from 'mol-repr/util';
+import { Theme } from 'mol-theme/theme';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
 
 export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup }
 
@@ -52,7 +55,7 @@ interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> {
     createLocationIterator(group: Unit.SymmetryGroup): LocationIterator
     getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci
     mark(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean): boolean
-    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
+    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme): void
 }
 
 interface UnitsVisualGeometryBuilder<P extends UnitsProps, G extends Geometry> extends UnitsVisualBuilder<P, G> {
@@ -68,6 +71,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu
 
     let renderObject: UnitsRenderObject | undefined
     let currentProps: P
+    let currentTheme: Theme
     let geometry: Geometry
     let currentGroup: Unit.SymmetryGroup
     let currentStructure: Structure
@@ -76,6 +80,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu
 
     async function create(ctx: VisualContext, group: Unit.SymmetryGroup, theme: Theme, props: Partial<P> = {}) {
         currentProps = Object.assign({}, defaultProps, props, { structure: currentStructure })
+        currentTheme = theme
         currentGroup = group
 
         const unit = group.units[0]
@@ -97,7 +102,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu
 
         locationIt.reset()
         VisualUpdateState.reset(updateState)
-        setUpdateState(updateState, newProps, currentProps)
+        setUpdateState(updateState, newProps, currentProps, theme, currentTheme)
 
         const newConformationId = Unit.conformationId(unit)
         if (newConformationId !== currentConformationId) {
@@ -107,7 +112,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu
 
         if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
 
-        if (colorChanged(currentProps, newProps)) updateState.updateColor = true
+        if (ColorTheme.areEqual(theme.color, currentTheme.color)) updateState.updateColor = true
         if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
 
         //
@@ -143,6 +148,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu
         updateRenderableState(renderObject.state, newProps)
 
         currentProps = newProps
+        currentTheme = theme
     }
 
     return {
@@ -212,9 +218,9 @@ export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> extends UnitsV
 export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> {
     return UnitsVisual({
         ...builder,
-        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
-            builder.setUpdateState(state, newProps, currentProps)
-            if (sizeChanged(currentProps, newProps)) state.createGeometry = true
+        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => {
+            builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme)
+            if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         createEmptyGeometry: Mesh.createEmpty,
         createRenderObject: createUnitsMeshRenderObject,
@@ -237,9 +243,9 @@ export function UnitsPointsVisual<P extends UnitsPointsProps>(builder: UnitsPoin
         ...builder,
         createEmptyGeometry: Points.createEmpty,
         createRenderObject: createUnitsPointsRenderObject,
-        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
-            builder.setUpdateState(state, newProps, currentProps)
-            if (sizeChanged(currentProps, newProps)) state.updateSize = true
+        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => {
+            builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme)
+            if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true
         },
         updateValues: Points.updateValues
     })
@@ -260,9 +266,9 @@ export function UnitsLinesVisual<P extends UnitsLinesProps>(builder: UnitsLinesV
         ...builder,
         createEmptyGeometry: Lines.createEmpty,
         createRenderObject: createUnitsLinesRenderObject,
-        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
-            builder.setUpdateState(state, newProps, currentProps)
-            if (sizeChanged(currentProps, newProps)) state.updateSize = true
+        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => {
+            builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme)
+            if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.updateSize = true
         },
         updateValues: Lines.updateValues
     })
@@ -283,9 +289,9 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builde
         ...builder,
         createEmptyGeometry: DirectVolume.createEmpty,
         createRenderObject: createUnitsDirectVolumeRenderObject,
-        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P) => {
-            builder.setUpdateState(state, newProps, currentProps)
-            if (sizeChanged(currentProps, newProps)) state.createGeometry = true
+        setUpdateState: (state: VisualUpdateState, newProps: P, currentProps: P, newTheme: Theme, currentTheme: Theme) => {
+            builder.setUpdateState(state, newProps, currentProps, newTheme, currentTheme)
+            if (SizeTheme.areEqual(newTheme.size, currentTheme.size)) state.createGeometry = true
         },
         updateValues: DirectVolume.updateValues
     })
diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts
index 9654d7b089baa34308453ae38255c723c5a63d78..eed3fe4ff172ece8ef9dd4f6d0739e8eafe78f51 100644
--- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts
+++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts
@@ -10,7 +10,6 @@ import { Vec3 } from 'mol-math/linear-algebra';
 import { createLinkCylinderMesh, LinkCylinderProps, LinkCylinderParams } from './util/link';
 import { OrderedSet, Interval } from 'mol-data/int';
 import { ComplexMeshVisual, ComplexVisual } from '../complex-visual';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { LinkType } from 'mol-model/structure/model/types';
 import { BitFlags } from 'mol-util';
 import { UnitsMeshParams } from '../units-visual';
@@ -19,8 +18,8 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { VisualUpdateState } from '../../util';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 // TODO create seperate visual
 // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) {
@@ -64,8 +63,9 @@ async function createCarbohydrateLinkCylinderMesh(ctx: VisualContext, structure:
 export const CarbohydrateLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
     detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
 export const DefaultCarbohydrateLinkProps = PD.getDefaultValues(CarbohydrateLinkParams)
diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts
index 2d760f0b10d0b122fa6bb8b28d55470327d4be92..629674d8c151b643eea44cf72ca876e08c38a492 100644
--- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts
+++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts
@@ -13,19 +13,18 @@ import { DiamondPrism, PentagonalPrism, HexagonalPrism } from 'mol-geo/primitive
 import { Structure, StructureElement } from 'mol-model/structure';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { ComplexMeshParams, ComplexMeshVisual } from '../complex-visual';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { ComplexVisual } from '../index';
+import { ComplexVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { OrderedSet, Interval } from 'mol-data/int';
 import { EmptyLoci, Loci } from 'mol-model/loci';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 const t = Mat4.identity()
 const sVec = Vec3.zero()
@@ -148,8 +147,9 @@ async function createCarbohydrateSymbolMesh(ctx: VisualContext, structure: Struc
 
 export const CarbohydrateSymbolParams = {
     ...ComplexMeshParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 1, 0, 10, 0.1),
     detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
 export const DefaultCarbohydrateSymbolProps = PD.getDefaultValues(CarbohydrateSymbolParams)
diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts
index 1f37817871e789dbd3ce08395919e4bf522b41b3..711b67717c104b8118698fdf5cdb731924514974 100644
--- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts
+++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts
@@ -5,22 +5,21 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { ComplexVisual } from '../index';
+import { ComplexVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { LinkCylinderProps, createLinkCylinderMesh, LinkCylinderParams } from './util/link';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual';
 import { Interval } from 'mol-data/int';
-import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { BitFlags } from 'mol-util';
 import { LinkType } from 'mol-model/structure/model/types';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) {
 
@@ -54,8 +53,9 @@ async function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structur
 export const CrossLinkRestraintParams = {
     ...ComplexMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
 }
 export const DefaultCrossLinkRestraintProps = PD.getDefaultValues(CrossLinkRestraintParams)
 export type CrossLinkRestraintProps = typeof DefaultCrossLinkRestraintProps
diff --git a/src/mol-repr/structure/visual/element-point.ts b/src/mol-repr/structure/visual/element-point.ts
index 6747ae9f889c15f9fcbdc2af94ad71b8cea30241..c906ac98f0cfce91121b56a95a5c999ee6c46cc9 100644
--- a/src/mol-repr/structure/visual/element-point.ts
+++ b/src/mol-repr/structure/visual/element-point.ts
@@ -5,22 +5,22 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { getElementLoci, StructureElementIterator, markElement } from './util/element';
 import { Vec3 } from 'mol-math/linear-algebra';
-import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Points } from 'mol-geo/geometry/points/points';
 import { PointsBuilder } from 'mol-geo/geometry/points/points-builder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 export const ElementPointParams = {
     ...UnitsPointsParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 3, 0, 20, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 3, 0, 20, 0.1),
     pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false),
 }
 export const DefaultElementPointProps = PD.getDefaultValues(ElementPointParams)
diff --git a/src/mol-repr/structure/visual/element-sphere.ts b/src/mol-repr/structure/visual/element-sphere.ts
index 73d25eb01ea69f678a8b73c7ecbd1299c5efc3db..29feb54d3bd815bfacd188ba59ce029449d3f505 100644
--- a/src/mol-repr/structure/visual/element-sphere.ts
+++ b/src/mol-repr/structure/visual/element-sphere.ts
@@ -5,18 +5,18 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 
 export const ElementSphereParams = {
     ...UnitsMeshParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    // sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
     detail: PD.Numeric('Sphere Detail', '', 0, 0, 3, 1),
 }
 export const DefaultElementSphereProps = PD.getDefaultValues(ElementSphereParams)
diff --git a/src/mol-repr/structure/visual/gaussian-density-point.ts b/src/mol-repr/structure/visual/gaussian-density-point.ts
index 5fd0069f1d7482b63d89baf3118d13b966a72781..2ad030a5cc8a371537e0275d369e6bdcd15f0ae8 100644
--- a/src/mol-repr/structure/visual/gaussian-density-point.ts
+++ b/src/mol-repr/structure/visual/gaussian-density-point.ts
@@ -5,25 +5,25 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { StructureElementIterator } from './util/element';
 import { EmptyLoci } from 'mol-model/loci';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsPointsVisual, UnitsPointsParams } from '../units-visual';
-import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Points } from 'mol-geo/geometry/points/points';
 import { PointsBuilder } from 'mol-geo/geometry/points/points-builder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 export const GaussianDensityPointParams = {
     ...UnitsPointsParams,
     ...GaussianDensityParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
     pointSizeAttenuation: PD.Boolean('Point Size Attenuation', '', false),
 }
 export const DefaultGaussianDensityPointProps = PD.getDefaultValues(GaussianDensityPointParams)
diff --git a/src/mol-repr/structure/visual/gaussian-density-volume.ts b/src/mol-repr/structure/visual/gaussian-density-volume.ts
index 89f8b90f0f191a0201e72288c454ffe1c892bdc5..b1afae789263296366672f9e6443ab1119c272f2 100644
--- a/src/mol-repr/structure/visual/gaussian-density-volume.ts
+++ b/src/mol-repr/structure/visual/gaussian-density-volume.ts
@@ -5,15 +5,15 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { UnitsDirectVolumeVisual, UnitsDirectVolumeParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { GaussianDensityProps, GaussianDensityParams, computeUnitGaussianDensityTexture } from 'mol-model/structure/structure/unit/gaussian-density';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createGaussianDensityVolume(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, directVolume?: DirectVolume): Promise<DirectVolume> {
     const { runtime, webgl } = ctx
diff --git a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
index 185cc9a3ce9e89a88755fd0c64d9093378016df6..74bb969be6d7ddc2f84ee739d3fb98f87f78ed65 100644
--- a/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
+++ b/src/mol-repr/structure/visual/gaussian-surface-mesh.ts
@@ -5,7 +5,7 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
@@ -13,8 +13,8 @@ import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createGaussianSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> {
     const { smoothness } = props
diff --git a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
index b8f0d342e21e49c6743fc60945471b7725d865c8..6cb7e9d4f6242e7a8faa6e77523f842d751702e0 100644
--- a/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
+++ b/src/mol-repr/structure/visual/gaussian-surface-wireframe.ts
@@ -5,17 +5,16 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { UnitsLinesVisual, UnitsLinesParams } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 import { computeMarchingCubesLines } from 'mol-geo/util/marching-cubes/algorithm';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, lines?: Lines): Promise<Lines> {
     const { smoothness } = props
@@ -36,8 +35,9 @@ async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure
 export const GaussianWireframeParams = {
     ...UnitsLinesParams,
     ...GaussianDensityParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 2, 0, 10, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 2, 0, 10, 0.1),
     lineSizeAttenuation: PD.Boolean('Line Size Attenuation', '', false),
 }
 export const DefaultGaussianWireframeProps = PD.getDefaultValues(GaussianWireframeParams)
diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
index 7a96419a33dff1f19d4710eb2a24768692e05ccb..5aa8319ec2346f29e121b2b6b1b90131ad0def2f 100644
--- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
+++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts
@@ -5,7 +5,7 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { ComplexVisual } from '../index';
+import { ComplexVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link';
 import { Vec3 } from 'mol-math/linear-algebra';
@@ -16,8 +16,8 @@ import { BitFlags } from 'mol-util';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { PickingId } from 'mol-geo/geometry/picking';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) {
     const links = structure.links
diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts
index 69d2aafd1fc1f377ebe200cd00511dc477d0d439..e177c362db55347c887d80df34823ab4f83a3e0f 100644
--- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts
+++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts
@@ -6,20 +6,19 @@
  */
 
 import { Unit, Link, StructureElement, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { UnitsMeshVisual, UnitsMeshParams, StructureGroup } from '../units-visual';
 import { Interval } from 'mol-data/int';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { BitFlags } from 'mol-util';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { PickingId } from 'mol-geo/geometry/picking';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: LinkCylinderProps, mesh?: Mesh) {
     if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh)
@@ -67,9 +66,10 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s
 export const IntraUnitLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
-    sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 0.2, 0, 10, 0.1),
+    // sizeFactor: PD.Numeric('Size Factor', '', 1, 0, 10, 0.1),
 }
 export const DefaultIntraUnitLinkProps = PD.getDefaultValues(IntraUnitLinkParams)
 export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps
diff --git a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts
index e92c42fa78d777109294ad211ae44056fd300415..9c341adbb6344dcd91eef82a31da0413566ac6ee 100644
--- a/src/mol-repr/structure/visual/nucleotide-block-mesh.ts
+++ b/src/mol-repr/structure/visual/nucleotide-block-mesh.ts
@@ -5,7 +5,7 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { Segmentation } from 'mol-data/int';
 import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types';
@@ -17,8 +17,8 @@ import { Box } from 'mol-geo/primitive/box';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 const p1 = Vec3.zero()
 const p2 = Vec3.zero()
@@ -34,10 +34,17 @@ const t = Mat4.identity()
 const sVec = Vec3.zero()
 const box = Box()
 
-// TODO define props, should be scalable
-async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: {}, mesh?: Mesh) {
+export const NucleotideBlockMeshParams = {
+    sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01),
+}
+export const DefaultNucleotideBlockMeshProps = PD.getDefaultValues(NucleotideBlockMeshParams)
+export type NucleotideBlockMeshProps = typeof DefaultNucleotideBlockMeshProps
+
+async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: NucleotideBlockMeshProps, mesh?: Mesh) {
     if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh)
 
+    const { sizeFactor } = props
+
     // TODO better vertex count estimate
     const builder = MeshBuilder.create(256, 128, mesh)
 
@@ -64,7 +71,7 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu
                 const parentId = modifiedResidues.parentId.get(compId)
                 if (parentId !== undefined) compId = parentId
                 let idx1 = -1, idx2 = -1, idx3 = -1, idx4 = -1, idx5 = -1, idx6 = -1
-                let width = 4.5, height = 4.5, depth = 0.5
+                let width = 4.5, height = 4.5, depth = 2.5 * sizeFactor
 
                 if (isPurinBase(compId)) {
                     height = 4.5
@@ -87,7 +94,7 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu
                 if (idx5 !== -1 && idx6 !== -1) {
                     pos(idx5, p5); pos(idx6, p6)
                     builder.setGroup(i)
-                    addCylinder(builder, p5, p6, 1, { radiusTop: 0.2, radiusBottom: 0.2 })
+                    addCylinder(builder, p5, p6, 1, { radiusTop: 1 * sizeFactor, radiusBottom: 1 * sizeFactor })
                     if (idx1 !== -1 && idx2 !== -1 && idx3 !== -1 && idx4 !== -1) {
                         pos(idx1, p1); pos(idx2, p2); pos(idx3, p3); pos(idx4, p4);
                         Vec3.normalize(v12, Vec3.sub(v12, p2, p1))
@@ -113,7 +120,8 @@ async function createNucleotideBlockMesh(ctx: VisualContext, unit: Unit, structu
 }
 
 export const NucleotideBlockParams = {
-    ...UnitsMeshParams
+    ...UnitsMeshParams,
+    ...NucleotideBlockMeshParams
 }
 export const DefaultNucleotideBlockProps = PD.getDefaultValues(NucleotideBlockParams)
 export type NucleotideBlockProps = typeof DefaultNucleotideBlockProps
diff --git a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
index 6e3d2a7ca6965267f8bccedfa4da95500d78dd41..9fab52627114e57d53c43c963ab74aec479d7cfa 100644
--- a/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
+++ b/src/mol-repr/structure/visual/polymer-backbone-cylinder.ts
@@ -5,7 +5,7 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { PolymerBackboneIterator } from './util/polymer';
 import { getElementLoci, markElement, StructureElementIterator } from './util/element';
@@ -17,8 +17,8 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { CylinderProps } from 'mol-geo/primitive/cylinder';
 import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 export const PolymerBackboneCylinderParams = {
     radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
diff --git a/src/mol-repr/structure/visual/polymer-direction-wedge.ts b/src/mol-repr/structure/visual/polymer-direction-wedge.ts
index d0f1fe4f5bc51174ea7555d4ef094d4a65931c40..24f5e022ed6a234b6fd161e12eff1c339cfe52c3 100644
--- a/src/mol-repr/structure/visual/polymer-direction-wedge.ts
+++ b/src/mol-repr/structure/visual/polymer-direction-wedge.ts
@@ -5,18 +5,17 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
-import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Wedge } from 'mol-geo/primitive/wedge';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 const t = Mat4.identity()
 const sVec = Vec3.zero()
@@ -31,15 +30,16 @@ const heightFactor = 6
 const wedge = Wedge()
 
 export const PolymerDirectionWedgeParams = {
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01),
 }
 export const DefaultPolymerDirectionWedgeProps = PD.getDefaultValues(PolymerDirectionWedgeParams)
 export type PolymerDirectionWedgeProps = typeof DefaultPolymerDirectionWedgeProps
 
 async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerDirectionWedgeProps, mesh?: Mesh) {
     const polymerElementCount = unit.polymerElements.length
+
     if (!polymerElementCount) return Mesh.createEmpty(mesh)
+    const { sizeFactor } = props
 
     const vertexCount = polymerElementCount * 24
     const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh)
@@ -62,7 +62,7 @@ async function createPolymerDirectionWedgeMesh(ctx: VisualContext, unit: Unit, s
         interpolateCurveSegment(state, v, tension, shift)
 
         if ((isSheet && !v.secStrucChange) || !isSheet) {
-            const size = theme.size.size(v.center)
+            const size = theme.size.size(v.center) * sizeFactor
             const depth = depthFactor * size
             const width = widthFactor * size
             const height = heightFactor * size
diff --git a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts
index 60585ab0d8965770c9662f1eb28825c750b64bf9..aa69b9bb663b72281429fdd9085934c50ce61559 100644
--- a/src/mol-repr/structure/visual/polymer-gap-cylinder.ts
+++ b/src/mol-repr/structure/visual/polymer-gap-cylinder.ts
@@ -5,12 +5,11 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
-import { SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { LinkCylinderParams } from './util/link';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -18,12 +17,13 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { CylinderProps } from 'mol-geo/primitive/cylinder';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { addFixedCountDashedCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 const segmentCount = 10
 
 export const PolymerGapCylinderParams = {
+    sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01),
     radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
 }
 export const DefaultPolymerGapCylinderProps = PD.getDefaultValues(PolymerGapCylinderParams)
@@ -33,7 +33,7 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru
     const polymerGapCount = unit.gapElements.length
     if (!polymerGapCount) return Mesh.createEmpty(mesh)
 
-    const { radialSegments } = props
+    const { sizeFactor, radialSegments } = props
 
     const vertexCountEstimate = segmentCount * radialSegments * 2 * polymerGapCount * 2
     const builder = MeshBuilder.create(vertexCountEstimate, vertexCountEstimate / 10, mesh)
@@ -57,11 +57,11 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru
             pos(centerA.element, pA)
             pos(centerB.element, pB)
 
-            cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA)
+            cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerA) * sizeFactor
             builder.setGroup(i)
             addFixedCountDashedCylinder(builder, pA, pB, 0.5, segmentCount, cylinderProps)
 
-            cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB)
+            cylinderProps.radiusTop = cylinderProps.radiusBottom = theme.size.size(centerB) * sizeFactor
             builder.setGroup(i + 1)
             addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps)
         }
@@ -78,9 +78,10 @@ async function createPolymerGapCylinderMesh(ctx: VisualContext, unit: Unit, stru
 export const InterUnitLinkParams = {
     ...UnitsMeshParams,
     ...LinkCylinderParams,
-    sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
-    sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
-    sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1),
+    // TODO
+    // sizeTheme: PD.Select<SizeThemeName>('Size Theme', '', 'physical', SizeThemeOptions),
+    // sizeValue: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+    // sizeFactor: PD.Numeric('Size Factor', '', 0.3, 0, 10, 0.1),
 }
 export const DefaultIntraUnitLinkProps = PD.getDefaultValues(InterUnitLinkParams)
 export type IntraUnitLinkProps = typeof DefaultIntraUnitLinkProps
diff --git a/src/mol-repr/structure/visual/polymer-trace-mesh.ts b/src/mol-repr/structure/visual/polymer-trace-mesh.ts
index 8f75d29ed49f88e8e72ec399f79b6f6801835a9d..f8c536954ac60e9de49e077c8d139a8ed3c23451 100644
--- a/src/mol-repr/structure/visual/polymer-trace-mesh.ts
+++ b/src/mol-repr/structure/visual/polymer-trace-mesh.ts
@@ -5,7 +5,7 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual } from '../index';
+import { UnitsVisual } from '../representation';
 import { VisualUpdateState } from '../../util';
 import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
@@ -15,10 +15,11 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addSheet } from 'mol-geo/geometry/mesh/builder/sheet';
 import { addTube } from 'mol-geo/geometry/mesh/builder/tube';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 export const PolymerTraceMeshParams = {
+    sizeFactor: PD.Numeric('Size Factor', '', 0.2, 0, 10, 0.01),
     linearSegments: PD.Numeric('Linear Segments', '', 8, 1, 48, 1),
     radialSegments: PD.Numeric('Radial Segments', '', 16, 3, 56, 1),
     aspectRatio: PD.Numeric('Aspect Ratio', '', 5, 0.1, 5, 0.1),
@@ -33,7 +34,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure:
     const polymerElementCount = unit.polymerElements.length
 
     if (!polymerElementCount) return Mesh.createEmpty(mesh)
-    const { linearSegments, radialSegments, aspectRatio, arrowFactor } = props
+    const { sizeFactor, linearSegments, radialSegments, aspectRatio, arrowFactor } = props
 
     const vertexCount = linearSegments * radialSegments * polymerElementCount + (radialSegments + 1) * polymerElementCount * 2
     const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh)
@@ -56,7 +57,7 @@ async function createPolymerTraceMesh(ctx: VisualContext, unit: Unit, structure:
 
         interpolateCurveSegment(state, v, tension, shift)
 
-        let width = theme.size.size(v.center)
+        let width = theme.size.size(v.center) * sizeFactor
         if (isCoarse) width *= aspectRatio / 2
 
         if (isSheet) {
diff --git a/src/mol-repr/structure/visual/util/common.ts b/src/mol-repr/structure/visual/util/common.ts
index 25598d6e34efc0d16031ab5984b1b25f4548f2a8..bff5b88337b5a7d3789e1200f163788d75d165dc 100644
--- a/src/mol-repr/structure/visual/util/common.ts
+++ b/src/mol-repr/structure/visual/util/common.ts
@@ -5,17 +5,18 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { StructureProps } from '../../index';
+import { StructureProps } from '../../representation';
 import { createMeshRenderObject, createPointsRenderObject, createLinesRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object';
 import { Mat4 } from 'mol-math/linear-algebra';
 import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
-import { createRenderableState, Theme } from 'mol-geo/geometry/geometry';
+import { createRenderableState } from 'mol-geo/geometry/geometry';
 import { Points } from 'mol-geo/geometry/points/points';
 import { Lines } from 'mol-geo/geometry/lines/lines';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
-import { VisualContext } from 'mol-repr';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 
 export function createUnitsTransform({ units }: Unit.SymmetryGroup, transformData?: TransformData) {
     const unitCount = units.length
diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts
index 5bc0407967feadb297c55e6570e0d1549d32398a..9f584171436fadb137e561b26d4553a502f2faae 100644
--- a/src/mol-repr/structure/visual/util/element.ts
+++ b/src/mol-repr/structure/visual/util/element.ts
@@ -14,8 +14,8 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
-import { VisualContext } from 'mol-repr';
-import { Theme } from 'mol-geo/geometry/geometry';
+import { VisualContext } from 'mol-repr/representation';
+import { Theme } from 'mol-theme/theme';
 import { StructureGroup } from 'mol-repr/structure/units-visual';
 
 export interface ElementSphereMeshProps {
diff --git a/src/mol-repr/structure/visual/util/link.ts b/src/mol-repr/structure/visual/util/link.ts
index 2ea26bff5c8311b488d343fbee6d9e18795eaf6a..a2c04d6251414bde2334ebf3a911740c4687ce32 100644
--- a/src/mol-repr/structure/visual/util/link.ts
+++ b/src/mol-repr/structure/visual/util/link.ts
@@ -13,7 +13,7 @@ import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { CylinderProps } from 'mol-geo/primitive/cylinder';
 import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
-import { VisualContext } from 'mol-repr';
+import { VisualContext } from 'mol-repr/representation';
 
 export const LinkCylinderParams = {
     linkScale: PD.Range('Link Scale', '', 0.4, 0, 1, 0.1),
diff --git a/src/mol-repr/util.ts b/src/mol-repr/util.ts
index 4db8e0cee7c100f8650074fb216192c9bec3379b..ad7d101646a55f50ca2820049e251d538b4ff006 100644
--- a/src/mol-repr/util.ts
+++ b/src/mol-repr/util.ts
@@ -7,8 +7,6 @@
 import { defaults } from 'mol-util';
 import { Structure } from 'mol-model/structure';
 import { VisualQuality } from 'mol-geo/geometry/geometry';
-import { SizeProps } from 'mol-geo/geometry/size-data';
-import { ColorProps } from 'mol-geo/geometry/color-data';
 
 export interface VisualUpdateState {
     updateTransform: boolean
@@ -33,24 +31,6 @@ export namespace VisualUpdateState {
     }
 }
 
-export function sizeChanged(oldProps: SizeProps, newProps: SizeProps) {
-    return (
-        oldProps.sizeTheme !== newProps.sizeTheme ||
-        oldProps.sizeValue !== newProps.sizeValue ||
-        oldProps.sizeFactor !== newProps.sizeFactor
-    )
-}
-
-export function colorChanged(oldProps: ColorProps, newProps: ColorProps) {
-    return (
-        oldProps.colorTheme !== newProps.colorTheme ||
-        oldProps.colorValue !== newProps.colorValue ||
-        oldProps.colorDomain !== newProps.colorDomain ||
-        oldProps.colorList !== newProps.colorList ||
-        oldProps.colorMap !== newProps.colorMap
-    )
-}
-
 //
 
 export interface QualityProps {
diff --git a/src/mol-repr/volume/direct-volume.ts b/src/mol-repr/volume/direct-volume.ts
index 50e4cc7a210b0e6bdc842251b5b8431f68c6374f..18c0ba431242aa8debc5b756f12b0ea6dd0f3bb0 100644
--- a/src/mol-repr/volume/direct-volume.ts
+++ b/src/mol-repr/volume/direct-volume.ts
@@ -6,7 +6,7 @@
 
 import { VolumeData } from 'mol-model/volume'
 import { RuntimeContext } from 'mol-task'
-import { VolumeVisual, VolumeRepresentation } from './index';
+import { VolumeVisual, VolumeRepresentation } from './representation';
 import { createDirectVolumeRenderObject } from 'mol-gl/render-object';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
@@ -17,11 +17,12 @@ import { createTexture } from 'mol-gl/webgl/texture';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
 import { DirectVolume } from 'mol-geo/geometry/direct-volume/direct-volume';
-import { Geometry, createRenderableState, Theme } from 'mol-geo/geometry/geometry';
+import { Geometry, createRenderableState } from 'mol-geo/geometry/geometry';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
 import { VisualUpdateState } from 'mol-repr/util';
-import { VisualContext, RepresentationContext } from 'mol-repr';
+import { VisualContext, RepresentationContext } from 'mol-repr/representation';
+import { ThemeProps, Theme } from 'mol-theme/theme';
 
 function getBoundingBox(gridDimension: Vec3, transform: Mat4) {
     const bbox = Box3D.empty()
@@ -213,16 +214,15 @@ export function DirectVolumeRepresentation(): VolumeRepresentation<DirectVolumeP
     const volumeRepr = VolumeRepresentation(DirectVolumeVisual)
     return {
         label: 'Direct Volume',
-        params: DirectVolumeParams,
         get renderObjects() {
             return [ ...volumeRepr.renderObjects ]
         },
         get props() {
             return { ...volumeRepr.props }
         },
-        createOrUpdate: (ctx: RepresentationContext, props: Partial<DirectVolumeProps> = {}, volume?: VolumeData) => {
+        createOrUpdate: (ctx: RepresentationContext, props: Partial<DirectVolumeProps> = {}, themeProps: ThemeProps = {}, volume?: VolumeData) => {
             currentProps = Object.assign({}, DefaultDirectVolumeProps, currentProps, props)
-            return volumeRepr.createOrUpdate(ctx, currentProps, volume)
+            return volumeRepr.createOrUpdate(ctx, currentProps, themeProps, volume)
         },
         getLoci: (pickingId: PickingId) => {
             return volumeRepr.getLoci(pickingId)
diff --git a/src/mol-repr/volume/isosurface-mesh.ts b/src/mol-repr/volume/isosurface-mesh.ts
index 13eb6f3744de657b50995a8c4ab0a736f23d8789..7ba955e50ab9810833ce675569975e8fd81520b3 100644
--- a/src/mol-repr/volume/isosurface-mesh.ts
+++ b/src/mol-repr/volume/isosurface-mesh.ts
@@ -6,7 +6,7 @@
  */
 
 import { VolumeData } from 'mol-model/volume'
-import { VolumeVisual, VolumeRepresentation } from './index';
+import { VolumeVisual, VolumeRepresentation } from './representation';
 import { createMeshRenderObject } from 'mol-gl/render-object';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
@@ -14,11 +14,12 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { computeMarchingCubesMesh } from 'mol-geo/util/marching-cubes/algorithm';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { createIdentityTransform } from 'mol-geo/geometry/transform-data';
-import { createRenderableState, Theme } from 'mol-geo/geometry/geometry';
+import { createRenderableState } from 'mol-geo/geometry/geometry';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction } from 'mol-geo/geometry/marker-data';
 import { VisualUpdateState } from 'mol-repr/util';
-import { RepresentationContext, VisualContext } from 'mol-repr';
+import { RepresentationContext, VisualContext } from 'mol-repr/representation';
+import { ThemeProps, Theme } from 'mol-theme/theme';
 
 interface VolumeIsosurfaceProps {
     isoValueAbsolute: number
@@ -72,16 +73,15 @@ export function IsosurfaceRepresentation(): VolumeRepresentation<IsosurfaceProps
     const volumeRepr = VolumeRepresentation(IsosurfaceVisual)
     return {
         label: 'Isosurface',
-        params: IsosurfaceParams,
         get renderObjects() {
             return [ ...volumeRepr.renderObjects ]
         },
         get props() {
             return { ...volumeRepr.props }
         },
-        createOrUpdate: (ctx: RepresentationContext, props: Partial<IsosurfaceProps> = {}, volume?: VolumeData) => {
+        createOrUpdate: (ctx: RepresentationContext, props: Partial<IsosurfaceProps> = {}, themeProps: ThemeProps = {}, volume?: VolumeData) => {
             currentProps = Object.assign({}, DefaultIsosurfaceProps, currentProps, props)
-            return volumeRepr.createOrUpdate(ctx, currentProps, volume)
+            return volumeRepr.createOrUpdate(ctx, currentProps, themeProps, volume)
         },
         getLoci: (pickingId: PickingId) => {
             return volumeRepr.getLoci(pickingId)
diff --git a/src/mol-repr/volume/registry.ts b/src/mol-repr/volume/registry.ts
new file mode 100644
index 0000000000000000000000000000000000000000..653649b286630970e26b3b536b927d71def5844d
--- /dev/null
+++ b/src/mol-repr/volume/registry.ts
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { RepresentationProvider, RepresentationRegistry } from '../representation';
+import { VolumeData } from 'mol-model/volume';
+
+export class VolumeRepresentationRegistry extends RepresentationRegistry<VolumeData> {
+    constructor() {
+        super()
+        Object.keys(BuiltInVolumeRepresentations).forEach(name => {
+            const p = (BuiltInVolumeRepresentations as { [k: string]: RepresentationProvider<VolumeData, any> })[name]
+            this.add(name, p.factory, p.params)
+        })
+    }
+}
+
+export const BuiltInVolumeRepresentations = {
+    // TODO
+}
+export type BuiltInVolumeRepresentationsName = keyof typeof BuiltInVolumeRepresentations
+export const BuiltInVolumeRepresentationsNames = Object.keys(BuiltInVolumeRepresentations)
+export const BuiltInVolumeRepresentationsOptions = BuiltInVolumeRepresentationsNames.map(n => [n, n] as [BuiltInVolumeRepresentationsName, string])
\ No newline at end of file
diff --git a/src/mol-repr/volume/index.ts b/src/mol-repr/volume/representation.ts
similarity index 94%
rename from src/mol-repr/volume/index.ts
rename to src/mol-repr/volume/representation.ts
index 729f53cff94fda9ccffa9a722ea05f9143ec643f..bca67799d3a48721e4efc251f556ab9cac909f91 100644
--- a/src/mol-repr/volume/index.ts
+++ b/src/mol-repr/volume/representation.ts
@@ -5,10 +5,10 @@
  */
 
 import { Task } from 'mol-task'
-import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext } from '..';
+import { RepresentationProps, Representation, Visual, RepresentationContext, VisualContext, RepresentationProvider } from '../representation';
 import { VolumeData, VolumeIsoValue } from 'mol-model/volume';
 import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
-import { Geometry, updateRenderableState, Theme, createTheme } from 'mol-geo/geometry/geometry';
+import { Geometry, updateRenderableState } from 'mol-geo/geometry/geometry';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { MarkerAction, applyMarkerAction } from 'mol-geo/geometry/marker-data';
@@ -19,6 +19,7 @@ import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { NullLocation } from 'mol-model/location';
 import { VisualUpdateState } from 'mol-repr/util';
 import { ValueCell } from 'mol-util';
+import { ThemeProps, Theme, createTheme } from 'mol-theme/theme';
 
 export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { }
 
@@ -134,6 +135,10 @@ export function VolumeVisual<P extends VolumeProps>(builder: VolumeVisualGeometr
 
 export interface VolumeRepresentation<P extends RepresentationProps = {}> extends Representation<VolumeData, P> { }
 
+export type VolumeRepresentationProvider<P extends PD.Params> = RepresentationProvider<VolumeData, P>
+
+//
+
 export const VolumeParams = {
     ...Geometry.Params,
     isoValueAbsolute: PD.Range('Iso Value Absolute', '', 0.22, -1, 1, 0.01),
@@ -148,9 +153,9 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD
     let _theme: Theme
     let busy = false
 
-    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, volumeData?: VolumeData) {
+    function createOrUpdate(ctx: RepresentationContext, props: Partial<P> = {}, themeProps: ThemeProps = {}, volumeData?: VolumeData) {
         _props = Object.assign({}, DefaultVolumeProps, _props, props)
-        _theme = createTheme(_props)
+        _theme = createTheme(ctx, _props, themeProps, {}, _theme)
 
         return Task.create('VolumeRepresentation.create', async runtime => {
             // TODO queue it somehow
@@ -173,7 +178,6 @@ export function VolumeRepresentation<P extends VolumeProps>(visualCtor: (volumeD
 
     return {
         label: 'Volume',
-        params: VolumeParams,
         get renderObjects() {
             return visual && visual.renderObject ? [ visual.renderObject ] : []
         },
diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts
index d087e249c80cbd17e3e30f49102a5bdde537f012..b92620b7c7e8109b03a5ff84cb228c2194865c9d 100644
--- a/src/mol-theme/color.ts
+++ b/src/mol-theme/color.ts
@@ -4,26 +4,25 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Color, ColorMap } from 'mol-util/color';
-import { Structure } from 'mol-model/structure';
+import { Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { ColorType } from 'mol-geo/geometry/color-data';
-
-import { ElementIndexColorTheme } from './color/element-index';
-import { CarbohydrateSymbolColorTheme } from './color/carbohydrate-symbol';
-import { ChainIdColorTheme } from './color/chain-id';
-import { ElementSymbolColorTheme } from './color/element-symbol';
-import { UnitIndexColorTheme } from './color/unit-index';
-import { UniformColorTheme } from './color/uniform';
-import { CrossLinkColorTheme } from './color/cross-link';
-import { ShapeGroupColorTheme } from './color/shape-group';
-import { CustomColorTheme } from './color/custom';
-import { ResidueNameColorTheme } from './color/residue-name';
-import { SequenceIdColorTheme } from './color/sequence-id';
-import { SecondaryStructureColorTheme } from './color/secondary-structure';
-import { MoleculeTypeColorTheme } from './color/molecule-type';
-import { PolymerIndexColorTheme } from './color/polymer-index';
-import { ColorMatplotlib, ColorBrewer, ColorOther } from 'mol-util/color/tables';
+import { CarbohydrateSymbolColorThemeProvider } from './color/carbohydrate-symbol';
+import { UniformColorTheme, UniformColorThemeProvider } from './color/uniform';
+import { deepEqual } from 'mol-util';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ChainIdColorThemeProvider } from './color/chain-id';
+import { CrossLinkColorThemeProvider } from './color/cross-link';
+import { ElementIndexColorThemeProvider } from './color/element-index';
+import { ElementSymbolColorThemeProvider } from './color/element-symbol';
+import { MoleculeTypeColorThemeProvider } from './color/molecule-type';
+import { PolymerIndexColorThemeProvider } from './color/polymer-index';
+import { ResidueNameColorThemeProvider } from './color/residue-name';
+import { SecondaryStructureColorThemeProvider } from './color/secondary-structure';
+import { SequenceIdColorThemeProvider } from './color/sequence-id';
+import { ShapeGroupColorThemeProvider } from './color/shape-group';
+import { UnitIndexColorThemeProvider } from './color/unit-index';
 
 export type LocationColor = (location: Location, isSecondary: boolean) => Color
 
@@ -37,29 +36,6 @@ export function ScaleLegend(minLabel: string, maxLabel: string, colors: Color[])
     return { kind: 'scale-legend', minLabel, maxLabel, colors }
 }
 
-export type ColorScaleName = (
-    'default' |
-    keyof typeof ColorBrewer | keyof typeof ColorMatplotlib | keyof typeof ColorOther
-)
-export const ColorScaleNames = [
-    'default',
-    ...Object.keys(ColorBrewer), ...Object.keys(ColorMatplotlib), ...Object.keys(ColorOther)
-]
-export const ColorScaleOptions = ColorScaleNames.map(n => [n, n] as [ColorScaleName, string])
-
-export function getColorScaleFromName(name: string) {
-    if (name === 'default') {
-        return
-    } else if (name in ColorBrewer) {
-        return ColorBrewer[name as keyof typeof ColorBrewer]
-    } else if (name in ColorMatplotlib) {
-        return ColorMatplotlib[name as keyof typeof ColorMatplotlib]
-    } else if (name in ColorOther) {
-        return ColorOther[name as keyof typeof ColorOther]
-    }
-    console.warn(`unknwon color list named '${name}'`)
-}
-
 export interface TableLegend {
     kind: 'table-legend'
     table: [ string, Color ][]
@@ -68,77 +44,76 @@ export function TableLegend(table: [ string, Color ][]): TableLegend {
     return { kind: 'table-legend', table }
 }
 
-export interface ColorThemeFeatures {
-    /** Does allow providing a structure object */
-    structure?: boolean
-    /** Does allow providing a volume object */
-    volume?: boolean
-    /** Does allow providing a list of colors (for creating a scale) */
-    list?: boolean
-    /** Does allow providing a map of colors */
-    map?: boolean
-    /** Does allow providing the boundaries for the scale */
-    domain?: boolean
-    /** Does allow providing a single/special color value */
-    value?: boolean
-}
+export type ColorThemeProps = { [k: string]: any }
 
-export interface ColorTheme {
-    features: ColorThemeFeatures
-    granularity: ColorType
-    color: LocationColor
-    description?: string
-    legend?: ScaleLegend | TableLegend
+export { ColorTheme }
+interface ColorTheme<P extends ColorThemeProps = {}> {
+    readonly granularity: ColorType
+    readonly color: LocationColor
+    readonly props: Readonly<P>
+    readonly description?: string
+    readonly legend?: Readonly<ScaleLegend | TableLegend>
 }
+namespace ColorTheme {
+    export type Props = { [k: string]: any }
+    export const Empty = UniformColorTheme({}, { value: Color(0xCCCCCC) })
 
-export function ColorTheme(props: ColorThemeProps): ColorTheme {
-    switch (props.name) {
-        case 'carbohydrate-symbol': return CarbohydrateSymbolColorTheme(props)
-        case 'chain-id': return ChainIdColorTheme(props)
-        case 'cross-link': return CrossLinkColorTheme(props)
-        case 'custom': return CustomColorTheme(props)
-        case 'element-index': return ElementIndexColorTheme(props)
-        case 'element-symbol': return ElementSymbolColorTheme(props)
-        case 'molecule-type': return MoleculeTypeColorTheme(props)
-        case 'polymer-index': return PolymerIndexColorTheme(props)
-        case 'residue-name': return ResidueNameColorTheme(props)
-        case 'secondary-structure': return SecondaryStructureColorTheme(props)
-        case 'sequence-id': return SequenceIdColorTheme(props)
-        case 'shape-group': return ShapeGroupColorTheme(props)
-        case 'unit-index': return UnitIndexColorTheme(props)
-        case 'uniform': return UniformColorTheme(props)
+    export function areEqual(themeA: ColorTheme, themeB: ColorTheme) {
+        return themeA === themeB && deepEqual(themeA.props, themeB.props)
     }
-}
 
-export interface ColorThemeProps {
-    name: ColorThemeName
-    domain?: [number, number]
-    value?: Color
-    list?: Color[]
-    map?: ColorMap<any>
-    structure?: Structure
-    color?: LocationColor
-    granularity?: ColorType,
-    description?: string,
-    legend?: ScaleLegend | TableLegend
+    export interface Provider<P extends PD.Params> {
+        readonly factory: (ctx: ThemeDataContext, props: PD.DefaultValues<P>) => ColorTheme<PD.DefaultValues<P>>
+        readonly params: (ctx: ThemeDataContext) => P
+    }
+
+    export class Registry {
+        private _list: { name: string, provider: Provider<any> }[] = []
+        private _map = new Map<string, Provider<any>>()
+
+        constructor() {
+            Object.keys(BuiltInColorThemes).forEach(name => {
+                const p = (BuiltInColorThemes as { [k: string]: Provider<any> })[name]
+                this.add(name, p.factory, p.params)
+            })
+        }
+
+        add<P extends PD.Params>(name: string, factory: Provider<P>['factory'], params: Provider<P>['params']) {
+            const provider = { factory, params } as Provider<P>
+            this._list.push({ name, provider })
+            this._map.set(name, provider)
+        }
+
+        get(id: string) {
+            return this._map.get(id)
+        }
+
+        create(id: string, ctx: ThemeDataContext, props = {}) {
+            const provider = this.get(id)
+            return provider ? provider.factory(ctx, { ...PD.getDefaultValues(provider.params(ctx)), ...props }) : Empty
+        }
+
+        get list() {
+            return this._list
+        }
+    }
 }
 
-export const ColorThemeInfo = {
-    'carbohydrate-symbol': {},
-    'chain-id': {},
-    'cross-link': {},
-    'custom': {},
-    'element-index': {},
-    'element-symbol': {},
-    'molecule-type': {},
-    'polymer-index': {},
-    'residue-name': {},
-    'secondary-structure': {},
-    'sequence-id': {},
-    'shape-group': {},
-    'unit-index': {},
-    'uniform': {},
+export const BuiltInColorThemes = {
+    'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider,
+    'chain-id': ChainIdColorThemeProvider,
+    'cross-link': CrossLinkColorThemeProvider,
+    'element-index': ElementIndexColorThemeProvider,
+    'element-symbol': ElementSymbolColorThemeProvider,
+    'molecule-type': MoleculeTypeColorThemeProvider,
+    'polymer-index': PolymerIndexColorThemeProvider,
+    'residue-name': ResidueNameColorThemeProvider,
+    'secondary-structure': SecondaryStructureColorThemeProvider,
+    'sequence-id': SequenceIdColorThemeProvider,
+    'shape-group': ShapeGroupColorThemeProvider,
+    'unit-index': UnitIndexColorThemeProvider,
+    'uniform': UniformColorThemeProvider,
 }
-export type ColorThemeName = keyof typeof ColorThemeInfo
-export const ColorThemeNames = Object.keys(ColorThemeInfo)
-export const ColorThemeOptions = ColorThemeNames.map(n => [n, n] as [ColorThemeName, string])
\ No newline at end of file
+export type BuiltInColorThemeName = keyof typeof BuiltInColorThemes
+export const BuiltInColorThemeNames = Object.keys(BuiltInColorThemes)
+export const BuiltInColorThemeOptions = BuiltInColorThemeNames.map(n => [n, n] as [BuiltInColorThemeName, string])
\ No newline at end of file
diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts
index a21853d87f941f899f7071ff3260b55b9d346541..24940f7a6e813e9c837e738615758ca21b02304f 100644
--- a/src/mol-theme/color/carbohydrate-symbol.ts
+++ b/src/mol-theme/color/carbohydrate-symbol.ts
@@ -8,17 +8,34 @@ import { StructureElement, Link, ElementIndex, Unit } from 'mol-model/structure'
 
 import { SaccharideColors, MonosaccharidesColorTable } from 'mol-model/structure/structure/carbohydrates/constants';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, LocationColor, TableLegend } from '../color';
+import { ColorTheme, LocationColor, TableLegend } from '../color';
 import { Color } from 'mol-util/color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Assigns colors according to the Symbol Nomenclature for Glycans (SNFG).'
 
-export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme {
+// name: ColorThemeName
+// domain?: [number, number]
+// value?: Color
+// list?: Color[]
+// map?: ColorMap<any>
+
+export const CarbohydrateSymbolColorThemeParams = {
+    // domain: PD.Interval('Color Domain', '', [0, 1]),
+    // value: PD.Color('Color Value', '', DefaultColor),
+}
+export function getCarbohydrateSymbolColorThemeParams(ctx: ThemeDataContext) {
+    return CarbohydrateSymbolColorThemeParams // TODO return copy
+}
+export type CarbohydrateSymbolColorThemeProps = PD.DefaultValues<typeof CarbohydrateSymbolColorThemeParams>
+
+export function CarbohydrateSymbolColorTheme(ctx: ThemeDataContext, props: CarbohydrateSymbolColorThemeProps): ColorTheme<CarbohydrateSymbolColorThemeProps> {
     let color: LocationColor
 
-    if (props.structure) {
-        const { elements, getElementIndex, getAnomericCarbon } = props.structure.carbohydrates
+    if (ctx.structure) {
+        const { elements, getElementIndex, getAnomericCarbon } = ctx.structure.carbohydrates
 
         const getColor = (unit: Unit, index: ElementIndex) => {
             const residueIndex = unit.model.atomicHierarchy.residueAtomSegments.index[index]
@@ -47,10 +64,14 @@ export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme
     }
 
     return {
-        features: {},
         granularity: 'group',
         color: color,
+        props: props,
         description: Description,
         legend: TableLegend(MonosaccharidesColorTable)
     }
+}
+
+export const CarbohydrateSymbolColorThemeProvider: ColorTheme.Provider<typeof CarbohydrateSymbolColorThemeParams> = {
+    factory: CarbohydrateSymbolColorTheme, params: getCarbohydrateSymbolColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts
index c91825e4729d16b1777eceb17796f75906109baf..90045dc3a4a795a072b1b88726bb6c9227405d83 100644
--- a/src/mol-theme/color/chain-id.ts
+++ b/src/mol-theme/color/chain-id.ts
@@ -8,11 +8,22 @@ import { Unit, StructureProperties, StructureElement, Link } from 'mol-model/str
 
 import { ColorScale, Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, LocationColor } from '../color';
+import { ColorTheme, LocationColor } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every chain a color based on its `asym_id` value.'
 
+export const ChainIdColorThemeParams = {
+    list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions),
+}
+export function getChainIdColorThemeParams(ctx: ThemeDataContext) {
+    return ChainIdColorThemeParams // TODO return copy
+}
+export type ChainIdColorThemeProps = PD.DefaultValues<typeof ChainIdColorThemeParams>
+
 function getAsymId(unit: Unit): StructureElement.Property<string> {
     switch (unit.kind) {
         case Unit.Kind.Atomic:
@@ -23,14 +34,13 @@ function getAsymId(unit: Unit): StructureElement.Property<string> {
     }
 }
 
-export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme {
+export function ChainIdColorTheme(ctx: ThemeDataContext, props: ChainIdColorThemeProps): ColorTheme<ChainIdColorThemeProps> {
     let color: LocationColor
-    const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' })
-    // const table: [string, Color][] = []
+    const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
 
-    if (props.structure) {
+    if (ctx.structure) {
         const l = StructureElement.create()
-        const { models } = props.structure
+        const { models } = ctx.structure
         const asymIdSerialMap = new Map<string, number>()
         let j = 0
         for (let i = 0, il = models.length; i <il; ++i) {
@@ -44,8 +54,6 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme {
         scale.setDomain(0, asymIdSerialMap.size - 1)
         const scaleColor = scale.color
 
-        // asymIdSerialMap.forEach((v, k) => table.push([k, scaleColor(v)]))
-
         color = (location: Location): Color => {
             if (StructureElement.isLocation(location)) {
                 const asym_id = getAsymId(location.unit)
@@ -63,11 +71,14 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { structure: true, list: true },
         granularity: 'group',
         color,
+        props,
         description: Description,
-        // legend: scale ? TableLegend(table) : undefined
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const ChainIdColorThemeProvider: ColorTheme.Provider<typeof ChainIdColorThemeParams> = {
+    factory: ChainIdColorTheme, params: getChainIdColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/cross-link.ts b/src/mol-theme/color/cross-link.ts
index d24b79e4a92b4e45f7f887df5e333066f0be69c0..031c57eeff17860c584b2fb3e6c8f8f26accd22e 100644
--- a/src/mol-theme/color/cross-link.ts
+++ b/src/mol-theme/color/cross-link.ts
@@ -8,14 +8,24 @@ import { Link } from 'mol-model/structure';
 
 import { Color, ColorScale } from 'mol-util/color';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, LocationColor } from '../color';
+import { ColorTheme, LocationColor } from '../color';
 import { Vec3 } from 'mol-math/linear-algebra';
-import { ColorBrewer } from 'mol-util/color/tables';
-import { defaults } from 'mol-util';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Colors cross-links by the deviation of the observed distance versus the modeled distance (e.g. `ihm_cross_link_restraint.distance_threshold`).'
 
+export const CrossLinkColorThemeParams = {
+    domain: PD.Interval('Color Domain', '', [-10, 10]),
+    list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions),
+}
+export function getCrossLinkColorThemeParams(ctx: ThemeDataContext) {
+    return CrossLinkColorThemeParams // TODO return copy
+}
+export type CrossLinkColorThemeProps = PD.DefaultValues<typeof CrossLinkColorThemeParams>
+
 const distVecA = Vec3.zero(), distVecB = Vec3.zero()
 function linkDistance(link: Link.Location) {
     link.aUnit.conformation.position(link.aIndex, distVecA)
@@ -23,15 +33,15 @@ function linkDistance(link: Link.Location) {
     return Vec3.distance(distVecA, distVecB)
 }
 
-export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme {
+export function CrossLinkColorTheme(ctx: ThemeDataContext, props: CrossLinkColorThemeProps): ColorTheme<CrossLinkColorThemeProps> {
     let color: LocationColor
     let scale: ColorScale | undefined = undefined
 
-    if (props.structure) {
-        const crosslinks = props.structure.crossLinkRestraints
+    if (ctx.structure) {
+        const crosslinks = ctx.structure.crossLinkRestraints
         scale = ColorScale.create({
-            domain: defaults(props.domain, [ -10, 10 ]),
-            list: defaults(props.list, ColorBrewer.RdYlBu)
+            domain: props.domain,
+            listOrName: props.list
         })
         const scaleColor = scale.color
 
@@ -49,10 +59,14 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { list: true, domain: true, structure: true },
         granularity: 'group',
         color,
+        props,
         description: Description,
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const CrossLinkColorThemeProvider: ColorTheme.Provider<typeof CrossLinkColorThemeParams> = {
+    factory: CrossLinkColorTheme, params: getCrossLinkColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/custom.ts b/src/mol-theme/color/custom.ts
deleted file mode 100644
index 4eb5a10ea4497ba5c419607e1467245b4758dc0e..0000000000000000000000000000000000000000
--- a/src/mol-theme/color/custom.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import { Color } from 'mol-util/color';
-import { ColorThemeProps, ColorTheme } from '../color';
-import { defaults } from 'mol-util';
-
-const DefaultColor = Color(0xCCCCCC)
-
-export function CustomColorTheme(props: ColorThemeProps): ColorTheme {
-    const value = defaults(props.value, DefaultColor)
-    return {
-        features: {},
-        granularity: defaults(props.granularity, 'uniform'),
-        color: defaults(props.color, () => value),
-        description: props.description,
-        legend: props.legend
-    }
-}
\ No newline at end of file
diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts
index 2ba30ce687307d87d5caa9fb34a9db98c71c4e91..68264878048d981b7e93296a629113c13222022b 100644
--- a/src/mol-theme/color/element-index.ts
+++ b/src/mol-theme/color/element-index.ts
@@ -8,17 +8,28 @@ import { ColorScale, Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { StructureElement, Link } from 'mol-model/structure';
 import { OrderedSet } from 'mol-data/int';
-import { ColorThemeProps, ColorTheme, LocationColor } from '../color';
+import { ColorTheme, LocationColor } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every element (atom or coarse sphere/gaussian) a unique color based on the position (index) of the element in the list of elements in the structure.'
 
-export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme {
+export const ElementIndexColorThemeParams = {
+    list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions),
+}
+export function getElementIndexColorThemeParams(ctx: ThemeDataContext) {
+    return ElementIndexColorThemeParams // TODO return copy
+}
+export type ElementIndexColorThemeProps = PD.DefaultValues<typeof ElementIndexColorThemeParams>
+
+export function ElementIndexColorTheme(ctx: ThemeDataContext, props: ElementIndexColorThemeProps): ColorTheme<ElementIndexColorThemeProps> {
     let color: LocationColor
-    let scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' })
+    let scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
 
-    if (props.structure) {
-        const { units } = props.structure
+    if (ctx.structure) {
+        const { units } = ctx.structure
         const unitCount = units.length
         const cummulativeElementCount = new Map<number, number>()
         const unitIdIndex = new Map<number, number>()
@@ -48,10 +59,14 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { structure: true, list: true },
         granularity: 'groupInstance',
         color,
+        props,
         description: Description,
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const ElementIndexColorThemeProvider: ColorTheme.Provider<typeof ElementIndexColorThemeParams> = {
+    factory: ElementIndexColorTheme, params: getElementIndexColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts
index 8d7f87b21d0d99e686fea90c4011a3df572d7b2d..8c5d2bb095de8e752289d60c33e263a35fcc326e 100644
--- a/src/mol-theme/color/element-symbol.ts
+++ b/src/mol-theme/color/element-symbol.ts
@@ -8,7 +8,9 @@ import { ElementSymbol } from 'mol-model/structure/model/types';
 import { Color, ColorMap } from 'mol-util/color';
 import { StructureElement, Unit, Link } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, TableLegend } from '../color';
+import { ColorTheme, TableLegend } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF)
 export const ElementSymbolColors = ColorMap({
@@ -18,12 +20,18 @@ export const ElementSymbolColors = ColorMap({
 const DefaultElementSymbolColor = Color(0xFFFFFF)
 const Description = 'Assigns a color to every atom according to its chemical element.'
 
+export const ElementSymbolColorThemeParams = {}
+export function getElementSymbolColorThemeParams(ctx: ThemeDataContext) {
+    return ElementSymbolColorThemeParams // TODO return copy
+}
+export type ElementSymbolColorThemeProps = PD.DefaultValues<typeof ElementSymbolColorThemeParams>
+
 export function elementSymbolColor(element: ElementSymbol): Color {
     const c = (ElementSymbolColors as { [k: string]: Color })[element];
     return c === undefined ? DefaultElementSymbolColor : c
 }
 
-export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme {
+export function ElementSymbolColorTheme(ctx: ThemeDataContext, props: ElementSymbolColorThemeProps): ColorTheme<ElementSymbolColorThemeProps> {
     function color(location: Location): Color {
         if (StructureElement.isLocation(location)) {
             if (Unit.isAtomic(location.unit)) {
@@ -40,12 +48,16 @@ export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: {},
         granularity: 'group',
         color,
+        props,
         description: Description,
         legend: TableLegend(Object.keys(ElementSymbolColors).map(name => {
             return [name, (ElementSymbolColors as any)[name] as Color] as [string, Color]
         }))
     }
+}
+
+export const ElementSymbolColorThemeProvider: ColorTheme.Provider<typeof ElementSymbolColorThemeParams> = {
+    factory: ElementSymbolColorTheme, params: getElementSymbolColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts
index 9bdc21d39a52dae10358d5f0d3c61feda2cabd44..18dd0440caf9890fd1ffeb02b71d844cd98e8034 100644
--- a/src/mol-theme/color/molecule-type.ts
+++ b/src/mol-theme/color/molecule-type.ts
@@ -7,9 +7,11 @@
 import { Color, ColorMap } from 'mol-util/color';
 import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, TableLegend } from '../color';
+import { ColorTheme, TableLegend } from '../color';
 import { MoleculeType } from 'mol-model/structure/model/types';
 import { getElementMoleculeType } from 'mol-model/structure/util';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 const MoleculeTypeColors = ColorMap({
     water: 0x386cb0,
@@ -24,6 +26,12 @@ const MoleculeTypeColors = ColorMap({
 const DefaultMoleculeTypeColor = Color(0xffff99)
 const Description = 'Assigns a color based on the molecule type of a residue.'
 
+export const MoleculeTypeColorThemeParams = {}
+export function getMoleculeTypeColorThemeParams(ctx: ThemeDataContext) {
+    return MoleculeTypeColorThemeParams // TODO return copy
+}
+export type MoleculeTypeColorThemeProps = PD.DefaultValues<typeof MoleculeTypeColorThemeParams>
+
 export function moleculeTypeColor(unit: Unit, element: ElementIndex): Color {
     const moleculeType = getElementMoleculeType(unit, element)
     switch (moleculeType) {
@@ -38,7 +46,7 @@ export function moleculeTypeColor(unit: Unit, element: ElementIndex): Color {
     return DefaultMoleculeTypeColor
 }
 
-export function MoleculeTypeColorTheme(props: ColorThemeProps): ColorTheme {
+export function MoleculeTypeColorTheme(ctx: ThemeDataContext, props: MoleculeTypeColorThemeProps): ColorTheme<MoleculeTypeColorThemeProps> {
     function color(location: Location): Color {
         if (StructureElement.isLocation(location)) {
             return moleculeTypeColor(location.unit, location.element)
@@ -49,12 +57,16 @@ export function MoleculeTypeColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: {},
         granularity: 'group',
         color,
+        props,
         description: Description,
         legend: TableLegend(Object.keys(MoleculeTypeColors).map(name => {
             return [name, (MoleculeTypeColors as any)[name] as Color] as [string, Color]
         }).concat([[ 'Other/unknown', DefaultMoleculeTypeColor ]]))
     }
+}
+
+export const MoleculeTypeColorThemeProvider: ColorTheme.Provider<typeof MoleculeTypeColorThemeParams> = {
+    factory: MoleculeTypeColorTheme, params: getMoleculeTypeColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts
index b17a57dfe8a526c52dc1de93d0e5cee1ba558c0f..4b54924ef469aca559fc65b70b55886f21cd5755 100644
--- a/src/mol-theme/color/polymer-index.ts
+++ b/src/mol-theme/color/polymer-index.ts
@@ -7,17 +7,28 @@
 import { ColorScale, Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { StructureElement, Link } from 'mol-model/structure';
-import { ColorTheme, ColorThemeProps, LocationColor } from '../color';
+import { ColorTheme, LocationColor } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListName, ColorListOptions } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every polymer a unique color based on the position (index) of the polymer in the list of polymers in the structure.'
 
-export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme {
+export const PolymerIndexColorThemeParams = {
+    list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions),
+}
+export function getPolymerIndexColorThemeParams(ctx: ThemeDataContext) {
+    return PolymerIndexColorThemeParams // TODO return copy
+}
+export type PolymerIndexColorThemeProps = PD.DefaultValues<typeof PolymerIndexColorThemeParams>
+
+export function PolymerIndexColorTheme(ctx: ThemeDataContext, props: PolymerIndexColorThemeProps): ColorTheme<PolymerIndexColorThemeProps> {
     let color: LocationColor
-    const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' })
+    const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
 
-    if (props.structure) {
-        const { units } = props.structure
+    if (ctx.structure) {
+        const { units } = ctx.structure
         let polymerCount = 0
         for (let i = 0, il = units.length; i <il; ++i) {
             if (units[i].polymerElements.length > 0) ++polymerCount
@@ -45,10 +56,14 @@ export function PolymerIndexColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { structure: true, list: true },
         granularity: 'instance',
         color,
+        props,
         description: Description,
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const PolymerIndexColorThemeProvider: ColorTheme.Provider<typeof PolymerIndexColorThemeParams> = {
+    factory: PolymerIndexColorTheme, params: getPolymerIndexColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts
index 756ef8c482458704ceaca1f097cfbe8f9fa9216a..ec2a645feacd0e73b395fd0fbc438f229354ab3b 100644
--- a/src/mol-theme/color/residue-name.ts
+++ b/src/mol-theme/color/residue-name.ts
@@ -7,7 +7,9 @@
 import { Color, ColorMap } from 'mol-util/color';
 import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, TableLegend } from '../color';
+import { ColorTheme, TableLegend } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 // protein colors from Jmol http://jmol.sourceforge.net/jscolors/
 const ResidueNameColors = ColorMap({
@@ -59,6 +61,12 @@ const ResidueNameColors = ColorMap({
 const DefaultResidueNameColor = Color(0xFF00FF)
 const Description = 'Assigns a color to every residue according to its name.'
 
+export const ResidueNameColorThemeParams = {}
+export function getResidueNameColorThemeParams(ctx: ThemeDataContext) {
+    return ResidueNameColorThemeParams // TODO return copy
+}
+export type ResidueNameColorThemeProps = PD.DefaultValues<typeof ResidueNameColorThemeParams>
+
 export function residueNameColor(residueName: string): Color {
     const c = (ResidueNameColors as { [k: string]: Color })[residueName];
     return c === undefined ? DefaultResidueNameColor : c
@@ -84,7 +92,7 @@ function getCoarseCompId(unit: Unit.Spheres | Unit.Gaussians, element: ElementIn
     }
 }
 
-export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme {
+export function ResidueNameColorTheme(ctx: ThemeDataContext, props: ResidueNameColorThemeProps): ColorTheme<ResidueNameColorThemeProps> {
     function color(location: Location): Color {
         if (StructureElement.isLocation(location)) {
             if (Unit.isAtomic(location.unit)) {
@@ -105,12 +113,16 @@ export function ResidueNameColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: {},
         granularity: 'group',
         color,
+        props,
         description: Description,
         legend: TableLegend(Object.keys(ResidueNameColors).map(name => {
             return [name, (ResidueNameColors as any)[name] as Color] as [string, Color]
         }).concat([[ 'Unknown', DefaultResidueNameColor ]]))
     }
+}
+
+export const ResidueNameColorThemeProvider: ColorTheme.Provider<typeof ResidueNameColorThemeParams> = {
+    factory: ResidueNameColorTheme, params: getResidueNameColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts
index d9a6fd7b6e15518dd354c721417e7e1c73ca75b6..b53171be85c73d1c7209d571a127bc19c8371670 100644
--- a/src/mol-theme/color/secondary-structure.ts
+++ b/src/mol-theme/color/secondary-structure.ts
@@ -7,9 +7,11 @@
 import { Color, ColorMap } from 'mol-util/color';
 import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme, TableLegend } from '../color';
+import { ColorTheme, TableLegend } from '../color';
 import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types';
 import { getElementMoleculeType } from 'mol-model/structure/util';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 // from Jmol http://jmol.sourceforge.net/jscolors/ (shapely)
 const SecondaryStructureColors = ColorMap({
@@ -29,6 +31,12 @@ const SecondaryStructureColors = ColorMap({
 const DefaultSecondaryStructureColor = Color(0x808080)
 const Description = 'Assigns a color based on the type of secondary structure and basic molecule type.'
 
+export const SecondaryStructureColorThemeParams = {}
+export function getSecondaryStructureColorThemeParams(ctx: ThemeDataContext) {
+    return SecondaryStructureColorThemeParams // TODO return copy
+}
+export type SecondaryStructureColorThemeProps = PD.DefaultValues<typeof SecondaryStructureColorThemeParams>
+
 export function secondaryStructureColor(unit: Unit, element: ElementIndex): Color {
     let secStrucType = SecondaryStructureType.create(SecondaryStructureType.Flag.None)
     if (Unit.isAtomic(unit)) {
@@ -61,7 +69,7 @@ export function secondaryStructureColor(unit: Unit, element: ElementIndex): Colo
     return DefaultSecondaryStructureColor
 }
 
-export function SecondaryStructureColorTheme(props: ColorThemeProps): ColorTheme {
+export function SecondaryStructureColorTheme(ctx: ThemeDataContext, props: SecondaryStructureColorThemeProps): ColorTheme<SecondaryStructureColorThemeProps> {
     function color(location: Location): Color {
         if (StructureElement.isLocation(location)) {
             return secondaryStructureColor(location.unit, location.element)
@@ -72,12 +80,16 @@ export function SecondaryStructureColorTheme(props: ColorThemeProps): ColorTheme
     }
 
     return {
-        features: {},
         granularity: 'group',
         color,
+        props,
         description: Description,
         legend: TableLegend(Object.keys(SecondaryStructureColors).map(name => {
             return [name, (SecondaryStructureColors as any)[name] as Color] as [string, Color]
         }).concat([[ 'Other', DefaultSecondaryStructureColor ]]))
     }
+}
+
+export const SecondaryStructureColorThemeProvider: ColorTheme.Provider<typeof SecondaryStructureColorThemeParams> = {
+    factory: SecondaryStructureColorTheme, params: getSecondaryStructureColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/sequence-id.ts b/src/mol-theme/color/sequence-id.ts
index 808e4ace55c17a952ee46d6dd8fc14f8c68dd8e5..a0b1b22d4a5b3d35661d67bbe3bb6dcf5db3f232 100644
--- a/src/mol-theme/color/sequence-id.ts
+++ b/src/mol-theme/color/sequence-id.ts
@@ -8,13 +8,22 @@ import { Unit, StructureElement, Link, ElementIndex } from 'mol-model/structure'
 
 import { ColorScale, Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
-import { ColorThemeProps, ColorTheme } from '../color';
-import { ColorOther } from 'mol-util/color/tables';
-import { defaults } from 'mol-util';
+import { ColorTheme } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every polymer residue a color based on its `seq_id` value.'
 
+export const SequenceIdColorThemeParams = {
+    list: PD.Select<ColorListName>('Color Scale', '', 'rainbow', ColorListOptions),
+}
+export function getSequenceIdColorThemeParams(ctx: ThemeDataContext) {
+    return SequenceIdColorThemeParams // TODO return copy
+}
+export type SequenceIdColorThemeProps = PD.DefaultValues<typeof SequenceIdColorThemeParams>
+
 function getSeqId(unit: Unit, element: ElementIndex): number {
     const { model } = unit
     switch (unit.kind) {
@@ -55,15 +64,12 @@ function getSequenceLength(unit: Unit, element: ElementIndex) {
     return model.sequence.byEntityKey[entityIndex].sequence.sequence.length
 }
 
-export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme {
-    const p = {
-        ...props,
-        list: defaults(props.list, ColorOther.rainbow),
+export function SequenceIdColorTheme(ctx: ThemeDataContext, props: SequenceIdColorThemeProps): ColorTheme<SequenceIdColorThemeProps> {
+    const scale = ColorScale.create({
+        listOrName: props.list,
         minLabel: 'Start',
         maxLabel: 'End',
-    }
-
-    const scale = ColorScale.create(p)
+    })
     const color = (location: Location): Color => {
         if (StructureElement.isLocation(location)) {
             const { unit, element } = location
@@ -84,11 +90,14 @@ export function SequenceIdColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { list: true },
         granularity: 'group',
         color,
+        props,
         description: Description,
-        // legend: scale ? TableLegend(table) : undefined
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const SequenceIdColorThemeProvider: ColorTheme.Provider<typeof SequenceIdColorThemeParams> = {
+    factory: SequenceIdColorTheme, params: getSequenceIdColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/shape-group.ts b/src/mol-theme/color/shape-group.ts
index 0d74a08c77afa0c23f265036e0279daf2c1d76b5..172052bd7e0037c4141e207ee614b7c1304f1da1 100644
--- a/src/mol-theme/color/shape-group.ts
+++ b/src/mol-theme/color/shape-group.ts
@@ -4,16 +4,24 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { ColorTheme, ColorThemeProps } from '../color';
+import { ColorTheme } from '../color';
 import { Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { Shape } from 'mol-model/shape';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 const DefaultColor = Color(0xCCCCCC)
+const Description = 'Assigns colors as defined by the shape object.'
 
-export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme {
+export const ShapeGroupColorThemeParams = {}
+export function getShapeGroupColorThemeParams(ctx: ThemeDataContext) {
+    return ShapeGroupColorThemeParams // TODO return copy
+}
+export type ShapeGroupColorThemeProps = PD.DefaultValues<typeof ShapeGroupColorThemeParams>
+
+export function ShapeGroupColorTheme(ctx: ThemeDataContext, props: ShapeGroupColorThemeProps): ColorTheme<ShapeGroupColorThemeProps> {
     return {
-        features: {},
         granularity: 'group',
         color: (location: Location): Color => {
             if (Shape.isLocation(location)) {
@@ -21,7 +29,11 @@ export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme {
             }
             return DefaultColor
         },
-        description: props.description,
-        legend: props.legend
+        props,
+        description: Description
     }
+}
+
+export const ShapeGroupColorThemeProvider: ColorTheme.Provider<typeof ShapeGroupColorThemeParams> = {
+    factory: ShapeGroupColorTheme, params: getShapeGroupColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts
index f7fb57769ecbdcfbdbe6a9ba6bda5507eedbd45f..c02644b3f2e9f209fa772a2c799fce408143b33b 100644
--- a/src/mol-theme/color/uniform.ts
+++ b/src/mol-theme/color/uniform.ts
@@ -4,20 +4,34 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { ColorTheme, ColorThemeProps, TableLegend } from '../color';
+import { ColorTheme, TableLegend } from '../color';
 import { Color } from 'mol-util/color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives everything the same, uniform color.'
 
-export function UniformColorTheme(props: ColorThemeProps): ColorTheme {
+export const UniformColorThemeParams = {
+    value: PD.Color('Color Value', '', DefaultColor),
+}
+export function getUniformColorThemeParams(ctx: ThemeDataContext) {
+    return UniformColorThemeParams // TODO return copy
+}
+export type UniformColorThemeProps = PD.DefaultValues<typeof UniformColorThemeParams>
+
+export function UniformColorTheme(ctx: ThemeDataContext, props: UniformColorThemeProps): ColorTheme<UniformColorThemeProps> {
     const color = props.value || DefaultColor
 
     return {
-        features: {},
         granularity: 'uniform',
         color: () => color,
+        props: props,
         description: Description,
         legend: TableLegend([['uniform', color]])
     }
+}
+
+export const UniformColorThemeProvider: ColorTheme.Provider<typeof UniformColorThemeParams> = {
+    factory: UniformColorTheme, params: getUniformColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts
index a17dc82b6e40a5c7ac2782a970d248b682e0fd7b..06760c3120e24769b6f7acf0712d267b0d19bcd8 100644
--- a/src/mol-theme/color/unit-index.ts
+++ b/src/mol-theme/color/unit-index.ts
@@ -7,17 +7,28 @@
 import { ColorScale, Color } from 'mol-util/color';
 import { Location } from 'mol-model/location';
 import { StructureElement, Link } from 'mol-model/structure';
-import { ColorTheme, ColorThemeProps, LocationColor } from '../color';
+import { ColorTheme, LocationColor } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every unit (single chain or collection of single elements) a unique color based on the position (index) of the unit in the list of units in the structure.'
 
-export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme {
+export const UnitIndexColorThemeParams = {
+    list: PD.Select<ColorListName>('Color Scale', '', 'RdYlBu', ColorListOptions),
+}
+export function getUnitIndexColorThemeParams(ctx: ThemeDataContext) {
+    return UnitIndexColorThemeParams // TODO return copy
+}
+export type UnitIndexColorThemeProps = PD.DefaultValues<typeof UnitIndexColorThemeParams>
+
+export function UnitIndexColorTheme(ctx: ThemeDataContext, props: UnitIndexColorThemeProps): ColorTheme<UnitIndexColorThemeProps> {
     let color: LocationColor
-    const scale = ColorScale.create({ list: props.list, minLabel: 'Start', maxLabel: 'End' })
+    const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
 
-    if (props.structure) {
-        const { units } = props.structure
+    if (ctx.structure) {
+        const { units } = ctx.structure
         scale.setDomain(0, units.length - 1)
         const unitIdColor = new Map<number, Color>()
         for (let i = 0, il = units.length; i <il; ++i) {
@@ -37,10 +48,14 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme {
     }
 
     return {
-        features: { structure: true, list: true },
         granularity: 'instance',
         color,
+        props,
         description: Description,
         legend: scale ? scale.legend : undefined
     }
+}
+
+export const UnitIndexColorThemeProvider: ColorTheme.Provider<typeof UnitIndexColorThemeParams> = {
+    factory: UnitIndexColorTheme, params: getUnitIndexColorThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/size.ts b/src/mol-theme/size.ts
index 65428f9d0ce22ffd84f4865a529cded363f4e083..55487c2663c3c311021a533ee82581ee32b6da92 100644
--- a/src/mol-theme/size.ts
+++ b/src/mol-theme/size.ts
@@ -4,35 +4,69 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Structure } from 'mol-model/structure';
 import { SizeType, LocationSize } from 'mol-geo/geometry/size-data';
+import { UniformSizeTheme, UniformSizeThemeProvider } from './size/uniform';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { ThemeDataContext } from 'mol-theme/theme';
+import { PhysicalSizeThemeProvider } from './size/physical';
+import { deepEqual } from 'mol-util';
 
-import { PhysicalSizeTheme } from './size/physical';
-import { UniformSizeTheme } from './size/uniform';
-
-export interface SizeTheme {
-    granularity: SizeType
-    size: LocationSize
+export { SizeTheme }
+interface SizeTheme<P extends SizeTheme.Props = {}> {
+    readonly granularity: SizeType
+    readonly size: LocationSize
+    readonly props: Readonly<P>
+    readonly description?: string
 }
+namespace SizeTheme {
+    export type Props = { [k: string]: any }
+    export const Empty = UniformSizeTheme({}, { value: 1 })
 
-export function SizeTheme(props: SizeThemeProps): SizeTheme {
-    switch (props.name) {
-        case 'physical': return PhysicalSizeTheme(props)
-        case 'uniform': return UniformSizeTheme(props)
+    export function areEqual(themeA: SizeTheme, themeB: SizeTheme) {
+        return themeA === themeB && deepEqual(themeA.props, themeB.props)
     }
-}
 
-export interface SizeThemeProps {
-    name: 'physical' | 'uniform'
-    value?: number
-    factor?: number
-    structure?: Structure
+    export interface Provider<P extends PD.Params> {
+        readonly factory: (ctx: ThemeDataContext, props: PD.DefaultValues<P>) => SizeTheme<PD.DefaultValues<P>>
+        readonly params: (ctx: ThemeDataContext) => P
+    }
+
+    export class Registry {
+        private _list: { name: string, provider: Provider<any> }[] = []
+        private _map = new Map<string, Provider<any>>()
+
+        constructor() {
+            Object.keys(BuiltInSizeThemes).forEach(name => {
+                const p = (BuiltInSizeThemes as { [k: string]: Provider<any> })[name]
+                this.add(name, p.factory, p.params)
+            })
+        }
+
+        add<P extends PD.Params>(name: string, factory: Provider<P>['factory'], params: Provider<P>['params']) {
+            const provider = { factory, params } as Provider<P>
+            this._list.push({ name, provider })
+            this._map.set(name, provider)
+        }
+
+        get(id: string) {
+            return this._map.get(id)
+        }
+
+        create(id: string, ctx: ThemeDataContext, props = {}) {
+            const provider = this.get(id)
+            return provider ? provider.factory(ctx, { ...PD.getDefaultValues(provider.params(ctx)), ...props }) : Empty
+        }
+
+        get list() {
+            return this._list
+        }
+    }
 }
 
-export const SizeThemeInfo = {
-    'physical': {},
-    'uniform': {}
+export const BuiltInSizeThemes = {
+    'physical': PhysicalSizeThemeProvider,
+    'uniform': UniformSizeThemeProvider
 }
-export type SizeThemeName = keyof typeof SizeThemeInfo
-export const SizeThemeNames = Object.keys(SizeThemeInfo)
-export const SizeThemeOptions = SizeThemeNames.map(n => [n, n] as [SizeThemeName, string])
\ No newline at end of file
+export type BuiltInSizeThemeName = keyof typeof BuiltInSizeThemes
+export const BuiltInSizeThemeNames = Object.keys(BuiltInSizeThemes)
+export const BuiltInSizeThemeOptions = BuiltInSizeThemeNames.map(n => [n, n] as [BuiltInSizeThemeName, string])
\ No newline at end of file
diff --git a/src/mol-theme/size/physical.ts b/src/mol-theme/size/physical.ts
index 43a885989c0faf14da2a57fbc8b3f02eabc2aede..45d43ceac6f8549e4f49c2c0db63854a047c0500 100644
--- a/src/mol-theme/size/physical.ts
+++ b/src/mol-theme/size/physical.ts
@@ -6,11 +6,19 @@
 
 import { StructureElement, Unit, Link, ElementIndex } from 'mol-model/structure';
 import { Location } from 'mol-model/location';
-import { SizeThemeProps, SizeTheme } from '../size';
+import { SizeTheme } from '../size';
 import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
 const DefaultSize = 1
-const DefaultFactor = 1
+const Description = 'Assigns a physical size.'
+
+export const PhysicalSizeThemeParams = {}
+export function getPhysicalSizeThemeParams(ctx: ThemeDataContext) {
+    return PhysicalSizeThemeParams // TODO return copy
+}
+export type PhysicalSizeThemeProps = PD.DefaultValues<typeof PhysicalSizeThemeParams>
 
 export function getPhysicalRadius(unit: Unit, element: ElementIndex): number {
     if (Unit.isAtomic(unit)) {
@@ -26,10 +34,8 @@ export function getPhysicalRadius(unit: Unit, element: ElementIndex): number {
  * Create attribute data with the physical size of an element,
  * i.e. vdw for atoms and radius for coarse spheres
  */
-export function PhysicalSizeTheme(props: SizeThemeProps): SizeTheme {
-    const factor = props.factor || DefaultFactor
-
-    function sizeFn(location: Location): number {
+export function PhysicalSizeTheme(ctx: ThemeDataContext, props: PhysicalSizeThemeProps): SizeTheme<PhysicalSizeThemeProps> {
+    function size(location: Location): number {
         let size: number
         if (StructureElement.isLocation(location)) {
             size = getPhysicalRadius(location.unit, location.element)
@@ -38,11 +44,17 @@ export function PhysicalSizeTheme(props: SizeThemeProps): SizeTheme {
         } else {
             size = DefaultSize
         }
-        return factor * size
+        return size
     }
 
     return {
         granularity: 'group',
-        size: sizeFn
+        size,
+        props,
+        description: Description
     }
+}
+
+export const PhysicalSizeThemeProvider: SizeTheme.Provider<typeof PhysicalSizeThemeParams> = {
+    factory: PhysicalSizeTheme, params: getPhysicalSizeThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/size/uniform.ts b/src/mol-theme/size/uniform.ts
index 28634f5ee67867bd55df0f95c95158cce5a27dbf..139a4bcbc3505fde6ef80ce5270234d868deafd1 100644
--- a/src/mol-theme/size/uniform.ts
+++ b/src/mol-theme/size/uniform.ts
@@ -4,18 +4,31 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { SizeTheme, SizeThemeProps } from '../size';
+import { SizeTheme } from '../size';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
 
-const DefaultSize = 1
-const DefaultFactor = 1
+const Description = 'Gives everything the same, uniform size.'
 
-export function UniformSizeTheme(props: SizeThemeProps): SizeTheme {
-    const value = props.value || DefaultSize
-    const factor = props.factor || DefaultFactor
-    const size = value * factor
+export const UniformSizeThemeParams = {
+    value: PD.Numeric('Size Value', '', 1, 0, 20, 0.1),
+}
+export function getUniformSizeThemeParams(ctx: ThemeDataContext) {
+    return UniformSizeThemeParams // TODO return copy
+}
+export type UniformSizeThemeProps = PD.DefaultValues<typeof UniformSizeThemeParams>
+
+export function UniformSizeTheme(ctx: ThemeDataContext, props: UniformSizeThemeProps): SizeTheme<UniformSizeThemeProps> {
+    const size = props.value
 
     return {
         granularity: 'uniform',
-        size: () => size
+        size: () => size,
+        props,
+        description: Description
     }
+}
+
+export const UniformSizeThemeProvider: SizeTheme.Provider<typeof UniformSizeThemeParams> = {
+    factory: UniformSizeTheme, params: getUniformSizeThemeParams
 }
\ No newline at end of file
diff --git a/src/mol-theme/theme.ts b/src/mol-theme/theme.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a5f1a3e80e8ec39bd68a122ab4eee34a3f6a2c60
--- /dev/null
+++ b/src/mol-theme/theme.ts
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ColorTheme } from './color';
+import { SizeTheme } from './size';
+import { Structure } from 'mol-model/structure';
+import { VolumeData } from 'mol-model/volume';
+
+export interface ThemeRegistryContext {
+    colorThemeRegistry: ColorTheme.Registry
+    sizeThemeRegistry: SizeTheme.Registry
+}
+
+export interface ThemeDataContext {
+    [k: string]: any
+    structure?: Structure
+    volume?: VolumeData
+}
+
+export interface ThemeProps { color?: {}, size?: {} }
+
+export interface Theme {
+    color: ColorTheme
+    size: SizeTheme
+    // label: LabelTheme // TODO
+}
+
+type Props = { [k: string]: any }
+
+export function createTheme(ctx: ThemeRegistryContext, data: ThemeDataContext, props: Props, themeProps: ThemeProps = {}, theme?: Theme) {
+    theme = theme || {
+        color: ColorTheme.Empty,
+        size: SizeTheme.Empty
+    }
+    // TODO check if props have changed
+    if (typeof props.colorTheme === 'string') {
+        theme.color = ctx.colorThemeRegistry.create(props.colorTheme, data, themeProps.color)
+    }
+    if (typeof props.sizeTheme === 'string') {
+        theme.size = ctx.sizeThemeRegistry.create(props.sizeTheme, data, themeProps.size)
+    }
+    return theme
+}
\ No newline at end of file
diff --git a/src/mol-util/color/scale.ts b/src/mol-util/color/scale.ts
index c7cf7980c114e7b5363ede0cc7b80a1b176c0f5e..7ed018496fcfdd4666f29f77325fe9f20fa92047 100644
--- a/src/mol-util/color/scale.ts
+++ b/src/mol-util/color/scale.ts
@@ -5,10 +5,32 @@
  */
 
 import { Color } from './color'
-import { ColorBrewer } from './tables'
+import { ColorBrewer, ColorMatplotlib, ColorOther } from './tables'
 import { ScaleLegend } from 'mol-theme/color';
 import { defaults } from 'mol-util';
 
+export type ColorListName = (
+    keyof typeof ColorBrewer | keyof typeof ColorMatplotlib | keyof typeof ColorOther
+)
+export const ColorListNames = [
+    ...Object.keys(ColorBrewer), ...Object.keys(ColorMatplotlib), ...Object.keys(ColorOther)
+]
+export const ColorListOptions = ColorListNames.map(n => [n, n] as [ColorListName, string])
+
+export function getColorListFromName(name: ColorListName) {
+    if (name in ColorBrewer) {
+        return ColorBrewer[name as keyof typeof ColorBrewer]
+    } else if (name in ColorMatplotlib) {
+        return ColorMatplotlib[name as keyof typeof ColorMatplotlib]
+    } else if (name in ColorOther) {
+        return ColorOther[name as keyof typeof ColorOther]
+    }
+    console.warn(`unknown color list named '${name}'`)
+    return ColorBrewer.RdYlBu
+}
+
+//
+
 export interface ColorScale {
     /** Returns hex color for given value */
     color: (value: number) => Color
@@ -22,20 +44,20 @@ export interface ColorScale {
     readonly legend: ScaleLegend
 }
 
-export const DefaultColorScale = {
+export const DefaultColorScaleProps = {
     domain: [0, 1],
     reverse: false,
-    list: ColorBrewer.RdYlBu,
+    listOrName: ColorBrewer.RdYlBu as Color[] | ColorListName,
     minLabel: '' as string | undefined,
     maxLabel: '' as string | undefined,
 }
-export type ColorScaleProps = Partial<typeof DefaultColorScale>
+export type ColorScaleProps = Partial<typeof DefaultColorScaleProps>
 
 export namespace ColorScale {
     export function create(props: ColorScaleProps): ColorScale {
-        // ensure that no undefined .list property exists so that the default assignment works
-        if (props.list === undefined) delete props.list
-        const { domain, reverse, list } = { ...DefaultColorScale, ...props }
+        const { domain, reverse, listOrName } = { ...DefaultColorScaleProps, ...props }
+        const list = typeof listOrName === 'string' ? getColorListFromName(listOrName) : listOrName
+
         const colors = reverse ? list.slice().reverse() : list
         const count1 = colors.length - 1
 
diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts
index 0ebf49dd83c29c74133912ff304a2ec92ec1128f..2b7804bc7a4fbbf6f6780749ceb55f5d2cf8649a 100644
--- a/src/mol-util/param-definition.ts
+++ b/src/mol-util/param-definition.ts
@@ -82,12 +82,20 @@ export namespace ParamDefinition {
         return { type: 'number', label, description, defaultValue, min, max, step }
     }
 
-    export type Any = /* ValueParam<any> | */ Select<any> | MultiSelect<any> | Boolean | Range | Text | Color | Numeric
+    export interface Interval extends Base<[number, number]> {
+        type: 'interval'
+    }
+    export function Interval(label: string, description: string, defaultValue: [number, number]): Interval {
+        return { type: 'interval', label, description, defaultValue }
+    }
+
+    export type Any = /* GenericValue<any> | */ Select<any> | MultiSelect<any> | Boolean | Range | Text | Color | Numeric | Interval
     export type Params = { [k: string]: Any }
+    export type DefaultValues<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] }
 
     export function getDefaultValues<T extends Params>(params: T) {
         const d: { [k: string]: any } = {}
         Object.keys(params).forEach(k => d[k] = params[k].defaultValue)
-        return d as { [k in keyof T]: T[k]['defaultValue'] }
+        return d as DefaultValues<T>
     }
 }
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
index b1aba103a11afae350c6929a901a92b15f0a37a7..0f85d141c04135fc627cc8855fcab338f179ef88 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,6 +1,7 @@
 const path = require('path');
 const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin');
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+// const CircularDependencyPlugin = require('circular-dependency-plugin');
 module.exports = {
     module: {
         rules: [
@@ -30,6 +31,11 @@ module.exports = {
         ]
     },
     plugins: [
+        // new CircularDependencyPlugin({
+        //     include: [ path.resolve(__dirname, 'build/node_modules/') ],
+        //     failOnError: false,
+        //     cwd: process.cwd(),
+        // }),
         new ExtraWatchWebpackPlugin({
             files: [
                 './build/node_modules/**/*.vert',