makeBuildCachedGeometryFromTree = (params) => {
  const defaults = {
    // how many passes we allow without cache hits before eliminating hashes/geometry from cache
    passesBeforeElimination: 1,
    lookup: {},
    lookupCounts: {}
  }
  const { passesBeforeElimination, lookup, lookupCounts } = Object.assign({}, defaults, params)
  const cache = makeCacheWithInvalidation(passesBeforeElimination, lookup, lookupCounts)

  const buildFinalResult = (tree, deep) => toArray(dfs(tree, cache))

  // main function, this can be called every time one needs to generate
  // geometry from the vtree
  return function (params, tree) {
    // FIXME: not sure: merge pre-emptive cache results
    /* specials.forEach(special => {
      // console.log('special', special.cache)
      Object.keys(special.cache.lookup).forEach(key => {
        cache.add(key, special.cache.lookup[key])
      })
    }) */

    const result = buildFinalResult(tree)

    // FIXME not sure
    /* flatten(specials).forEach(function (childNode) {
      dfs(childNode, cache)
    }) */
    // console.log('specials', JSON.stringify(specials))

    // to remove potential no-hit items
    cache.update()
    return result
  }
}
higher order function returning a function that can be called to generate
geometry from a vtree, using caching (for root elements for now)