diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index efe284651a..f39d84caaf 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -1592,7 +1592,7 @@ void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
     scene->enqueuePendingChanges(pendingChanges);
 }
 
-bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) {
+bool RenderablePolyVoxEntityItem::getMeshes(MeshProxyList& result) {
     if (!updateDependents()) {
         return false;
     }
@@ -1615,8 +1615,8 @@ bool RenderablePolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QS
                 _mesh->map([=](glm::vec3 position){ return glm::vec3(transform * glm::vec4(position, 1.0f)); },
                            [=](glm::vec3 normal){ return glm::vec3(transform * glm::vec4(normal, 0.0f)); },
                            [&](uint32_t index){ return index; }));
-            result = meshToScriptValue(engine, meshProxy);
+            result << meshProxy;
         }
     });
-    return success;
+    return meshProxy;
 }
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
index e6467be987..a0d5c38a14 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
@@ -135,7 +135,6 @@ public:
     QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const;
 
     void setMesh(model::MeshPointer mesh);
-    bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) override;
     void setCollisionPoints(ShapeInfo::PointCollection points, AABox box);
     PolyVox::SimpleVolume<uint8_t>* getVolData() { return _volData; }
 
@@ -147,6 +146,8 @@ public:
     // Transparent polyvox didn't seem to be working so disable for now
     bool isTransparent() override { return false; }
 
+    bool getMeshes(MeshProxyList& result) override;
+
 protected:
     virtual void locationChanged(bool tellPhysics = true) override;
 
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 163b4d9e45..b973d916e6 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -63,6 +63,8 @@ namespace render {
 #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10))
 #define debugTreeVector(V) V << "[" << V << " in meters ]"
 
+class MeshProxyList;
+
 
 /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available
 /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate
@@ -470,9 +472,11 @@ public:
 
     QUuid getLastEditedBy() const { return _lastEditedBy; }
     void setLastEditedBy(QUuid value) { _lastEditedBy = value; }
-    
+
     bool matchesJSONFilters(const QJsonObject& jsonFilters) const;
 
+    virtual bool getMeshes(MeshProxyList& result) { return true; }
+
 protected:
 
     void setSimulated(bool simulated) { _simulated = simulated; }
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index 88d7acf7bf..0888dd4fb9 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -21,6 +21,7 @@
 #include <VariantMapToScriptValue.h>
 #include <SharedUtil.h>
 #include <SpatialParentFinder.h>
+#include <model/MeshProxy.h>
 
 #include "EntitiesLogging.h"
 #include "EntityActionFactoryInterface.h"
@@ -1040,21 +1041,6 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3
     });
 }
 
-void EntityScriptingInterface::voxelsToMesh(QUuid entityID, QScriptValue callback) {
-    PROFILE_RANGE(script_entities, __FUNCTION__);
-
-    bool success { false };
-    QScriptValue mesh { false };
-
-    polyVoxWorker(entityID, [&](PolyVoxEntityItem& polyVoxEntity) mutable {
-        success = polyVoxEntity.getMeshAsScriptValue(callback.engine(), mesh);
-        return true;
-    });
-
-    QScriptValueList args { mesh, success };
-    callback.call(QScriptValue(), args);
-}
-
 bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
     PROFILE_RANGE(script_entities, __FUNCTION__);
 
@@ -1671,6 +1657,30 @@ bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, cons
     return aaBox.findCapsulePenetration(start, end, radius, penetration);
 }
 
+void EntityScriptingInterface::getMeshes(QUuid entityID, QScriptValue callback) {
+    PROFILE_RANGE(script_entities, __FUNCTION__);
+
+    EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
+    if (!entity) {
+        qCDebug(entities) << "EntityScriptingInterface::getMeshes no entity with ID" << entityID;
+        QScriptValueList args { false, false };
+        callback.call(QScriptValue(), args);
+        return;
+    }
+
+    MeshProxyList result;
+    bool success = entity->getMeshes(result);
+
+    if (success) {
+        QScriptValue resultAsScriptValue = meshesToScriptValue(callback.engine(), result);
+        QScriptValueList args { resultAsScriptValue, true };
+        callback.call(QScriptValue(), args);
+    } else {
+        QScriptValueList args { callback.engine()->undefinedValue(), false };
+        callback.call(QScriptValue(), args);
+    }
+}
+
 glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) {
     glm::mat4 result;
     if (_entityTree) {
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 944c2bb8d5..7b4c2ff800 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -266,7 +266,6 @@ public slots:
     Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
     Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
                                        const glm::vec3& cuboidSize, int value);
-    Q_INVOKABLE void voxelsToMesh(QUuid entityID, QScriptValue callback);
 
     Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
     Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
@@ -331,6 +330,8 @@ public slots:
                                             const glm::vec3& start, const glm::vec3& end, float radius);
 
 
