diff --git a/graf3d/eve7/inc/ROOT/REveGeomData.hxx b/graf3d/eve7/inc/ROOT/REveGeomData.hxx
index f25bbf797ac078f62d9e82b715158386ad2d9823..f5b7d1309cd87e2b4a0152b4b21e60da38c7c7d1 100644
--- a/graf3d/eve7/inc/ROOT/REveGeomData.hxx
+++ b/graf3d/eve7/inc/ROOT/REveGeomData.hxx
@@ -111,10 +111,11 @@ public:
 class REveGeomDrawing {
 public:
    int numnodes{0};                         ///< total number of nodes in description
-   std::vector<REveGeomNode*> nodes;        ///< all used nodes to display visible items and not known for client
-   std::vector<REveGeomVisible> visibles;   ///< all visible items
    std::string drawopt;                     ///< draw options for TGeoPainter
+   int nsegm{0};                            ///< number of segments for cylindrical shapes
    int binlen{0};                           ///< extra binary data for that drawing
+   std::vector<REveGeomNode*> nodes;        ///< all used nodes to display visible items and not known for client
+   std::vector<REveGeomVisible> visibles;   ///< all visible items
 };
 
 
@@ -176,8 +177,9 @@ class REveGeomDescription {
    int fFacesLimit{0};              ///<! maximal number of faces to be selected for drawing
    int fNodesLimit{0};              ///<! maximal number of nodes to be selected for drawing
    bool fPreferredOffline{false};   ///<! indicates that full description should be provided to client
+   bool fBuildShapes{true};         ///<! if TGeoShape build already on server (default) or send as is to client
 
-   int fJsonComp{103};              ///<! default JSON compression - all class info can be removed
+   int fJsonComp{0};                ///<! default JSON compression
 
    void PackMatrix(std::vector<float> &arr, TGeoMatrix *matr);
 
@@ -262,13 +264,25 @@ public:
 
    void SelectNode(TGeoNode *);
 
+   /** Set number of segments for cylindrical shapes, if 0 - default value will be used */
    void SetNSegments(int n = 0) { fNSegments = n; }
+   /** Return of segments for cylindrical shapes, if 0 - default value will be used */
    int GetNSegments() const { return fNSegments; }
 
-   void SetJsonComp(int comp = 103) { fJsonComp = comp; }
+   /** Set JSON compression level for data transfer */
+   void SetJsonComp(int comp = 0) { fJsonComp = comp; }
+   /** Returns JSON compression level for data transfer */
    int GetJsonComp() const  { return fJsonComp; }
 
+   /** Set draw options as string for JSROOT TGeoPainter */
    void SetDrawOptions(const std::string &opt = "") { fDrawOptions = opt; }
+   /** Returns draw options, used for JSROOT TGeoPainter */
+   std::string GetDrawOptions() const { return fDrawOptions; }
+
+   /** Instruct to build binary 3D model already on the server (true) or send TGeoShape as is to client, which can build model itself */
+   void SetBuildShapes(bool on = true) { fBuildShapes = on; }
+   /** Retuns true if binary 3D model build already by C++ server (default) */
+   bool IsBuildShapes() const { return fBuildShapes; }
 
    std::unique_ptr<REveGeomNodeInfo> MakeNodeInfo(const std::string &path);
 };
