diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp
index 0708ede5b6..6bad482ca1 100644
--- a/libraries/metavoxels/src/Bitstream.cpp
+++ b/libraries/metavoxels/src/Bitstream.cpp
@@ -865,6 +865,21 @@ QVariant TypeReader::read(Bitstream& in) const {
     return object;
 }
 
+void TypeReader::readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const {
+    if (_exactMatch) {
+        _streamer->readDelta(in, object, reference);
+        return;
+    }
+    if (_valueReader) {
+        // TODO: collection deltas
+        
+    } else {
+        foreach (const FieldReader& field, _fields) {
+            field.readDelta(in, _streamer, object, reference);
+        }    
+    }
+}
+
 bool TypeReader::matchesExactly(const TypeStreamer* streamer) const {
     return _exactMatch && _streamer == streamer;
 }
@@ -885,6 +900,10 @@ void FieldReader::read(Bitstream& in, const TypeStreamer* streamer, QVariant& ob
     }    
 }
 
+void FieldReader::readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const {
+    // TODO: field delta
+}
+
 ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject,
         const QVector<PropertyReader>& properties) :
     _className(className),
diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h
index 769ae4a250..cd885d9f81 100644
--- a/libraries/metavoxels/src/Bitstream.h
+++ b/libraries/metavoxels/src/Bitstream.h
@@ -268,6 +268,9 @@ public:
     /// Removes a shared object from the read mappings.
     void clearSharedObject(int id);
 
+    template<class T> void writeDelta(const T& value, const T& reference);
+    template<class T> void readDelta(T& value, const T& reference); 
+    
     Bitstream& operator<<(bool value);
     Bitstream& operator>>(bool& value);
     
@@ -378,6 +381,23 @@ private:
     static QVector<PropertyReader> getPropertyReaders(const QMetaObject* metaObject);
 };
 
+template<class T> inline void Bitstream::writeDelta(const T& value, const T& reference) {
+    if (value == reference) {
+        *this << false;
+    } else {
+        *this << true;
+        *this << value;
+    }
+}
+
+template<class T> inline void Bitstream::readDelta(T& value, const T& reference) {
+    bool changed;
+    *this >> changed;
+    if (changed) {
+        *this >> value;
+    }
+}
+
 template<class T> inline Bitstream& Bitstream::operator<<(const QList<T>& list) {
     *this << list.size();
     foreach (const T& entry, list) {
@@ -458,6 +478,7 @@ public:
     const TypeStreamer* getStreamer() const { return _streamer; }
 
     QVariant read(Bitstream& in) const;
+    void readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const;
 
     bool matchesExactly(const TypeStreamer* streamer) const;
 
@@ -486,7 +507,8 @@ public:
     int getIndex() const { return _index; }
 
     void read(Bitstream& in, const TypeStreamer* streamer, QVariant& object) const;
-
+    void readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const;
+    
 private:
     
     TypeReader _reader;
@@ -565,6 +587,9 @@ public:
     virtual void write(Bitstream& out, const QVariant& value) const = 0;
     virtual QVariant read(Bitstream& in) const = 0;
 
+    virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0;
+    virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0;
+
     virtual const QVector<MetaField>& getMetaFields() const;
     virtual int getFieldIndex(const QByteArray& name) const;
     virtual void setField(int index, QVariant& object, const QVariant& value) const;
@@ -590,6 +615,10 @@ public:
     
     virtual void write(Bitstream& out, const QVariant& value) const { out << value.value<T>(); }
     virtual QVariant read(Bitstream& in) const { T value; in >> value; return QVariant::fromValue(value); }
+    virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
+        out.writeDelta(value.value<T>(), reference.value<T>()); }
+    virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
+        in.readDelta(*static_cast<T*>(value.data()), reference.value<T>()); }
 };
 
 /// A streamer for types compiled by mtc.
@@ -652,6 +681,8 @@ public:
 #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
     Bitstream& operator<<(Bitstream& out, const X& obj); \
     Bitstream& operator>>(Bitstream& in, X& obj); \
+    template<> void Bitstream::writeDelta(const X& value, const X& reference); \
+    template<> void Bitstream::readDelta(X& value, const X& reference); \
     bool operator==(const X& first, const X& second); \
     bool operator!=(const X& first, const X& second); \
     static const int* _TypePtr##X = &X::Type;
@@ -659,6 +690,8 @@ public:
 #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
     Bitstream& operator<<(Bitstream& out, const X& obj); \
     Bitstream& operator>>(Bitstream& in, X& obj); \
