diff --git a/src/mol-app/ui/visualization/sequence-view.tsx b/src/mol-app/ui/visualization/sequence-view.tsx
index 6025eea22076a5e71ed57bc3c2d5be2ded4be068..69a88950239c43d2f3584337264af20a39d8a24e 100644
--- a/src/mol-app/ui/visualization/sequence-view.tsx
+++ b/src/mol-app/ui/visualization/sequence-view.tsx
@@ -7,10 +7,9 @@
 import * as React from 'react'
 import { View } from '../view';
 import { SequenceViewController } from '../../controller/visualization/sequence-view';
-import { Structure, StructureSequence, Queries, Selection, StructureProperties } from 'mol-model/structure';
+import { Structure, StructureSequence, Queries, StructureSelection, StructureProperties, StructureQuery } from 'mol-model/structure';
 import { Context } from '../../context/context';
 import { InteractivityEvents } from '../../event/basic';
-import { SyncRuntimeContext } from 'mol-task/execution/synchronous';
 import { EmptyLoci } from 'mol-model/loci';
 
 export class SequenceView extends View<SequenceViewController, {}, {}> {
@@ -27,8 +26,8 @@ export class SequenceView extends View<SequenceViewController, {}, {}> {
 
 function createQuery(entityId: string, label_seq_id: number) {
     return Queries.generators.atoms({
-        entityTest: l => StructureProperties.entity.id(l) === entityId,
-        residueTest: l => StructureProperties.residue.label_seq_id(l) === label_seq_id
+        entityTest: ctx => StructureProperties.entity.id(ctx.element) === entityId,
+        residueTest: ctx => StructureProperties.residue.label_seq_id(ctx.element) === label_seq_id
     });
 }
 
@@ -42,7 +41,7 @@ class EntitySequence extends React.Component<{ ctx: Context, seq: StructureSeque
         }
 
         const query = createQuery(this.props.seq.entityId, seqId);
-        const loci = Selection.toLoci(await query(this.props.structure, SyncRuntimeContext));
+        const loci = StructureSelection.toLoci(await StructureQuery.run(query, this.props.structure));
         if (loci.elements.length === 0) InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci);
         else InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, loci);
     }
diff --git a/src/mol-model/structure/model/formats/mmcif/assembly.ts b/src/mol-model/structure/model/formats/mmcif/assembly.ts
index c86abd27cfd5b2d3a156268cc3ed5967e7639160..e89690e1723ca31eca3c7295114331e97c9c786a 100644
--- a/src/mol-model/structure/model/formats/mmcif/assembly.ts
+++ b/src/mol-model/structure/model/formats/mmcif/assembly.ts
@@ -8,7 +8,7 @@ import { Mat4, Tensor } from 'mol-math/linear-algebra'
 import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator'
 import Format from '../../format'
 import { Assembly, OperatorGroup, OperatorGroups } from '../../properties/symmetry'
-import { Queries as Q, Query } from '../../../query'
+import { Queries as Q } from '../../../query'
 
 import mmCIF_Format = Format.mmCIF
 import { StructureProperties } from '../../../structure';
@@ -58,10 +58,10 @@ function operatorGroupsProvider(generators: Generator[], matrices: Matrices): ()
             const operatorList = parseOperatorList(gen.expression);
             const operatorNames = expandOperators(operatorList);
             const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset);
-            const selector = Query(Q.generators.atoms({ chainTest: Q.pred.and(
-                Q.pred.eq(StructureProperties.unit.operator_name, SymmetryOperator.DefaultName),
-                Q.pred.inSet(StructureProperties.chain.label_asym_id, gen.asymIds)
-            )}));
+            const selector = Q.generators.atoms({ chainTest: Q.pred.and(
+                Q.pred.eq(ctx => StructureProperties.unit.operator_name(ctx.element), SymmetryOperator.DefaultName),
+                Q.pred.inSet(ctx => StructureProperties.chain.label_asym_id(ctx.element), gen.asymIds)
+            )});
             groups[groups.length] = { selector, operators };
             operatorOffset += operators.length;
         }
