diff --git a/src/mol-plugin/behavior.ts b/src/mol-plugin/behavior.ts
index 78fdaf11f59a02ae5e05cbae8eee5117b11f343b..db04070ecb343ec2c46b18dff1d545a6c8569b9b 100644
--- a/src/mol-plugin/behavior.ts
+++ b/src/mol-plugin/behavior.ts
@@ -6,7 +6,9 @@
 
 export * from './behavior/behavior'
 import * as Data from './behavior/data'
+import * as Representation from './behavior/representation'
 
 export const PluginBehaviors = {
-    Data
+    Data,
+    Representation
 }
\ No newline at end of file
diff --git a/src/mol-plugin/behavior/behavior.ts b/src/mol-plugin/behavior/behavior.ts
index 08d4c2af524386eb2e8e19fb5b4a33590414debc..ac667eee751a42cf025f9f62e41400a91f27343c 100644
--- a/src/mol-plugin/behavior/behavior.ts
+++ b/src/mol-plugin/behavior/behavior.ts
@@ -10,6 +10,7 @@ import { Transformer } from 'mol-state';
 import { Task } from 'mol-task';
 import { PluginContext } from 'mol-plugin/context';
 import { PluginCommand } from '../command';
+import { Observable } from 'rxjs';
 
 export { PluginBehavior }
 
