diff --git a/src/apps/viewer/index.html b/src/apps/viewer/index.html
index e65ee3281561d7e5cf111c03740d03ffa38072fb..9a57c1d04577e84284f8bb4b9fcf4318a918b97f 100644
--- a/src/apps/viewer/index.html
+++ b/src/apps/viewer/index.html
@@ -8,6 +8,7 @@
             * {
                 margin: 0;
                 padding: 0;
+                box-sizing: border-box;
             }
             html, body {
                 width: 100%;
diff --git a/src/mol-app/component/parameters.tsx b/src/mol-app/component/parameters.tsx
index 02e47939a7d0a7b064c8482d3ea8ab88917a6347..c5c0c673ccecee6122783cfe0e0ca61427dd4d9e 100644
--- a/src/mol-app/component/parameters.tsx
+++ b/src/mol-app/component/parameters.tsx
@@ -48,7 +48,7 @@ export class ParametersComponent<P extends PD.Params> extends React.Component<Pa
     }
 
     render() {
-        return <div>
+        return <div style={{ width: '100%' }}>
             { Object.keys(this.props.params).map(k => {
                 const param = this.props.params[k]
                 const value = this.props.values[k]
diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts
index 50718e3e7e9d8d888ff52ec89236b47e8c8cf779..12f4a76b64c6d6f806b3b9d00fea8ce0ab8da522 100644
--- a/src/mol-plugin/context.ts
+++ b/src/mol-plugin/context.ts
@@ -100,6 +100,11 @@ export class PluginContext {
         PluginCommands.Data.Update.dispatch(this, { tree });
     }
 
+    _test_updateTransform(a: Transform.Ref, params: any) {
+        const tree = StateTree.updateParams(this.state.data.tree, a, params);
+        PluginCommands.Data.Update.dispatch(this, { tree });
+    }
+
     _test_createState(url: string) {
         const b = StateTree.build(this.state.data.tree);
 
diff --git a/src/mol-plugin/ui/controls.tsx b/src/mol-plugin/ui/controls.tsx
index 71723f5b754201b6d07b7c522d86ac8613d3ed69..ccf64d214db9be04d8a9f7e4f2d6256f45514526 100644
--- a/src/mol-plugin/ui/controls.tsx
+++ b/src/mol-plugin/ui/controls.tsx
@@ -6,7 +6,7 @@
 
 import * as React from 'react';
 import { PluginContext } from '../context';
-import { Transform, Transformer } from 'mol-state';
+import { Transform, Transformer, StateSelection } from 'mol-state';
 import { ParametersComponent } from 'mol-app/component/parameters';
 
 export class Controls extends React.Component<{ plugin: PluginContext }, { id: string }> {
@@ -88,4 +88,55 @@ export class _test_CreateTransform extends React.Component<{ plugin: PluginConte
             <button onClick={() => this.create()} style={{ width: '100%' }}>Create</button>
         </div>
     }
+}
+
+export class _test_UpdateTransform extends React.Component<{ plugin: PluginContext, nodeRef: Transform.Ref }, { params: any }> {
+    private getTransform() {
+        const t = this.props.plugin.state.data.tree.nodes.get(this.props.nodeRef)!;
+        return t ? t.value : t;
+    }
+
+    private getParamDef() {
+        const def = this.getTransform().transformer.definition;
+        if (!def.params || !def.params.controls) return void 0;
+
+        const src = StateSelection.ancestorOfType(this.props.nodeRef, def.from).select(this.props.plugin.state.data)[0];
+
+        console.log(src, def.from);
+
+        if (!src || !src.obj) return void 0;
+        return def.params.controls(src.obj, this.props.plugin);
+    }
+
+    private update() {
+        console.log(this.props.nodeRef, this.state.params);
+        this.props.plugin._test_updateTransform(this.props.nodeRef, this.state.params);
+    }
+
+    // componentDidMount() {
+    //     const t = this.props.plugin.state.data.tree.nodes.get(this.props.nodeRef)!;
+    //     if (t) this.setState({ params: t.value.params });
+    // }
+
+    state = { params: this.getTransform() ? this.getTransform().params : { } };
+
+    render() {
+        const transform = this.getTransform();
+        if (!transform || transform.ref === this.props.plugin.state.data.tree.rootRef) {
+            return <div />;
+        }
+
+        const params = this.getParamDef();
+        if (!params) return <div />;
+
+        const tr = transform.transformer;
+
+        return <div key={`${this.props.nodeRef} ${tr.id}`}>
+            <div style={{ borderBottom: '1px solid #999'}}>{(tr.definition.display && tr.definition.display.name) || tr.definition.name}</div>
+            <ParametersComponent params={params} values={this.state.params as any} onChange={(k, v) => {
+                this.setState({ params: { ...this.state.params, [k]: v } });
+            }} />
+            <button onClick={() => this.update()} style={{ width: '100%' }}>Update</button>
+        </div>
+    }
 }
\ No newline at end of file
diff --git a/src/mol-plugin/ui/plugin.tsx b/src/mol-plugin/ui/plugin.tsx
index 520b55069ed12fa8ca601bbf27b02e6e93a66eb0..4c0eb7a9d4d515c2b2d08c07a18bc93a3123c979 100644
--- a/src/mol-plugin/ui/plugin.tsx
+++ b/src/mol-plugin/ui/plugin.tsx
@@ -8,7 +8,7 @@ import * as React from 'react';
 import { PluginContext } from '../context';
 import { StateTree } from './state-tree';
 import { Viewport } from './viewport';
-import { Controls, _test_CreateTransform } from './controls';
+import { Controls, _test_CreateTransform, _test_UpdateTransform } from './controls';
 import { Transformer } from 'mol-state';
 
 // TODO: base object with subscribe helpers, separate behavior list etc
@@ -52,6 +52,10 @@ export class _test_CurrentObject extends React.Component<{ plugin: PluginContext
         return <div>
             Current Ref: {this.props.plugin.behaviors.state.data.currentObject.value.ref}
             <hr />
+            <h3>Update</h3>
+            <_test_UpdateTransform key={`${ref} update`} plugin={this.props.plugin} nodeRef={ref} />
+            <hr />
+            <h3>Create</h3>
             {
                 transforms.map((t, i) => <_test_CreateTransform key={`${t.id} ${ref} ${i}`} plugin={this.props.plugin} transformer={t} nodeRef={ref} />)
             }
diff --git a/src/mol-plugin/ui/state-tree.tsx b/src/mol-plugin/ui/state-tree.tsx
index 7159725571a87b72d6f93e92dacb248046d57585..66967f956c17a548e29be316cc443e4e44a991f1 100644
--- a/src/mol-plugin/ui/state-tree.tsx
+++ b/src/mol-plugin/ui/state-tree.tsx
@@ -35,19 +35,25 @@ export class StateTreeNode extends React.Component<{ plugin: PluginContext, node
             PluginCommands.Data.RemoveObject.dispatch(this.props.plugin, { ref: this.props.nodeRef });
         }}>X</a>]</>
 
+        let label: any;
         if (cell.status !== 'ok' || !cell.obj) {
-            return <div style={{ borderLeft: '1px solid black', paddingLeft: '7px' }}>
-                {remove} {cell.status} {cell.errorText}
-            </div>;
-        }
-        const obj = cell.obj as PluginStateObject.Any;
-        const props = obj.props;
-        const type = obj.type;
-        return <div style={{ borderLeft: '0px solid #999', paddingLeft: '0px' }}>
-            {remove}[<span title={type.description}>{ type.shortName }</span>] <a href='#' onClick={e => {
+            const name = (n.value.transformer.definition.display && n.value.transformer.definition.display.name) || n.value.transformer.definition.name;
+            label = <><b>{cell.status}</b> <a href='#' onClick={e => {
+                e.preventDefault();
+                PluginCommands.Data.SetCurrentObject.dispatch(this.props.plugin, { ref: this.props.nodeRef });
+            }}>{name}</a>: <i>{cell.errorText}</i></>;
+        } else {
+            const obj = cell.obj as PluginStateObject.Any;
+            const props = obj.props;
+            const type = obj.type;
+            label = <>[<span title={type.description}>{ type.shortName }</span>] <a href='#' onClick={e => {
                 e.preventDefault();
                 PluginCommands.Data.SetCurrentObject.dispatch(this.props.plugin, { ref: this.props.nodeRef });
-            }}>{props.label}</a> {props.description ? <small>{props.description}</small> : void 0}
+            }}>{props.label}</a> {props.description ? <small>{props.description}</small> : void 0}</>;
+        }
+
+        return <div>
+            {remove}{label}
             {n.children.size === 0
                 ? void 0
                 : <div style={{ marginLeft: '7px', paddingLeft: '3px', borderLeft: '1px solid #999' }}>{n.children.map(c => <StateTreeNode plugin={this.props.plugin} state={this.props.state} nodeRef={c!} key={c} />)}</div>
diff --git a/src/mol-state/immutable-tree.ts b/src/mol-state/immutable-tree.ts
index dd7ce8f90afa53c5580857edfff29f1b585e1c4f..3d94a90d5a2fc828438e3b96b6057ed1e964afaf 100644
--- a/src/mol-state/immutable-tree.ts
+++ b/src/mol-state/immutable-tree.ts
@@ -72,7 +72,7 @@ export namespace ImmutableTree {
     /**
      * Visit all nodes in a subtree in "post order", meaning leafs get visited first.
      */
-    export function doPostOrder<T, S>(tree: ImmutableTree<T>, root: Node<T>, state: S, f: (node: Node<T>, nodes: Nodes<T>, state: S) => boolean | undefined | void) {
+    export function doPostOrder<T, S>(tree: ImmutableTree<T>, root: Node<T>, state: S, f: (node: Node<T>, nodes: Nodes<T>, state: S) => boolean | undefined | void): S {
         const ctx: VisitorCtx = { nodes: tree.nodes, state, f };
         _doPostOrder(ctx, root);
         return ctx.state;
@@ -91,7 +91,7 @@ export namespace ImmutableTree {
      * Visit all nodes in a subtree in "pre order", meaning leafs get visited last.
      * If the visitor function returns false, the visiting for that branch is interrupted.
      */
-    export function doPreOrder<T, S>(tree: ImmutableTree<T>, root: Node<T>, state: S, f: (node: Node<T>, nodes: Nodes<T>, state: S) => boolean | undefined | void) {
+    export function doPreOrder<T, S>(tree: ImmutableTree<T>, root: Node<T>, state: S, f: (node: Node<T>, nodes: Nodes<T>, state: S) => boolean | undefined | void): S {
         const ctx: VisitorCtx = { nodes: tree.nodes, state, f };
         _doPreOrder(ctx, root);
         return ctx.state;
@@ -218,18 +218,23 @@ export namespace ImmutableTree {
             return node;
         }
 
-        remove<T>(ref: ImmutableTree.Ref): Node<T>[] {
+        remove(ref: ImmutableTree.Ref): Node<T>[] {
+            if (ref === this.rootRef) {
+                return this.removeChildren(ref);
+            }
+
             const { nodes, mutations } = this;
             const node = nodes.get(ref);
             if (!node) return [];
             const parent = nodes.get(node.parent)!;
-            const children = this.mutate(parent.ref).children;
+            this.mutate(parent.ref).children.delete(ref);
+
             const st = subtreePostOrder(this, node);
-            if (ref !== this.rootRef) children.delete(ref);
             for (const n of st) {
-                nodes.delete(n.value.ref);
-                mutations.delete(n.value.ref);
+                nodes.delete(n.ref);
+                mutations.delete(n.ref);
             }
+
             return st;
         }
 
@@ -239,11 +244,12 @@ export namespace ImmutableTree {
             if (!node || !node.children.size) return [];
             node = this.mutate(ref);
             const st = subtreePostOrder(this, node);
+            // remove the last node which is the parent
+            st.pop();
             node.children.clear();
             for (const n of st) {
-                if (n === node) continue;
-                nodes.delete(n.value.ref);
-                mutations.delete(n.value.ref);
+                nodes.delete(n.ref);
+                mutations.delete(n.ref);
             }
             return st;
         }
diff --git a/src/mol-state/selection.ts b/src/mol-state/selection.ts
index e7eb61d63f257c04a176925101a334ae464f026f..e61dd2611e541476f57e2c7419684974f49bdb3a 100644
--- a/src/mol-state/selection.ts
+++ b/src/mol-state/selection.ts
@@ -47,13 +47,20 @@ namespace StateSelection {
         parent(): Builder;
         first(): Builder;
         filter(p: (n: StateObjectCell) => boolean): Builder;
+        withStatus(s: StateObjectCell.Status): Builder;
         subtree(): Builder;
         children(): Builder;
         ofType(t: StateObject.Type): Builder;
         ancestorOfType(t: StateObject.Type): Builder;
+
+        select(state: State): CellSeq
     }
 
-    const BuilderPrototype: any = {};
+    const BuilderPrototype: any = {
+        select(state: State) {
+            return select(this, state);
+        }
+    };
 
     function registerModifier(name: string, f: Function) {
         BuilderPrototype[name] = function (this: any, ...args: any[]) { return f.call(void 0, this, ...args) };
@@ -135,6 +142,9 @@ namespace StateSelection {
     registerModifier('filter', filter);
     export function filter(b: Selector, p: (n: StateObjectCell) => boolean) { return flatMap(b, n => p(n) ? [n] : []); }
 
+    registerModifier('withStatus', withStatus);
+    export function withStatus(b: Selector, s: StateObjectCell.Status) { return filter(b, n => n.status === s); }
+
     registerModifier('subtree', subtree);
     export function subtree(b: Selector) {
         return flatMap(b, (n, s) => {
@@ -157,20 +167,22 @@ namespace StateSelection {
     export function ofType(b: Selector, t: StateObject.Type) { return filter(b, n => n.obj ? n.obj.type === t : false); }
 
     registerModifier('ancestorOfType', ancestorOfType);
-    export function ancestorOfType(b: Selector, t: StateObject.Type) { return unique(mapEntity(b, (n, s) => findAncestorOfType(s, n.ref, t))); }
+    export function ancestorOfType(b: Selector, types: StateObject.Ctor[]) { return unique(mapEntity(b, (n, s) => findAncestorOfType(s, n.ref, types))); }
 
     registerModifier('parent', parent);
     export function parent(b: Selector) { return unique(mapEntity(b, (n, s) => s.cells.get(s.tree.nodes.get(n.ref)!.parent))); }
 
-    function findAncestorOfType({ tree, cells }: State, root: string, type: StateObject.Type): StateObjectCell | undefined {
-        let current = tree.nodes.get(root)!;
+    function findAncestorOfType({ tree, cells }: State, root: string, types: StateObject.Ctor[]): StateObjectCell | undefined {
+        let current = tree.nodes.get(root)!, len = types.length;
         while (true) {
             current = tree.nodes.get(current.parent)!;
             if (current.ref === tree.rootRef) {
                 return cells.get(tree.rootRef);
             }
             const obj = cells.get(current.ref)!.obj!;
-            if (obj.type === type) return cells.get(current.ref);
+            for (let i = 0; i < len; i++) {
+                if (obj.type === types[i].type) return cells.get(current.ref);
+            }
         }
     }
 }
diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts
index 5851edbd99380b66604ee36b49ac837c6704db1f..0176e2fefabd1e7463675e81492dbe851afc3402 100644
--- a/src/mol-state/state.ts
+++ b/src/mol-state/state.ts
@@ -68,7 +68,7 @@ class State {
                     taskCtx,
                     oldTree,
                     tree: tree,
-                    objects: this.cells,
+                    cells: this.cells,
                     transformCache: this.transformCache
                 };
                 // TODO: have "cancelled" error? Or would this be handled automatically?
@@ -120,16 +120,16 @@ namespace State {
         taskCtx: RuntimeContext,
         oldTree: StateTree,
         tree: StateTree,
-        objects: State.Cells,
+        cells: State.Cells,
         transformCache: Map<Ref, unknown>
     }
 
     async function update(ctx: UpdateContext) {
-        const roots = findUpdateRoots(ctx.objects, ctx.tree);
+        const roots = findUpdateRoots(ctx.cells, ctx.tree);
         const deletes = findDeletes(ctx);
         for (const d of deletes) {
-            const obj = ctx.objects.has(d) ? ctx.objects.get(d)!.obj : void 0;
-            ctx.objects.delete(d);
+            const obj = ctx.cells.has(d) ? ctx.cells.get(d)!.obj : void 0;
+            ctx.cells.delete(d);
             ctx.transformCache.delete(d);
             ctx.stateCtx.events.object.removed.next({ ref: d, obj });
             // TODO: handle current object change
@@ -168,7 +168,7 @@ namespace State {
     function findDeletes(ctx: UpdateContext): Ref[] {
         // TODO: do this in some sort of "tree order"?
         const deletes: Ref[] = [];
-        const keys = ctx.objects.keys();
+        const keys = ctx.cells.keys();
         while (true) {
             const key = keys.next();
             if (key.done) break;
@@ -179,14 +179,14 @@ namespace State {
 
     function setObjectState(ctx: UpdateContext, ref: Ref, status: StateObjectCell.Status, errorText?: string) {
         let changed = false;
-        if (ctx.objects.has(ref)) {
-            const obj = ctx.objects.get(ref)!;
+        if (ctx.cells.has(ref)) {
+            const obj = ctx.cells.get(ref)!;
             changed = obj.status !== status;
             obj.status = status;
             obj.errorText = errorText;
         } else {
             const obj: StateObjectCell = { ref, status, version: UUID.create(), errorText, props: { ...ctx.stateCtx.defaultObjectProps } };
-            ctx.objects.set(ref, obj);
+            ctx.cells.set(ref, obj);
             changed = true;
         }
         if (changed) ctx.stateCtx.events.object.stateChanged.next({ ref });
@@ -204,7 +204,7 @@ namespace State {
 
     function doError(ctx: UpdateContext, ref: Ref, errorText: string) {
         setObjectState(ctx, ref, 'error', errorText);
-        const wrap = ctx.objects.get(ref)!;
+        const wrap = ctx.cells.get(ref)!;
         if (wrap.obj) {
             ctx.stateCtx.events.object.removed.next({ ref });
             ctx.transformCache.delete(ref);
@@ -258,14 +258,14 @@ namespace State {
     }
 
     async function updateNode(ctx: UpdateContext, currentRef: Ref) {
-        const { oldTree, tree, objects } = ctx;
+        const { oldTree, tree, cells } = ctx;
         const transform = tree.getValue(currentRef)!;
-        const parent = findAncestor(tree, objects, currentRef, transform.transformer.definition.from);
+        const parent = findAncestor(tree, cells, currentRef, transform.transformer.definition.from);
         // console.log('parent', transform.transformer.id, transform.transformer.definition.from[0].type, parent ? parent.ref : 'undefined')
-        if (!oldTree.nodes.has(currentRef) || !objects.has(currentRef)) {
+        if (!oldTree.nodes.has(currentRef) || !cells.has(currentRef)) {
             // console.log('creating...', transform.transformer.id, oldTree.nodes.has(currentRef), objects.has(currentRef));
             const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
-            objects.set(currentRef, {
+            cells.set(currentRef, {
                 ref: currentRef,
                 obj,
                 status: 'ok',
@@ -275,12 +275,17 @@ namespace State {
             return { action: 'created', obj };
         } else {
             // console.log('updating...', transform.transformer.id);
-            const current = objects.get(currentRef)!;
+            const current = cells.get(currentRef)!;
             const oldParams = oldTree.getValue(currentRef)!.params;
-            switch (await updateObject(ctx, currentRef, transform.transformer, parent, current.obj!, oldParams, transform.params)) {
+
+            const updateKind = current.status === 'ok'
+                ? await updateObject(ctx, currentRef, transform.transformer, parent, current.obj!, oldParams, transform.params)
+                : Transformer.UpdateResult.Recreate;
+
+            switch (updateKind) {
                 case Transformer.UpdateResult.Recreate: {
                     const obj = await createObject(ctx, currentRef, transform.transformer, parent, transform.params);
-                    objects.set(currentRef, {
+                    cells.set(currentRef, {
                         ref: currentRef,
                         obj,
                         status: 'ok',
diff --git a/src/mol-state/transformer.ts b/src/mol-state/transformer.ts
index f58771db7f445eb6524acbb892c94aee27acf241..914dda1111f260e9a083fa666a395057ad9a49b7 100644
--- a/src/mol-state/transformer.ts
+++ b/src/mol-state/transformer.ts
@@ -42,8 +42,8 @@ export namespace Transformer {
 
     export interface Definition<A extends StateObject = StateObject, B extends StateObject = StateObject, P = unknown> {
         readonly name: string,
-        readonly from: { type: StateObject.Type }[],
-        readonly to: { type: StateObject.Type }[],
+        readonly from: StateObject.Ctor[],
+        readonly to: StateObject.Ctor[],
         readonly display?: { readonly name: string, readonly description?: string },
 
         /**