+    template<> void Bitstream::writeDelta(const X& value, const X& reference); \
+    template<> void Bitstream::readDelta(X& value, const X& reference); \
     bool operator==(const X& first, const X& second); \
     bool operator!=(const X& first, const X& second); \
     __attribute__((unused)) static const int* _TypePtr##X = &X::Type;
@@ -667,6 +700,8 @@ public:
 #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \
     Bitstream& operator<<(Bitstream& out, const X& obj); \
     Bitstream& operator>>(Bitstream& in, X& obj); \
+    template<> void Bitstream::writeDelta(const X& value, const X& reference); \
+    template<> void Bitstream::readDelta(X& value, const X& reference); \
     bool operator==(const X& first, const X& second); \
     bool operator!=(const X& first, const X& second); \
     static const int* _TypePtr##X = &X::Type; \
diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp
index e95958ac76..36257a740f 100644
--- a/libraries/metavoxels/src/SharedObject.cpp
+++ b/libraries/metavoxels/src/SharedObject.cpp
@@ -37,7 +37,7 @@ void SharedObject::decrementReferenceCount() {
     }
 }
 
-SharedObject* SharedObject::clone() const {
+SharedObject* SharedObject::clone(bool withID) const {
     // default behavior is to make a copy using the no-arg constructor and copy the stored properties
     const QMetaObject* metaObject = this->metaObject();
     SharedObject* newObject = static_cast<SharedObject*>(metaObject->newInstance());
@@ -50,6 +50,9 @@ SharedObject* SharedObject::clone() const {
     foreach (const QByteArray& propertyName, dynamicPropertyNames()) {
         newObject->setProperty(propertyName, property(propertyName));
     }
+    if (withID) {
+        newObject->setID(_id);
+    }
     return newObject;
 }
 
@@ -91,6 +94,11 @@ void SharedObject::dump(QDebug debug) const {
     }
 }
 
+void SharedObject::setID(int id) {
+    _weakHash.remove(_id);
+    _weakHash.insert(_id = id, this);
+}
+
 int SharedObject::_lastID = 0;
 WeakSharedObjectHash SharedObject::_weakHash;
 
diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h
index 66e6474972..435127fffd 100644
--- a/libraries/metavoxels/src/SharedObject.h
+++ b/libraries/metavoxels/src/SharedObject.h
@@ -47,7 +47,8 @@ public:
     void decrementReferenceCount();
 
     /// Creates a new clone of this object.
-    virtual SharedObject* clone() const;
+    /// \param withID if true, give the clone the same ID as this object
+    virtual SharedObject* clone(bool withID = false) const;
 
     /// Tests this object for equality with another.    
     virtual bool equals(const SharedObject* other) const;
@@ -57,6 +58,8 @@ public:
 
 private:
     
+    void setID(int id);
+    
     int _id;
     int _remoteID;
     int _referenceCount;
diff --git a/tools/mtc/src/main.cpp b/tools/mtc/src/main.cpp
index 7a546ab529..e6f1827870 100644
--- a/tools/mtc/src/main.cpp
+++ b/tools/mtc/src/main.cpp
@@ -172,6 +172,26 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
         out << "    return in;\n";
         out << "}\n";
 
+        out << "template<> void Bitstream::writeDelta(const " << name << "& value, const " << name << "& reference) {\n";
+        foreach (const QString& base, str.clazz.bases) {
+            out << "    writeDelta(static_cast<const " << base << "&>(value), static_cast<const " <<
+                base << "&>(reference));\n";
+        }
+        foreach (const Field& field, str.fields) {
+            out << "    writeDelta(value." << field.name << ", reference." << field.name << ");\n";
+        }
+        out << "}\n";
+
+        out << "template<> void Bitstream::readDelta(" << name << "& value, const " << name << "& reference) {\n";
+        foreach (const QString& base, str.clazz.bases) {
+            out << "    readDelta(static_cast<" << base << "&>(value), static_cast<const " <<
+                base << "&>(reference));\n";
+        }
+        foreach (const Field& field, str.fields) {
+            out << "    readDelta(value." << field.name << ", reference." << field.name << ");\n";
+        }
+        out << "}\n";
+        
         out << "bool operator==(const " << name << "& first, const " << name << "& second) {\n";
         if (str.clazz.bases.isEmpty() && str.fields.isEmpty()) {
             out << "    return true";