diff --git a/graf3d/eve7/src/REveGeomData.cxx b/graf3d/eve7/src/REveGeomData.cxx
index 07949c979e54b1dde01441c3ac8bfe139b36bc86..c7840e562ba26a7f5496dad8632769513da55a86 100644
--- a/graf3d/eve7/src/REveGeomData.cxx
+++ b/graf3d/eve7/src/REveGeomData.cxx
@@ -576,9 +576,7 @@ std::string ROOT::Experimental::REveGeomDescription::ProcessBrowserRequest(const
       for (auto &item : fDesc)
          vect[cnt++]= &item;
 
-      res = "DESCR:";
-
-      res.append(TBufferJSON::ToJSON(&vect,GetJsonComp()).Data());
+      res = "DESCR:"s + TBufferJSON::ToJSON(&vect,GetJsonComp()).Data();
 
       // example how iterator can be used
       RGeomBrowserIter iter(*this);
@@ -619,8 +617,7 @@ std::string ROOT::Experimental::REveGeomDescription::ProcessBrowserRequest(const
       for (auto &n : temp_nodes)
          reply.nodes.emplace_back(&n);
 
-      res = "BREPL:";
-      res.append(TBufferJSON::ToJSON(&reply, GetJsonComp()).Data());
+      res = "BREPL:"s + TBufferJSON::ToJSON(&reply, GetJsonComp()).Data();
    }
 
    return res;
@@ -650,12 +647,10 @@ ROOT::Experimental::REveGeomDescription::MakeShapeDescr(TGeoShape *shape, bool a
 {
    auto &elem = FindShapeDescr(shape);
 
-   if (!elem.fRenderData) {
+   if (elem.nfaces == 0) {
       TGeoCompositeShape *comp = dynamic_cast<TGeoCompositeShape *>(shape);
 
-      bool create_binaries = true;
-
-      if (create_binaries) {
+      if (IsBuildShapes() || (comp != nullptr)) {
 
          auto poly = std::make_unique<REveGeoPolyShape>();
 
@@ -684,7 +679,7 @@ ROOT::Experimental::REveGeomDescription::MakeShapeDescr(TGeoShape *shape, bool a
          ri.rnr_func.clear();
          ri.rnr_offset = 0;
          ri.vert_size = ri.norm_size = ri.index_size = 0;
-      } else if (ri.rnr_offset < 0) {
+      } else if (rd && (ri.rnr_offset < 0)) {
          ri.shape = nullptr;
          ri.rnr_offset = fRndrOffest;
          fRndrOffest += rd->GetBinarySize();
@@ -820,6 +815,7 @@ bool ROOT::Experimental::REveGeomDescription::CollectVisibles()
 
    REveGeomDrawing drawing;
    ResetRndrInfos();
+   bool has_shape = false;
 
    ScanNodes(true, [&, this](REveGeomNode &node, std::vector<int> &stack, bool) {
       if (node.sortid < fDrawIdCut) {
@@ -834,6 +830,7 @@ bool ROOT::Experimental::REveGeomDescription::CollectVisibles()
          auto &sd = MakeShapeDescr(volume->GetShape(), true);
 
          item.ri = sd.rndr_info();
+         if (item.ri->shape) has_shape = true;
       }
       return true;
    });
@@ -843,10 +840,12 @@ bool ROOT::Experimental::REveGeomDescription::CollectVisibles()
    // create binary data with all produced shapes
    BuildRndrBinary(fDrawBinary);
 
-   drawing.drawopt = fDrawOptions;
+   drawing.drawopt = GetDrawOptions();
+   drawing.nsegm = GetNSegments();
    drawing.binlen = fDrawBinary.size();
 
-   fDrawJson = "GDRAW:"s + TBufferJSON::ToJSON(&drawing, GetJsonComp()).Data();
+   int compcut = has_shape ? 100 : 1000;
+   fDrawJson = "GDRAW:"s + TBufferJSON::ToJSON(&drawing, GetJsonComp() % compcut).Data();
 
    return true;
 }
@@ -977,6 +976,7 @@ int ROOT::Experimental::REveGeomDescription::SearchVisibles(const std::string &f
    ResetRndrInfos();
 
    REveGeomDrawing drawing;
+   bool has_shape = true;
 
    ScanNodes(false, [&, this](REveGeomNode &node, std::vector<int> &stack, bool is_vis) {
       // select only nodes which should match
@@ -1029,16 +1029,19 @@ int ROOT::Experimental::REveGeomDescription::SearchVisibles(const std::string &f
       auto &sd = MakeShapeDescr(volume->GetShape(), true);
 
       item.ri = sd.rndr_info();
+      if (item.ri->shape) has_shape = true;
       return true;
    });
 
-   hjson = "FESCR:"s + TBufferJSON::ToJSON(&found_desc, GetJsonComp()).Data();
+   int compcut = has_shape ? 100 : 1000;
+   hjson = "FESCR:"s + TBufferJSON::ToJSON(&found_desc, GetJsonComp() % compcut).Data();
 
    CollectNodes(drawing);
 
    BuildRndrBinary(binary);
 
-   drawing.drawopt = fDrawOptions;
+   drawing.drawopt = GetDrawOptions();
+   drawing.nsegm = GetNSegments();
    drawing.binlen = binary.size();
 
    json = "FDRAW:"s + TBufferJSON::ToJSON(&drawing, GetJsonComp()).Data();
@@ -1188,9 +1191,7 @@ std::string ROOT::Experimental::REveGeomDescription::ProduceModifyReply(int node
       if (fNodes[id++]->GetVolume() == vol)
          nodes.emplace_back(&desc);
 
-   std::string res = "MODIF:";
-   res.append(TBufferJSON::ToJSON(&nodes, GetJsonComp()).Data());
-   return res;
+   return "MODIF:"s + TBufferJSON::ToJSON(&nodes, GetJsonComp()).Data();
 }
 
 
@@ -1237,20 +1238,26 @@ bool ROOT::Experimental::REveGeomDescription::ProduceDrawingFor(int nodeid, std:
 
    ResetRndrInfos();
 
+   bool has_shape = false;
+
    auto &sd = MakeShapeDescr(vol->GetShape(), true);
 
    // assign shape data
-   for (auto &item : drawing.visibles)
+   for (auto &item : drawing.visibles) {
       item.ri = sd.rndr_info();
+      if (item.ri->shape) has_shape = true;
+   }
 
    CollectNodes(drawing);
 
    BuildRndrBinary(binary);
 
-   drawing.drawopt = fDrawOptions;
+   drawing.drawopt = GetDrawOptions();
+   drawing.nsegm = GetNSegments();
    drawing.binlen = binary.size();
 
-   json.append(TBufferJSON::ToJSON(&drawing, GetJsonComp()).Data());
+   int compcut = has_shape ? 100 : 1000;
+   json.append(TBufferJSON::ToJSON(&drawing, GetJsonComp() % compcut).Data());
 
    return true;
 }
@@ -1326,12 +1333,9 @@ std::unique_ptr<ROOT::Experimental::REveGeomNodeInfo> ROOT::Experimental::REveGe
 
          res->ri = &shape_descr.fRenderInfo; // temporary pointer, can be used preserved for short time
 
-         printf("OFFSET %d\n", fRndrOffest);
-
          BuildRndrBinary(res->rndr_binary);
 
          printf("BINARY SIZE %u\n", (unsigned) res->rndr_binary.size());
-
       }
 
    }
diff --git a/graf3d/eve7/src/REveGeomViewer.cxx b/graf3d/eve7/src/REveGeomViewer.cxx
index 3f809667ee540efcfa046049a2ee068f8a9ee8f0..daff1c7dccabe66550f111af383ef33541001fc6 100644
--- a/graf3d/eve7/src/REveGeomViewer.cxx
+++ b/graf3d/eve7/src/REveGeomViewer.cxx
@@ -40,8 +40,8 @@ ROOT::Experimental::REveGeomViewer::REveGeomViewer(TGeoManager *mgr)
    if (mgr) SetGeometry(mgr);
 
    fDesc.SetPreferredOffline(gEnv->GetValue("WebGui.PreferredOffline",0) != 0);
-   auto comp = gEnv->GetValue("WebGui.JsonComp", -1);
-   if (comp >= 0) fDesc.SetJsonComp(comp);
+   fDesc.SetJsonComp(gEnv->GetValue("WebGui.JsonComp", TBufferJSON::kSkipTypeInfo + TBufferJSON::kNoSpaces));
+   fDesc.SetBuildShapes(gEnv->GetValue("WebGui.GeomBuildShapes", 1) > 0);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////////
@@ -138,7 +138,8 @@ void ROOT::Experimental::REveGeomViewer::SendGeometry(unsigned connid)
 
    fWebWindow->Send(connid, json);
 
-   fWebWindow->SendBinary(connid, binary.data(), binary.size());
+   if (binary.size() > 0)
+      fWebWindow->SendBinary(connid, binary.data(), binary.size());
 }
 
 
diff --git a/ui5/eve7/controller/GeomViewer.controller.js b/ui5/eve7/controller/GeomViewer.controller.js
index e1e4bd47e7498ce40357ce01320d79df7542fe86..76610d2f52090f7a081c6f89ad6ae70bccd1a83e 100644
--- a/ui5/eve7/controller/GeomViewer.controller.js
+++ b/ui5/eve7/controller/GeomViewer.controller.js
@@ -301,7 +301,7 @@ sap.ui.define(['sap/ui/core/Component',
        * Draw message is vector of REveGeomVisible objects, including info where shape is in raw data */
       extractRawShapes: function(draw_msg) {
 
-         var nodes = null;
+         var nodes = null, old_gradpersegm = 0;
 
          // array for descriptors for each node
          // if array too large (>1M), use JS object while only ~1K nodes are expected to be used
@@ -324,6 +324,11 @@ sap.ui.define(['sap/ui/core/Component',
             this.geo_clones.name_prefix = this.geo_clones.GetNodeName(0);
          }
 
+         if (draw_msg.nsegm) {
+            old_gradpersegm = JSROOT.GEO.GradPerSegm;
+            JSROOT.GEO.GradPerSegm = 360 / Math.max(draw_msg.nsegm,6);
+         }
+
          for (var cnt = 0; cnt < draw_msg.visibles.length; ++cnt) {
             var item = draw_msg.visibles[cnt], rd = item.ri;
 
@@ -339,6 +344,9 @@ sap.ui.define(['sap/ui/core/Component',
                this.createServerShape(rd, draw_msg.raw, draw_msg.offset);
          }
 
+         if (old_gradpersegm)
+            JSROOT.GEO.GradPerSegm = old_gradpersegm;
+
          return true;
       },