diff --git a/src/mol-app/component/color-theme.tsx b/src/mol-app/component/color-theme.tsx
deleted file mode 100644
index a98f423fe3f590df91363083f7c24b8dad7b65cb..0000000000000000000000000000000000000000
--- a/src/mol-app/component/color-theme.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
-
-import * as React from 'react'
-import { ColorTheme } from '../../mol-theme/color';
-import { Color } from '../../mol-util/color';
-
-export interface ColorThemeComponentProps {
-    colorTheme: ColorTheme<any>
-}
-
-export interface ColorThemeComponentState {
-
-}
-
-export class ColorThemeComponent extends React.Component<ColorThemeComponentProps, ColorThemeComponentState> {
-    state = {
-
-    }
-
-    render() {
-        const ct = this.props.colorTheme
-        return <div>
-            <span>Color Theme Info </span>
-
-            {ct.description ? <div><i>{ct.description}</i></div> : ''}
-            {
-                ct.legend && ct.legend.kind === 'scale-legend'
-                    ? <div
-                        style={{
-                            width: '100%',
-                            height: '30px',
-                            background: `linear-gradient(to right, ${ct.legend.colors.map(c => Color.toStyle(c)).join(', ')})`
-                        }}
-                    >
-                        <span style={{float: 'left', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.minLabel}</span>
-                        <span style={{float: 'right', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.maxLabel}</span>
-                    </div>
-                : ct.legend && ct.legend.kind === 'table-legend'
-                    ? <div>
-                        {ct.legend.table.map((value, i) => {
-                            const [name, color] = value
-                            return <div key={i} style={{minWidth: '60px', marginRight: '5px', display: 'inline-block'}}>
-                                <div style={{width: '30px', height: '20px', backgroundColor: Color.toStyle(color), display: 'inline-block'}}></div>
-                                {name}
-                            </div>
-                        })}
-                    </div>
-                : ''
-            }
-        </div>;
-    }
-}
\ No newline at end of file
diff --git a/src/mol-model-props/common/custom-element-property.ts b/src/mol-model-props/common/custom-element-property.ts
index 96e1725aea6b878e92d8a4e3f93e6021c8bd5995..e8c94d90516c4176479ce59f20d9442085282ba3 100644
--- a/src/mol-model-props/common/custom-element-property.ts
+++ b/src/mol-model-props/common/custom-element-property.ts
@@ -12,7 +12,7 @@ import { Task } from '../../mol-task';
 import { ThemeDataContext, ThemeProvider } from '../../mol-theme/theme';
 import { ColorTheme, LocationColor } from '../../mol-theme/color';
 import { Color } from '../../mol-util/color';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { Loci } from '../../mol-model/loci';
 import { OrderedSet } from '../../mol-data/int';
 
diff --git a/src/mol-model-props/pdbe/themes/structure-quality-report.ts b/src/mol-model-props/pdbe/themes/structure-quality-report.ts
index f71be143439fd657a5134a812736e792d078b345..e7b474229291ee82cd4d86f3bfa2ba680cf8dc5e 100644
--- a/src/mol-model-props/pdbe/themes/structure-quality-report.ts
+++ b/src/mol-model-props/pdbe/themes/structure-quality-report.ts
@@ -10,7 +10,7 @@ import { StructureElement } from '../../../mol-model/structure';
 import { ColorTheme, LocationColor } from '../../../mol-theme/color';
 import { ThemeDataContext } from '../../../mol-theme/theme';
 import { Color } from '../../../mol-util/color';
-import { TableLegend } from '../../../mol-util/color/lists';
+import { TableLegend } from '../../../mol-util/legend';
 
 const ValidationColors = [
     Color.fromRgb(170, 170, 170), // not applicable
diff --git a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts
index 565a01dc44936762ef0634c1a1b4afaf3150ba20..50215e718df8b8fe29a44b5f1b38d580378ccf21 100644
--- a/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts
+++ b/src/mol-model-props/rcsb/themes/assembly-symmetry-cluster.ts
@@ -12,10 +12,9 @@ import { AssemblySymmetry } from '../assembly-symmetry';
 import { Color } from '../../../mol-util/color';
 import { Unit, StructureElement, StructureProperties } from '../../../mol-model/structure';
 import { Location } from '../../../mol-model/location';
-import { ScaleLegend } from '../../../mol-util/color/scale';
+import { ScaleLegend, TableLegend } from '../../../mol-util/legend';
 import { getSymmetrySelectParam } from '../util';
 import { getPalette, getPaletteParams } from '../../../mol-util/color/palette';
-import { TableLegend } from '../../../mol-util/color/lists';
 
 const DefaultColor = Color(0xCCCCCC)
 
diff --git a/src/mol-plugin/skin/base/components/controls.scss b/src/mol-plugin/skin/base/components/controls.scss
index 5d40894a68651f05f19b55e03ec93e0ff64c08b7..367d6e783f7b7e05eb86eb949b5a82ea599898bf 100644
--- a/src/mol-plugin/skin/base/components/controls.scss
+++ b/src/mol-plugin/skin/base/components/controls.scss
@@ -302,5 +302,64 @@
     > div {
         line-height: $row-height;
         text-align: center;
+        color: color-lower-contrast($font-color, 15%);
+    }
+}
+
+.msp-help span {
+    display: none;
+}
+
+.msp-help:hover span {
+    display: inline-block;
+    background: linear-gradient($default-background, change-color($default-background, $alpha: 0.5));
+}
+
+.msp-help-text {
+    height: auto !important;
+
+    > div {
+        padding: ($control-spacing / 2) $control-spacing;
+        text-align: left;
+        color: color-lower-contrast($font-color, 15%);
+    }
+}
+
+.msp-help-description {
+    font-style: italic;
+}
+
+.msp-help-legend {
+    padding-top: $control-spacing;
+}
+
+.msp-scale-legend {
+    > div {
+        width: 100%;
+        height: $control-spacing * 3;
+
+        > span {
+            padding: $control-spacing / 2;
+            color: white;
+            font-weight: bold;
+            background-color: rgba(0, 0, 0, 0.2);
+        }
+    }
+}
+
+.msp-table-legend {
+    > div {
+        // min-width: 60px;
+        margin-right: $control-spacing / 2;
+        display: inline-flex;
+
+        .msp-table-legend-color {
+            width: $control-spacing * 3;
+            height: $control-spacing * 2;
+        }
+
+        .msp-table-legend-text {
+            margin: 0 ($control-spacing / 2);
+        }
     }
 }
\ No newline at end of file
diff --git a/src/mol-plugin/skin/base/icons.scss b/src/mol-plugin/skin/base/icons.scss
index 7c642ee711538fcf36bd3a881feb6d163d119e6f..49162eda4eb043fc06bee6c41b35a9f767c3afa0 100644
--- a/src/mol-plugin/skin/base/icons.scss
+++ b/src/mol-plugin/skin/base/icons.scss
@@ -4,45 +4,45 @@
   font-style: normal;
   font-weight: normal;
   speak: none;
- 
+
   display: inline-block;
   text-decoration: inherit;
   width: 1em;
   margin-right: .2em;
   text-align: center;
   /* opacity: .8; */
- 
+
   /* For safety - reset parent styles, that can break glyph codes*/
   font-variant: normal;
   text-transform: none;
- 
+
   /* fix buttons height, for twitter bootstrap */
   line-height: 1em;
- 
+
   /* Animation center compensation - margins should be symmetric */
   /* remove if not needed */
   margin-left: .2em;
- 
+
   /* you can be more comfortable with increased icons size */
   /* font-size: 120%; */
- 
+
   /* Font smoothing. That was taken from TWBS */
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
- 
+
   /* Uncomment for 3D effect */
   /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
 }
 
-.msp-icon-expand-layout:before { 
+.msp-icon-expand-layout:before {
 	content: "\e84a";
 }
 
-.msp-icon-plus:before { 
+.msp-icon-plus:before {
 	content: "\e816";
 }
 
-.msp-icon-minus:before { 
+.msp-icon-minus:before {
 	content: "\e819";
 }
 
@@ -50,19 +50,19 @@
 	content: "\e891";
 }
 
-.msp-icon-ok:before { 
+.msp-icon-ok:before {
 	content: "\e812";
 }
 
-.msp-icon-back:before { 
+.msp-icon-back:before {
 	content: "\e820";
 }
 
-.msp-icon-cross:before { 
+.msp-icon-cross:before {
 	content: "\e868";
 }
 
-.msp-icon-off:before { 
+.msp-icon-off:before {
 	content: "\e813";
 }
 
@@ -70,23 +70,23 @@
 	content: "\e885";
 }
 
-.msp-icon-collapse:before { 
+.msp-icon-collapse:before {
 	content: "\e883";
 }
 
-.msp-icon-visual-visibility:before { 
+.msp-icon-visual-visibility:before {
 	content: "\e826";
 }
 
-.msp-icon-abort:before { 
+.msp-icon-abort:before {
 	content: "\e814";
 }
 
-.msp-icon-focus-on-visual:before { 
+.msp-icon-focus-on-visual:before {
 	content: "\e8a3";
 }
 
-.msp-icon-settings:before  { 
+.msp-icon-settings:before  {
 	content: "\e855";
 }
 
@@ -106,6 +106,10 @@
     content: '\e81c'
 }
 
+.msp-icon-help-circle:before {
+	content: '\e81d';
+}
+
 .msp-icon-info:before {
     content: '\e81e'
 }
@@ -126,18 +130,10 @@
     content: '\e875'
 }
 
-.msp-icon-screenshot:before { 
+.msp-icon-screenshot:before {
 	content: "\e80f";
 }
 
-.msp-icon-help:before { 
-	content: "\e81c";
-}
-
-.msp-icon-help-circle:before { 
-	content: "\e81d";
-}
-
 .msp-icon-model-prev:before {
     content: "\e884";
 }
diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts
index 5e993e95f558cd92084045e86a5b55b292b6ae79..4ba293a3ebbd06942a793b6b5b36fda206684e40 100644
--- a/src/mol-plugin/state/transforms/representation.ts
+++ b/src/mol-plugin/state/transforms/representation.ts
@@ -135,6 +135,15 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
         const type = registry.get(registry.default.name);
 
         if (!a) {
+            const colorThemeInfo = {
+                help: (value: { name: string, params: {} }) => {
+                    const { name, params } = value
+                    const p = themeCtx.colorThemeRegistry.get(name)
+                    const ct = p.factory({}, params)
+                    return { description: ct.description, legend: ct.legend }
+                }
+            }
+
             return {
                 type: PD.Mapped<any>(
                     registry.default.name,
@@ -143,7 +152,8 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
                 colorTheme: PD.Mapped<any>(
                     type.defaultColorTheme,
                     themeCtx.colorThemeRegistry.types,
-                    name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ structure: Structure.Empty }))
+                    name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams({ structure: Structure.Empty })),
+                    colorThemeInfo
                 ),
                 sizeTheme: PD.Mapped<any>(
                     type.defaultSizeTheme,
@@ -154,6 +164,15 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
         }
 
         const dataCtx = { structure: a.data }
+        const colorThemeInfo = {
+            help: (value: { name: string, params: {} }) => {
+                const { name, params } = value
+                const p = themeCtx.colorThemeRegistry.get(name)
+                const ct = p.factory(dataCtx, params)
+                return { description: ct.description, legend: ct.legend }
+            }
+        }
+
         return ({
             type: PD.Mapped<any>(
                 registry.default.name,
@@ -162,7 +181,8 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
             colorTheme: PD.Mapped<any>(
                 type.defaultColorTheme,
                 themeCtx.colorThemeRegistry.getApplicableTypes(dataCtx),
-                name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx))
+                name => PD.Group<any>(themeCtx.colorThemeRegistry.get(name).getParams(dataCtx)),
+                colorThemeInfo
             ),
             sizeTheme: PD.Mapped<any>(
                 type.defaultSizeTheme,
diff --git a/src/mol-plugin/ui/controls/legend.tsx b/src/mol-plugin/ui/controls/legend.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..93463cef9668aba9bc5932f28e23620305449efb
--- /dev/null
+++ b/src/mol-plugin/ui/controls/legend.tsx
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2019 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 * as React from 'react';
+import { _Props, _State } from '../base';
+import { Legend as LegendData, ScaleLegend as ScaleLegendData, TableLegend as TableLegendData } from '../../../mol-util/legend';
+
+export type LegendProps<L extends LegendData> = { legend: L }
+export type Legend = React.ComponentClass<LegendProps<any>>
+
+export function legendFor(legend: LegendData): Legend | undefined {
+    switch (legend.kind) {
+        case 'scale-legend': return ScaleLegend
+        case 'table-legend': return TableLegend
+        default:
+            const _: never = legend;
+            console.warn(`${_} has no associated UI component`);
+            return void 0;
+    }
+}
+
+export class ScaleLegend extends React.PureComponent<LegendProps<ScaleLegendData>> {
+    render() {
+        const { legend } = this.props
+        const colors = legend.colors.map(c => Color.toStyle(c)).join(', ')
+        return  <div className='msp-scale-legend'>
+            <div style={{ background: `linear-gradient(to right, ${colors})` }}>
+                <span style={{float: 'left'}}>{legend.minLabel}</span>
+                <span style={{float: 'right'}}>{legend.maxLabel}</span>
+            </div>
+        </div>
+    }
+}
+
+export class TableLegend extends React.PureComponent<LegendProps<TableLegendData>> {
+    render() {
+        const { legend } = this.props
+        return <div className='msp-table-legend'>
+            {legend.table.map((value, i) => {
+                const [name, color] = value
+                return <div key={i}>
+                    <div className='msp-table-legend-color' style={{backgroundColor: Color.toStyle(color)}}></div>
+                    <div className='msp-table-legend-text'>{name}</div>
+                </div>
+            })}
+        </div>
+    }
+}
\ No newline at end of file
diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx
index fb373164cee802fa78321cbea798dd1ea168b029..58ffcae56db8367902441b597df5b21cf7047558 100644
--- a/src/mol-plugin/ui/controls/parameters.tsx
+++ b/src/mol-plugin/ui/controls/parameters.tsx
@@ -17,6 +17,8 @@ import LineGraphComponent from './line-graph/line-graph-component';
 import { Slider, Slider2 } from './slider';
 import { NumericInput, IconButton, ControlGroup } from './common';
 import { _Props, _State } from '../base';
+import { legendFor } from './legend';
+import { Legend as LegendData } from '../../../mol-util/legend';
 
 export interface ParameterControlsProps<P extends PD.Params = PD.Params> {
     params: P,
@@ -73,13 +75,34 @@ function controlFor(param: PD.Any): ParamControl | undefined {
     }
 }
 
-// type ParamWrapperProps = { name: string, value: any, param: PD.Base<any>, onChange: ParamOnChange, control: ValueControl, onEnter?: () => void, isEnabled?: boolean }
+export class ParamHelp<L extends LegendData> extends React.PureComponent<{ legend?: L, description?: string }> {
+    render() {
+        const { legend, description } = this.props
+        const Legend = legend && legendFor(legend)
+
+        return <div className='msp-control-row msp-help-text'>
+            <div>
+                <div className='msp-help-description'><span className={`msp-icon msp-icon-help-circle`} />{description}</div>
+                <div className='msp-help-legend'>{Legend && <Legend legend={legend} />}</div>
+            </div>
+        </div>
+    }
+}
 
 export type ParamOnChange = (params: { param: PD.Base<any>, name: string, value: any }) => void
-export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> { name: string, value: P['defaultValue'], param: P, isDisabled?: boolean, onChange: ParamOnChange, onEnter?: () => void }
+export interface ParamProps<P extends PD.Base<any> = PD.Base<any>> {
+    name: string,
+    value: P['defaultValue'],
+    param: P,
+    isDisabled?: boolean,
+    onChange: ParamOnChange,
+    onEnter?: () => void
+}
 export type ParamControl = React.ComponentClass<ParamProps<any>>
 
-export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<ParamProps<P>> {
+export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<ParamProps<P>, { isExpanded: boolean }> {
+    state = { isExpanded: false };
+
     protected update(value: P['defaultValue']) {
         this.props.onChange({ param: this.props.param, name: this.props.name, value });
     }
@@ -93,14 +116,33 @@ export abstract class SimpleParam<P extends PD.Any> extends React.PureComponent<
         return className.join(' ')
     }
 
+    toggleExpanded = () => this.setState({ isExpanded: !this.state.isExpanded });
+
     render() {
         const label = this.props.param.label || camelCaseToWords(this.props.name);
-        return <div className={this.className}>
-            <span title={this.props.param.description}>{label}</span>
-            <div>
-                {this.renderControl()}
+        const help = this.props.param.help
+            ? this.props.param.help(this.props.value)
+            : { description: this.props.param.description, legend: this.props.param.legend }
+        const hasHelp = help.description || help.legend
+        return <>
+            <div className={this.className}>
+                <span title={this.props.param.description}>
+                    {label}
+                    {hasHelp &&
+                        <button className='msp-help msp-btn-link msp-btn-icon msp-conrol-group-expander' onClick={this.toggleExpanded} title={`${this.state.isExpanded ? 'Hide' : 'Show'} help`}
+                                style={{ background: 'transparent', textAlign: 'left', padding: '0' }}>
+                                <span className={`msp-icon msp-icon-help-circle`} />
+                        </button>
+                    }
+                </span>
+                <div>
+                    {this.renderControl()}
+                </div>
             </div>
-        </div>;
+            {hasHelp && this.state.isExpanded && <div className='msp-control-offset'>
+                <ParamHelp legend={help.legend} description={help.description} />
+            </div>}
+        </>;
     }
 }
 
@@ -526,16 +568,24 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any>
         const label = this.props.param.label || camelCaseToWords(this.props.name);
         const Mapped = controlFor(param);
 
-        const select = <SelectControl param={this.props.param.select}
+        const help = this.props.param.help
+        const select = help
+            ? {
+                ...this.props.param.select,
+                help: (name: any) => help({ name, params: this.getValues(name) })
+            }
+            : this.props.param.select
+
+        const Select = <SelectControl param={select}
             isDisabled={this.props.isDisabled} onChange={this.onChangeName} onEnter={this.props.onEnter}
             name={label} value={value.name} />
 
         if (!Mapped) {
-            return select;
+            return Select;
         }
 
         return <>
-            {select}
+            {Select}
             <Mapped param={param} value={value.params} name={`${label} Properties`} onChange={this.onChangeParam} onEnter={this.props.onEnter} isDisabled={this.props.isDisabled} />
         </>
     }
diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts
index 18edc8457a92f6972cf8f77cdbf78060bda91c18..0b7cf68dc79c7a859aacd33ab327907c2c34d113 100644
--- a/src/mol-theme/color.ts
+++ b/src/mol-theme/color.ts
@@ -24,8 +24,7 @@ import { SecondaryStructureColorThemeProvider } from './color/secondary-structur
 import { SequenceIdColorThemeProvider } from './color/sequence-id';
 import { ShapeGroupColorThemeProvider } from './color/shape-group';
 import { UnitIndexColorThemeProvider } from './color/unit-index';
-import { ScaleLegend } from '../mol-util/color/scale';
-import { TableLegend } from '../mol-util/color/lists';
+import { ScaleLegend, TableLegend } from '../mol-util/legend';
 import { UncertaintyColorThemeProvider } from './color/uncertainty';
 import { EntitySourceColorThemeProvider } from './color/entity-source';
 import { IllustrativeColorThemeProvider } from './color/illustrative';
diff --git a/src/mol-theme/color/carbohydrate-symbol.ts b/src/mol-theme/color/carbohydrate-symbol.ts
index 6f338108a6161ed12bb2cdfc87ee5448e35ee59f..2a56f21d3a6415f3b07e709b547db1837d37824e 100644
--- a/src/mol-theme/color/carbohydrate-symbol.ts
+++ b/src/mol-theme/color/carbohydrate-symbol.ts
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,7 +11,7 @@ import { ColorTheme, LocationColor } from '../color';
 import { Color } from '../../mol-util/color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Assigns colors according to the Symbol Nomenclature for Glycans (SNFG).'
diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts
index e03b204091dd055508feca7cad06082e26c71732..e7188bedb41210eb565990d7962e663747d48c0c 100644
--- a/src/mol-theme/color/chain-id.ts
+++ b/src/mol-theme/color/chain-id.ts
@@ -10,9 +10,8 @@ import { Location } from '../../mol-model/location';
 import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
-import { ScaleLegend } from '../../mol-util/color/scale';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 import { Segmentation } from '../../mol-data/int';
 
 const DefaultColor = Color(0xFAFAFA)
diff --git a/src/mol-theme/color/element-index.ts b/src/mol-theme/color/element-index.ts
index 66146728d08feaf9a3929004a553e165a33b6ea5..990068c8177b1584826d66c988b2cce31f6fe7c8 100644
--- a/src/mol-theme/color/element-index.ts
+++ b/src/mol-theme/color/element-index.ts
@@ -12,8 +12,7 @@ import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
-import { TableLegend } from '../../mol-util/color/lists';
-import { ScaleLegend } from '../../mol-util/color/scale';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 
 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.'
diff --git a/src/mol-theme/color/element-symbol.ts b/src/mol-theme/color/element-symbol.ts
index 46ca5dd74ff05741f44c7a7237be70b7c8289a05..27e0c117ce15a267db3b69fed2eb4180c0ff5ed6 100644
--- a/src/mol-theme/color/element-symbol.ts
+++ b/src/mol-theme/color/element-symbol.ts
@@ -11,7 +11,7 @@ import { Location } from '../../mol-model/location';
 import { ColorTheme } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { getAdjustedColorMap } from '../../mol-util/color/color';
 
 // from Jmol http://jmol.sourceforge.net/jscolors/ (or 0xFFFFFF)
diff --git a/src/mol-theme/color/entity-source.ts b/src/mol-theme/color/entity-source.ts
index ac8ebd3c86d4e8d81d6578e5021c6032626ebc86..92b4d60ee6aef963eaffbe3e8c836268f58cfdf2 100644
--- a/src/mol-theme/color/entity-source.ts
+++ b/src/mol-theme/color/entity-source.ts
@@ -10,11 +10,10 @@ import { Location } from '../../mol-model/location';
 import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
-import { ScaleLegend } from '../../mol-util/color/scale';
 import { Table, Column } from '../../mol-data/db';
 import { mmCIF_Schema } from '../../mol-io/reader/cif/schema/mmcif';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 
 const DefaultColor = Color(0xFAFAFA)
 const Description = 'Gives ranges of a polymer chain a color based on the entity source it originates from. Genes get the same color per entity.'
diff --git a/src/mol-theme/color/model-index.ts b/src/mol-theme/color/model-index.ts
index faf151815d4110dacb2502b15188ca26694dd7cd..39d398c8824e5531321e4f5fd578a10b792e0ea6 100644
--- a/src/mol-theme/color/model-index.ts
+++ b/src/mol-theme/color/model-index.ts
@@ -10,9 +10,8 @@ import { StructureElement, Link } from '../../mol-model/structure';
 import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
-import { ScaleLegend } from '../../mol-util/color/scale';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every model a unique color based on the position (index) of the model in the list of models in the structure.'
diff --git a/src/mol-theme/color/molecule-type.ts b/src/mol-theme/color/molecule-type.ts
index 7bc5eca8637e557c33eab3033ddb984ba02ec988..a1c808c3b488201d970540f4dc6153b1908ee928 100644
--- a/src/mol-theme/color/molecule-type.ts
+++ b/src/mol-theme/color/molecule-type.ts
@@ -12,7 +12,7 @@ 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 '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { getAdjustedColorMap } from '../../mol-util/color/color';
 
 export const MoleculeTypeColors = ColorMap({
diff --git a/src/mol-theme/color/polymer-id.ts b/src/mol-theme/color/polymer-id.ts
index 3910089d83cc8e80665627d1a0b21fd888ddc707..5df2bc59983be4f5a6117b0a4b9e33f625acb308 100644
--- a/src/mol-theme/color/polymer-id.ts
+++ b/src/mol-theme/color/polymer-id.ts
@@ -12,8 +12,7 @@ import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
 import { getPalette, getPaletteParams } from '../../mol-util/color/palette';
-import { ScaleLegend } from '../../mol-util/color/scale';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 import { Segmentation } from '../../mol-data/int';
 
 const DefaultColor = Color(0xFAFAFA)
diff --git a/src/mol-theme/color/polymer-index.ts b/src/mol-theme/color/polymer-index.ts
index 1dc4d59fcca5fedd5d361c3444fee59a09107587..2233487402935173084c68fcfc5dc90c9ddd9f01 100644
--- a/src/mol-theme/color/polymer-index.ts
+++ b/src/mol-theme/color/polymer-index.ts
@@ -10,8 +10,7 @@ import { StructureElement, Link, Structure } from '../../mol-model/structure';
 import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
-import { ScaleLegend } from '../../mol-util/color/scale';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
 
 const DefaultColor = Color(0xCCCCCC)
diff --git a/src/mol-theme/color/residue-name.ts b/src/mol-theme/color/residue-name.ts
index 06151d63dae8a5f7521d9c3e37699ec1cbaf0771..c2e98072409845f197ef2f377f0d079e0c67bd38 100644
--- a/src/mol-theme/color/residue-name.ts
+++ b/src/mol-theme/color/residue-name.ts
@@ -10,7 +10,7 @@ import { Location } from '../../mol-model/location';
 import { ColorTheme } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { getAdjustedColorMap } from '../../mol-util/color/color';
 
 // protein colors from Jmol http://jmol.sourceforge.net/jscolors/
diff --git a/src/mol-theme/color/secondary-structure.ts b/src/mol-theme/color/secondary-structure.ts
index afa12534c3464d0e36b0e1f49e61d731f18177ee..006a3dbaab484afa41cabae8874626019029f6b0 100644
--- a/src/mol-theme/color/secondary-structure.ts
+++ b/src/mol-theme/color/secondary-structure.ts
@@ -12,7 +12,7 @@ import { SecondaryStructureType, MoleculeType } from '../../mol-model/structure/
 import { getElementMoleculeType } from '../../mol-model/structure/util';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { ComputedSecondaryStructure } from '../../mol-model-props/computed/secondary-structure';
 import { getAdjustedColorMap } from '../../mol-util/color/color';
 
diff --git a/src/mol-theme/color/uniform.ts b/src/mol-theme/color/uniform.ts
index 4fdb7c2d427129cd9d1be257650a49037e67a14b..6bc0e8bdc70be6be9be3c061eb5c7936ab8d270d 100644
--- a/src/mol-theme/color/uniform.ts
+++ b/src/mol-theme/color/uniform.ts
@@ -8,7 +8,7 @@ import { ColorTheme } from '../color';
 import { Color } from '../../mol-util/color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../theme';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend } from '../../mol-util/legend';
 import { defaults } from '../../mol-util';
 
 const DefaultColor = Color(0xCCCCCC)
diff --git a/src/mol-theme/color/unit-index.ts b/src/mol-theme/color/unit-index.ts
index a57d648762fe13559b8526e850c978eb3a3cd172..c1f42c49ff897b64d5bee1c1adc5dbf4ad812d52 100644
--- a/src/mol-theme/color/unit-index.ts
+++ b/src/mol-theme/color/unit-index.ts
@@ -10,9 +10,8 @@ import { StructureElement, Link } from '../../mol-model/structure';
 import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from '../../mol-util/param-definition'
 import { ThemeDataContext } from '../../mol-theme/theme';
-import { ScaleLegend } from '../../mol-util/color/scale';
 import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
-import { TableLegend } from '../../mol-util/color/lists';
+import { TableLegend, ScaleLegend } from '../../mol-util/legend';
 
 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.'
diff --git a/src/mol-util/color/lists.ts b/src/mol-util/color/lists.ts
index 531f92ff0af159a0515d5194defd49b03c6085fd..e0ade6d6ffd10d24e3058fbf94c4d544e9a8d069 100644
--- a/src/mol-util/color/lists.ts
+++ b/src/mol-util/color/lists.ts
@@ -4,15 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Color, ColorList } from './color';
-
-export interface TableLegend {
-    kind: 'table-legend'
-    table: [ string, Color ][]
-}
-export function TableLegend(table: [ string, Color ][]): TableLegend {
-    return { kind: 'table-legend', table }
-}
+import { ColorList } from './color';
 
 export const ColorLists = {
     /**
diff --git a/src/mol-util/color/palette.ts b/src/mol-util/color/palette.ts
index e0791f8f9c105b86681b5b8150db3dfdc55ccd9b..d05fa5aa52033fc00da71c8920af0f06844a2484 100644
--- a/src/mol-util/color/palette.ts
+++ b/src/mol-util/color/palette.ts
@@ -6,9 +6,10 @@
 
 import { ParamDefinition as PD } from '../param-definition'
 import { DistinctColorsParams, distinctColors } from './distinct';
-import { ScaleLegend, ColorScale } from './scale';
+import { ColorScale } from './scale';
 import { Color } from '.';
-import { TableLegend, ColorListName, ColorListOptionsScale, ColorListOptionsSet, getColorListFromName } from './lists';
+import { ColorListName, ColorListOptionsScale, ColorListOptionsSet, getColorListFromName } from './lists';
+import { TableLegend, ScaleLegend } from '../legend';
 
 type PaletteType = 'generate' | 'scale' | 'set'
 
@@ -71,6 +72,7 @@ export function getPalette(count: number, props: PaletteProps) {
             colors = distinctColors(count, props.palette.params)
         }
         const colorsLength = colors.length
+        legend = TableLegend(colors.map((c, i) => [`${i + 1}`, c]))
         color = (i: number) => colors[i % colorsLength]
     }
 
diff --git a/src/mol-util/color/scale.ts b/src/mol-util/color/scale.ts
index 31b33f774487522593ba480d83a8949b3105de99..9745506ae6e6278337d174602869d14857261ccf 100644
--- a/src/mol-util/color/scale.ts
+++ b/src/mol-util/color/scale.ts
@@ -8,16 +8,7 @@ import { Color } from './color'
 import { getColorListFromName, ColorListName } from './lists'
 import { defaults } from '../../mol-util';
 import { NumberArray } from '../../mol-util/type-helpers';
-
-export interface ScaleLegend {
-    kind: 'scale-legend'
-    minLabel: string,
-    maxLabel: string,
-    colors: Color[]
-}
-export function ScaleLegend(minLabel: string, maxLabel: string, colors: Color[]): ScaleLegend {
-    return { kind: 'scale-legend', minLabel, maxLabel, colors }
-}
+import { ScaleLegend } from '../legend';
 
 export interface ColorScale {
     /** Returns hex color for given value */
diff --git a/src/mol-util/legend.ts b/src/mol-util/legend.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4079fa8c3e7e8bc5511c1d189179538fbbd4c094
--- /dev/null
+++ b/src/mol-util/legend.ts
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Color } from './color';
+
+export type Legend = TableLegend | ScaleLegend
+
+export interface TableLegend {
+    kind: 'table-legend'
+    table: [ string, Color ][]
+}
+export function TableLegend(table: [ string, Color ][]): TableLegend {
+    return { kind: 'table-legend', table }
+}
+
+export interface ScaleLegend {
+    kind: 'scale-legend'
+    minLabel: string,
+    maxLabel: string,
+    colors: Color[]
+}
+export function ScaleLegend(minLabel: string, maxLabel: string, colors: Color[]): ScaleLegend {
+    return { kind: 'scale-legend', minLabel, maxLabel, colors }
+}
\ No newline at end of file
diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts
index 51792e49b8e3dac2721e22fdbdcaec6ffe1f9ac0..486acb15ef0fb99e2fcbd995395f595f29637e09 100644
--- a/src/mol-util/param-definition.ts
+++ b/src/mol-util/param-definition.ts
@@ -10,25 +10,32 @@ import { shallowEqual } from './index';
 import { Vec2 as Vec2Data, Vec3 as Vec3Data } from '../mol-math/linear-algebra';
 import { deepClone } from './object';
 import { Script as ScriptData } from '../mol-script/script';
+import { Legend } from './legend';
 
 export namespace ParamDefinition {
     export interface Info {
         label?: string,
         description?: string,
+        legend?: Legend,
         fieldLabels?: { [name: string]: string },
         isHidden?: boolean,
         shortLabel?: boolean,
         twoColumns?: boolean,
+
+        help?: (value: any) => { description?: string, legend?: Legend }
     }
 
     function setInfo<T extends Info>(param: T, info?: Info): T {
         if (!info) return param;
         if (info.label) param.label = info.label;
         if (info.description) param.description = info.description;
+        if (info.legend) param.legend = info.legend;
         if (info.fieldLabels) param.fieldLabels = info.fieldLabels;
         if (info.isHidden) param.isHidden = info.isHidden;
         if (info.shortLabel) param.shortLabel = info.shortLabel;
         if (info.twoColumns) param.twoColumns = info.twoColumns;
+
+        if (info.help) param.help = info.help;
         return param;
     }
 
diff --git a/src/mol-util/type-helpers.ts b/src/mol-util/type-helpers.ts
index a6e5f3c4206311ab97ceea6d6ff591c68577830d..22e9b6ae51afe0c1832ccafc3d2db7ef09f09e85 100644
--- a/src/mol-util/type-helpers.ts
+++ b/src/mol-util/type-helpers.ts
@@ -5,9 +5,9 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-export type Mutable<T> = {
-    -readonly [P in keyof T]: T[P]
-}
+export type Mutable<T> = { -readonly [P in keyof T]: T[P] }
+export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
+
 export type TypedIntArray = Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array
 export type TypedFloatArray = Float32Array | Float64Array