diff --git a/src/mol-model/structure/model/properties/symmetry.ts b/src/mol-model/structure/model/properties/symmetry.ts
index fab3c37987b0b2c7cb36e7810ff97b93d2a9b913..c1ffee05e76c293118f5455a847157f9b820af39 100644
--- a/src/mol-model/structure/model/properties/symmetry.ts
+++ b/src/mol-model/structure/model/properties/symmetry.ts
@@ -6,13 +6,13 @@
 
 import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator'
 import { arrayFind } from 'mol-data/util'
-import { Query } from '../../query'
+import { StructureQuery } from '../../query'
 import { Model } from '../../model'
 import { Spacegroup } from 'mol-math/geometry';
 
 /** Determine an atom set and a list of operators that should be applied to that set  */
 export interface OperatorGroup {
-    readonly selector: Query,
+    readonly selector: StructureQuery,
     readonly operators: ReadonlyArray<SymmetryOperator>
 }
 
diff --git a/src/mol-model/structure/query.ts b/src/mol-model/structure/query.ts
index 428d976d85872f423b3c4756cc77340d96844c7e..e4f3190a4303e31567ba5b95d81369ef5ad1c93e 100644
--- a/src/mol-model/structure/query.ts
+++ b/src/mol-model/structure/query.ts
@@ -4,8 +4,9 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Selection from './query/selection'
-import Query from './query/query'
+import { StructureSelection } from './query/selection'
+import { StructureQuery } from './query/query'
+export * from './query/context'
 import * as generators from './query/generators'
 import * as modifiers from './query/modifiers'
 import pred from './query/predicates'
@@ -16,4 +17,4 @@ export const Queries = {
     pred
 }
 
-export { Selection, Query }
\ No newline at end of file
+export { StructureSelection, StructureQuery }
\ No newline at end of file
diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts
index f116f6f15e1c95941f0f2fd5ca8600fcc95040b6..eedd8d3e3988679615591e243846dee69b51a287 100644
--- a/src/mol-model/structure/query/context.ts
+++ b/src/mol-model/structure/query/context.ts
@@ -8,7 +8,6 @@ import { RuntimeContext } from 'mol-task';
 import { Structure, StructureElement } from '../structure';
 
 export interface QueryContextView {
-    readonly taskCtx: RuntimeContext;
     readonly element: StructureElement;
 }
 
diff --git a/src/mol-model/structure/query/query.ts b/src/mol-model/structure/query/query.ts
index 1985a40680e5c7b7a73a7f9cb9c689221470f669..a4c87dc503374201ae19c3f9fa125f714963a0fc 100644
--- a/src/mol-model/structure/query/query.ts
+++ b/src/mol-model/structure/query/query.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { RuntimeContext } from 'mol-task'
+import { RuntimeContext, Task } from 'mol-task'
 import { Structure } from '../structure'
 import { StructureSelection } from './selection'
 import { QueryContext } from './context';
@@ -14,6 +14,10 @@ namespace StructureQuery {
     export function run(query: StructureQuery, structure: Structure, ctx?: RuntimeContext) {
         return query(new QueryContext(structure, ctx || RuntimeContext.Synchronous))
     }
+
+    export function asTask(query: StructureQuery, structure: Structure) {
+        return Task.create('Structure Query', ctx => query(new QueryContext(structure, ctx)));
+    }
 }
 
 export { StructureQuery }
\ No newline at end of file
diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts
index 5c71b11142568faa9c0fbbc5a49312cd60265170..c5f8d25165114be3bdfded5d64774c03c51b3dd3 100644
--- a/src/mol-model/structure/structure/symmetry.ts
+++ b/src/mol-model/structure/structure/symmetry.ts
@@ -5,7 +5,7 @@
  */
 
 import Structure from './structure'
