diff --git a/src/mol-gl/scene.ts b/src/mol-gl/scene.ts
index 5e7c91763c4f73f327bb51f8b35da1442da72c23..3649546ee50f84db26e0c2d56fee3312f425b4d8 100644
--- a/src/mol-gl/scene.ts
+++ b/src/mol-gl/scene.ts
@@ -8,11 +8,9 @@ import { PointRenderable, MeshRenderable, Renderable } from './renderable'
 
 import { ValueCell } from 'mol-util';
 import { Context } from './webgl/context';
+import { idFactory } from 'mol-util/id-factory';
 
-let _renderObjectId = 0;
-function getNextId() {
-    return _renderObjectId++ % 0x7FFFFFFF;
-}
+const getNextId = idFactory(0, 0x7FFFFFFF)
 
 export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> }
 
diff --git a/src/mol-task/task.ts b/src/mol-task/task.ts
index ee5474fa9175064d06a0ed97e0e4fa9230de8ca5..92203f50e8b67155aac7bca1996b07731d49b543 100644
--- a/src/mol-task/task.ts
+++ b/src/mol-task/task.ts
@@ -8,6 +8,7 @@ import { RuntimeContext } from './execution/runtime-context'
 import { Progress } from './execution/progress'
 import { ExecuteObservable, ExecuteObservableChild, ExecuteInContext } from './execution/observable';
 import { SyncRuntimeContext } from 'mol-task/execution/synchronous';
+import { idFactory } from 'mol-util/id-factory';
 
 // A "named function wrapper" with built in "computation tree progress tracking".
 // Use Run(t, ?observer, ?updateRate) to execute
@@ -48,7 +49,7 @@ namespace Task {
         }
 
         constructor(public name: string, public f: (ctx: RuntimeContext) => Promise<T>, public onAbort?: () => void) {
-            this.id = nextId();
+            this.id = getNextId();
         }
     }
 
@@ -74,12 +75,7 @@ namespace Task {
         max: number
     }
 
-    let _id = 0;
-    function nextId() {
-        const ret = _id;
-        _id = (_id + 1) % 0x3fffffff;
-        return ret;
-    }
+    const getNextId = idFactory(0, 0x3fffffff)
 }
 
 export { Task }
\ No newline at end of file
diff --git a/src/mol-util/_spec/id-factory.spec.ts b/src/mol-util/_spec/id-factory.spec.ts
index 4c2c9cbe90fed42cb694869b08ed11af9d692283..a5ad68bdd4fc6fa559a407d3e11299169a097797 100644
--- a/src/mol-util/_spec/id-factory.spec.ts
+++ b/src/mol-util/_spec/id-factory.spec.ts
@@ -24,4 +24,12 @@ describe('id-factory', () => {
         expect(getNextId()).toBe(-1)
         expect(getNextId()).toBe(0)
     })
+
+    it('max-id', () => {
+        const getNextId = idFactory(0, 2)
+        expect(getNextId()).toBe(0)
+        expect(getNextId()).toBe(1)
+        expect(getNextId()).toBe(0)
+        expect(getNextId()).toBe(1)
+    })
 });
\ No newline at end of file
diff --git a/src/mol-util/id-factory.ts b/src/mol-util/id-factory.ts
index 0de5654ff7194cf31ac15dd50e1d08d190e49cd9..0c7ad893b57f7aa5aef1a12ba178a840117c6248 100644
--- a/src/mol-util/id-factory.ts
+++ b/src/mol-util/id-factory.ts
@@ -4,7 +4,12 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-export function idFactory(firstId = 0) {
+/** Builds id function returning ids within [firstId, maxId) */
+export function idFactory(firstId = 0, maxId = Number.MAX_SAFE_INTEGER) {
     let _nextId = firstId
-    return () => _nextId++
+    return () => {
+        const ret = _nextId
+        _nextId = (_nextId + 1) % maxId
+        return ret
+    }
 }
\ No newline at end of file
diff --git a/src/mol-util/value-cell.ts b/src/mol-util/value-cell.ts
index a778756347f661935c0bd23d35c2a5094318089d..948f5d2837a0a9e1b32750235ec6fd14b8519530 100644
--- a/src/mol-util/value-cell.ts
+++ b/src/mol-util/value-cell.ts
@@ -4,6 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
+import { idFactory } from './id-factory'
+
 /** A mutable value reference. */
 interface ValueRef<T> { ref: T }
 
@@ -12,17 +14,14 @@ namespace ValueRef {
     export function set<T>(ref: ValueRef<T>, value: T) { ref.ref = value; return ref; }
 }
 
-let _valueBoxId = 0;
-function getNextId() {
-    return _valueBoxId++ % 0x7FFFFFFF;
-}
+const getNextId = idFactory(0, 0x7FFFFFFF)
 
 /**
  * An immutable value box that also holds a version of the attribute.
  * Optionally includes automatically propadated "metadata".
  */
 type ValueBox<T, D = never> = {
-    // Unique identifier in the range 0 to 0x7FFFFFFF
+    /** Unique identifier in the range 0 to 0x7FFFFFFF */
     readonly id: number,
     readonly version: number,
     readonly metadata: D,