@@ -29,14 +30,14 @@ namespace PluginBehavior {
         ctor: Ctor<P>,
         label?: (params: P) => { label: string, description?: string },
         display: { name: string, description?: string },
-        params?: Transformer.Definition<SO.Root, SO.Behavior, P>['params']
+        params?: Transformer.Definition<SO.BehaviorRoot, SO.Behavior, P>['params']
     }
 
     export function create<P>(params: CreateParams<P>) {
-        return PluginStateTransform.Create<SO.Root, SO.Behavior, P>({
+        return PluginStateTransform.Create<SO.BehaviorRoot, SO.Behavior, P>({
             name: params.name,
             display: params.display,
-            from: [SO.Root],
+            from: [SO.BehaviorRoot],
             to: [SO.Behavior],
             params: params.params,
             apply({ params: p }, ctx: PluginContext) {
@@ -53,7 +54,7 @@ namespace PluginBehavior {
         });
     }
 
-    export function commandHandler<T>(cmd: PluginCommand<T>, action: (data: T, ctx: PluginContext) => void | Promise<void>) {
+    export function simpleCommandHandler<T>(cmd: PluginCommand<T>, action: (data: T, ctx: PluginContext) => void | Promise<void>) {
         return class implements PluginBehavior<undefined> {
             private sub: PluginCommand.Subscription | undefined = void 0;
             register(): void {
@@ -66,4 +67,25 @@ namespace PluginBehavior {
             constructor(private ctx: PluginContext) { }
         }
     }
+
+    export abstract class Handler implements PluginBehavior<undefined> {
+        private subs: PluginCommand.Subscription[] = [];
+        protected subscribeCommand<T>(cmd: PluginCommand<T>, action: PluginCommand.Action<T>) {
+            this.subs.push(cmd.subscribe(this.ctx, action));
+        }
+        protected subscribeObservable<T>(o: Observable<T>, action: (v: T) => void) {
+            this.subs.push(o.subscribe(action));
+        }
+        protected track<T>(sub: PluginCommand.Subscription) {
+            this.subs.push(sub);
+        }
+        abstract register(): void;
+        unregister() {
+            for (const s of this.subs) s.unsubscribe();
+            this.subs = [];
+        }
+        constructor(protected ctx: PluginContext) {
+
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/mol-plugin/behavior/data.ts b/src/mol-plugin/behavior/data.ts
index 1b7e1467893e43b73f766f0615279e4c9c8dbfac..8f68045783fe2176ea7f254ba06ab47cb6933311 100644
--- a/src/mol-plugin/behavior/data.ts
+++ b/src/mol-plugin/behavior/data.ts
@@ -1,4 +1,3 @@
-
 /**
  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
@@ -8,28 +7,14 @@
 import { PluginBehavior } from './behavior';
 import { PluginCommands } from 'mol-plugin/command';
 
-// export class SetCurrentObject implements PluginBehavior<undefined> {
-//     private sub: PluginCommand.Subscription | undefined = void 0;
-
-//     register(): void {
-//         this.sub = PluginCommands.Data.SetCurrentObject.subscribe(this.ctx, ({ ref }) => this.ctx.state.data.setCurrent(ref));
-//     }
-//     unregister(): void {
-//         if (this.sub) this.sub.unsubscribe();
-//         this.sub = void 0;
-//     }
-
-//     constructor(private ctx: PluginContext) { }
-// }
-
 export const SetCurrentObject = PluginBehavior.create({
     name: 'set-current-data-object-behavior',
-    ctor: PluginBehavior.commandHandler(PluginCommands.Data.SetCurrentObject, ({ ref }, ctx) => ctx.state.data.setCurrent(ref)),
+    ctor: PluginBehavior.simpleCommandHandler(PluginCommands.Data.SetCurrentObject, ({ ref }, ctx) => ctx.state.data.setCurrent(ref)),
     display: { name: 'Set Current Handler' }
 });
 
 export const Update = PluginBehavior.create({
     name: 'update-data-behavior',
-    ctor: PluginBehavior.commandHandler(PluginCommands.Data.Update, ({ tree }, ctx) => ctx.runTask(ctx.state.data.update(tree))),
+    ctor: PluginBehavior.simpleCommandHandler(PluginCommands.Data.Update, ({ tree }, ctx) => ctx.runTask(ctx.state.data.update(tree))),
     display: { name: 'Update Data Handler' }
 });
\ No newline at end of file
diff --git a/src/mol-plugin/behavior/representation.ts b/src/mol-plugin/behavior/representation.ts
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f2b1ddf54b886a5f9b57e5d03dd74c1caa425fcb 100644
--- a/src/mol-plugin/behavior/representation.ts
+++ b/src/mol-plugin/behavior/representation.ts
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { PluginBehavior } from './behavior';
+import { PluginStateObjects as SO } from '../state/objects';
+
+class _AddRepresentationToCanvas extends PluginBehavior.Handler {
+    register(): void {
+        this.subscribeObservable(this.ctx.events.state.data.object.created, o => {
+            if (!SO.StructureRepresentation3D.is(o.obj)) return;
+            this.ctx.canvas3d.add(o.obj.data.repr);
+            this.ctx.canvas3d.requestDraw(true);
+        });
+        this.subscribeObservable(this.ctx.events.state.data.object.updated, o => {
+            const oo = o.obj;
+            if (!SO.StructureRepresentation3D.is(oo)) return;
+            this.ctx.canvas3d.add(oo.data.repr);
+            this.ctx.canvas3d.requestDraw(true);
+        });
+        this.subscribeObservable(this.ctx.events.state.data.object.removed, o => {
+            const oo = o.obj;
+            console.log('removed', o.ref, oo && oo.type);
+            if (!SO.StructureRepresentation3D.is(oo)) return;
+            this.ctx.canvas3d.remove(oo.data.repr);
+            console.log('removed from canvas', o.ref);
+            this.ctx.canvas3d.requestDraw(true);
+            oo.data.repr.destroy();
+        });
+        this.subscribeObservable(this.ctx.events.state.data.object.replaced, o => {
+            if (o.oldObj && SO.StructureRepresentation3D.is(o.oldObj)) {
+                this.ctx.canvas3d.remove(o.oldObj.data.repr);
+                this.ctx.canvas3d.requestDraw(true);
+                o.oldObj.data.repr.destroy();
+            }
+            if (o.newObj && SO.StructureRepresentation3D.is(o.newObj)) {
+                this.ctx.canvas3d.add(o.newObj.data.repr);
+                this.ctx.canvas3d.requestDraw(true);
+            }
+        });
+    }
+}
+
+export const AddRepresentationToCanvas = PluginBehavior.create({
+    name: 'add-representation-to-canvas',
+    ctor: _AddRepresentationToCanvas,
+    display: { name: 'Add Representation To Canvas' }
+});
\ No newline at end of file
diff --git a/src/mol-plugin/command/command.ts b/src/mol-plugin/command/command.ts
index 6148919f19c34cc3646dc99453008cdd3ac3f422..a76186d5aeaaaae2753c8dd3228c80a035eda76a 100644
--- a/src/mol-plugin/command/command.ts
+++ b/src/mol-plugin/command/command.ts
@@ -87,7 +87,7 @@ namespace PluginCommand {
         /** Resolves after all actions have completed */
         dispatch<T>(cmd: PluginCommand<T> | Id, params: T) {
             return new Promise<void>((resolve, reject) => {
-                if (!this.disposing) {
+                if (this.disposing) {
                     reject('disposed');
                     return;
                 }
diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts
index 5fb5d42ba7121ad2115f07fad62f63c8a9688df7..ff593b78ad3c1e437386fc0b7780f48e7624abc8 100644
--- a/src/mol-plugin/context.ts
+++ b/src/mol-plugin/context.ts
@@ -4,15 +4,17 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { StateTree, StateSelection, Transformer } from 'mol-state';
+import { StateTree, StateSelection, Transformer, Transform } from 'mol-state';
 import Canvas3D from 'mol-canvas3d/canvas3d';
 import { StateTransforms } from './state/transforms';
 import { PluginStateObjects as SO } from './state/objects';
 import { RxEventHelper } from 'mol-util/rx-event-helper';
 import { PluginState } from './state';
 import { MolScriptBuilder } from 'mol-script/language/builder';
-import { PluginCommand } from './command';
+import { PluginCommand, PluginCommands } from './command';
 import { Task } from 'mol-task';
+import { merge } from 'rxjs';
+import { PluginBehaviors } from './behavior';
 
 export class PluginContext {
     private disposed = false;
@@ -22,10 +24,17 @@ export class PluginContext {
     readonly commands = new PluginCommand.Manager();
 
     readonly events = {
-        data: this.state.data.context.events
+        state: {
+            data: this.state.data.context.events,
+            behavior: this.state.behavior.context.events
+        }
     };
 
     readonly behaviors = {
+        state: {
+            data: this.state.data.context.behaviors,
+            behavior: this.state.behavior.context.behaviors
+        },
         command: this.commands.behaviour
     };
 
@@ -66,6 +75,21 @@ export class PluginContext {
         this.disposed = true;
     }
 
+    async _test_initBehaviours() {
+        const tree = StateTree.build(this.state.behavior.tree)
+            .toRoot().apply(PluginBehaviors.Data.SetCurrentObject)
+            .and().toRoot().apply(PluginBehaviors.Data.Update)
+            .and().toRoot().apply(PluginBehaviors.Representation.AddRepresentationToCanvas)
+            .getTree();
+
+        await this.state.updateBehaviour(tree);
+    }
+
+    _test_applyTransform(a: Transform.Ref, transformer: Transformer, params: any) {
+        const tree = StateTree.build(this.state.data.tree).to(a).apply(transformer, params).getTree();
+        PluginCommands.Data.Update.dispatch(this, { tree });
+    }
+
     _test_createState(url: string) {
         const b = StateTree.build(this.state.data.tree);
 
@@ -94,23 +118,27 @@ export class PluginContext {
     }
 
     private initEvents() {
-        this.state.data.context.events.object.created.subscribe(o => {
-            if (!SO.StructureRepresentation3D.is(o.obj)) return;
-            console.log('adding repr', o.obj.data.repr);
-            this.canvas3d.add(o.obj.data.repr);
-            this.canvas3d.requestDraw(true);
+        merge(this.events.state.data.object.created, this.events.state.behavior.object.created).subscribe(o => {
+            console.log('creating', o.obj.type);
+            if (!SO.Behavior.is(o.obj)) return;
+            o.obj.data.register();
+        });
+
+        merge(this.events.state.data.object.removed, this.events.state.behavior.object.removed).subscribe(o => {
+            if (!SO.Behavior.is(o.obj)) return;
+            o.obj.data.unregister();
         });
-        this.state.data.context.events.object.updated.subscribe(o => {
-            const oo = o.obj;
-            if (!SO.StructureRepresentation3D.is(oo)) return;
-            console.log('updating repr', oo.data.repr);
-            this.canvas3d.add(oo.data.repr);
-            this.canvas3d.requestDraw(true);
+
+        merge(this.events.state.data.object.replaced, this.events.state.behavior.object.replaced).subscribe(o => {
+            if (o.oldObj && SO.Behavior.is(o.oldObj)) o.oldObj.data.unregister();
+            if (o.newObj && SO.Behavior.is(o.newObj)) o.newObj.data.register();
         });
     }
 
     _test_centerView() {
-        const sel = StateSelection.select('structure', this.state.data);
+        const sel = StateSelection.select(StateSelection.root().subtree().ofType(SO.Structure.type), this.state.data);
+        if (!sel.length) return;
+
         const center = (sel[0].obj! as SO.Structure).data.boundary.sphere.center;
         console.log({ sel, center, rc: this.canvas3d.reprCount });
         this.canvas3d.center(center);
@@ -135,6 +163,8 @@ export class PluginContext {
 
     constructor() {
         this.initEvents();
+
+        this._test_initBehaviours();
     }
 
     // logger = ;
diff --git a/src/mol-plugin/state.ts b/src/mol-plugin/state.ts
index b9de2611e58498780a885a253172f2b08651c91f..7118673aa5c7ce466b745c6c538241f68325059d 100644
--- a/src/mol-plugin/state.ts
+++ b/src/mol-plugin/state.ts
@@ -12,41 +12,47 @@ export { PluginState }
 
 class PluginState {
     readonly data: State;
-    readonly behaviour: State;
-
-    readonly canvas = {
-        camera: CombinedCamera.create()
-    };
+    readonly behavior: State;
 
     getSnapshot(): PluginState.Snapshot {
         return {
             data: this.data.getSnapshot(),
-            behaviour: this.behaviour.getSnapshot(),
-            canvas: {
-                camera: { ...this.canvas.camera }
+            behaviour: this.behavior.getSnapshot(),
+            canvas3d: {
+                camera: { ...this.plugin.canvas3d.camera }
             }
         };
     }
 
     setSnapshot(snapshot: PluginState.Snapshot) {
-        // TODO events
-        this.behaviour.setSnapshot(snapshot.behaviour);
+        this.behavior.setSnapshot(snapshot.behaviour);
         this.data.setSnapshot(snapshot.data);
-        this.canvas.camera = { ...snapshot.canvas.camera };
+
+        // TODO: handle camera
+        // console.log({ old: { ...this.plugin.canvas3d.camera  }, new: snapshot.canvas3d.camera });
+        // CombinedCamera.copy(snapshot.canvas3d.camera, this.plugin.canvas3d.camera);
+        // CombinedCamera.update(this.plugin.canvas3d.camera);
+        // this.plugin.canvas3d.center
+        // console.log({ copied: { ...this.plugin.canvas3d.camera  } });
+        // this.plugin.canvas3d.requestDraw(true);
+        // console.log('updated camera');
+    }
+
+    updateData(tree: StateTree) {
+        return this.plugin.runTask(this.data.update(tree));
     }
 
-    async updateData(tree: StateTree) {
-        // TODO: "task observer"
-        await this.data.update(tree).run(p => console.log(p), 250);
+    updateBehaviour(tree: StateTree) {
+        return this.plugin.runTask(this.behavior.update(tree));
     }
 
     dispose() {
         this.data.dispose();
     }
 
-    constructor(globalContext: unknown) {
-        this.data = State.create(new SO.Root({ label: 'Root' }, { }), { globalContext });
-        this.behaviour = State.create(new SO.Root({ label: 'Root' }, { }), { globalContext });
+    constructor(private plugin: import('./context').PluginContext) {
+        this.data = State.create(new SO.DataRoot({ label: 'Root' }, { }), { globalContext: plugin });
+        this.behavior = State.create(new SO.BehaviorRoot({ label: 'Root' }, { }), { globalContext: plugin });
     }
 }
 
@@ -54,6 +60,8 @@ namespace PluginState {
     export interface Snapshot {
         data: State.Snapshot,
         behaviour: State.Snapshot,
-        canvas: PluginState['canvas']
+        canvas3d: {
+            camera: CombinedCamera
+        }
     }
 }
diff --git a/src/mol-plugin/state/objects.ts b/src/mol-plugin/state/objects.ts
index 53b57be5a948c13ec11d82d249b7bb5be6e1dbe2..e043e4d2fda7a24670b8c4091da40e6b051d1d89 100644
--- a/src/mol-plugin/state/objects.ts
+++ b/src/mol-plugin/state/objects.ts
@@ -12,7 +12,9 @@ import { StructureRepresentation } from 'mol-repr/structure/index';
 const _create = PluginStateObject.Create
 
 namespace PluginStateObjects {
-    export class Root extends _create({ name: 'Root', shortName: 'R', typeClass: 'Root', description: 'Where everything begins.' }) { }
+    export class DataRoot extends _create({ name: 'Root', shortName: 'R', typeClass: 'Root', description: 'Where everything begins.' }) { }
+    export class BehaviorRoot extends _create({ name: 'Root', shortName: 'R', typeClass: 'Root', description: 'Where everything begins.' }) { }
+
     export class Group extends _create({ name: 'Group', shortName: 'G', typeClass: 'Group', description: 'A group on entities.' }) { }
 
     export class Behavior extends _create<import('../behavior').PluginBehavior>({ name: 'Behavior', shortName: 'B', typeClass: 'Behavior', description: 'Modifies plugin functionality.' }) { }
diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts
index 7d4aaf81d4af067d8fa1891684f0071af5c903c7..67899a9c666663370ce38be4717ef5d37428776e 100644
--- a/src/mol-plugin/state/transforms/data.ts
+++ b/src/mol-plugin/state/transforms/data.ts
@@ -13,15 +13,18 @@ import { ParamDefinition as PD } from 'mol-util/param-definition';
 
 export { Download }
 namespace Download { export interface Params { url: string, isBinary?: boolean, label?: string } }
-const Download = PluginStateTransform.Create<SO.Root, SO.Data.String | SO.Data.Binary, Download.Params>({
+const Download = PluginStateTransform.Create<SO.DataRoot, SO.Data.String | SO.Data.Binary, Download.Params>({
     name: 'download',
     display: {
         name: 'Download',
         description: 'Download string or binary data from the specified URL'
     },
-    from: [SO.Root],
+    from: [SO.DataRoot],
     to: [SO.Data.String, SO.Data.Binary],
     params: {
+        default: () => ({
+            url: 'https://www.ebi.ac.uk/pdbe/static/entry/1cbs_updated.cif'
+        }),
         controls: () => ({
             url: PD.Text('URL', 'Resource URL. Must be the same domain or support CORS.', ''),
             isBinary: PD.Boolean('Binary', 'If true, download data as binary (string otherwise)', false)
diff --git a/src/mol-plugin/state/transforms/visuals.ts b/src/mol-plugin/state/transforms/visuals.ts
index 978143e45412d955336322086aaaee9239bcd8c1..368bed5383c0d0858de9ba08fdcba96233c3f0eb 100644
--- a/src/mol-plugin/state/transforms/visuals.ts
+++ b/src/mol-plugin/state/transforms/visuals.ts
@@ -15,6 +15,7 @@ export { CreateStructureRepresentation }
 namespace CreateStructureRepresentation { export interface Params { } }
 const CreateStructureRepresentation = PluginStateTransform.Create<SO.Structure, SO.StructureRepresentation3D, CreateStructureRepresentation.Params>({
     name: 'create-structure-representation',
+    display: { name: 'Create 3D Representation' },
     from: [SO.Structure],
     to: [SO.StructureRepresentation3D],
     apply({ a, params }) {
diff --git a/src/mol-plugin/ui/controls.tsx b/src/mol-plugin/ui/controls.tsx
index 33b01ff280ab637a4ccd4b459a5932ceb4f7abf6..b591ce97f28429411b15fe7f6c25800c5a606c7c 100644
--- a/src/mol-plugin/ui/controls.tsx
+++ b/src/mol-plugin/ui/controls.tsx
@@ -6,6 +6,8 @@
 
 import * as React from 'react';
 import { PluginContext } from '../context';
+import { Transform, Transformer, StateObject } from 'mol-state';
+import { ParametersComponent } from 'mol-app/component/parameters';
 
 export class Controls extends React.Component<{ plugin: PluginContext }, { id: string }> {
     state = { id: '1grm' };
@@ -16,6 +18,16 @@ export class Controls extends React.Component<{ plugin: PluginContext }, { id: s
         this.props.plugin._test_createState(url);
     }
 
+    private _snap:any = void 0;
+    private getSnapshot = () => {
+        this._snap = this.props.plugin.state.getSnapshot();
+        console.log(btoa(JSON.stringify(this._snap)));
+    }
+    private setSnapshot = () => {
+        if (!this._snap) return;
+        this.props.plugin.state.setSnapshot(this._snap);
+    }
+
     render() {
         return <div>
             <input type='text' defaultValue={this.state.id} onChange={e => this.setState({ id: e.currentTarget.value })} />
@@ -23,6 +35,55 @@ export class Controls extends React.Component<{ plugin: PluginContext }, { id: s
             <button onClick={() => this.props.plugin._test_centerView()}>Center View</button><br/>
             <button onClick={() => this.props.plugin._test_nextModel()}>Next Model</button><br/>
             <button onClick={() => this.props.plugin._test_playModels()}>Play Models</button><br/>
+            <hr />
+            <button onClick={this.getSnapshot}>Get Snapshot</button>
+            <button onClick={this.setSnapshot}>Set Snapshot</button>
         </div>;
     }
+}
+
+export class _test_CreateTransform extends React.Component<{ plugin: PluginContext, nodeRef: Transform.Ref, transformer: Transformer }, { params: any }> {
+    private getObj() {
+        const obj = this.props.plugin.state.data.objects.get(this.props.nodeRef)!;
+        return obj;
+    }
+
+    private getDefaultParams() {
+        const p = this.props.transformer.definition.params;
+        if (!p || !p.default) return { };
+        const obj = this.getObj();
+        if (!obj.obj) return { };
+        return p.default(obj.obj, this.props.plugin);
+    }
+
+    private getParamDef() {
+        const p = this.props.transformer.definition.params;
+        if (!p || !p.controls) return { };
+        const obj = this.getObj();
+        if (!obj.obj) return { };
+        return p.controls(obj.obj, this.props.plugin);
+    }
+
+    private create() {
+        console.log(this.props.transformer.definition.name, this.state.params);
+        this.props.plugin._test_applyTransform(this.props.nodeRef, this.props.transformer, this.state.params);
+    }
+
+    state = { params: this.getDefaultParams() }
+
+    render() {
+        const obj = this.getObj();
+        if (obj.state !== StateObject.StateType.Ok) {
+            // TODO filter this elsewhere
+            return <div />;
+        }
+
+        const t = this.props.transformer;
+
+        return <div key={`${this.props.nodeRef} ${this.props.transformer.id}`}>
+            <div style={{ borderBottom: '1px solid #999'}}>{(t.definition.display && t.definition.display.name) || t.definition.name}</div>
+            <ParametersComponent params={this.getParamDef()} values={this.state.params as any} onChange={params => this.setState({ params })} />
+            <button onClick={() => this.create()} style={{ width: '100%' }}>Create</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 b5a301b8560cde72e5ecfffc512a9ddafc39da9d..949fb997ada3af12e8d6e94a80944c95092dfab8 100644
--- a/src/mol-plugin/ui/plugin.tsx
+++ b/src/mol-plugin/ui/plugin.tsx
@@ -6,17 +6,22 @@
 
 import * as React from 'react';
 import { PluginContext } from '../context';
-import { Tree } from './tree';
+import { StateTree } from './state-tree';
 import { Viewport } from './viewport';
-import { Controls } from './controls';
+import { Controls, _test_CreateTransform } from './controls';
+import { Transformer } from 'mol-state';
+
+// TODO: base object with subscribe helpers
 
 export class Plugin extends React.Component<{ plugin: PluginContext }, { }> {
     render() {
         return <div style={{ position: 'absolute', width: '100%', height: '100%' }}>
-            <div style={{ position: 'absolute', width: '250px', height: '100%' }}>
-                <Tree plugin={this.props.plugin} />
+            <div style={{ position: 'absolute', width: '350px', height: '100%', overflowY: 'scroll' }}>
+                <StateTree plugin={this.props.plugin} />
+                <hr />
+                <_test_CurrentObject plugin={this.props.plugin} />
             </div>
-            <div style={{ position: 'absolute', left: '250px', right: '250px', height: '100%' }}>
+            <div style={{ position: 'absolute', left: '350px', right: '250px', height: '100%' }}>
                 <Viewport plugin={this.props.plugin} />
             </div>
             <div style={{ position: 'absolute', width: '250px', right: '0', height: '100%' }}>
@@ -24,4 +29,28 @@ export class Plugin extends React.Component<{ plugin: PluginContext }, { }> {
             </div>
         </div>;
     }
+}
+
+export class _test_CurrentObject extends React.Component<{ plugin: PluginContext }, { }> {
+    componentWillMount() {
+        this.props.plugin.behaviors.state.data.currentObject.subscribe(() => this.forceUpdate());
+    }
+    render() {
+        const ref = this.props.plugin.behaviors.state.data.currentObject.value.ref;
+        // const n = this.props.plugin.state.data.tree.nodes.get(ref)!;
+        const obj = this.props.plugin.state.data.objects.get(ref)!;
+
+        const type = obj && obj.obj ? obj.obj.type : void 0;
+
+        const transforms = type
+            ? Transformer.fromType(type)
+            : []
+        return <div>
+            Current Ref: {this.props.plugin.behaviors.state.data.currentObject.value.ref}
+            <hr />
+            {
+                transforms.map((t, i) => <_test_CreateTransform key={`${t.id} ${ref} ${i}`} plugin={this.props.plugin} transformer={t} nodeRef={ref} />)
+            }
+        </div>;
+    }
 }
\ No newline at end of file
diff --git a/src/mol-plugin/ui/tree.tsx b/src/mol-plugin/ui/state-tree.tsx
similarity index 51%
rename from src/mol-plugin/ui/tree.tsx
rename to src/mol-plugin/ui/state-tree.tsx
index c5ded6963a737d43649a57418881c2c9d6b687ae..8c4a5c5d628aeff23b6f3af624aa383887f8b080 100644
--- a/src/mol-plugin/ui/tree.tsx
+++ b/src/mol-plugin/ui/state-tree.tsx
@@ -8,21 +8,23 @@ import * as React from 'react';
 import { PluginContext } from '../context';
 import { PluginStateObject } from 'mol-plugin/state/base';
 import { StateObject } from 'mol-state'
+import { PluginCommands } from 'mol-plugin/command';
 
-export class Tree extends React.Component<{ plugin: PluginContext }, { }> {
-
+export class StateTree extends React.Component<{ plugin: PluginContext }, { }> {
     componentWillMount() {
-        this.props.plugin.events.data.updated.subscribe(() => this.forceUpdate());
+        this.props.plugin.events.state.data.updated.subscribe(() => this.forceUpdate());
     }
     render() {
-        const n = this.props.plugin.state.data.tree.nodes.get(this.props.plugin.state.data.tree.rootRef)!;
+        // const n = this.props.plugin.state.data.tree.nodes.get(this.props.plugin.state.data.tree.rootRef)!;
+        const n = this.props.plugin.state.data.tree.rootRef;
         return <div>
-            {n.children.map(c => <TreeNode plugin={this.props.plugin} nodeRef={c!} key={c} />)}
+            <StateTreeNode plugin={this.props.plugin} nodeRef={n} key={n} />
+            { /* n.children.map(c => <StateTreeNode plugin={this.props.plugin} nodeRef={c!} key={c} />) */}
         </div>;
     }
 }
 
-export class TreeNode extends React.Component<{ plugin: PluginContext, nodeRef: string }, { }> {
+export class StateTreeNode extends React.Component<{ plugin: PluginContext, nodeRef: string }, { }> {
     render() {
         const n = this.props.plugin.state.data.tree.nodes.get(this.props.nodeRef)!;
         const obj = this.props.plugin.state.data.objects.get(this.props.nodeRef)!;
@@ -33,10 +35,14 @@ export class TreeNode extends React.Component<{ plugin: PluginContext, nodeRef:
         }
         const props = obj.obj!.props as PluginStateObject.Props;
         return <div style={{ borderLeft: '1px solid black', paddingLeft: '5px' }}>
-            {props.label} {props.description ? <small>{props.description}</small> : void 0}
+            <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}
             {n.children.size === 0
                 ? void 0
-                : <div style={{ marginLeft: '10px' }}>{n.children.map(c => <TreeNode plugin={this.props.plugin} nodeRef={c!} key={c} />)}</div>
+                : <div style={{ marginLeft: '10px' }}>{n.children.map(c => <StateTreeNode plugin={this.props.plugin} nodeRef={c!} key={c} />)}</div>
             }
         </div>;
     }
diff --git a/src/mol-state/state.ts b/src/mol-state/state.ts
index 5f5e411892741dff2953b3553553c14eb4622412..c6660c0038daea876beeb4eccff59e89996ad16e 100644
--- a/src/mol-state/state.ts
+++ b/src/mol-state/state.ts
@@ -43,8 +43,8 @@ class State {
 
     setSnapshot(snapshot: State.Snapshot): void {
         const tree = StateTree.fromJSON(snapshot.tree);
-        // TODO: support props
-        this.update(tree);
+        // TODO: support props and async
+        this.update(tree).run();
     }
 
     setCurrent(ref: Transform.Ref) {
@@ -128,9 +128,10 @@ namespace State {
         const roots = findUpdateRoots(ctx.objects, 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);
             ctx.transformCache.delete(d);
-            ctx.stateCtx.events.object.removed.next({ ref: d });
+            ctx.stateCtx.events.object.removed.next({ ref: d, obj });
             // TODO: handle current object change
         }
 
diff --git a/src/mol-state/tree.ts b/src/mol-state/tree.ts
index b8e569a2852a04892f42a7974182c31851f0456c..c21c11d9f9a3478e80e3c50f53c0e7456b5efd9d 100644
--- a/src/mol-state/tree.ts
+++ b/src/mol-state/tree.ts
@@ -52,8 +52,8 @@ namespace StateTree {
 
         export class Root implements Builder {
             private state: State;
-            to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref); }
-            toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.rootRef as any); }
+            to<A extends StateObject>(ref: Transform.Ref) { return new To<A>(this.state, ref, this); }
+            toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.rootRef as any, this); }
             delete(ref: Transform.Ref) { this.state.tree.remove(ref); return this; }
             getTree(): StateTree { return this.state.tree.asImmutable(); }
             constructor(tree: StateTree) { this.state = { tree: ImmutableTree.asTransient(tree) } }
@@ -63,12 +63,14 @@ namespace StateTree {
             apply<T extends Transformer<A, any, any>>(tr: T, params?: Transformer.Params<T>, props?: Partial<Transform.Options>): To<Transformer.To<T>> {
                 const t = tr.apply(params, props);
                 this.state.tree.add(this.ref, t);
-                return new To(this.state, t.ref);
+                return new To(this.state, t.ref, this.root);
             }
 
+            and() { return this.root; }
+
             getTree(): StateTree { return this.state.tree.asImmutable(); }
 
-            constructor(private state: State, private ref: Transform.Ref) {
+            constructor(private state: State, private ref: Transform.Ref, private root: Root) {
                 if (!this.state.tree.nodes.has(ref)) {
                     throw new Error(`Could not find node '${ref}'.`);
                 }