+    Q_INVOKABLE void getMeshes(QUuid entityID, QScriptValue callback);
+
     /**jsdoc
      * Returns object to world transform, excluding scale
      *
diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp
index 90344d6c4b..2a374c1d17 100644
--- a/libraries/entities/src/PolyVoxEntityItem.cpp
+++ b/libraries/entities/src/PolyVoxEntityItem.cpp
@@ -242,7 +242,3 @@ const QByteArray PolyVoxEntityItem::getVoxelData() const {
     });
     return voxelDataCopy;
 }
-
-bool PolyVoxEntityItem::getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result) {
-    return false;
-}
diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h
index 311a002a4a..cf7531fc9e 100644
--- a/libraries/entities/src/PolyVoxEntityItem.h
+++ b/libraries/entities/src/PolyVoxEntityItem.h
@@ -135,8 +135,6 @@ class PolyVoxEntityItem : public EntityItem {
     void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); }
     virtual void recomputeMesh() {};
 
-    virtual bool getMeshAsScriptValue(QScriptEngine *engine, QScriptValue& result);
-
  protected:
     glm::vec3 _voxelVolumeSize; // this is always 3 bytes
 
diff --git a/libraries/script-engine/src/MeshProxy.h b/libraries/model/src/model/MeshProxy.h
similarity index 68%
rename from libraries/script-engine/src/MeshProxy.h
rename to libraries/model/src/model/MeshProxy.h
index 82f5038348..fcd36e6e9c 100644
--- a/libraries/script-engine/src/MeshProxy.h
+++ b/libraries/model/src/model/MeshProxy.h
@@ -1,6 +1,6 @@
 //
 //  MeshProxy.h
-//  libraries/script-engine/src
+//  libraries/model/src/model/
 //
 //  Created by Seth Alves on 2017-1-27.
 //  Copyright 2017 High Fidelity, Inc.
@@ -12,7 +12,11 @@
 #ifndef hifi_MeshProxy_h
 #define hifi_MeshProxy_h
 
-#include <model/Geometry.h>
+#include <QScriptEngine>
+#include <QScriptValueIterator>
+#include <QtScript/QScriptValue>
+
+#include "Geometry.h"
 
 using MeshPointer = std::shared_ptr<model::Mesh>;
 
@@ -38,4 +42,11 @@ Q_DECLARE_METATYPE(MeshProxy*);
 class MeshProxyList : public QList<MeshProxy*> {}; // typedef and using fight with the Qt macros/templates, do this instead
 Q_DECLARE_METATYPE(MeshProxyList);
 
+
+QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
+void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out);
+
+QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in);
+void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out);
+
 #endif // hifi_MeshProxy_h
diff --git a/libraries/script-engine/src/ModelScriptingInterface.cpp b/libraries/script-engine/src/ModelScriptingInterface.cpp
index 833ac5b64d..22b7eb89ed 100644
--- a/libraries/script-engine/src/ModelScriptingInterface.cpp
+++ b/libraries/script-engine/src/ModelScriptingInterface.cpp
@@ -18,30 +18,8 @@
 
 ModelScriptingInterface::ModelScriptingInterface(QObject* parent) : QObject(parent) {
     _modelScriptEngine = qobject_cast<ScriptEngine*>(parent);
-}
 
-QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in) {
-    return engine->newQObject(in, QScriptEngine::QtOwnership,
-                              QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
-}
-
-void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out) {
-    out = qobject_cast<MeshProxy*>(value.toQObject());
-}
-
-QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in) {
-    return engine->toScriptValue(in);
-}
-
-void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out) {
-    QScriptValueIterator itr(value);
-    while(itr.hasNext()) {
-        itr.next();
-        MeshProxy* meshProxy = qscriptvalue_cast<MeshProxyList::value_type>(itr.value());
-        if (meshProxy) {
-            out.append(meshProxy);
-        }
-    }
+    qScriptRegisterSequenceMetaType<QList<MeshProxy*>>(_modelScriptEngine);
 }
 
 QString ModelScriptingInterface::meshToOBJ(MeshProxyList in) {
diff --git a/libraries/script-engine/src/ModelScriptingInterface.h b/libraries/script-engine/src/ModelScriptingInterface.h
index 14789943e3..105d6d548e 100644
--- a/libraries/script-engine/src/ModelScriptingInterface.h
+++ b/libraries/script-engine/src/ModelScriptingInterface.h
@@ -17,7 +17,7 @@
 #include <QScriptValue>
 #include <OBJWriter.h>
 #include <model/Geometry.h>
-#include "MeshProxy.h"
+#include <model/MeshProxy.h>
 
 using MeshPointer = std::shared_ptr<model::Mesh>;
 class ScriptEngine;
@@ -36,10 +36,4 @@ private:
     ScriptEngine* _modelScriptEngine { nullptr };
 };
 
-QScriptValue meshToScriptValue(QScriptEngine* engine, MeshProxy* const &in);
-void meshFromScriptValue(const QScriptValue& value, MeshProxy* &out);
-
-QScriptValue meshesToScriptValue(QScriptEngine* engine, const MeshProxyList &in);
-void meshesFromScriptValue(const QScriptValue& value, MeshProxyList &out);
-
 #endif // hifi_ModelScriptingInterface_h