-import { Selection } from '../query'
+import { StructureSelection, QueryContext } from '../query'
 import { ModelSymmetry } from '../model'
 import { Task, RuntimeContext } from 'mol-task';
 import { SortedArray } from 'mol-data/int';
@@ -25,12 +25,14 @@ namespace StructureSymmetry {
 
             const assembler = Structure.Builder();
 
+            const queryCtx = new QueryContext(structure, ctx);
+
             for (const g of assembly.operatorGroups) {
-                const selection = await g.selector(structure).runAsChild(ctx);
-                if (Selection.structureCount(selection) === 0) {
+                const selection = await g.selector(queryCtx);
+                if (StructureSelection.structureCount(selection) === 0) {
                     continue;
                 }
-                const { units } = Selection.unionStructure(selection);
+                const { units } = StructureSelection.unionStructure(selection);
 
                 for (const oper of g.operators) {
                     for (const unit of units) {
diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts
index 90566d25f7202a16ad1ef7c6bb458297f41b3d29..ba9543895b7f7d0102bde4c834890f58bb23f964 100644
--- a/src/perf-tests/structure.ts
+++ b/src/perf-tests/structure.ts
@@ -11,7 +11,7 @@ import * as fs from 'fs'
 import fetch from 'node-fetch'
 import CIF from 'mol-io/reader/cif'
 
-import { Structure, Model, Queries as Q, StructureElement, Selection, StructureSymmetry, Query, Format, StructureProperties as SP } from 'mol-model/structure'
+import { Structure, Model, Queries as Q, StructureElement, StructureSelection, StructureSymmetry, StructureQuery, Format, StructureProperties as SP } from 'mol-model/structure'
 //import { Segmentation, OrderedSet } from 'mol-data/int'
 
 import to_mmCIF from 'mol-model/structure/export/mmcif'
@@ -325,13 +325,13 @@ export namespace PropertyAccess {
         const auth_comp_id = SP.residue.auth_comp_id, op = SP.unit.operator_name;
         //const q1 = Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'REA' });
         const q1 = Q.modifiers.includeSurroundings(Q.generators.atoms({
-            chainTest: l => op(l) === '1_555',
-            residueTest: l => auth_comp_id(l) === 'REA'
+            chainTest: l => op(l.element) === '1_555',
+            residueTest: l => auth_comp_id(l.element) === 'REA'
         }), {
             radius: 5,
             wholeResidues: true
         });
-        const surr = Selection.unionStructure(await query(Query(q1), a));
+        const surr = StructureSelection.unionStructure(await StructureQuery.run(q1, a));
         console.timeEnd('symmetry')
 
         // for (const u of surr.units) {
@@ -371,8 +371,8 @@ export namespace PropertyAccess {
     //     console.log('group count', uniqueGroups.groups.length);
     // }
 
-    function query(q: Query, s: Structure) {
-        return q(s).run();
+    function query(q: StructureQuery, s: Structure) {
+        return StructureQuery.run(q, s);
     }
 
     export async function run() {
@@ -431,14 +431,14 @@ export namespace PropertyAccess {
         //const auth_asym_id = SP.chain.auth_asym_id;
         //const set =  new Set(['A', 'B', 'C', 'D']);
         //const q = Q.generators.atomGroups({ atomTest: l => auth_seq_id(l) < 3 });
-        const q = Query(Q.generators.atoms({ atomTest: Q.pred.eq(SP.residue.auth_comp_id, 'ALA') }));
+        const q = Q.generators.atoms({ atomTest: Q.pred.eq(l => SP.residue.auth_comp_id(l.element), 'ALA') });
         const P = SP
         //const q0 = Q.generators.atoms({ atomTest: l => auth_comp_id(l) === 'ALA' });
-        const q1 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA' }));
-        const q2 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA', groupBy: SP.residue.key }));
-        const q3 = Query(Q.generators.atoms({
-            chainTest: Q.pred.inSet(P.chain.auth_asym_id, ['A', 'B', 'C', 'D']),
-            residueTest: Q.pred.eq(P.residue.auth_comp_id, 'ALA')
+        const q1 = (Q.generators.atoms({ residueTest: l => auth_comp_id(l.element) === 'ALA' }));
+        const q2 = (Q.generators.atoms({ residueTest: l => auth_comp_id(l.element) === 'ALA', groupBy: l => SP.residue.key(l.element) }));
+        const q3 = (Q.generators.atoms({
+            chainTest: Q.pred.inSet(l => P.chain.auth_asym_id(l.element), ['A', 'B', 'C', 'D']),
+            residueTest: Q.pred.eq(l => P.residue.auth_comp_id(l.element), 'ALA')
         }));
         await query(q, structures[0]);
         //console.log(to_mmCIF('test', Selection.union(q0r)));
@@ -452,7 +452,7 @@ export namespace PropertyAccess {
         console.time('q2')
         const q2r = await query(q2, structures[0]);
         console.timeEnd('q2')
-        console.log(Selection.structureCount(q2r));
+        console.log(StructureSelection.structureCount(q2r));
         //console.log(q1(structures[0]));
 
         const col = models[0].atomicConformation.atomId.value;
diff --git a/src/servers/model/server/api.ts b/src/servers/model/server/api.ts
index 0e60d47074d27b278086f6eb3015906ae65153b9..95879cce0d577d835c825e8c12f643b6cc4878e5 100644
--- a/src/servers/model/server/api.ts
+++ b/src/servers/model/server/api.ts
@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Query, Queries, Structure, StructureElement, StructureSymmetry, StructureProperties as Props } from 'mol-model/structure';
+import { StructureQuery, Queries, Structure, StructureElement, StructureSymmetry, StructureProperties as Props, QueryPredicate } from 'mol-model/structure';
 
 export enum QueryParamType {
     String,
@@ -26,7 +26,7 @@ export interface QueryDefinition {
     name: string,
     niceName: string,
     exampleId: string, // default is 1cbs
-    query: (params: any, structure: Structure) => Query,
+    query: (params: any, structure: Structure) => StructureQuery,
     description: string,
     params: QueryParamInfo[],
     structureTransform?: (params: any, s: Structure) => Promise<Structure>
@@ -51,25 +51,25 @@ const AtomSiteParameters = {
 //     return Element.property(l => p(l) === id);
 // }
 
-function entityTest1_555(params: any): StructureElement.Predicate | undefined {
-    if (typeof params.entity_id === 'undefined') return StructureElement.property(l => l.unit.conformation.operator.isIdentity);
+function entityTest1_555(params: any): QueryPredicate | undefined {
+    if (typeof params.entity_id === 'undefined') return ctx => ctx.element.unit.conformation.operator.isIdentity;
     const p = Props.entity.id, id = '' + params.entityId;
-    return StructureElement.property(l => l.unit.conformation.operator.isIdentity && p(l) === id);
+    return ctx => ctx.element.unit.conformation.operator.isIdentity && p(ctx.element) === id;
 }
 
-function chainTest(params: any): StructureElement.Predicate | undefined {
+function chainTest(params: any): QueryPredicate | undefined {
     if (typeof params.label_asym_id !== 'undefined') {
         const p = Props.chain.label_asym_id, id = '' + params.label_asym_id;
-        return StructureElement.property(l => p(l) === id);
+        return ctx => p(ctx.element) === id;
     }
     if (typeof params.auth_asym_id !== 'undefined') {
         const p = Props.chain.auth_asym_id, id = '' + params.auth_asym_id;
-        return StructureElement.property(l => p(l) === id);
+        return ctx => p(ctx.element) === id;
     }
     return void 0;
 }
 
-function residueTest(params: any): StructureElement.Predicate | undefined {
+function residueTest(params: any): QueryPredicate | undefined {
     const props: StructureElement.Property<any>[] = [], values: any[] = [];
 
     if (typeof params.label_seq_id !== 'undefined') {
@@ -99,15 +99,15 @@ function residueTest(params: any): StructureElement.Predicate | undefined {
 
     switch (props.length) {
         case 0: return void 0;
-        case 1: return StructureElement.property(l => props[0](l) === values[0]);
-        case 2: return StructureElement.property(l => props[0](l) === values[0] && props[1](l) === values[1]);
-        case 3: return StructureElement.property(l => props[0](l) === values[0] && props[1](l) === values[1] && props[2](l) === values[2]);
+        case 1: return ctx => props[0](ctx.element) === values[0];
+        case 2: return ctx => props[0](ctx.element) === values[0] && props[1](ctx.element) === values[1];
+        case 3: return ctx => props[0](ctx.element) === values[0] && props[1](ctx.element) === values[1] && props[2](ctx.element) === values[2];
         default: {
             const len = props.length;
-            return StructureElement.property(l => {
-                for (let i = 0; i < len; i++) if (!props[i](l) !== values[i]) return false;
+            return ctx => {
+                for (let i = 0; i < len; i++) if (!props[i](ctx.element) !== values[i]) return false;
                 return true;
-            });
+            };
         }
     }
 }
@@ -117,13 +117,13 @@ function residueTest(params: any): StructureElement.Predicate | undefined {
 // }
 
 const QueryMap: { [id: string]: Partial<QueryDefinition> } = {
-    'full': { niceName: 'Full Structure', query: () => Query(Queries.generators.all), description: 'The full structure.' },
+    'full': { niceName: 'Full Structure', query: () => Queries.generators.all, description: 'The full structure.' },
     'residueInteraction': {
         niceName: 'Residues Inside a Sphere',
         description: 'Identifies all residues within the given radius from the source residue.',
         query(p) {
             const center = Queries.generators.atoms({ entityTest: entityTest1_555(p), chainTest: chainTest(p), residueTest: residueTest(p) });
-            return Query(Queries.modifiers.includeSurroundings(center, { radius: p.radius, wholeResidues: true }));
+            return Queries.modifiers.includeSurroundings(center, { radius: p.radius, wholeResidues: true });
         },
         structureTransform(p, s) {
             return StructureSymmetry.builderSymmetryMates(s, p.radius).run();
diff --git a/src/servers/model/server/query.ts b/src/servers/model/server/query.ts
index 2dc635c4ee79bdeaa7735533615cd7a49a7e2f5d..4a1049524fb9698e8a8d63d71e21e5700718f6c6 100644
--- a/src/servers/model/server/query.ts
+++ b/src/servers/model/server/query.ts
@@ -13,7 +13,7 @@ import { ConsoleLogger } from 'mol-util/console-logger';
 import Writer from 'mol-io/writer/writer';
 import { CifWriter } from 'mol-io/writer/cif'
 import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
-import { Selection } from 'mol-model/structure';
+import { StructureSelection, StructureQuery } from 'mol-model/structure';
 import Version from '../version'
 import { Column } from 'mol-data/db';
 import { PerformanceMonitor } from 'mol-util/performance-monitor';
@@ -69,7 +69,7 @@ export async function resolveRequest(req: Request, writer: Writer) {
         ? await req.queryDefinition.structureTransform(req.normalizedParams, wrappedStructure.structure)
         : wrappedStructure.structure;
     const query = req.queryDefinition.query(req.normalizedParams, structure);
-    const result = Selection.unionStructure(await query(structure).run(abortingObserver, 250));
+    const result = StructureSelection.unionStructure(await StructureQuery.asTask(query, structure).run(abortingObserver, 250));
     perf.end('query');
 
     ConsoleLogger.logId(req.id, 'Query', 'Query finished.');