diff --git a/Guide.md b/Guide.md
index 1076e08..546b0d8 100644
--- a/Guide.md
+++ b/Guide.md
@@ -150,6 +150,24 @@ gui.addColor( obj, 'colorObject', 255 );
gui.addColor( obj, 'colorArray', 255 );
```
+### Custom Color Spaces
+
+lil-gui allows you to work with colors outside of the typical sRGB color space, so long as they provide conversion methods to and from sRGB hex integers.
+
+```js
+class MyColor {
+
+ // convert this color to hex int (0xff00aa)
+ getHex() { return hexInt; }
+
+ // parse int and convert to this color space
+ setHex( hexInt ) {}
+
+}
+```
+
+If present, lil-gui will use these methods instead of reading or writing the `{ r, g, b }` components directly.
+
## Folders
You can organize controllers in collapsible groups using `addFolder()`. The method returns a new GUI
diff --git a/Migrating.md b/Migrating.md
index d38e1c2..b399b07 100644
--- a/Migrating.md
+++ b/Migrating.md
@@ -51,6 +51,8 @@ params = { color };
lil_gui.addColor( params, 'color' );
```
+_Note: lil-gui is automatically converting color spaces under the hood since THREE.Color provides getHex/setHex methods._
+
The other differences in color handling are fairly minor:
- lil-gui always writes to `#rrggbb` format for strings, even those defined as `rgb()` or `#RGB`.
diff --git a/examples/custom-color/custom-color.js b/examples/custom-color/custom-color.js
new file mode 100644
index 0000000..c149bc9
--- /dev/null
+++ b/examples/custom-color/custom-color.js
@@ -0,0 +1,36 @@
+import * as THREE from 'https://cdn.jsdelivr.net/npm/three/build/three.module.js';
+import GUI from '../../dist/lil-gui.esm.js';
+
+const debugDiv = document.getElementById( 'debug-div' );
+
+const scene = new THREE.Scene();
+
+const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+camera.position.z = 2;
+
+const renderer = new THREE.WebGLRenderer();
+renderer.setSize( window.innerWidth, window.innerHeight );
+document.body.appendChild( renderer.domElement );
+
+const geometry = new THREE.BoxGeometry();
+const material = new THREE.MeshBasicMaterial( { color: 0x00aaff } );
+const cube = new THREE.Mesh( geometry, material );
+
+scene.add( cube );
+const gui = new GUI();
+const ctrl = gui.addColor( material, 'color' );
+
+function animate() {
+
+ requestAnimationFrame( animate );
+
+ cube.rotation.x += 0.01;
+ cube.rotation.y += 0.01;
+
+ debugDiv.style.backgroundColor = '#' + ctrl.$text.value;
+
+ renderer.render( scene, camera );
+
+}
+
+animate();
diff --git a/examples/custom-color/index.html b/examples/custom-color/index.html
new file mode 100644
index 0000000..0f90d9f
--- /dev/null
+++ b/examples/custom-color/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/homepage/guide-examples.js b/homepage/guide-examples.js
index e6e92e7..2474d33 100644
--- a/homepage/guide-examples.js
+++ b/homepage/guide-examples.js
@@ -122,7 +122,7 @@ example( 12, ( gui, code ) => {
} );
-example( 13, gui => {
+example( 14, gui => {
const params = {
scale: 1,
@@ -139,7 +139,7 @@ example( 13, gui => {
} );
-example( 17, gui => {
+example( 18, gui => {
const params = { feedback: 0 };
@@ -154,7 +154,7 @@ example( 17, gui => {
} );
-example( 18, gui => {
+example( 19, gui => {
let saved = {};
diff --git a/src/utils/getColorFormat.js b/src/utils/getColorFormat.js
index f170576..5fb4c87 100644
--- a/src/utils/getColorFormat.js
+++ b/src/utils/getColorFormat.js
@@ -43,6 +43,25 @@ const ARRAY = {
}
};
+// When getHex/setHex methods are available, prefer them over modifying RGB
+// components directly. In some software (e.g. three.js and Blender), hex
+// triplets are sRGB by convention, like the color picker's input and display,
+// while RGB components are Linear sRGB.
+const CUSTOM = {
+ isPrimitive: false,
+ match: v => Object( v ) === v && v.getHex && v.setHex,
+ fromHexString( string, target ) {
+
+ target.setHex( INT.fromHexString( string ) );
+
+ },
+ toHexString( target ) {
+
+ return INT.toHexString( target.getHex() );
+
+ }
+};
+
const OBJECT = {
isPrimitive: false,
match: v => Object( v ) === v,
@@ -68,7 +87,7 @@ const OBJECT = {
}
};
-const FORMATS = [ STRING, INT, ARRAY, OBJECT ];
+const FORMATS = [ STRING, INT, ARRAY, CUSTOM, OBJECT ];
export default function( value ) {
return FORMATS.find( format => format.match( value ) );
diff --git a/tests/color-parsing.js b/tests/color-parsing.js
index 4ed0773..eef56c2 100644
--- a/tests/color-parsing.js
+++ b/tests/color-parsing.js
@@ -1,6 +1,8 @@
import assert from 'assert';
import GUI from '../dist/lil-gui.esm.min.js';
+import CallTracker from './utils/CallTracker.js';
+
export default () => {
const gui = new GUI();
@@ -21,6 +23,32 @@ export default () => {
assert.strictEqual( gui.addColor( { int }, 'int' ).$input.value, string );
assert.strictEqual( gui.addColor( { string }, 'string' ).$input.value, string );
+ // custom getHex/setHex methods
+
+ const getHexTracker = new CallTracker();
+ const setHexTracker = new CallTracker();
+
+ class CustomColorFormat {
+ _hex = 0x7a26ab;
+ getHex() {
+ getHexTracker.handler();
+ return this._hex;
+ }
+ setHex( hex ) {
+ setHexTracker.handler();
+ this._hex = hex;
+ }
+ }
+
+ const custom = new CustomColorFormat();
+ const customColorController = gui.addColor( { custom }, 'custom' );
+
+ assert.strictEqual( customColorController.$input.value, string );
+ assert( getHexTracker.numCalls > 0 );
+
+ customColorController._setValueFromHexString( '#334455' );
+ assert.strictEqual( setHexTracker.numCalls, 1 );
+
// todo: it doesn't get hit with any edge cases or malformed colors
};