diff --git a/src/mol-base/math/linear-algebra-3d.ts b/src/mol-base/math/linear-algebra-3d.ts
index cbfe8de21086a9199cc577c46fe736a6c98d32bd..0f998a1260911d79c9d688b56a8126099a7e0bab 100644
--- a/src/mol-base/math/linear-algebra-3d.ts
+++ b/src/mol-base/math/linear-algebra-3d.ts
@@ -568,7 +568,7 @@ export namespace Vec3 {
         return out;
     }
 
-    export function transformMat4(out: Vec3, a: Vec3, m: number[]) {
+    export function transformMat4(out: Vec3, a: Vec3, m: Mat4) {
         const x = a[0], y = a[1], z = a[2],
             w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
         out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
diff --git a/src/mol-data/structure/query/properties.ts b/src/mol-data/structure/query/properties.ts
index df1dbfdd517c81b2ff30f5de714909ca8ee4483d..ef9ef07dfb581e5a6fd55556cabfcc4440ef9e23 100644
--- a/src/mol-data/structure/query/properties.ts
+++ b/src/mol-data/structure/query/properties.ts
@@ -13,6 +13,10 @@ const constant = {
 }
 
 const atom = {
+    x: Atom.property(l => l.unit.x(l.atom)),
+    y: Atom.property(l => l.unit.y(l.atom)),
+    z: Atom.property(l => l.unit.z(l.atom)),
+
     type_symbol: Atom.property(l => l.unit.hierarchy.atoms.type_symbol.value(l.atom))
 }
 
diff --git a/src/mol-data/structure/structure/atom.ts b/src/mol-data/structure/structure/atom.ts
index 2a5b1c0192e1f407224187ac47a5fc0515339d96..61aea8741c1235b8b7980703c330600f8505d4e2 100644
--- a/src/mol-data/structure/structure/atom.ts
+++ b/src/mol-data/structure/structure/atom.ts
@@ -28,7 +28,7 @@ namespace Atom {
     export interface Property<T> { (location: Location): T }
     export interface Predicate extends Property<boolean> { }
 
-    export function setLocation(structure: Structure, l: Location, atom: Atom) {
+    export function updateLocation(structure: Structure, l: Location, atom: Atom) {
         l.unit = structure.units[unit(atom)];
         l.atom = index(atom);
     }
diff --git a/src/mol-data/structure/structure/operator.ts b/src/mol-data/structure/structure/operator.ts
index dd1df5c18cf4d1ad2add8429adf8424bbe2d1e31..e6fc2fd2f5aadfd7b715f8bf71d63ce559084b41 100644
--- a/src/mol-data/structure/structure/operator.ts
+++ b/src/mol-data/structure/structure/operator.ts
@@ -9,7 +9,7 @@ import { Mat4 } from 'mol-base/math/linear-algebra-3d'
 interface Operator extends Readonly<{
     name: string,
     hkl: number[], // defaults to [0, 0, 0] for non symmetry entries
-    transform: Mat4,
+    matrix: Mat4,
     // cache the inverse of the transform
     inverse: Mat4,
     // optimize the identity case
@@ -17,7 +17,7 @@ interface Operator extends Readonly<{
 }> { }
 
 namespace Operator {
-    export const Identity: Operator = { name: '1_555', hkl: [0, 0, 0], transform: Mat4.identity(), inverse: Mat4.identity(), isIdentity: true };
+    export const Identity: Operator = { name: '1_555', hkl: [0, 0, 0], matrix: Mat4.identity(), inverse: Mat4.identity(), isIdentity: true };
 }
 
 export default Operator
\ No newline at end of file
diff --git a/src/mol-data/structure/structure/unit.ts b/src/mol-data/structure/structure/unit.ts
index a90e87c243b16b9b4b649d5f22ce704bae23ff4c..b58145ca2d4ed29d25f0cabd1cfaceca6e62c5d6 100644
--- a/src/mol-data/structure/structure/unit.ts
+++ b/src/mol-data/structure/structure/unit.ts
@@ -6,6 +6,7 @@
 
 import { Model } from '../model'
 import Operator from './operator'
+import { Vec3, Mat4 } from 'mol-base/math/linear-algebra-3d'
 
 interface Unit extends Readonly<{
     // Structure-level unique identifier of the unit.
@@ -18,22 +19,30 @@ interface Unit extends Readonly<{
     // The transform and and inverse are baked into the "getPosition" function
     operator: Operator,
 
-    // Cache residue and chain indices for fast access.
+    // Reference some commonly accessed things for faster access.
     residueIndex: ArrayLike<number>,
     chainIndex: ArrayLike<number>,
     hierarchy: Model['hierarchy'],
     conformation: Model['conformation']
 }> {
-    // // returns the untransformed position. Used for spatial queries.
-    // getInvariantPosition(atom: number, slot: Vec3): Vec3
+    // returns the untransformed position. Used for spatial queries.
+    getInvariantPosition(atom: number, slot: Vec3): Vec3,
 
-    // // gets the transformed position of the specified atom
-    // getPosition(atom: number, slot: Vec3): Vec3
+    // gets the transformed position of the specified atom.
+    getPosition(atom: number, slot: Vec3): Vec3,
+
+    // optimized x/y/z coordinate projections for your query needs.
+    x(atom: number): number,
+    y(atom: number): number,
+    z(atom: number): number
 }
 
 namespace Unit {
     export function create(model: Model, operator: Operator): Unit {
         const h = model.hierarchy;
+        const { __x: x, __y: y, __z: z } = model.conformation;
+        const getInvariantPosition = makeGetInvariantPosition(x, y, z);
+        const getPosition = operator.isIdentity ? getInvariantPosition : makeGetPosition(operator.matrix, x, y, z);
         return {
             id: nextUnitId(),
             model,
@@ -41,7 +50,12 @@ namespace Unit {
             residueIndex: h.residueSegments.segmentMap,
             chainIndex: h.chainSegments.segmentMap,
             hierarchy: model.hierarchy,
-            conformation: model.conformation
+            conformation: model.conformation,
+            getInvariantPosition,
+            getPosition,
+            x: operator.isIdentity ? makeGetCoord(x) : makeX(operator.matrix, x, y, z),
+            y: operator.isIdentity ? makeGetCoord(y) : makeY(operator.matrix, x, y, z),
+            z: operator.isIdentity ? makeGetCoord(z) : makeZ(operator.matrix, x, y, z)
         };
     }
 }
@@ -53,4 +67,73 @@ function nextUnitId() {
     const ret = _id;
     _id = (_id + 1) % 0x3fffffff;
     return ret;
+}
+
+function makeGetInvariantPosition(x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number>) {
+    return (a: number, r: Vec3): Vec3 => {
+        r[0] = x[a];
+        r[1] = y[a];
+        r[2] = z[a];
+        return r;
+    }
+}
+
+function makeGetCoord(xs: ArrayLike<number>) {
+    return (i: number) => xs[i];
+}
+
+function isWConst(m: Mat4) {
+    return m[3] === 0 && m[7] === 0 && m[11] === 0;
+}
+
+function makeX(m: Mat4, xs: ArrayLike<number>, ys: ArrayLike<number>, zs: ArrayLike<number>) {
+    const xx = m[0], yy = m[4], zz = m[8], ww = m[12];
+
+    if (isWConst(m)) {
+        const w = m[15] || 1.0;
+        return (i: number) => (xx * xs[i] + yy * ys[i] + zz * zs[i] + ww) / w;
+    }
+
+    return (i: number) => {
+        const x = xs[i], y = ys[i], z = zs[i], w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
+        return (xx * x + yy * y + zz * z + ww) / w;
+    }
+}
+
+function makeY(m: Mat4, xs: ArrayLike<number>, ys: ArrayLike<number>, zs: ArrayLike<number>) {
+    const xx = m[1], yy = m[5], zz = m[9], ww = m[13];
+
+    if (isWConst(m)) {
+        const w = m[15] || 1.0;
+        return (i: number) => (xx * xs[i] + yy * ys[i] + zz * zs[i] + ww) / w;
+    }
+
+    return (i: number) => {
+        const x = xs[i], y = ys[i], z = zs[i], w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
+        return (xx * x + yy * y + zz * z + ww) / w;
+    }
+}
+
+function makeZ(m: Mat4, xs: ArrayLike<number>, ys: ArrayLike<number>, zs: ArrayLike<number>) {
+    const xx = m[2], yy = m[6], zz = m[10], ww = m[14];
+
+    if (isWConst(m)) {
+        const w = m[15] || 1.0;
+        return (i: number) => (xx * xs[i] + yy * ys[i] + zz * zs[i] + ww) / w;
+    }
+
+    return (i: number) => {
+        const x = xs[i], y = ys[i], z = zs[i], w = (m[3] * x + m[7] * y + m[11] * z + m[15]) || 1.0;
+        return (xx * x + yy * y + zz * z + ww) / w;
+    }
+}
+
+function makeGetPosition(m: Mat4, x: ArrayLike<number>, y: ArrayLike<number>, z: ArrayLike<number>) {
+    return (a: number, r: Vec3): Vec3 => {
+        r[0] = x[a];
+        r[1] = y[a];
+        r[2] = z[a];
+        Vec3.transformMat4(r, r, m);
+        return r;
+    }
 }
\ No newline at end of file
diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts
index 11b08e456a37ade7ec3c45ffe9563ed01138ef0d..f35ba202252ec608a74664a6163ab44613df1999 100644
--- a/src/perf-tests/structure.ts
+++ b/src/perf-tests/structure.ts
@@ -251,6 +251,13 @@ export namespace PropertyAccess {
         console.log(sumDirect(structures[0]));
         console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])));
 
+        console.time('atom.x');
+        console.log('atom.x', sumProperty(structures[0], Q.props.atom.x));
+        console.timeEnd('atom.x');
+        console.time('__x')
+        console.log('__x', sumProperty(structures[0], l => l.unit.conformation.__x[l.atom]));
+        console.timeEnd('__x')
+
         //const authSeqId = Atom.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]));
 
         //const auth_seq_id = Q.props.residue.auth_seq_id;
@@ -277,7 +284,7 @@ export namespace PropertyAccess {
         console.time('q2')
         const q2r = q2(structures[0]);
         console.timeEnd('q2')
-        console.log(Selection.structureCount(q2r))
+        console.log(Selection.structureCount(q2r));
         //console.log(q1(structures[0]));
 
         //const col = models[0].conformation.atomId.value;