diff --git a/.gitignore b/.gitignore index c2658d7..b715909 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +/public/ \ No newline at end of file diff --git a/dist/main-1260c732d19e67143a06.js.map b/dist/main-1260c732d19e67143a06.js.map new file mode 100644 index 0000000..da83373 --- /dev/null +++ b/dist/main-1260c732d19e67143a06.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./src/styles.css?44b2","webpack:///./src/constants.js","webpack:///./src/utils.js","webpack:///./src/create-texture-atlas.js","webpack:///./src/remap-uvs.js","webpack:///./src/gltf-cubic-spline-interpolant.js","webpack:///./src/merge-geometry.js","webpack:///./src/mesh-combination.js","webpack:///./src/utils/has-hubs-component.js","webpack:///./src/export.js","webpack:///./src/assets.js","webpack:///./src/uv-scroll.js","webpack:///./src/idle-eyes.js","webpack:///./src/game.js","webpack:///./src/url-for.js","webpack:///./src/create-skydome.js","webpack:///./src/render-thumbnail.js","webpack:///./src/react-components/Toolbar.js","webpack:///./src/react-components/UploadButton.js","webpack:///./src/react-components/MoreMenu.js","webpack:///./src/dispatch.js","webpack:///./src/react-components/ToolbarContainer.js","webpack:///./src/react-components/ButtonTip.js","webpack:///./src/react-components/AvatarPreviewContainer.js","webpack:///./src/react-components/AvatarPartContainer.js","webpack:///./src/react-components/Thumbnail.js","webpack:///./src/react-components/Chevron.js","webpack:///./src/react-components/CategoryHeading.js","webpack:///./src/react-components/Collapsible.js","webpack:///./src/react-components/AvatarPartSelector.js","webpack:///./src/react-components/ThumbnailButton.js","webpack:///./src/react-components/CategoryContainer.js","webpack:///./src/react-components/AvatarConfigurationPanel.js","webpack:///./src/react-components/AvatarEditor.js","webpack:///./src/generate-random-config.js","webpack:///./src/persistence.js","webpack:///./src/react-components/AvatarEditorContainer.js","webpack:///./src/utils/debounce.js","webpack:///./src/index.js","webpack:///./assets/fonts/Poppins.css","webpack:///./src/styles.css","webpack:///webpack/bootstrap","webpack:///webpack/runtime/compat get default export","webpack:///webpack/runtime/define property getters","webpack:///webpack/runtime/global","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///webpack/runtime/publicPath","webpack:///webpack/runtime/jsonp chunk loading","webpack:///webpack/startup"],"names":["findChild","candidates","predicate","length","candidate","shift","concat","children","findChildByName","root","name","o","findChildren","results","push","findChildrenByType","type","loadGLTF","loader","GLTFLoader","url","Promise","resolve","reject","load","loadGLTFCached","cache","Map","cached","get","promise","then","gltf","error","console","delete","set","isThumbnailMode","URLSearchParams","location","search","createContext","width","height","canvas","document","createElement","context","getContext","fillStyle","fillRect","getTextureImage","material","textureName","image","createTextureAtlas","ATLAS_SIZE_PX","IMAGE_NAMES","async","meshes","contexts","Object","fromEntries","map","numTiles","Math","floor","sqrt","tileSize","uvs","mesh","i","min","THREE","multiplyScalar","max","x","y","forEach","globalCompositeOperation","drawImage","colorClone","color","clone","convertLinearToGamma","getHexString","aoMapIntensity","roughness","metalness","textures","all","texture","toBlob","blob","URL","createObjectURL","onload","src","canvasToImage","encoding","flipY","lerp","t","newMin","newMax","GLTFCubicSplineInterpolant","parameterPositions","sampleValues","sampleSize","resultBuffer","this","findSceneGroup","object3D","parent","dedupBy","items","propName","deduped","Set","item","add","Array","from","value","find","CubicSplineFrameOffsets","numMorphs","frameSize","tanIn","tanOut","mergeGeometry","source","attributes","m","geometry","morphAttributes","morphTargetDictionaries","morphTargetDictionary","morphTargetInfluences","animationClips","animations","dest","sourceAttributes","propertyNames","allSourceAttributes","values","keys","destAttributes","BufferGeometryUtils","flat","mergeSourceAttributes","destMorphTargetDictionary","sourceMorphTargetDictionaries","morphNames","dictionary","mergeSourceMorphTargetDictionaries","sourceMorphAttributes","propertyNameSet","unmerged","entries","morphName","destMorphIndex","bufferAttribute","hasOwnProperty","sourceMorphIndex","attribute","array","constructor","fill","itemSize","normalized","merged","mergeSourceMorphAttributes","destMorphTargetInfluences","destIndex","sourceIndex","mergeMorphTargetInfluences","index","indexOffset","mergedIndex","j","count","getX","position","mergeSourceIndices","clip","duration","tracks","track","endsWith","sourceMorphTargetDictionary","sourceOffsets","destOffsets","destKeyframes","numFrames","times","destMorphNames","frameIndex","sourceFrame","slice","destFrame","destTrack","createInterpolant","result","getValueSize","isInterpolantFactoryMethodGLTFCubicSpline","remapMorphTrack","split","remapKeyframeTrack","blendMode","remapAnimationClips","combine","avatar","meshesToExclude","filter","transparent","componentName","obj","gltfExtensions","userData","hubsComponents","MOZ_hubs_components","hasHubsComponent","includes","uv","uv2","remapUVs","bakedMorphIndices","morphIndex","splice","_morphIndex","removeBakedMorphs","morphTargetsRelative","propertyName","buffers","morphBufferAttribute","weight","bakedAttribute","morphAttribute","addIn","bakeMorphs","setIndex","normalMap","aoMap","roughnessMap","metalnessMap","constants","minValue","maxValue","clones","skeleton","cloneSkeleton","bind","group","bones","paused","skinnedMesh","pose","boneClones","bone","traverse","child","b","ensureHubsComponents","prototype","create","copySampleValue_","valueSize","offset","beforeStart_","afterEnd_","interpolate_","i1","t0","t1","stride","stride2","stride3","td","p","pp","ppp","offset1","offset0","s2","s3","s0","s1","p0","m0","p1","m1","exportGLTF","exporter","GLTFExporter","binary","parse","addNonDuplicateAnimationClips","scene","clipsToAdd","findIndex","clonedAnimation","uvScrollComponentFromMesh","isValidMesh","hasUVScrollComponent","isSkinnedMesh","initialStateForMesh","uvScrollComponent","emissiveMap","speed","increment","update","delta","addScaledVector","idleEyesAnimationNames","idleEyesAnimationsForGltf","hasIdleEyes","idleEyesAnimations","mixerForGltf","mixer","animation","action","clipAction","enabled","setLoop","Infinity","play","window","combineCurrentAvatar","state","avatarGroup","reactIsLoaded","shouldResize","didInit","camera","renderer","controls","clock","envMap","testExportGroup","avatarNodes","avatarConfig","newAvatarConfig","shouldApplyNewAvatarConfig","shouldExportAvatar","shouldResetView","thumbnailConfig","shouldRenderThumbnail","shouldRotateLeft","shouldRotateRight","idleEyesMixers","uvScrollMaps","quietMode","shouldRenderInQuietMode","shouldApplyMorphRelationships","onKeyChange","e","key","ensureAvatarNode","category","initializeGltf","idleEyes","fn","isMeshStandardMaterial","envMapIntensity","anisotropy","capabilities","getMaxAnisotropy","needsUpdate","isArray","uvScroll","resetMorphTargetInfluences","node","initialMorphTargetInfluences","applyMorphRelationships","part","morphRelationships","targetCategoryName","targetMorphName","targetMorphValue","getObjectByProperty","morphTargetIndex","undefined","loadIntoGroup","startsWith","clear","ex","gameState","onresize","addEventListener","detail","requestAnimationFrame","tick","time","skydome","radius","uniforms","topColor","bottomColor","exponent","vertexShader","fragmentShader","side","createSkydome","innerWidth","innerHeight","directionalLight","getElementById","antialias","physicallyCorrectLights","gammaOutput","sky","Sky","scale","setScalar","PI","createSky","skyScene","pmremGenerator","renderTarget","fromScene","dispose","remove","generateEnvironmentMap","OrbitControls","domElement","target","saveState","currentCameraPosition","prevCameraPosition","init","getDelta","parentNode","clientWidth","clientHeight","setSize","aspect","updateProjectionMatrix","categories","categoryName","assets","parts","gltfScene","partValue","angle","bisectInThumbnail","shouldBisect","center","setFromObject","getCenter","toNonIndexed","verts","getAttribute","attributeNames","newAttributes","Float32Array","attributeName","oldAttr","setAttribute","bisectGeometry","rotateY","rotateX","box","size","getSize","halfWidth","halfHeight","camSize","unitZ","copy","z","render","id","body","append","renderThumbnail","setTime","clonedScene","scenes","avatarRoots","clonedAvatarRoot","avatarRoot","a","assign","clonedSkinnedMeshes","clonedSkeleton","cloneIntoAvatar","glb","exportAvatar","Blob","el","style","display","href","download","click","reset","autoRotate","autoRotateSpeed","uvScrollState","didCameraMove","equals","setFromMatrixPosition","matrixWorld","Toolbar","className","UploadButton","onGLBUploaded","tabIndex","onChange","accept","MoreMenu","menuVisible","setMenuVisible","useState","onClick","dispatch","eventName","dispatchEvent","CustomEvent","dispatchResetView","dispatchExportAvatar","ToolbarContainer","randomizeConfig","ButtonTip","visible","top","left","text","AvatarPreviewContainer","thumbnailMode","canvasUrl","backgroundImage","AvatarPartContainer","React","onKeyDown","isExpanded","ref","role","Thumbnail","as","Component","props","cx","Chevron","icon","faChevronDown","faChevronRight","CategoryHeading","selectedPartName","Collapsible","AvatarPartSelector","setExpanded","expandedContent","currentSelection","containerEl","useRef","useEffect","current","scrollIntoView","behavior","block","currentTarget","preventDefault","stopPropagation","displayName","ThumbnailButton","tip","selected","onMouseOver","onMouseOut","aria-label","AvatarPart","isSelected","onSelectAvatarPart","onHoverAvatarPart","onUnhoverAvatarPart","buttonRef","rect","getClientRects","SubCategory","CategoryContainer","description","optionName","isPrimaryOption","options","option","param","match","capitalize","str","toUpperCase","substring","join","parseSubCategories","AvatarConfigurationPanel","onScroll","expandedCategory","setExpandedCategory","partSelectors","expand","scrollableNodeProps","AvatarEditor","leftPanel","rightPanel","buttonTip","toolbar","chooseWeightedRandom","partsWithWeightInfo","reduce","acc","partWeight","randomizationWeight","sum","randomNum","random","info","maybeReplaceWithMatchingCategory","newConfig","matchRandomization","categoryNameToMatch","partToMatch","matchRandomizationToNull","currentPart","primaryOption","secondaryOption","matchingAsset","randomMatchingAsset","generateRandomConfig","categoryNames","categoryAssets","excludeFromRandomize","storageKey","getConfigFromLocalStorage","stored","localStorage","getItem","JSON","avatars","getAvatarConfigSlotKeys","log","storedConfig","AvatarEditorContainer","setAssets","initialAssets","hoveredConfig","setHoveredConfig","debouncedSetHoveredConfig","useCallback","wait","timeoutId","args","clearTimeout","setTimeout","debounce","setCanvasUrl","initialConfig","setAvatarConfig","tipState","setTipState","updateAvatarConfig","hideTip","ctx","lineWidth","beginPath","moveTo","lineTo","quadraticCurveTo","quarterHeight","closePath","saveConfig","slotKey","config","setItem","stringify","saveAvatarConfig","loadConfig","getAvatarConfig","listStoredConfigs","bottom","file","files","fullname","categoryNamePrefix","fallbackCategoryName","filename","lastIndexOf","hyphenatedCategory","hyphenatedName","parseFilename","ReactDOM","___CSS_LOADER_EXPORT___","___CSS_LOADER_URL_REPLACEMENT_0___","___CSS_LOADER_URL_REPLACEMENT_1___","___CSS_LOADER_URL_REPLACEMENT_2___","___CSS_LOADER_URL_REPLACEMENT_3___","___CSS_LOADER_URL_REPLACEMENT_4___","module","__webpack_module_cache__","__webpack_require__","moduleId","exports","__webpack_modules__","n","getter","__esModule","d","definition","defineProperty","enumerable","g","globalThis","Function","prop","call","installedChunks","179","deferredModules","checkDeferredModules","webpackJsonpCallback","parentChunkLoadingFunction","data","chunkId","chunkIds","moreModules","runtime","executeModules","resolves","apply","chunkLoadingGlobal","self","checkDeferredModulesImpl","deferredModule","fulfilled","depId","s","startup"],"mappings":"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ACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,yBACT,YAAe,gBACf,YAAe,CACb,MAAS,UACT,MAAS,UAGb,CACE,MAAS,8BACT,YAAe,qBACf,YAAe,CACb,MAAS,UACT,MAAS,eAGb,CACE,MAAS,wBACT,YAAe,eACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,+BACT,YAAe,sBACf,YAAe,CACb,MAAS,UACT,MAAS,gBAGb,CACE,MAAS,wBACT,YAAe,eACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,uBACT,YAAe,cACf,YAAe,CACb,MAAS,UACT,MAAS,QAGb,CACE,MAAS,yBACT,YAAe,gBACf,YAAe,CACb,MAAS,UACT,MAAS,UAGb,CACE,MAAS,yBACT,YAAe,gBACf,YAAe,CACb,MAAS,UACT,MAAS,UAGb,CACE,MAAS,0BACT,YAAe,iBACf,YAAe,CACb,MAAS,UACT,MAAS,WAGb,CACE,MAAS,wBACT,YAAe,eACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,yBACT,YAAe,gBACf,YAAe,CACb,MAAS,UACT,MAAS,UAGb,CACE,MAAS,8BACT,YAAe,qBACf,YAAe,CACb,MAAS,UACT,MAAS,eAGb,CACE,MAAS,wBACT,YAAe,eACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,+BACT,YAAe,sBACf,YAAe,CACb,MAAS,UACT,MAAS,gBAGb,CACE,MAAS,wBACT,YAAe,eACf,YAAe,CACb,MAAS,UACT,MAAS,SAGb,CACE,MAAS,uBACT,YAAe,cACf,YAAe,CACb,MAAS,UACT,MAAS,QAGb,CACE,MAAS,yBACT,YAAe,gBACf,YAAe,CACb,MAAS,UACT,MAAS,WAIf,YAAe,CACb,MAAS,CACP,QAAW,CACT,KACA,UACA,UACA,UACA,WAEF,iBAAmB,GAErB,MAAS,CACP,QAAW,CACT,QACA,SACA,OACA,QACA,aACA,OACA,cACA,OACA,MACA,WAIN,mBAAqB,GAEvB,MAAS,CACP,MAAS,CACP,CACE,MAAS,KACT,YAAe,OACf,sBAAwB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","file":"main-1260c732d19e67143a06.js","sourcesContent":["import api from \"!../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import content from \"!!../node_modules/css-loader/dist/cjs.js!./styles.css\";\n\nvar options = {};\n\noptions.insert = \"head\";\noptions.singleton = false;\n\nvar update = api(content, options);\n\n\n\nexport default content.locals || {};","export default {\n avatarConfigChanged: \"avatarConfigChanged\",\n exportAvatar: \"exportAvatar\",\n resetView: \"resetView\",\n reactIsLoaded: \"reactIsLoaded\",\n renderThumbnail: \"renderThumbnail\",\n thumbnailResult: \"thumbnailResult\",\n combinedMeshName: \"CombinedMesh\",\n};\n","import * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader\";\nimport { Sky } from \"three/examples/jsm/objects/Sky\";\n\nexport function findChild({ candidates, predicate }) {\n if (!candidates.length) {\n return null;\n }\n\n const candidate = candidates.shift();\n if (predicate(candidate)) return candidate;\n\n candidates = candidates.concat(candidate.children);\n return findChild({ candidates, predicate });\n}\n\nexport function findChildByName(root, name) {\n return findChild({\n candidates: [root],\n predicate: (o) => o.name === name,\n });\n}\n\nexport function findChildByType(root, type) {\n return findChild({\n candidates: [root],\n predicate: (o) => o.type === type,\n });\n}\n\nfunction findChildren({ candidates, predicate, results = [] }) {\n if (!candidates.length) {\n return results;\n }\n\n const candidate = candidates.shift();\n if (predicate(candidate)) {\n results.push(candidate);\n }\n\n candidates = candidates.concat(candidate.children);\n return findChildren({ candidates, predicate, results });\n}\n\nexport function findChildrenByType(root, type) {\n return findChildren({\n candidates: [root],\n predicate: (o) => o.type === type,\n });\n}\n\nfunction traverseWithDepth({ object3D, depth = 0, callback, result }) {\n result.push(callback(object3D, depth));\n const children = object3D.children;\n for (let i = 0; i < children.length; i++) {\n traverseWithDepth({ object3D: children[i], depth: depth + 1, callback, result });\n }\n return result;\n}\n\nconst describe = (function () {\n const prefix = \" \";\n return function describe(object3D, indentation) {\n const description = `${object3D.type} | ${object3D.name} | ${JSON.stringify(object3D.userData)}`;\n let firstBone = \"\";\n if (object3D.type === \"SkinnedMesh\") {\n firstBone = \"\\n\"\n .concat(prefix.repeat(indentation))\n .concat(\"First bone id: \")\n .concat(object3D.skeleton.bones[0].uuid);\n }\n let boneId = \"\";\n if (object3D.type === \"Bone\") {\n boneId = \"\\n\".concat(prefix.repeat(indentation)).concat(\"Bone id: \").concat(object3D.uuid);\n }\n\n return prefix.repeat(indentation).concat(description).concat(firstBone).concat(boneId);\n };\n})();\n\nexport function describeObject3D(root) {\n return traverseWithDepth({ object3D: root, callback: describe, result: [] }).join(\"\\n\");\n}\n\nexport const loadGLTF = (function () {\n const loader = new GLTFLoader();\n return function loadGLTF(url) {\n return new Promise(function (resolve, reject) {\n loader.load(url, resolve, null, reject);\n });\n };\n})();\n\nexport const loadGLTFCached = (function () {\n const cache = new Map();\n return function loadGLTFCached(url) {\n const cached = cache.get(url);\n if (cached) {\n return cached;\n } else {\n const promise = loadGLTF(url).then(\n (gltf) => {\n return gltf;\n },\n (error) => {\n console.error(`Failed to load ${url}`, error);\n cache.delete(url);\n return null;\n }\n );\n cache.set(url, promise);\n return promise;\n }\n };\n})();\n\nexport function forEachMaterial(object3D, fn) {\n if (!object3D.material) return;\n\n if (Array.isArray(object3D.material)) {\n object3D.material.forEach(fn);\n } else {\n fn(object3D.material);\n }\n}\n\nexport function generateEnvironmentMap(sky, renderer) {\n const skyScene = new THREE.Scene();\n skyScene.add(sky);\n\n const pmremGenerator = new THREE.PMREMGenerator(renderer);\n const renderTarget = pmremGenerator.fromScene(skyScene);\n pmremGenerator.dispose();\n\n skyScene.remove(sky);\n\n return renderTarget.texture;\n}\n\nexport function createSky() {\n const sky = new Sky();\n sky.scale.setScalar(450000);\n\n const uniforms = sky.material.uniforms;\n uniforms[\"turbidity\"].value = 1.5;\n uniforms[\"rayleigh\"].value = 1.5;\n uniforms[\"mieCoefficient\"].value = 0.005;\n uniforms[\"mieDirectionalG\"].value = 0.7;\n\n const inclination = 0.7;\n const azimuth = 0.55;\n const theta = Math.PI * (inclination - 0.5);\n const phi = 2 * Math.PI * (azimuth - 0.5);\n\n uniforms[\"sunPosition\"].value.set(10, 20, 5);\n\n return sky;\n}\n\nexport function generateWave() {\n return new Promise((resolve) => {\n const center = 30;\n const amplitude = 15;\n const height = 200;\n const halfHeight = height / 2;\n const quarterHeight = height / 4;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = center + amplitude;\n canvas.height = height;\n\n const ctx = canvas.getContext(\"2d\");\n ctx.fillStyle = \"white\";\n ctx.lineWidth = 4;\n\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(center, 0);\n ctx.quadraticCurveTo(center + amplitude, quarterHeight, center, halfHeight);\n ctx.quadraticCurveTo(center - amplitude, quarterHeight * 3, center, height);\n ctx.lineTo(0, height);\n ctx.closePath();\n\n ctx.fill();\n\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob));\n });\n });\n}\n\nexport function isThumbnailMode() {\n return new URLSearchParams(location.search).get(\"thumbnail\") !== null;\n}\n","import * as THREE from \"three\";\nimport debugConfig from \"./debug-config\";\n\nfunction createContext({ width, height }) {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const context = canvas.getContext(\"2d\");\n context.fillStyle = \"white\";\n context.fillRect(0, 0, canvas.width, canvas.height);\n\n return context;\n}\n\nfunction getTextureImage(material, textureName) {\n return material[textureName] && material[textureName].image;\n}\n\nasync function canvasToImage(canvas) {\n const url = await new Promise((resolve) => {\n canvas.toBlob((blob) => {\n resolve(URL.createObjectURL(blob));\n });\n });\n\n const image = document.createElement(\"img\");\n await new Promise((resolve) => {\n image.onload = resolve;\n image.src = url;\n });\n\n return image;\n}\n\nexport const createTextureAtlas = (function () {\n const ATLAS_SIZE_PX = 2048;\n const IMAGE_NAMES = [\"diffuse\", \"normal\", \"orm\"];\n\n return async function createTextureAtlas({ meshes }) {\n const contexts = Object.fromEntries(\n IMAGE_NAMES.map((name) => [name, createContext({ width: ATLAS_SIZE_PX, height: ATLAS_SIZE_PX })])\n );\n\n if (debugConfig.debugCanvases) {\n const previous = document.getElementById(\"debug-canvases\");\n if (previous) {\n previous.parentNode.removeChild(previous);\n }\n\n const domElement = document.createElement(\"div\");\n domElement.setAttribute(\"id\", \"debug-canvases\");\n document.body.append(domElement);\n\n IMAGE_NAMES.map((name) => {\n const title = document.createElement(\"h1\");\n title.innerText = name;\n domElement.append(title);\n domElement.append(contexts[name].canvas);\n });\n }\n\n const numTiles = Math.floor(Math.sqrt(meshes.length) + 1);\n const tileSize = ATLAS_SIZE_PX / numTiles;\n\n const uvs = new Map(\n meshes.map((mesh, i) => {\n const min = new THREE.Vector2(i % numTiles, Math.floor(i / numTiles)).multiplyScalar(1 / numTiles);\n const max = new THREE.Vector2(min.x + 1 / numTiles, min.y + 1 / numTiles);\n return [mesh, { min, max }];\n })\n );\n\n // Draw image for diffuse map\n {\n const context = contexts[\"diffuse\"];\n meshes.forEach((mesh) => {\n const image = getTextureImage(mesh.material, \"map\");\n const { min, max } = uvs.get(mesh);\n if (image) {\n context.globalCompositeOperation = \"source-over\";\n context.drawImage(image, min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n }\n\n context.globalCompositeOperation = image ? \"multiply\" : \"source-over\";\n\n const colorClone = mesh.material.color.clone();\n colorClone.convertLinearToGamma();\n\n context.fillStyle = `#${colorClone.getHexString()}`;\n context.fillRect(min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n });\n }\n\n // Draw image for normal map\n {\n const context = contexts[\"normal\"];\n context.globalCompositeOperation = \"source-over\";\n meshes.forEach((mesh) => {\n const image = getTextureImage(mesh.material, \"normalMap\");\n const { min, max } = uvs.get(mesh);\n if (image) {\n context.drawImage(image, min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n } else {\n context.fillStyle = \"#8080ff\"; // default color encodes the vector (0,0,1)\n context.fillRect(min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n }\n });\n }\n\n // Draw image for orm map(s)\n {\n {\n const context = contexts[\"orm\"];\n meshes.forEach((mesh) => {\n const material = mesh.material;\n const image =\n getTextureImage(material, \"aoMap\") ||\n getTextureImage(material, \"roughnessMap\") ||\n getTextureImage(material, \"metalnessMap\");\n const { min, max } = uvs.get(mesh);\n if (image) {\n context.globalCompositeOperation = \"source-over\";\n context.drawImage(image, min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n }\n\n context.globalCompositeOperation = image ? \"multiply\" : \"source-over\";\n const color = new THREE.Color(material.aoMapIntensity, material.roughness, material.metalness);\n context.fillStyle = `#${color.getHexString()}`;\n context.fillRect(min.x * ATLAS_SIZE_PX, min.y * ATLAS_SIZE_PX, tileSize, tileSize);\n });\n }\n }\n\n // TODO Draw image for emission maps\n\n // Create textures from canvases\n const textures = Object.fromEntries(\n await Promise.all(\n IMAGE_NAMES.map(async (name) => {\n const texture = new THREE.Texture(await canvasToImage(contexts[name].canvas));\n // TODO: What is encoding?\n texture.encoding = THREE.sRGBEncoding;\n texture.flipY = false;\n return [name, texture];\n })\n )\n );\n\n return { textures, uvs };\n };\n})();\n","function lerp(t, min, max, newMin, newMax) {\n const progress = (t - min) / (max - min);\n return newMin + progress * (newMax - newMin);\n}\n\nexport function remapUVs({ mesh, uvs }) {\n // TODO: Should we mutate the existing geometry instead?\n // What is the appropriate contract between this function and\n // its calling context?\n const geometry = mesh.geometry.clone();\n mesh.geometry = geometry;\n\n const { min, max } = uvs;\n const uv = geometry.attributes.uv;\n if (uv) {\n for (let i = 0; i < uv.array.length; i += 2) {\n uv.array[i] = lerp(uv.array[i], 0, 1, min.x, max.x);\n uv.array[i + 1] = lerp(uv.array[i + 1], 0, 1, min.y, max.y);\n }\n }\n const uv2 = geometry.attributes.uv2;\n if (uv2) {\n for (let i = 0; i < uv2.array.length; i += 2) {\n uv2.array[i] = lerp(uv2.array[i], 0, 1, min.x, max.x);\n uv2.array[i + 1] = lerp(uv2.array[i + 1], 0, 1, min.y, max.y);\n }\n }\n}\n","import * as THREE from \"three\";\n\n\t/*********************************/\n\t/********** INTERPOLATION ********/\n\t/*********************************/\n\n\t// Spline Interpolation\n\t// Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation\nexport\tfunction GLTFCubicSplineInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tTHREE.Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tGLTFCubicSplineInterpolant.prototype = Object.create( THREE.Interpolant.prototype );\n\tGLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant;\n\n\tGLTFCubicSplineInterpolant.prototype.copySampleValue_ = function ( index ) {\n\n\t\t// Copies a sample value to the result buffer. See description of glTF\n\t\t// CUBICSPLINE values layout in interpolate_() function below.\n\n\t\tvar result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tvalueSize = this.valueSize,\n\t\t\toffset = index * valueSize * 3 + valueSize;\n\n\t\tfor ( var i = 0; i !== valueSize; i ++ ) {\n\n\t\t\tresult[ i ] = values[ offset + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t};\n\n\tGLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;\n\n\tGLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_;\n\n\tGLTFCubicSplineInterpolant.prototype.interpolate_ = function ( i1, t0, t, t1 ) {\n\n\t\tvar result = this.resultBuffer;\n\t\tvar values = this.sampleValues;\n\t\tvar stride = this.valueSize;\n\n\t\tvar stride2 = stride * 2;\n\t\tvar stride3 = stride * 3;\n\n\t\tvar td = t1 - t0;\n\n\t\tvar p = ( t - t0 ) / td;\n\t\tvar pp = p * p;\n\t\tvar ppp = pp * p;\n\n\t\tvar offset1 = i1 * stride3;\n\t\tvar offset0 = offset1 - stride3;\n\n\t\tvar s2 = - 2 * ppp + 3 * pp;\n\t\tvar s3 = ppp - pp;\n\t\tvar s0 = 1 - s2;\n\t\tvar s1 = s3 - pp + p;\n\n\t\t// Layout of keyframe output values for CUBICSPLINE animations:\n\t\t// [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ]\n\t\tfor ( var i = 0; i !== stride; i ++ ) {\n\n\t\t\tvar p0 = values[ offset0 + i + stride ]; // splineVertex_k\n\t\t\tvar m0 = values[ offset0 + i + stride2 ] * td; // outTangent_k * (t_k+1 - t_k)\n\t\t\tvar p1 = values[ offset1 + i + stride ]; // splineVertex_k+1\n\t\t\tvar m1 = values[ offset1 + i ] * td; // inTangent_k+1 * (t_k+1 - t_k)\n\n\t\t\tresult[ i ] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1;\n\n\t\t}\n\n\t\treturn result;\n\n\t};\n","import * as THREE from \"three\";\nimport { BufferGeometryUtils } from \"three/examples/jsm/utils/BufferGeometryUtils\";\nimport constants from \"./constants\";\nimport { GLTFCubicSplineInterpolant } from \"./gltf-cubic-spline-interpolant\";\n\nfunction mergeMorphTargetInfluences({ meshes, sourceMorphTargetDictionaries, destMorphTargetDictionary }) {\n const destMorphTargetInfluences = [];\n Object.entries(destMorphTargetDictionary).map(([morphName, destIndex]) => {\n const mesh = meshes.find((mesh) => {\n return sourceMorphTargetDictionaries.get(mesh).hasOwnProperty(morphName);\n });\n\n const sourceIndex = mesh.morphTargetDictionary[morphName];\n destMorphTargetInfluences[destIndex] = mesh.morphTargetInfluences[sourceIndex];\n // TODO: Stop / reset animations so that animated morph influences return to their \"at rest\" values.\n // Maybe the \"at rest\" values should be baked into attributes (e.g. eye brow shapes) to allow more\n // active morph targets in the combined mesh. Not all morphs should be baked. (e.g. The eyelids\n // that are animated with the \"Blinks\" animation should not be baked.)\n });\n return destMorphTargetInfluences;\n}\n\nfunction findSceneGroup(object3D) {\n if (object3D.name === \"Scene\" && object3D.type === \"Group\") {\n return object3D;\n }\n if (!object3D.parent) {\n return null;\n }\n return findSceneGroup(object3D.parent);\n}\n\nfunction mergeSourceAttributes({ sourceAttributes }) {\n const propertyNames = new Set(); // e.g. [\"normal\", \"position\", \"skinIndex\", \"skinWeight\", \"tangent\", \"uv\", \"uv2\"]\n const allSourceAttributes = Array.from(sourceAttributes.values());\n allSourceAttributes.forEach((sourceAttributes) => {\n Object.keys(sourceAttributes).forEach((name) => propertyNames.add(name));\n });\n\n const destAttributes = {};\n Array.from(propertyNames.keys()).map((name) => {\n destAttributes[name] = BufferGeometryUtils.mergeBufferAttributes(\n allSourceAttributes.map((sourceAttributes) => sourceAttributes[name]).flat()\n );\n });\n\n return destAttributes;\n}\n\nfunction mergeSourceMorphTargetDictionaries({ sourceMorphTargetDictionaries }) {\n const morphNames = new Set(); // e.g. [\"MouthFlap\", \"Blink\", \"Eye Narrow\", \"Eye Rotation\"]\n const allSourceDictionaries = Array.from(sourceMorphTargetDictionaries.values());\n allSourceDictionaries.forEach((dictionary) => {\n Object.keys(dictionary).forEach((name) => morphNames.add(name));\n });\n\n const destMorphTargetDictionary = {};\n Array.from(morphNames.keys()).map((name, i) => {\n destMorphTargetDictionary[name] = i;\n });\n\n return destMorphTargetDictionary;\n}\n\nfunction mergeSourceMorphAttributes({\n meshes,\n sourceMorphTargetDictionaries,\n sourceMorphAttributes,\n destMorphTargetDictionary,\n}) {\n const propertyNameSet = new Set(); // e.g. [\"position\", \"normal\"]\n const allSourceMorphAttributes = Array.from(sourceMorphAttributes.values());\n allSourceMorphAttributes.forEach((sourceMorphAttributes) => {\n Object.keys(sourceMorphAttributes).forEach((name) => propertyNameSet.add(name));\n });\n\n const propertyNames = Array.from(propertyNameSet);\n const morphNames = Object.keys(destMorphTargetDictionary);\n\n const unmerged = {};\n propertyNames.forEach((propName) => {\n unmerged[propName] = [];\n Object.entries(destMorphTargetDictionary).forEach(([morphName, destMorphIndex]) => {\n unmerged[propName][destMorphIndex] = [];\n\n meshes.forEach((mesh) => {\n let bufferAttribute;\n const morphTargetDictionary = sourceMorphTargetDictionaries.get(mesh);\n if (morphTargetDictionary.hasOwnProperty(morphName)) {\n const sourceMorphIndex = morphTargetDictionary[morphName];\n bufferAttribute = mesh.geometry.morphAttributes[propName][sourceMorphIndex];\n } else {\n const attribute = mesh.geometry.attributes[propName];\n const array = new attribute.array.constructor(new Array(attribute.array.length).fill(0));\n bufferAttribute = new THREE.BufferAttribute(array, attribute.itemSize, attribute.normalized);\n }\n unmerged[propName][destMorphIndex].push(bufferAttribute);\n });\n });\n });\n\n const merged = {};\n propertyNames.forEach((propName) => {\n merged[propName] = [];\n Object.entries(destMorphTargetDictionary).forEach(([morphName, destMorphIndex]) => {\n merged[propName][destMorphIndex] = BufferGeometryUtils.mergeBufferAttributes(unmerged[propName][destMorphIndex]);\n });\n });\n\n return merged;\n}\n\nfunction mergeSourceIndices({ meshes }) {\n var indexOffset = 0;\n var mergedIndex = [];\n\n meshes.forEach((mesh) => {\n const index = mesh.geometry.index;\n\n for (var j = 0; j < index.count; ++j) {\n mergedIndex.push(index.getX(j) + indexOffset);\n }\n\n indexOffset += mesh.geometry.attributes.position.count;\n });\n\n return mergedIndex;\n}\n\nfunction dedupBy(items, propName) {\n const deduped = new Set();\n items.forEach((item) => {\n deduped.add(item[propName]);\n });\n return Array.from(deduped).map((value) => {\n return items.find((item) => item[propName] === value);\n });\n}\n\nfunction CubicSplineFrameOffsets({ numMorphs }) {\n const frameSize = numMorphs * 3;\n return {\n frameSize,\n tanIn: 0,\n value: frameSize / 3,\n tanOut: (frameSize * 2) / 3,\n };\n}\n\n// remapMorphTrack\n//\n// Remap tracks that animate morph target influences.\n//\n// We assume the sourceTrack is\n// - using CubicSpline interpolation and\n// - animating morphTargetInfluences.\n//\n// TODO: Support other interpolation types. (Adding linear should be easy.)\n//\n// The values buffer of the sourceTrack contains a sequence of keyframes:\n//\n// [ frame 0 | frame 1 | frame 2 | frame 3 ... ]\n//\n// Each keyframe contains three numbers for each morph target (influence) of the sourceMesh:\n// - an inTangent (tanIn)\n// - an influence (value)\n// - an outTangent (tanOut)\n//\n// Each frame orders the numbers by type: inTangents first, then values, then outTangents.\n// So if there are M morph targets, frame N will look like:\n// [\n// ...\n// | | | |\n// | tanIn_N_0, ... , tanIn_N_M, | value_N_0, ... , value_N_M, | tanOut_N_0, ... , tanOut_N_M, | // < -- frame N\n// | | | |\n// ...\n// ]\n//\n// So for example, if the sourceMesh has 2 morph targets and the track has three keyframes, the values buffer contains:\n// [\n// tanIn_0_0, tanIn_0_1, value_0_0, value_0_1, tanOut_0_0, tanOut_0_1, // <-- Frame 0\n// tanIn_1_0, tanIn_1_1, value_1_0, value_1_1, tanOut_1_0, tanOut_1_1, // <-- Frame 1\n// tanIn_2_0, tanIn_2_1, value_2_0, value_2_1, tanOut_2_0, tanOut_2_1 // <-- Frame 2\n// ]\n//\n// See the GLTF spec for details about how this is represented in GLTF:\n// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#animations\n// See THREE's GLTFLoader for details about how this is loaded and represented in THREE:\n// https://github.com/mrdoob/three.js/blob/350f0a021943d6fa1d039a7c14c303653daa463f/examples/jsm/loaders/GLTFLoader.js#L3634\n//\n// This function creates a new (dest) track that can will work with the combined (dest) mesh.\n// Each morph target influence index in the source mesh has a corresponding index in the dest mesh.\n// The dest mesh will have the sum of all the morph targets of its source meshes, so we will\n// insert several zeros into the track so the dest mesh's morphTargetInfluences that should not\n// be changed by this track are left alone.\n//\n// Continuing the example above,\n// If the sourceMesh has two morph targets and sourceTrack has three keyframes,\n// and if the destMesh has three morph targets, then there will be some mapping\n// of morphTargetInfluences from source to dest:\n// {\n// sourceMorph0 -> destMorph2,\n// sourceMorph1 -> destMorph1\n// }\n//\n// Assuming the same values buffer from before, the new values buffer will be:\n// [\n// 0, tanIn_0_1, tanIn_0_0, 0, value_0_1, value_0_0, 0, tanOut_0_1, tanOut_0_0, // <-- Frame 0\n// 0, tanIn_1_1, tanIn_1_0, 0, value_1_1, value_1_0, 0, tanOut_1_1, tanOut_1_0, // <-- Frame 1\n// 0, tanIn_2_1, tanIn_2_0, 0, value_2_1, value_2_0, 0, tanOut_2_1, tanOut_2_0 // <-- Frame 2\n// ]\n//\n// Notice that:\n// - zeroes have been inserted for destMorph0,\n// - the numbers associated with sourceMorph0 will now be associated with destMorph2, and\n// - the numbers associated with sourceMorph1 will now be associated with destMorph1\nfunction remapMorphTrack({ track, sourceMorphTargetDictionary, destMorphTargetDictionary }) {\n const sourceOffsets = CubicSplineFrameOffsets({ numMorphs: Object.keys(sourceMorphTargetDictionary).length });\n const destOffsets = CubicSplineFrameOffsets({ numMorphs: Object.keys(destMorphTargetDictionary).length });\n\n const destKeyframes = [];\n const numFrames = track.times.length;\n const destMorphNames = Object.keys(destMorphTargetDictionary);\n for (let frameIndex = 0; frameIndex < numFrames; frameIndex++) {\n const sourceFrame = track.values.slice(\n frameIndex * sourceOffsets.frameSize,\n frameIndex * sourceOffsets.frameSize + sourceOffsets.frameSize\n );\n const destFrame = [];\n destMorphNames.forEach((morphName) => {\n const destMorphIndex = destMorphTargetDictionary[morphName];\n const isMorphInSourceTrack = sourceMorphTargetDictionary.hasOwnProperty(morphName);\n if (isMorphInSourceTrack) {\n const sourceMorphIndex = sourceMorphTargetDictionary[morphName];\n destFrame[destOffsets.tanIn + destMorphIndex] = sourceFrame[sourceOffsets.tanIn + sourceMorphIndex];\n destFrame[destOffsets.value + destMorphIndex] = sourceFrame[sourceOffsets.value + sourceMorphIndex];\n destFrame[destOffsets.tanOut + destMorphIndex] = sourceFrame[sourceOffsets.tanOut + sourceMorphIndex];\n } else {\n destFrame[destOffsets.tanIn + destMorphIndex] = 0;\n destFrame[destOffsets.value + destMorphIndex] = 0;\n destFrame[destOffsets.tanOut + destMorphIndex] = 0;\n }\n });\n destKeyframes.push(destFrame);\n }\n\n const destTrackName = `${constants.combinedMeshName}.morphTargetInfluences`;\n const destTrack = new THREE.NumberKeyframeTrack(destTrackName, track.times, destKeyframes.flat());\n\n // Make sure the track will interpolate correctly\n // (Copied from THREE.GLTFLoader : https://github.com/mrdoob/three.js/blob/350f0a021943d6fa1d039a7c14c303653daa463f/examples/jsm/loaders/GLTFLoader.js#L3634 )\n destTrack.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) {\n return new GLTFCubicSplineInterpolant(this.times, this.values, this.getValueSize() / 3, result);\n };\n destTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;\n\n return destTrack;\n}\n\nfunction remapKeyframeTrack({ track, sourceMorphTargetDictionaries, meshes, destMorphTargetDictionary }) {\n if (track.name.endsWith(\"morphTargetInfluences\")) {\n return remapMorphTrack({\n track,\n sourceMorphTargetDictionary: sourceMorphTargetDictionaries.get(\n meshes.find((mesh) => mesh.name === track.name.split(\".\")[0])\n ),\n destMorphTargetDictionary,\n });\n } else {\n return track;\n }\n}\n\nfunction remapAnimationClips({ animationClips, sourceMorphTargetDictionaries, meshes, destMorphTargetDictionary }) {\n return animationClips.map(\n (clip) =>\n new THREE.AnimationClip(\n clip.name,\n clip.duration,\n clip.tracks.map((track) =>\n remapKeyframeTrack({ track, sourceMorphTargetDictionaries, meshes, destMorphTargetDictionary })\n ),\n clip.blendMode\n )\n );\n}\n\nexport function mergeGeometry({ meshes }) {\n const source = {\n meshes,\n attributes: new Map(meshes.map((m) => [m, m.geometry.attributes])),\n morphAttributes: new Map(meshes.map((m) => [m, m.geometry.morphAttributes])),\n morphTargetDictionaries: new Map(meshes.map((m) => [m, m.morphTargetDictionary || {}])),\n morphTargetInfluences: new Map(meshes.map((m) => [m, m.morphTargetInfluences || []])),\n animationClips: new Map(meshes.map((m) => [m, findSceneGroup(m).animations])),\n };\n\n const dest = {};\n dest.attributes = mergeSourceAttributes({ sourceAttributes: source.attributes });\n const destMorphTargetDictionary = mergeSourceMorphTargetDictionaries({\n sourceMorphTargetDictionaries: source.morphTargetDictionaries,\n });\n dest.morphTargetDictionary = destMorphTargetDictionary;\n dest.morphAttributes = mergeSourceMorphAttributes({\n meshes,\n sourceMorphAttributes: source.morphAttributes,\n sourceMorphTargetDictionaries: source.morphTargetDictionaries,\n destMorphTargetDictionary,\n });\n dest.morphTargetInfluences = mergeMorphTargetInfluences({\n meshes,\n sourceMorphTargetDictionaries: source.morphTargetDictionaries,\n destMorphTargetDictionary,\n });\n dest.index = mergeSourceIndices({ meshes });\n dest.animations = remapAnimationClips({\n meshes,\n animationClips: dedupBy(Array.from(source.animationClips.values()).flat(), \"name\"),\n sourceMorphTargetDictionaries: source.morphTargetDictionaries,\n destMorphTargetDictionary,\n });\n\n return { source, dest };\n}\n","import * as THREE from \"three\";\nimport { findChildrenByType } from \"./utils\";\nimport hasHubsComponent from \"./utils/has-hubs-component\";\nimport { createTextureAtlas } from \"./create-texture-atlas\";\nimport { remapUVs } from \"./remap-uvs\";\nimport { cloneSkeleton } from \"./export\";\nimport { mergeGeometry } from \"./merge-geometry\";\nimport constants from \"./constants\";\n\nfunction addIn({ bakedAttribute, morphAttribute, weight }) {\n for (let i = 0; i < bakedAttribute.array.length; i++) {\n bakedAttribute.array[i] += morphAttribute.array[i] * weight;\n }\n}\n\nfunction bakeMorphs(mesh) {\n const bakedMorphIndices = new Set();\n if (!mesh.morphTargetInfluences) return bakedMorphIndices;\n if (!mesh.geometry.morphTargetsRelative) return bakedMorphIndices;\n\n const morphAttributes = mesh.geometry.morphAttributes;\n\n Object.entries(morphAttributes).forEach(([propertyName, buffers]) => {\n buffers.forEach((morphBufferAttribute, index) => {\n const weight = mesh.morphTargetInfluences[index];\n if (weight > 0) {\n bakedMorphIndices.add(index);\n addIn({\n bakedAttribute: mesh.geometry.attributes[propertyName],\n morphAttribute: morphBufferAttribute,\n weight,\n });\n }\n });\n });\n\n return bakedMorphIndices;\n}\n\nfunction removeBakedMorphs(mesh, bakedMorphIndices) {\n bakedMorphIndices.forEach((morphIndex) => {\n delete mesh.geometry.morphAttributes[morphIndex];\n mesh.morphTargetInfluences.splice(morphIndex, 1);\n\n const [morphName, _morphIndex] = Object.entries(mesh.morphTargetDictionary).find(\n ([morphName, index]) => index === morphIndex\n );\n delete mesh.morphTargetDictionary[morphName];\n });\n}\n\nexport async function combine({ avatar }) {\n const meshesToExclude = findChildrenByType(avatar, \"SkinnedMesh\").filter(\n (mesh) => mesh.material.transparent || hasHubsComponent(mesh, \"uv-scroll\")\n );\n\n const meshes = findChildrenByType(avatar, \"SkinnedMesh\").filter((mesh) => !meshesToExclude.includes(mesh));\n\n const { textures, uvs } = await createTextureAtlas({ meshes });\n meshes.forEach((mesh) => remapUVs({ mesh, uvs: uvs.get(mesh) }));\n\n meshes.forEach((mesh) => removeBakedMorphs(mesh, bakeMorphs(mesh)));\n\n meshes.forEach((mesh) => {\n const geometry = mesh.geometry;\n if (!geometry.attributes.uv2) {\n geometry.attributes.uv2 = geometry.attributes.uv;\n }\n // Exlude the currently \"activated\" morph attributes before merging.\n // The BufferAttributes are not lost; they remain in `mesh.geometry.morphAttributes`\n // and the influences remain in `mesh.morphTargetInfluences`.\n for (let i = 0; i < 8; i++) {\n delete geometry.attributes[`morphTarget${i}`];\n delete geometry.attributes[`morphNormal${i}`];\n }\n });\n\n const { source, dest } = mergeGeometry({ meshes });\n\n const geometry = new THREE.BufferGeometry();\n geometry.attributes = dest.attributes;\n geometry.morphAttributes = dest.morphAttributes;\n geometry.morphTargetsRelative = true;\n geometry.setIndex(dest.index);\n\n const material = new THREE.MeshStandardMaterial({\n map: textures[\"diffuse\"],\n normalMap: textures[\"normal\"],\n aoMap: textures[\"orm\"],\n roughnessMap: textures[\"orm\"],\n metalnessMap: textures[\"orm\"],\n });\n material.metalness = 1;\n\n const mesh = new THREE.SkinnedMesh(geometry, material);\n mesh.name = constants.combinedMeshName;\n mesh.morphTargetInfluences = dest.morphTargetInfluences;\n mesh.morphTargetDictionary = dest.morphTargetDictionary;\n\n if (\"MouthFlap\" in mesh.morphTargetDictionary) {\n mesh.userData = {\n gltfExtensions: {\n MOZ_hubs_components: {\n \"morph-audio-feedback\": {\n minValue: 0,\n maxValue: 1,\n name: \"MouthFlap\",\n },\n },\n },\n };\n }\n\n // Add unmerged meshes\n const clones = meshesToExclude.map((o) => {\n return o.clone(false);\n });\n\n const skeleton = cloneSkeleton(meshes[0]);\n mesh.bind(skeleton);\n clones.forEach((clone) => {\n clone.bind(skeleton);\n });\n\n const group = new THREE.Object3D();\n group.name = \"AvatarRoot\";\n group.animations = dest.animations;\n group.add(mesh);\n group.add(skeleton.bones[0]);\n clones.forEach((clone) => {\n group.add(clone);\n });\n\n group.userData = {\n gltfExtensions: {\n MOZ_hubs_components: {\n \"loop-animation\": {\n clip: \"idle_eyes,Blinks\",\n paused: false,\n },\n },\n },\n };\n return group;\n}\n","import { findChild } from \"../utils\";\n\nexport default function hasHubsComponent(mesh, componentName) {\n\treturn !!findChild({\n\t\tcandidates: [mesh],\n\t\tpredicate: (obj) => {\n\t\t\tconst gltfExtensions = obj.userData.gltfExtensions;\n\t\t\tconst hubsComponents = gltfExtensions && gltfExtensions.MOZ_hubs_components;\n\t\t\tif (hubsComponents && hubsComponents[componentName]) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\t});\n}\n","import * as THREE from \"three\";\nimport { GLTFExporter } from \"three/examples/jsm/exporters/GLTFExporter\";\nimport { findChildrenByType, findChildByName, describeObject3D } from \"./utils\";\nimport { combine } from \"./mesh-combination\";\nimport debugConfig from \"./debug-config\";\n\nexport function cloneSkeleton(skinnedMesh) {\n skinnedMesh.skeleton.pose();\n\n const boneClones = new Map();\n\n for (const bone of skinnedMesh.skeleton.bones) {\n const clone = bone.clone(false);\n boneClones.set(bone, clone);\n }\n\n // Preserve original bone structure\n // Assume bones[0] is root bone\n skinnedMesh.skeleton.bones[0].traverse((o) => {\n if (o.type !== \"Bone\") return;\n const clone = boneClones.get(o);\n for (const child of o.children) {\n clone.add(boneClones.get(child));\n }\n });\n\n return new THREE.Skeleton(skinnedMesh.skeleton.bones.map((b) => boneClones.get(b)));\n}\n\nfunction ensureHubsComponents(userData) {\n if (!userData.gltfExtensions) {\n userData.gltfExtensions = {};\n }\n if (!userData.gltfExtensions.MOZ_hubs_components) {\n userData.gltfExtensions.MOZ_hubs_components = {};\n }\n return userData;\n}\n\nexport function combineHubsComponents(a, b) {\n ensureHubsComponents(a);\n ensureHubsComponents(b);\n if (a.gltfExtensions.MOZ_hubs_components)\n // TODO: Deep merge\n a.gltfExtensions.MOZ_hubs_components = Object.assign(\n a.gltfExtensions.MOZ_hubs_components,\n b.gltfExtensions.MOZ_hubs_components\n );\n\n return a;\n}\n\nexport const exportGLTF = (function () {\n const exporter = new GLTFExporter();\n return function exportGLTF(object3D, { binary, animations }) {\n return new Promise((resolve) => {\n exporter.parse(object3D, (gltf) => resolve({ gltf }), { binary, animations });\n });\n };\n})();\n\nfunction addNonDuplicateAnimationClips(clone, scene) {\n const clipsToAdd = [];\n\n for (const clip of scene.animations) {\n const index = clone.animations.findIndex((clonedAnimation) => {\n return clonedAnimation.name === clip.name;\n });\n if (index === -1) {\n clipsToAdd.push(clip);\n }\n }\n\n for (const clip of clipsToAdd) {\n clone.animations.push(clip);\n }\n}\n\nfunction cloneIntoAvatar(avatarGroup) {\n const clonedScene = new THREE.Group();\n clonedScene.name = \"Scene\";\n\n // Combine the root \"Scene\" nodes\n const scenes = avatarGroup.children\n .map((o) => {\n return findChildByName(o, \"Scene\");\n })\n .filter((o) => !!o);\n for (const scene of scenes) {\n addNonDuplicateAnimationClips(clonedScene, scene);\n }\n\n // Combine the \"AvatarRoot\" nodes\n const avatarRoots = avatarGroup.children\n .map((o) => {\n return findChildByName(o, \"AvatarRoot\");\n })\n .filter((o) => !!o);\n const clonedAvatarRoot = avatarRoots[0].clone(false);\n for (const avatarRoot of avatarRoots) {\n clonedAvatarRoot.userData = combineHubsComponents(clonedAvatarRoot.userData, avatarRoot.userData);\n }\n\n // Clone skinned meshes, bind them to a new skeleton\n const clonedSkinnedMeshes = findChildrenByType(avatarGroup, \"SkinnedMesh\").map((o) => {\n return o.clone(false);\n });\n const clonedSkeleton = cloneSkeleton(clonedSkinnedMeshes[0]);\n for (const skinnedMesh of clonedSkinnedMeshes) {\n skinnedMesh.bind(clonedSkeleton);\n }\n\n // Combine clones\n clonedScene.add(clonedAvatarRoot);\n clonedAvatarRoot.add(clonedSkeleton.bones[0]); // Assume bones[0] is root bone\n for (const skinnedMesh of clonedSkinnedMeshes) {\n clonedAvatarRoot.add(skinnedMesh);\n }\n return clonedScene;\n}\n\nexport async function exportAvatar(avatarGroup) {\n // TODO: Re-evaluate whether we want to perform this step.\n // The intention (for now) is to make combination optional,\n // so that it is easy to debug and also if non-mergable meshes\n // are added, there's a workaround for them.\n const clone = cloneIntoAvatar(avatarGroup);\n\n const avatar = await combine({ avatar: clone });\n\n if (debugConfig.debugGLTF) {\n console.log(\"avatar\", avatar);\n const { gltf } = await exportGLTF(avatar, { binary: false, animations: avatar.animations });\n console.log(\"gltf\", gltf);\n }\n\n const { gltf: glb } = await exportGLTF(avatar, { binary: true, animations: avatar.animations });\n return { glb };\n}\n","export default {\n \"Hair\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false\n },\n {\n \"value\": \"hair_aLine-asym-black\",\n \"displayName\": \"ALine Asym Black\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-blonde\",\n \"displayName\": \"ALine Asym Blonde\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-blue\",\n \"displayName\": \"ALine Asym Blue\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-brown\",\n \"displayName\": \"ALine Asym Brown\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-dark brown\",\n \"displayName\": \"ALine Asym Dark brown\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-gray\",\n \"displayName\": \"ALine Asym Gray\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-light brown\",\n \"displayName\": \"ALine Asym Light brown\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-pink\",\n \"displayName\": \"ALine Asym Pink\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-red\",\n \"displayName\": \"ALine Asym Red\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_aLine-asym-white\",\n \"displayName\": \"ALine Asym White\",\n \"description\": {\n \"Type\": \"aLine-asym\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_afro-1-black\",\n \"displayName\": \"Afro 1 Black\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_afro-1-blonde\",\n \"displayName\": \"Afro 1 Blonde\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_afro-1-blue\",\n \"displayName\": \"Afro 1 Blue\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_afro-1-brown\",\n \"displayName\": \"Afro 1 Brown\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_afro-1-dark brown\",\n \"displayName\": \"Afro 1 Dark brown\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_afro-1-gray\",\n \"displayName\": \"Afro 1 Gray\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_afro-1-light brown\",\n \"displayName\": \"Afro 1 Light brown\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_afro-1-pink\",\n \"displayName\": \"Afro 1 Pink\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_afro-1-red\",\n \"displayName\": \"Afro 1 Red\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_afro-1-white\",\n \"displayName\": \"Afro 1 White\",\n \"description\": {\n \"Type\": \"afro-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_afro-2-black\",\n \"displayName\": \"Afro 2 Black\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_afro-2-blonde\",\n \"displayName\": \"Afro 2 Blonde\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_afro-2-blue\",\n \"displayName\": \"Afro 2 Blue\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_afro-2-brown\",\n \"displayName\": \"Afro 2 Brown\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_afro-2-dark brown\",\n \"displayName\": \"Afro 2 Dark brown\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_afro-2-gray\",\n \"displayName\": \"Afro 2 Gray\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_afro-2-light brown\",\n \"displayName\": \"Afro 2 Light brown\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_afro-2-pink\",\n \"displayName\": \"Afro 2 Pink\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_afro-2-red\",\n \"displayName\": \"Afro 2 Red\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_afro-2-white\",\n \"displayName\": \"Afro 2 White\",\n \"description\": {\n \"Type\": \"afro-2\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_bob-1-black\",\n \"displayName\": \"Bob 1 Black\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_bob-1-blonde\",\n \"displayName\": \"Bob 1 Blonde\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_bob-1-blue\",\n \"displayName\": \"Bob 1 Blue\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_bob-1-brown\",\n \"displayName\": \"Bob 1 Brown\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_bob-1-dark brown\",\n \"displayName\": \"Bob 1 Dark brown\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_bob-1-gray\",\n \"displayName\": \"Bob 1 Gray\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_bob-1-light brown\",\n \"displayName\": \"Bob 1 Light brown\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_bob-1-pink\",\n \"displayName\": \"Bob 1 Pink\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_bob-1-red\",\n \"displayName\": \"Bob 1 Red\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_bob-1-white\",\n \"displayName\": \"Bob 1 White\",\n \"description\": {\n \"Type\": \"bob-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_braided-bun-black\",\n \"displayName\": \"Braided Bun Black\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_braided-bun-blonde\",\n \"displayName\": \"Braided Bun Blonde\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_braided-bun-blue\",\n \"displayName\": \"Braided Bun Blue\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_braided-bun-brown\",\n \"displayName\": \"Braided Bun Brown\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_braided-bun-dark brown\",\n \"displayName\": \"Braided Bun Dark brown\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_braided-bun-gray\",\n \"displayName\": \"Braided Bun Gray\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_braided-bun-light brown\",\n \"displayName\": \"Braided Bun Light brown\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_braided-bun-pink\",\n \"displayName\": \"Braided Bun Pink\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_braided-bun-red\",\n \"displayName\": \"Braided Bun Red\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_braided-bun-white\",\n \"displayName\": \"Braided Bun White\",\n \"description\": {\n \"Type\": \"braided-bun\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-black\",\n \"displayName\": \"Eraser Top 1 Black\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-blonde\",\n \"displayName\": \"Eraser Top 1 Blonde\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-blue\",\n \"displayName\": \"Eraser Top 1 Blue\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-brown\",\n \"displayName\": \"Eraser Top 1 Brown\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-dark brown\",\n \"displayName\": \"Eraser Top 1 Dark brown\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-gray\",\n \"displayName\": \"Eraser Top 1 Gray\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-light brown\",\n \"displayName\": \"Eraser Top 1 Light brown\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-pink\",\n \"displayName\": \"Eraser Top 1 Pink\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-red\",\n \"displayName\": \"Eraser Top 1 Red\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_eraser-top-1-white\",\n \"displayName\": \"Eraser Top 1 White\",\n \"description\": {\n \"Type\": \"eraser-top-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-black\",\n \"displayName\": \"Fauxhawk 1 Black\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-blonde\",\n \"displayName\": \"Fauxhawk 1 Blonde\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-blue\",\n \"displayName\": \"Fauxhawk 1 Blue\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-brown\",\n \"displayName\": \"Fauxhawk 1 Brown\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-dark brown\",\n \"displayName\": \"Fauxhawk 1 Dark brown\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-gray\",\n \"displayName\": \"Fauxhawk 1 Gray\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-light brown\",\n \"displayName\": \"Fauxhawk 1 Light brown\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-pink\",\n \"displayName\": \"Fauxhawk 1 Pink\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-red\",\n \"displayName\": \"Fauxhawk 1 Red\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_fauxhawk-1-white\",\n \"displayName\": \"Fauxhawk 1 White\",\n \"description\": {\n \"Type\": \"fauxhawk-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-black\",\n \"displayName\": \"Flat Top 1 Black\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-blonde\",\n \"displayName\": \"Flat Top 1 Blonde\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-blue\",\n \"displayName\": \"Flat Top 1 Blue\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-brown\",\n \"displayName\": \"Flat Top 1 Brown\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-dark brown\",\n \"displayName\": \"Flat Top 1 Dark brown\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-gray\",\n \"displayName\": \"Flat Top 1 Gray\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-light brown\",\n \"displayName\": \"Flat Top 1 Light brown\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-pink\",\n \"displayName\": \"Flat Top 1 Pink\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-red\",\n \"displayName\": \"Flat Top 1 Red\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_flat-top-1-white\",\n \"displayName\": \"Flat Top 1 White\",\n \"description\": {\n \"Type\": \"flat-top-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-black\",\n \"displayName\": \"French Braid Buns Black\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-blonde\",\n \"displayName\": \"French Braid Buns Blonde\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-blue\",\n \"displayName\": \"French Braid Buns Blue\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-brown\",\n \"displayName\": \"French Braid Buns Brown\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-dark brown\",\n \"displayName\": \"French Braid Buns Dark brown\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-gray\",\n \"displayName\": \"French Braid Buns Gray\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-light brown\",\n \"displayName\": \"French Braid Buns Light brown\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-pink\",\n \"displayName\": \"French Braid Buns Pink\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-red\",\n \"displayName\": \"French Braid Buns Red\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_french-braid-buns-white\",\n \"displayName\": \"French Braid Buns White\",\n \"description\": {\n \"Type\": \"french-braid-buns\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-black\",\n \"displayName\": \"French Braids Double Black\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-blonde\",\n \"displayName\": \"French Braids Double Blonde\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-blue\",\n \"displayName\": \"French Braids Double Blue\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-brown\",\n \"displayName\": \"French Braids Double Brown\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-dark brown\",\n \"displayName\": \"French Braids Double Dark brown\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-gray\",\n \"displayName\": \"French Braids Double Gray\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-light brown\",\n \"displayName\": \"French Braids Double Light brown\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-pink\",\n \"displayName\": \"French Braids Double Pink\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-red\",\n \"displayName\": \"French Braids Double Red\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_french-braids-double-white\",\n \"displayName\": \"French Braids Double White\",\n \"description\": {\n \"Type\": \"french-braids-double\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-black\",\n \"displayName\": \"Mohawk 1 Black\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-blonde\",\n \"displayName\": \"Mohawk 1 Blonde\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-blue\",\n \"displayName\": \"Mohawk 1 Blue\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-brown\",\n \"displayName\": \"Mohawk 1 Brown\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-dark brown\",\n \"displayName\": \"Mohawk 1 Dark brown\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-gray\",\n \"displayName\": \"Mohawk 1 Gray\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-light brown\",\n \"displayName\": \"Mohawk 1 Light brown\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-pink\",\n \"displayName\": \"Mohawk 1 Pink\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-red\",\n \"displayName\": \"Mohawk 1 Red\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_mohawk-1-white\",\n \"displayName\": \"Mohawk 1 White\",\n \"description\": {\n \"Type\": \"mohawk-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_mullet-1-black\",\n \"displayName\": \"Mullet 1 Black\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_mullet-1-blonde\",\n \"displayName\": \"Mullet 1 Blonde\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_mullet-1-blue\",\n \"displayName\": \"Mullet 1 Blue\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_mullet-1-brown\",\n \"displayName\": \"Mullet 1 Brown\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_mullet-1-dark brown\",\n \"displayName\": \"Mullet 1 Dark brown\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_mullet-1-gray\",\n \"displayName\": \"Mullet 1 Gray\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_mullet-1-light brown\",\n \"displayName\": \"Mullet 1 Light brown\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_mullet-1-pink\",\n \"displayName\": \"Mullet 1 Pink\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_mullet-1-red\",\n \"displayName\": \"Mullet 1 Red\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_mullet-1-white\",\n \"displayName\": \"Mullet 1 White\",\n \"description\": {\n \"Type\": \"mullet-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_parted-1-black\",\n \"displayName\": \"Parted 1 Black\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_parted-1-blonde\",\n \"displayName\": \"Parted 1 Blonde\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_parted-1-blue\",\n \"displayName\": \"Parted 1 Blue\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_parted-1-brown\",\n \"displayName\": \"Parted 1 Brown\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_parted-1-dark brown\",\n \"displayName\": \"Parted 1 Dark brown\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_parted-1-gray\",\n \"displayName\": \"Parted 1 Gray\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_parted-1-light brown\",\n \"displayName\": \"Parted 1 Light brown\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_parted-1-pink\",\n \"displayName\": \"Parted 1 Pink\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_parted-1-red\",\n \"displayName\": \"Parted 1 Red\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_parted-1-white\",\n \"displayName\": \"Parted 1 White\",\n \"description\": {\n \"Type\": \"parted-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-black\",\n \"displayName\": \"Parted Long 1 Black\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-blonde\",\n \"displayName\": \"Parted Long 1 Blonde\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-blue\",\n \"displayName\": \"Parted Long 1 Blue\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-brown\",\n \"displayName\": \"Parted Long 1 Brown\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-dark brown\",\n \"displayName\": \"Parted Long 1 Dark brown\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-gray\",\n \"displayName\": \"Parted Long 1 Gray\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-light brown\",\n \"displayName\": \"Parted Long 1 Light brown\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-pink\",\n \"displayName\": \"Parted Long 1 Pink\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-red\",\n \"displayName\": \"Parted Long 1 Red\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_parted-long-1-white\",\n \"displayName\": \"Parted Long 1 White\",\n \"description\": {\n \"Type\": \"parted-long-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-black\",\n \"displayName\": \"Pigtails 1 Black\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-blonde\",\n \"displayName\": \"Pigtails 1 Blonde\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-blue\",\n \"displayName\": \"Pigtails 1 Blue\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-brown\",\n \"displayName\": \"Pigtails 1 Brown\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-dark brown\",\n \"displayName\": \"Pigtails 1 Dark brown\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-gray\",\n \"displayName\": \"Pigtails 1 Gray\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-light brown\",\n \"displayName\": \"Pigtails 1 Light brown\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-pink\",\n \"displayName\": \"Pigtails 1 Pink\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-red\",\n \"displayName\": \"Pigtails 1 Red\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_pigtails-1-white\",\n \"displayName\": \"Pigtails 1 White\",\n \"description\": {\n \"Type\": \"pigtails-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-black\",\n \"displayName\": \"Pony Tail 1 Black\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-blonde\",\n \"displayName\": \"Pony Tail 1 Blonde\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-blue\",\n \"displayName\": \"Pony Tail 1 Blue\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-brown\",\n \"displayName\": \"Pony Tail 1 Brown\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-dark brown\",\n \"displayName\": \"Pony Tail 1 Dark brown\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-gray\",\n \"displayName\": \"Pony Tail 1 Gray\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-light brown\",\n \"displayName\": \"Pony Tail 1 Light brown\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-pink\",\n \"displayName\": \"Pony Tail 1 Pink\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-red\",\n \"displayName\": \"Pony Tail 1 Red\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_pony-tail-1-white\",\n \"displayName\": \"Pony Tail 1 White\",\n \"description\": {\n \"Type\": \"pony-tail-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-black\",\n \"displayName\": \"Pony Tail 2 Black\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-blonde\",\n \"displayName\": \"Pony Tail 2 Blonde\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-blue\",\n \"displayName\": \"Pony Tail 2 Blue\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-brown\",\n \"displayName\": \"Pony Tail 2 Brown\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-dark brown\",\n \"displayName\": \"Pony Tail 2 Dark brown\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-gray\",\n \"displayName\": \"Pony Tail 2 Gray\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-light brown\",\n \"displayName\": \"Pony Tail 2 Light brown\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-pink\",\n \"displayName\": \"Pony Tail 2 Pink\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-red\",\n \"displayName\": \"Pony Tail 2 Red\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_pony-tail-2-white\",\n \"displayName\": \"Pony Tail 2 White\",\n \"description\": {\n \"Type\": \"pony-tail-2\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-black\",\n \"displayName\": \"Pony Tail 3 Black\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-blonde\",\n \"displayName\": \"Pony Tail 3 Blonde\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-blue\",\n \"displayName\": \"Pony Tail 3 Blue\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-brown\",\n \"displayName\": \"Pony Tail 3 Brown\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-dark brown\",\n \"displayName\": \"Pony Tail 3 Dark brown\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-gray\",\n \"displayName\": \"Pony Tail 3 Gray\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-light brown\",\n \"displayName\": \"Pony Tail 3 Light brown\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-pink\",\n \"displayName\": \"Pony Tail 3 Pink\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-red\",\n \"displayName\": \"Pony Tail 3 Red\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_pony-tail-3-white\",\n \"displayName\": \"Pony Tail 3 White\",\n \"description\": {\n \"Type\": \"pony-tail-3\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_spikey-1-black\",\n \"displayName\": \"Spikey 1 Black\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_spikey-1-blonde\",\n \"displayName\": \"Spikey 1 Blonde\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_spikey-1-blue\",\n \"displayName\": \"Spikey 1 Blue\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_spikey-1-brown\",\n \"displayName\": \"Spikey 1 Brown\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_spikey-1-dark brown\",\n \"displayName\": \"Spikey 1 Dark brown\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_spikey-1-gray\",\n \"displayName\": \"Spikey 1 Gray\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_spikey-1-light brown\",\n \"displayName\": \"Spikey 1 Light brown\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_spikey-1-pink\",\n \"displayName\": \"Spikey 1 Pink\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_spikey-1-red\",\n \"displayName\": \"Spikey 1 Red\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_spikey-1-white\",\n \"displayName\": \"Spikey 1 White\",\n \"description\": {\n \"Type\": \"spikey-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-black\",\n \"displayName\": \"Taper Afro 2 Black\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-blonde\",\n \"displayName\": \"Taper Afro 2 Blonde\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-blue\",\n \"displayName\": \"Taper Afro 2 Blue\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-brown\",\n \"displayName\": \"Taper Afro 2 Brown\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-dark brown\",\n \"displayName\": \"Taper Afro 2 Dark brown\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-gray\",\n \"displayName\": \"Taper Afro 2 Gray\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-light brown\",\n \"displayName\": \"Taper Afro 2 Light brown\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-pink\",\n \"displayName\": \"Taper Afro 2 Pink\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-red\",\n \"displayName\": \"Taper Afro 2 Red\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"hair_taper-afro-2-white\",\n \"displayName\": \"Taper Afro 2 White\",\n \"description\": {\n \"Type\": \"taper-afro-2\",\n \"Color\": \"white\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"aLine-asym\",\n \"afro-1\",\n \"afro-2\",\n \"bob-1\",\n \"braided-bun\",\n \"eraser-top-1\",\n \"fauxhawk-1\",\n \"flat-top-1\",\n \"french-braid-buns\",\n \"french-braids-double\",\n \"mohawk-1\",\n \"mullet-1\",\n \"parted-1\",\n \"parted-long-1\",\n \"pigtails-1\",\n \"pony-tail-1\",\n \"pony-tail-2\",\n \"pony-tail-3\",\n \"spikey-1\",\n \"taper-afro-2\"\n ],\n \"isPrimaryOption\": true\n },\n \"Color\": {\n \"options\": [\n \"black\",\n \"blonde\",\n \"blue\",\n \"brown\",\n \"dark brown\",\n \"gray\",\n \"light brown\",\n \"pink\",\n \"red\",\n \"white\"\n ]\n }\n }\n },\n \"Head\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"head_bald-skin-1\",\n \"displayName\": \"Bald Skin 1\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-1\"\n }\n },\n {\n \"value\": \"head_bald-skin-2\",\n \"displayName\": \"Bald Skin 2\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-2\"\n }\n },\n {\n \"value\": \"head_bald-skin-3\",\n \"displayName\": \"Bald Skin 3\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-3\"\n }\n },\n {\n \"value\": \"head_bald-skin-4\",\n \"displayName\": \"Bald Skin 4\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-4\"\n }\n },\n {\n \"value\": \"head_bald-skin-5\",\n \"displayName\": \"Bald Skin 5\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-5\"\n }\n },\n {\n \"value\": \"head_bald-skin-6\",\n \"displayName\": \"Bald Skin 6\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-6\"\n }\n },\n {\n \"value\": \"head_bald-skin-7\",\n \"displayName\": \"Bald Skin 7\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-7\"\n }\n },\n {\n \"value\": \"head_bald-skin-8\",\n \"displayName\": \"Bald Skin 8\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-8\"\n }\n },\n {\n \"value\": \"head_bald-skin-a\",\n \"displayName\": \"Bald Skin A\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-a\"\n }\n },\n {\n \"value\": \"head_bald-skin-b\",\n \"displayName\": \"Bald Skin B\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-b\"\n }\n },\n {\n \"value\": \"head_bald-skin-c\",\n \"displayName\": \"Bald Skin C\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-c\"\n }\n },\n {\n \"value\": \"head_bald-skin-d\",\n \"displayName\": \"Bald Skin D\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-d\"\n }\n },\n {\n \"value\": \"head_bald-skin-e\",\n \"displayName\": \"Bald Skin E\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-e\"\n }\n },\n {\n \"value\": \"head_bald-skin-f\",\n \"displayName\": \"Bald Skin F\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-f\"\n }\n },\n {\n \"value\": \"head_bald-skin-g\",\n \"displayName\": \"Bald Skin G\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-g\"\n }\n },\n {\n \"value\": \"head_bald-skin-h\",\n \"displayName\": \"Bald Skin H\",\n \"description\": {\n \"Type\": \"bald\",\n \"Skin Tone\": \"skin-h\"\n }\n },\n {\n \"value\": \"head_freckles-skin-1\",\n \"displayName\": \"Freckles Skin 1\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-1\"\n }\n },\n {\n \"value\": \"head_freckles-skin-2\",\n \"displayName\": \"Freckles Skin 2\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-2\"\n }\n },\n {\n \"value\": \"head_freckles-skin-3\",\n \"displayName\": \"Freckles Skin 3\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-3\"\n }\n },\n {\n \"value\": \"head_freckles-skin-4\",\n \"displayName\": \"Freckles Skin 4\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-4\"\n }\n },\n {\n \"value\": \"head_freckles-skin-5\",\n \"displayName\": \"Freckles Skin 5\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-5\"\n }\n },\n {\n \"value\": \"head_freckles-skin-6\",\n \"displayName\": \"Freckles Skin 6\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-6\"\n }\n },\n {\n \"value\": \"head_freckles-skin-7\",\n \"displayName\": \"Freckles Skin 7\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-7\"\n }\n },\n {\n \"value\": \"head_freckles-skin-8\",\n \"displayName\": \"Freckles Skin 8\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-8\"\n }\n },\n {\n \"value\": \"head_freckles-skin-a\",\n \"displayName\": \"Freckles Skin A\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-a\"\n }\n },\n {\n \"value\": \"head_freckles-skin-b\",\n \"displayName\": \"Freckles Skin B\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-b\"\n }\n },\n {\n \"value\": \"head_freckles-skin-c\",\n \"displayName\": \"Freckles Skin C\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-c\"\n }\n },\n {\n \"value\": \"head_freckles-skin-d\",\n \"displayName\": \"Freckles Skin D\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-d\"\n }\n },\n {\n \"value\": \"head_freckles-skin-e\",\n \"displayName\": \"Freckles Skin E\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-e\"\n }\n },\n {\n \"value\": \"head_freckles-skin-f\",\n \"displayName\": \"Freckles Skin F\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-f\"\n }\n },\n {\n \"value\": \"head_freckles-skin-g\",\n \"displayName\": \"Freckles Skin G\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-g\"\n }\n },\n {\n \"value\": \"head_freckles-skin-h\",\n \"displayName\": \"Freckles Skin H\",\n \"description\": {\n \"Type\": \"freckles\",\n \"Skin Tone\": \"skin-h\"\n }\n },\n {\n \"value\": \"head_shaved-skin-1\",\n \"displayName\": \"Shaved Skin 1\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-1\"\n }\n },\n {\n \"value\": \"head_shaved-skin-2\",\n \"displayName\": \"Shaved Skin 2\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-2\"\n }\n },\n {\n \"value\": \"head_shaved-skin-3\",\n \"displayName\": \"Shaved Skin 3\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-3\"\n }\n },\n {\n \"value\": \"head_shaved-skin-4\",\n \"displayName\": \"Shaved Skin 4\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-4\"\n }\n },\n {\n \"value\": \"head_shaved-skin-5\",\n \"displayName\": \"Shaved Skin 5\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-5\"\n }\n },\n {\n \"value\": \"head_shaved-skin-6\",\n \"displayName\": \"Shaved Skin 6\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-6\"\n }\n },\n {\n \"value\": \"head_shaved-skin-7\",\n \"displayName\": \"Shaved Skin 7\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-7\"\n }\n },\n {\n \"value\": \"head_shaved-skin-8\",\n \"displayName\": \"Shaved Skin 8\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-8\"\n }\n },\n {\n \"value\": \"head_shaved-skin-a\",\n \"displayName\": \"Shaved Skin A\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-a\"\n }\n },\n {\n \"value\": \"head_shaved-skin-b\",\n \"displayName\": \"Shaved Skin B\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-b\"\n }\n },\n {\n \"value\": \"head_shaved-skin-c\",\n \"displayName\": \"Shaved Skin C\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-c\"\n }\n },\n {\n \"value\": \"head_shaved-skin-d\",\n \"displayName\": \"Shaved Skin D\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-d\"\n }\n },\n {\n \"value\": \"head_shaved-skin-e\",\n \"displayName\": \"Shaved Skin E\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-e\"\n }\n },\n {\n \"value\": \"head_shaved-skin-f\",\n \"displayName\": \"Shaved Skin F\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-f\"\n }\n },\n {\n \"value\": \"head_shaved-skin-g\",\n \"displayName\": \"Shaved Skin G\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-g\"\n }\n },\n {\n \"value\": \"head_shaved-skin-h\",\n \"displayName\": \"Shaved Skin H\",\n \"description\": {\n \"Type\": \"shaved\",\n \"Skin Tone\": \"skin-h\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"bald\",\n \"freckles\",\n \"shaved\"\n ],\n \"isPrimaryOption\": true\n },\n \"Skin Tone\": {\n \"options\": [\n \"skin-1\",\n \"skin-2\",\n \"skin-3\",\n \"skin-4\",\n \"skin-5\",\n \"skin-6\",\n \"skin-7\",\n \"skin-8\",\n \"skin-a\",\n \"skin-b\",\n \"skin-c\",\n \"skin-d\",\n \"skin-e\",\n \"skin-f\",\n \"skin-g\",\n \"skin-h\"\n ]\n }\n }\n },\n \"Eyes\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"eyes_style-1-blue\",\n \"displayName\": \"Style 1 Blue\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-1-brown\",\n \"displayName\": \"Style 1 Brown\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-1-gray\",\n \"displayName\": \"Style 1 Gray\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-1-green\",\n \"displayName\": \"Style 1 Green\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-1-hazel\",\n \"displayName\": \"Style 1 Hazel\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"hazel\"\n }\n },\n {\n \"value\": \"eyes_style-11-blue\",\n \"displayName\": \"Style 11 Blue\",\n \"description\": {\n \"Style\": \"style-11\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-11-brown\",\n \"displayName\": \"Style 11 Brown\",\n \"description\": {\n \"Style\": \"style-11\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-11-gray\",\n \"displayName\": \"Style 11 Gray\",\n \"description\": {\n \"Style\": \"style-11\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-11-green\",\n \"displayName\": \"Style 11 Green\",\n \"description\": {\n \"Style\": \"style-11\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-11-hazel\",\n \"displayName\": \"Style 11 Hazel\",\n \"description\": {\n \"Style\": \"style-11\",\n \"Color\": \"hazel\"\n }\n },\n {\n \"value\": \"eyes_style-12-blue\",\n \"displayName\": \"Style 12 Blue\",\n \"description\": {\n \"Style\": \"style-12\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-12-brown\",\n \"displayName\": \"Style 12 Brown\",\n \"description\": {\n \"Style\": \"style-12\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-12-gray\",\n \"displayName\": \"Style 12 Gray\",\n \"description\": {\n \"Style\": \"style-12\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-12-green\",\n \"displayName\": \"Style 12 Green\",\n \"description\": {\n \"Style\": \"style-12\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-12-hazel\",\n \"displayName\": \"Style 12 Hazel\",\n \"description\": {\n \"Style\": \"style-12\",\n \"Color\": \"hazel\"\n }\n },\n {\n \"value\": \"eyes_style-13-blue\",\n \"displayName\": \"Style 13 Blue\",\n \"description\": {\n \"Style\": \"style-13\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-13-brown\",\n \"displayName\": \"Style 13 Brown\",\n \"description\": {\n \"Style\": \"style-13\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-13-gray\",\n \"displayName\": \"Style 13 Gray\",\n \"description\": {\n \"Style\": \"style-13\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-13-green\",\n \"displayName\": \"Style 13 Green\",\n \"description\": {\n \"Style\": \"style-13\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-13-hazel\",\n \"displayName\": \"Style 13 Hazel\",\n \"description\": {\n \"Style\": \"style-13\",\n \"Color\": \"hazel\"\n }\n },\n {\n \"value\": \"eyes_style-14-blue\",\n \"displayName\": \"Style 14 Blue\",\n \"description\": {\n \"Style\": \"style-14\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-14-brown\",\n \"displayName\": \"Style 14 Brown\",\n \"description\": {\n \"Style\": \"style-14\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-14-gray\",\n \"displayName\": \"Style 14 Gray\",\n \"description\": {\n \"Style\": \"style-14\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-14-green\",\n \"displayName\": \"Style 14 Green\",\n \"description\": {\n \"Style\": \"style-14\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-14-hazel\",\n \"displayName\": \"Style 14 Hazel\",\n \"description\": {\n \"Style\": \"style-14\",\n \"Color\": \"hazel\"\n }\n },\n {\n \"value\": \"eyes_style-15-blue\",\n \"displayName\": \"Style 15 Blue\",\n \"description\": {\n \"Style\": \"style-15\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyes_style-15-brown\",\n \"displayName\": \"Style 15 Brown\",\n \"description\": {\n \"Style\": \"style-15\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyes_style-15-gray\",\n \"displayName\": \"Style 15 Gray\",\n \"description\": {\n \"Style\": \"style-15\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyes_style-15-green\",\n \"displayName\": \"Style 15 Green\",\n \"description\": {\n \"Style\": \"style-15\",\n \"Color\": \"green\"\n }\n },\n {\n \"value\": \"eyes_style-15-hazel\",\n \"displayName\": \"Style 15 Hazel\",\n \"description\": {\n \"Style\": \"style-15\",\n \"Color\": \"hazel\"\n }\n }\n ],\n \"description\": {\n \"Style\": {\n \"options\": [\n null,\n \"style-1\",\n \"style-11\",\n \"style-12\",\n \"style-13\",\n \"style-14\",\n \"style-15\"\n ],\n \"isPrimaryOption\": true\n },\n \"Color\": {\n \"options\": [\n \"blue\",\n \"brown\",\n \"gray\",\n \"green\",\n \"hazel\"\n ]\n }\n },\n \"bisectInThumbnail\": true\n },\n \"Eyebrows\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"eyebrows_style-1-black\",\n \"displayName\": \"Style 1 Black\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-blonde\",\n \"displayName\": \"Style 1 Blonde\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-blue\",\n \"displayName\": \"Style 1 Blue\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-brown\",\n \"displayName\": \"Style 1 Brown\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-dark brown\",\n \"displayName\": \"Style 1 Dark brown\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-gray\",\n \"displayName\": \"Style 1 Gray\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-light brown\",\n \"displayName\": \"Style 1 Light brown\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-pink\",\n \"displayName\": \"Style 1 Pink\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-red\",\n \"displayName\": \"Style 1 Red\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"eyebrows_style-1-white\",\n \"displayName\": \"Style 1 White\",\n \"description\": {\n \"Style\": \"style-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-black\",\n \"displayName\": \"Style 2 Black\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-blonde\",\n \"displayName\": \"Style 2 Blonde\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-blue\",\n \"displayName\": \"Style 2 Blue\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-brown\",\n \"displayName\": \"Style 2 Brown\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-dark brown\",\n \"displayName\": \"Style 2 Dark brown\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-gray\",\n \"displayName\": \"Style 2 Gray\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-light brown\",\n \"displayName\": \"Style 2 Light brown\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-pink\",\n \"displayName\": \"Style 2 Pink\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-red\",\n \"displayName\": \"Style 2 Red\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"eyebrows_style-2-white\",\n \"displayName\": \"Style 2 White\",\n \"description\": {\n \"Style\": \"style-2\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-black\",\n \"displayName\": \"Style 3 Black\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-blonde\",\n \"displayName\": \"Style 3 Blonde\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-blue\",\n \"displayName\": \"Style 3 Blue\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-brown\",\n \"displayName\": \"Style 3 Brown\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-dark brown\",\n \"displayName\": \"Style 3 Dark brown\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-gray\",\n \"displayName\": \"Style 3 Gray\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-light brown\",\n \"displayName\": \"Style 3 Light brown\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-pink\",\n \"displayName\": \"Style 3 Pink\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-red\",\n \"displayName\": \"Style 3 Red\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"eyebrows_style-3-white\",\n \"displayName\": \"Style 3 White\",\n \"description\": {\n \"Style\": \"style-3\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-black\",\n \"displayName\": \"Style 4 Black\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-blonde\",\n \"displayName\": \"Style 4 Blonde\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-blue\",\n \"displayName\": \"Style 4 Blue\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"blue\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-brown\",\n \"displayName\": \"Style 4 Brown\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-dark brown\",\n \"displayName\": \"Style 4 Dark brown\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-gray\",\n \"displayName\": \"Style 4 Gray\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-light brown\",\n \"displayName\": \"Style 4 Light brown\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-pink\",\n \"displayName\": \"Style 4 Pink\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"pink\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-red\",\n \"displayName\": \"Style 4 Red\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"eyebrows_style-4-white\",\n \"displayName\": \"Style 4 White\",\n \"description\": {\n \"Style\": \"style-4\",\n \"Color\": \"white\"\n }\n }\n ],\n \"description\": {\n \"Style\": {\n \"options\": [\n null,\n \"style-1\",\n \"style-2\",\n \"style-3\",\n \"style-4\"\n ],\n \"isPrimaryOption\": true\n },\n \"Color\": {\n \"options\": [\n \"black\",\n \"blonde\",\n \"blue\",\n \"brown\",\n \"dark brown\",\n \"gray\",\n \"light brown\",\n \"pink\",\n \"red\",\n \"white\"\n ]\n }\n },\n \"bisectInThumbnail\": true\n },\n \"Mouth\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"mouth_neutral-skin-1\",\n \"displayName\": \"Neutral Skin 1\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-1\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-2\",\n \"displayName\": \"Neutral Skin 2\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-2\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-3\",\n \"displayName\": \"Neutral Skin 3\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-3\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-4\",\n \"displayName\": \"Neutral Skin 4\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-4\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-5\",\n \"displayName\": \"Neutral Skin 5\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-5\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-6\",\n \"displayName\": \"Neutral Skin 6\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-6\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-7\",\n \"displayName\": \"Neutral Skin 7\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-7\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-8\",\n \"displayName\": \"Neutral Skin 8\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-8\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-a\",\n \"displayName\": \"Neutral Skin A\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-a\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-b\",\n \"displayName\": \"Neutral Skin B\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-b\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-c\",\n \"displayName\": \"Neutral Skin C\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-c\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-d\",\n \"displayName\": \"Neutral Skin D\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-d\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-e\",\n \"displayName\": \"Neutral Skin E\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-e\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-f\",\n \"displayName\": \"Neutral Skin F\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-f\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-g\",\n \"displayName\": \"Neutral Skin G\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-g\"\n }\n },\n {\n \"value\": \"mouth_neutral-skin-h\",\n \"displayName\": \"Neutral Skin H\",\n \"description\": {\n \"Type\": \"neutral\",\n \"Skin Tone\": \"skin-h\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-1\",\n \"displayName\": \"Smirk Skin 1\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-1\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-2\",\n \"displayName\": \"Smirk Skin 2\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-2\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-3\",\n \"displayName\": \"Smirk Skin 3\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-3\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-4\",\n \"displayName\": \"Smirk Skin 4\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-4\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-5\",\n \"displayName\": \"Smirk Skin 5\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-5\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-6\",\n \"displayName\": \"Smirk Skin 6\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-6\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-7\",\n \"displayName\": \"Smirk Skin 7\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-7\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-8\",\n \"displayName\": \"Smirk Skin 8\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-8\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-a\",\n \"displayName\": \"Smirk Skin A\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-a\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-b\",\n \"displayName\": \"Smirk Skin B\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-b\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-c\",\n \"displayName\": \"Smirk Skin C\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-c\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-d\",\n \"displayName\": \"Smirk Skin D\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-d\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-e\",\n \"displayName\": \"Smirk Skin E\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-e\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-f\",\n \"displayName\": \"Smirk Skin F\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-f\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-g\",\n \"displayName\": \"Smirk Skin G\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-g\"\n }\n },\n {\n \"value\": \"mouth_smirk-skin-h\",\n \"displayName\": \"Smirk Skin H\",\n \"description\": {\n \"Type\": \"smirk\",\n \"Skin Tone\": \"skin-h\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"neutral\",\n \"smirk\"\n ],\n \"isPrimaryOption\": true\n },\n \"Skin Tone\": {\n \"options\": [\n \"skin-1\",\n \"skin-2\",\n \"skin-3\",\n \"skin-4\",\n \"skin-5\",\n \"skin-6\",\n \"skin-7\",\n \"skin-8\",\n \"skin-a\",\n \"skin-b\",\n \"skin-c\",\n \"skin-d\",\n \"skin-e\",\n \"skin-f\",\n \"skin-g\",\n \"skin-h\"\n ]\n }\n }\n },\n \"Facial Hair\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false,\n \"randomizationWeight\": 59\n },\n {\n \"value\": \"facial-hair_beard-full-1-black\",\n \"displayName\": \"Beard Full 1 Black\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-blonde\",\n \"displayName\": \"Beard Full 1 Blonde\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-brown\",\n \"displayName\": \"Beard Full 1 Brown\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-dark brown\",\n \"displayName\": \"Beard Full 1 Dark brown\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-gray\",\n \"displayName\": \"Beard Full 1 Gray\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-light brown\",\n \"displayName\": \"Beard Full 1 Light brown\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-red\",\n \"displayName\": \"Beard Full 1 Red\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-1-white\",\n \"displayName\": \"Beard Full 1 White\",\n \"description\": {\n \"Type\": \"beard-full-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-black\",\n \"displayName\": \"Beard Full 2 Black\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-blonde\",\n \"displayName\": \"Beard Full 2 Blonde\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-brown\",\n \"displayName\": \"Beard Full 2 Brown\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-dark brown\",\n \"displayName\": \"Beard Full 2 Dark brown\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-gray\",\n \"displayName\": \"Beard Full 2 Gray\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-light brown\",\n \"displayName\": \"Beard Full 2 Light brown\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-red\",\n \"displayName\": \"Beard Full 2 Red\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_beard-full-2-white\",\n \"displayName\": \"Beard Full 2 White\",\n \"description\": {\n \"Type\": \"beard-full-2\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-black\",\n \"displayName\": \"Goatee 1 Black\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-blonde\",\n \"displayName\": \"Goatee 1 Blonde\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-brown\",\n \"displayName\": \"Goatee 1 Brown\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-dark brown\",\n \"displayName\": \"Goatee 1 Dark brown\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-gray\",\n \"displayName\": \"Goatee 1 Gray\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-light brown\",\n \"displayName\": \"Goatee 1 Light brown\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-red\",\n \"displayName\": \"Goatee 1 Red\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-1-white\",\n \"displayName\": \"Goatee 1 White\",\n \"description\": {\n \"Type\": \"goatee-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-2-brown\",\n \"displayName\": \"Goatee 2 Brown\",\n \"description\": {\n \"Type\": \"goatee-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-black\",\n \"displayName\": \"Goatee 3 Black\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-blonde\",\n \"displayName\": \"Goatee 3 Blonde\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-brown\",\n \"displayName\": \"Goatee 3 Brown\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-dark brown\",\n \"displayName\": \"Goatee 3 Dark brown\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-gray\",\n \"displayName\": \"Goatee 3 Gray\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-light brown\",\n \"displayName\": \"Goatee 3 Light brown\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-red\",\n \"displayName\": \"Goatee 3 Red\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-3-white\",\n \"displayName\": \"Goatee 3 White\",\n \"description\": {\n \"Type\": \"goatee-3\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-black\",\n \"displayName\": \"Goatee 4 Black\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-blonde\",\n \"displayName\": \"Goatee 4 Blonde\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-brown\",\n \"displayName\": \"Goatee 4 Brown\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-dark brown\",\n \"displayName\": \"Goatee 4 Dark brown\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-gray\",\n \"displayName\": \"Goatee 4 Gray\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-light brown\",\n \"displayName\": \"Goatee 4 Light brown\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-red\",\n \"displayName\": \"Goatee 4 Red\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-4-white\",\n \"displayName\": \"Goatee 4 White\",\n \"description\": {\n \"Type\": \"goatee-4\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_goatee-5-brown\",\n \"displayName\": \"Goatee 5 Brown\",\n \"description\": {\n \"Type\": \"goatee-5\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-black\",\n \"displayName\": \"Mustache 1 Black\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-blonde\",\n \"displayName\": \"Mustache 1 Blonde\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-brown\",\n \"displayName\": \"Mustache 1 Brown\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-dark brown\",\n \"displayName\": \"Mustache 1 Dark brown\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-gray\",\n \"displayName\": \"Mustache 1 Gray\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-light brown\",\n \"displayName\": \"Mustache 1 Light brown\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-red\",\n \"displayName\": \"Mustache 1 Red\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-1-white\",\n \"displayName\": \"Mustache 1 White\",\n \"description\": {\n \"Type\": \"mustache-1\",\n \"Color\": \"white\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-black\",\n \"displayName\": \"Mustache 2 Black\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-blonde\",\n \"displayName\": \"Mustache 2 Blonde\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"blonde\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-brown\",\n \"displayName\": \"Mustache 2 Brown\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-dark brown\",\n \"displayName\": \"Mustache 2 Dark brown\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"dark brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-gray\",\n \"displayName\": \"Mustache 2 Gray\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"gray\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-light brown\",\n \"displayName\": \"Mustache 2 Light brown\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"light brown\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-red\",\n \"displayName\": \"Mustache 2 Red\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"facial-hair_mustache-2-white\",\n \"displayName\": \"Mustache 2 White\",\n \"description\": {\n \"Type\": \"mustache-2\",\n \"Color\": \"white\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"beard-full-1\",\n \"beard-full-2\",\n \"goatee-1\",\n \"goatee-2\",\n \"goatee-3\",\n \"goatee-4\",\n \"goatee-5\",\n \"mustache-1\",\n \"mustache-2\"\n ],\n \"isPrimaryOption\": true\n },\n \"Color\": {\n \"options\": [\n \"black\",\n \"blonde\",\n \"brown\",\n \"dark brown\",\n \"gray\",\n \"light brown\",\n \"red\",\n \"white\"\n ]\n }\n }\n },\n \"Hands\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"hands_skin-1\",\n \"displayName\": \"Skin 1\"\n },\n {\n \"value\": \"hands_skin-2\",\n \"displayName\": \"Skin 2\"\n },\n {\n \"value\": \"hands_skin-3\",\n \"displayName\": \"Skin 3\"\n },\n {\n \"value\": \"hands_skin-4\",\n \"displayName\": \"Skin 4\"\n },\n {\n \"value\": \"hands_skin-5\",\n \"displayName\": \"Skin 5\"\n },\n {\n \"value\": \"hands_skin-6\",\n \"displayName\": \"Skin 6\"\n },\n {\n \"value\": \"hands_skin-7\",\n \"displayName\": \"Skin 7\"\n },\n {\n \"value\": \"hands_skin-8\",\n \"displayName\": \"Skin 8\"\n },\n {\n \"value\": \"hands_skin-a\",\n \"displayName\": \"Skin A\"\n },\n {\n \"value\": \"hands_skin-b\",\n \"displayName\": \"Skin B\"\n },\n {\n \"value\": \"hands_skin-c\",\n \"displayName\": \"Skin C\"\n },\n {\n \"value\": \"hands_skin-d\",\n \"displayName\": \"Skin D\"\n },\n {\n \"value\": \"hands_skin-e\",\n \"displayName\": \"Skin E\"\n },\n {\n \"value\": \"hands_skin-f\",\n \"displayName\": \"Skin F\"\n },\n {\n \"value\": \"hands_skin-g\",\n \"displayName\": \"Skin G\"\n },\n {\n \"value\": \"hands_skin-h\",\n \"displayName\": \"Skin H\"\n }\n ],\n \"bisectInThumbnail\": true\n },\n \"Torso\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": true\n },\n {\n \"value\": \"torso_style-1-baseball-giants\",\n \"displayName\": \"Style 1 Baseball Giants\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"baseball-giants\"\n }\n },\n {\n \"value\": \"torso_style-1-bowling-shirt-1-red\",\n \"displayName\": \"Style 1 Bowling Shirt 1 Red\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"bowling-shirt-1-red\"\n },\n \"matchRandomizationToNull\": true\n },\n {\n \"value\": \"torso_style-1-combat-vest-red\",\n \"displayName\": \"Style 1 Combat Vest Red\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"combat-vest-red\"\n },\n \"matchRandomizationToNull\": true\n },\n {\n \"value\": \"torso_style-1-sport-coat-1-dark\",\n \"displayName\": \"Style 1 Sport Coat 1 Dark\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"sport-coat-1-dark\"\n },\n \"matchRandomizationToNull\": true\n },\n {\n \"value\": \"torso_style-1-sport-coat-1-gray\",\n \"displayName\": \"Style 1 Sport Coat 1 Gray\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"sport-coat-1-gray\"\n },\n \"matchRandomizationToNull\": true\n },\n {\n \"value\": \"torso_style-1-tshirt-1-hubs-black\",\n \"displayName\": \"Style 1 Tshirt 1 Hubs Black\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-hubs-black\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt-1-hubs-gray\",\n \"displayName\": \"Style 1 Tshirt 1 Hubs Gray\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-hubs-gray\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt-1-hubs-light-gray\",\n \"displayName\": \"Style 1 Tshirt 1 Hubs Light Gray\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-hubs-light-gray\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt-1-hubs-white\",\n \"displayName\": \"Style 1 Tshirt 1 Hubs White\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-hubs-white\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt-1-moz\",\n \"displayName\": \"Style 1 Tshirt 1 Moz\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-moz\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt-1-union-jack\",\n \"displayName\": \"Style 1 Tshirt 1 Union Jack\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt-1-union-jack\"\n }\n },\n {\n \"value\": \"torso_style-1-tshirt1-reactor\",\n \"displayName\": \"Style 1 Tshirt1 Reactor\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"tshirt1-reactor\"\n }\n },\n {\n \"value\": \"torso_style-1-ugly-christmas-1\",\n \"displayName\": \"Style 1 Ugly Christmas 1\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"ugly-christmas-1\"\n },\n \"matchRandomizationToNull\": true\n },\n {\n \"value\": \"torso_style-2-baseball-giants\",\n \"displayName\": \"Style 2 Baseball Giants\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"baseball-giants\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-baby-unicorn\",\n \"displayName\": \"Style 2 Tshirt 1 Baby Unicorn\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-baby-unicorn\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-heart-animated\",\n \"displayName\": \"Style 2 Tshirt 1 Heart Animated\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-heart-animated\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-heart\",\n \"displayName\": \"Style 2 Tshirt 1 Heart\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-heart\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-hubs-black\",\n \"displayName\": \"Style 2 Tshirt 1 Hubs Black\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-hubs-black\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-hubs-gray\",\n \"displayName\": \"Style 2 Tshirt 1 Hubs Gray\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-hubs-gray\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-hubs-light-gray\",\n \"displayName\": \"Style 2 Tshirt 1 Hubs Light Gray\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-hubs-light-gray\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-hubs-white\",\n \"displayName\": \"Style 2 Tshirt 1 Hubs White\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-hubs-white\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-1-moz\",\n \"displayName\": \"Style 2 Tshirt 1 Moz\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-1-moz\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt-union-jack\",\n \"displayName\": \"Style 2 Tshirt Union Jack\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt-union-jack\"\n }\n },\n {\n \"value\": \"torso_style-2-tshirt1-reactor\",\n \"displayName\": \"Style 2 Tshirt1 Reactor\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"tshirt1-reactor\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"style-1\",\n \"style-2\"\n ],\n \"isPrimaryOption\": true\n },\n \"Outfit\": {\n \"options\": [\n \"baseball-giants\",\n \"bowling-shirt-1-red\",\n \"combat-vest-red\",\n \"sport-coat-1-dark\",\n \"sport-coat-1-gray\",\n \"tshirt-1-hubs-black\",\n \"tshirt-1-hubs-gray\",\n \"tshirt-1-hubs-light-gray\",\n \"tshirt-1-hubs-white\",\n \"tshirt-1-moz\",\n \"tshirt-1-union-jack\",\n \"tshirt1-reactor\",\n \"ugly-christmas-1\",\n \"tshirt-1-baby-unicorn\",\n \"tshirt-1-heart-animated\",\n \"tshirt-1-heart\",\n \"tshirt-union-jack\"\n ]\n }\n }\n },\n \"Torso Jacket\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false,\n \"randomizationWeight\": 25\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-black\",\n \"displayName\": \"Style 1 Hoodie 1 Black\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-black\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-blue\",\n \"displayName\": \"Style 1 Hoodie 1 Blue\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-blue\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-gray\",\n \"displayName\": \"Style 1 Hoodie 1 Gray\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-gray\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-green\",\n \"displayName\": \"Style 1 Hoodie 1 Green\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-green\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-light-gray\",\n \"displayName\": \"Style 1 Hoodie 1 Light Gray\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-light-gray\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-hoodie-1-red\",\n \"displayName\": \"Style 1 Hoodie 1 Red\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"hoodie-1-red\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-black\",\n \"displayName\": \"Style 1 Punk Leather 1 Black\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-black\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-blue\",\n \"displayName\": \"Style 1 Punk Leather 1 Blue\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-blue\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-brown\",\n \"displayName\": \"Style 1 Punk Leather 1 Brown\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-brown\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-cognac\",\n \"displayName\": \"Style 1 Punk Leather 1 Cognac\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-cognac\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-maroon\",\n \"displayName\": \"Style 1 Punk Leather 1 Maroon\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-maroon\"\n }\n },\n {\n \"value\": \"torso-jacket_style-1-punk-leather-1-red\",\n \"displayName\": \"Style 1 Punk Leather 1 Red\",\n \"description\": {\n \"Type\": \"style-1\",\n \"Outfit\": \"punk-leather-1-red\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-black\",\n \"displayName\": \"Style 2 Hoodie 1 Black\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-black\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-blue\",\n \"displayName\": \"Style 2 Hoodie 1 Blue\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-blue\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-gray\",\n \"displayName\": \"Style 2 Hoodie 1 Gray\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-gray\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-light-gray\",\n \"displayName\": \"Style 2 Hoodie 1 Light Gray\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-light-gray\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-pink\",\n \"displayName\": \"Style 2 Hoodie 1 Pink\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-pink\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-hoodie-1-purple\",\n \"displayName\": \"Style 2 Hoodie 1 Purple\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"hoodie-1-purple\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-black\",\n \"displayName\": \"Style 2 Punk Leather 1 Black\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-black\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-blue\",\n \"displayName\": \"Style 2 Punk Leather 1 Blue\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-blue\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-brown\",\n \"displayName\": \"Style 2 Punk Leather 1 Brown\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-brown\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-cognac\",\n \"displayName\": \"Style 2 Punk Leather 1 Cognac\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-cognac\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-maroon\",\n \"displayName\": \"Style 2 Punk Leather 1 Maroon\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-maroon\"\n }\n },\n {\n \"value\": \"torso-jacket_style-2-punk-leather-1-red\",\n \"displayName\": \"Style 2 Punk Leather 1 Red\",\n \"description\": {\n \"Type\": \"style-2\",\n \"Outfit\": \"punk-leather-1-red\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"style-1\",\n \"style-2\"\n ],\n \"isPrimaryOption\": true\n },\n \"Outfit\": {\n \"options\": [\n \"hoodie-1-black\",\n \"hoodie-1-blue\",\n \"hoodie-1-gray\",\n \"hoodie-1-green\",\n \"hoodie-1-light-gray\",\n \"hoodie-1-red\",\n \"punk-leather-1-black\",\n \"punk-leather-1-blue\",\n \"punk-leather-1-brown\",\n \"punk-leather-1-cognac\",\n \"punk-leather-1-maroon\",\n \"punk-leather-1-red\",\n \"hoodie-1-pink\",\n \"hoodie-1-purple\"\n ]\n }\n },\n \"matchRandomization\": {\n \"categoryName\": \"Torso\",\n \"primaryOption\": \"Type\",\n \"secondaryOption\": \"Outfit\"\n }\n },\n \"Headwear\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false,\n \"randomizationWeight\": 20\n },\n {\n \"value\": \"headwear_baseball-giants-black\",\n \"displayName\": \"Baseball Giants Black\",\n \"description\": {\n \"Type\": \"baseball-giants\",\n \"Color\": \"black\"\n }\n },\n {\n \"value\": \"headwear_beach-umbrella-mixed\",\n \"displayName\": \"Beach Umbrella Mixed\",\n \"description\": {\n \"Type\": \"beach-umbrella\",\n \"Color\": \"mixed\"\n }\n },\n {\n \"value\": \"headwear_beanie-1-red\",\n \"displayName\": \"Beanie 1 Red\",\n \"description\": {\n \"Type\": \"beanie-1\",\n \"Color\": \"red\"\n }\n },\n {\n \"value\": \"headwear_hijab-black\",\n \"displayName\": \"Hijab Black\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"black\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_hijab-blue\",\n \"displayName\": \"Hijab Blue\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"blue\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_hijab-gray\",\n \"displayName\": \"Hijab Gray\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"gray\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_hijab-lavender\",\n \"displayName\": \"Hijab Lavender\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"lavender\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_hijab-pink\",\n \"displayName\": \"Hijab Pink\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"pink\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_hijab-white\",\n \"displayName\": \"Hijab White\",\n \"description\": {\n \"Type\": \"hijab\",\n \"Color\": \"white\"\n },\n \"morphRelationships\": [\n {\n \"targetCategoryName\": \"Head\",\n \"targetMorphName\": \"ear rotate back\",\n \"targetMorphValue\": 1\n }\n ],\n \"randomizationWeight\": 0.05\n },\n {\n \"value\": \"headwear_spokemon-mixed\",\n \"displayName\": \"Spokemon Mixed\",\n \"description\": {\n \"Type\": \"spokemon\",\n \"Color\": \"mixed\"\n },\n \"randomizationWeight\": 0.1\n },\n {\n \"value\": \"headwear_top-hat-1-black\",\n \"displayName\": \"Top Hat 1 Black\",\n \"description\": {\n \"Type\": \"top-hat-1\",\n \"Color\": \"black\"\n }\n }\n ],\n \"description\": {\n \"Type\": {\n \"options\": [\n null,\n \"baseball-giants\",\n \"beach-umbrella\",\n \"beanie-1\",\n \"hijab\",\n \"spokemon\",\n \"top-hat-1\"\n ],\n \"isPrimaryOption\": true\n },\n \"Color\": {\n \"options\": [\n \"black\",\n \"mixed\",\n \"red\",\n \"blue\",\n \"gray\",\n \"lavender\",\n \"pink\",\n \"white\"\n ]\n }\n }\n },\n \"Eyewear\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false,\n \"randomizationWeight\": 20\n },\n {\n \"value\": \"eyewear_arnette\",\n \"displayName\": \"Arnette\"\n },\n {\n \"value\": \"eyewear_aviators1\",\n \"displayName\": \"Aviators1\"\n },\n {\n \"value\": \"eyewear_glam-2\",\n \"displayName\": \"Glam 2\"\n },\n {\n \"value\": \"eyewear_heart-1-pink\",\n \"displayName\": \"Heart 1 Pink\"\n },\n {\n \"value\": \"eyewear_metal-1\",\n \"displayName\": \"Metal 1\"\n },\n {\n \"value\": \"eyewear_oakleys-red\",\n \"displayName\": \"Oakleys Red\"\n },\n {\n \"value\": \"eyewear_punk-2\",\n \"displayName\": \"Punk 2\"\n },\n {\n \"value\": \"eyewear_wire-frame-1-gold\",\n \"displayName\": \"Wire Frame 1 Gold\"\n }\n ]\n },\n \"Earring\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false,\n \"randomizationWeight\": 5\n },\n {\n \"value\": \"earring_hoop-high-left-silver\",\n \"displayName\": \"Hoop High Left Silver\"\n },\n {\n \"value\": \"earring_hoop-high-right-silver\",\n \"displayName\": \"Hoop High Right Silver\"\n },\n {\n \"value\": \"earring_hoop-large-both-gold\",\n \"displayName\": \"Hoop Large Both Gold\",\n \"bisectInThumbnail\": true\n },\n {\n \"value\": \"earring_hoop-small-both-gold\",\n \"displayName\": \"Hoop Small Both Gold\",\n \"bisectInThumbnail\": true\n }\n ]\n },\n \"Accessory\": {\n \"parts\": [\n {\n \"value\": null,\n \"displayName\": \"None\",\n \"excludeFromRandomize\": false\n },\n {\n \"value\": \"accessory_duck-floaty\",\n \"displayName\": \"Duck Floaty\"\n },\n {\n \"value\": \"accessory_face-mask-1-animated\",\n \"displayName\": \"Face Mask 1 Animated\",\n \"randomizationWeight\": 0.5\n },\n {\n \"value\": \"accessory_headband-cat-ears-1\",\n \"displayName\": \"Headband Cat Ears 1\"\n },\n {\n \"value\": \"accessory_headphones-1-black\",\n \"displayName\": \"Headphones 1 Black\"\n },\n {\n \"value\": \"accessory_pool-mask-1\",\n \"displayName\": \"Pool Mask 1\",\n \"randomizationWeight\": 0.1\n }\n ]\n }\n};","import * as THREE from \"three\";\n\nfunction uvScrollComponentFromMesh(mesh) {\n const { userData } = mesh;\n const hubsComponents = userData.gltfExtensions && userData.gltfExtensions.MOZ_hubs_components;\n return hubsComponents && hubsComponents[\"uv-scroll\"];\n}\n\nexport default {\n isValidMesh(mesh) {\n const hasUVScrollComponent = !!uvScrollComponentFromMesh(mesh);\n return mesh.isSkinnedMesh && hasUVScrollComponent;\n },\n\n initialStateForMesh(mesh) {\n const uvScrollComponent = uvScrollComponentFromMesh(mesh);\n return {\n map: mesh.material.map || mesh.material.emissiveMap,\n speed: uvScrollComponent.speed,\n increment: uvScrollComponent.increment,\n offset: new THREE.Vector2(),\n };\n },\n\n update({ offset, speed, increment, map }, delta) {\n offset.addScaledVector(speed, delta);\n\n offset.x = offset.x % 1.0;\n offset.y = offset.y % 1.0;\n\n map.offset.x = increment.x ? offset.x - (offset.x % increment.x) : offset.x;\n map.offset.y = increment.y ? offset.y - (offset.y % increment.y) : offset.y;\n },\n};\n","import * as THREE from \"three\";\n\nconst idleEyesAnimationNames = [\"idle_eyes\", \"Blinks\"];\n\nfunction idleEyesAnimationsForGltf(gltf) {\n return gltf.animations && gltf.animations.filter(({ name }) => idleEyesAnimationNames.includes(name));\n}\n\nexport default {\n hasIdleEyes(gltf) {\n const idleEyesAnimations = idleEyesAnimationsForGltf(gltf);\n return !!(idleEyesAnimations && idleEyesAnimations.length);\n },\n\n mixerForGltf(gltf) {\n const mixer = new THREE.AnimationMixer(gltf.scene);\n const idleEyesAnimations = idleEyesAnimationsForGltf(gltf);\n for (const animation of idleEyesAnimations) {\n const action = mixer.clipAction(animation);\n action.enabled = true;\n action.setLoop(THREE.LoopRepeat, Infinity).play();\n }\n return mixer;\n },\n};\n","import * as THREE from \"three\";\nimport { OrbitControls } from \"three/examples/jsm/controls/OrbitControls\";\nimport constants from \"./constants\";\nimport { exportAvatar } from \"./export\";\nimport {\n loadGLTF,\n loadGLTFCached,\n forEachMaterial,\n generateEnvironmentMap,\n createSky,\n isThumbnailMode,\n findChildrenByType,\n} from \"./utils\";\nimport { renderThumbnail } from \"./render-thumbnail\";\nimport { combine } from \"./mesh-combination\";\nimport { getMaterialInfo } from \"./get-material-info\";\nimport { urlFor } from \"./url-for\";\nimport { createSkydome } from \"./create-skydome\";\nimport uvScroll from \"./uv-scroll\";\nimport idleEyes from \"./idle-eyes\";\nimport assets from \"./assets\";\nimport debugConfig from \"./debug-config\";\n\n// Used to test mesh combination\nwindow.combineCurrentAvatar = async function () {\n return await combine({ avatar: state.avatarGroup });\n};\n\nconst state = {\n reactIsLoaded: false,\n shouldResize: true,\n didInit: false,\n scene: null,\n camera: null,\n renderer: null,\n controls: null,\n clock: null,\n delta: 0,\n envMap: null,\n avatarGroup: null,\n testExportGroup: null,\n avatarNodes: {},\n avatarConfig: {},\n newAvatarConfig: {},\n shouldApplyNewAvatarConfig: false,\n shouldExportAvatar: false,\n shouldResetView: false,\n thumbnailConfig: {},\n shouldRenderThumbnail: false,\n shouldRotateLeft: false,\n shouldRotateRight: false,\n idleEyesMixers: {},\n uvScrollMaps: {},\n quietMode: false,\n shouldRenderInQuietMode: true,\n shouldApplyMorphRelationships: false,\n};\nwindow.gameState = state;\n\nwindow.onresize = () => {\n state.shouldResize = true;\n};\ndocument.addEventListener(constants.reactIsLoaded, () => {\n state.reactIsLoaded = true;\n});\ndocument.addEventListener(constants.avatarConfigChanged, (e) => {\n state.newAvatarConfig = e.detail.avatarConfig;\n state.shouldApplyNewAvatarConfig = true;\n});\ndocument.addEventListener(constants.renderThumbnail, (e) => {\n state.thumbnailConfig = e.detail.thumbnailConfig;\n state.shouldRenderThumbnail = true;\n});\ndocument.addEventListener(constants.exportAvatar, () => {\n state.shouldExportAvatar = true;\n});\ndocument.addEventListener(constants.resetView, () => {\n state.shouldResetView = true;\n});\n\nfunction onKeyChange(e) {\n switch (e.key) {\n case \"ArrowRight\":\n state.shouldRotateRight = e.type === \"keydown\";\n break;\n case \"ArrowLeft\":\n state.shouldRotateLeft = e.type === \"keydown\";\n break;\n }\n}\n[\"keydown\", \"keyup\"].map((e) => {\n document.addEventListener(e, onKeyChange);\n});\ndocument.addEventListener(\"blur\", () => {\n state.shouldRotateLeft = false;\n state.shouldRotateRight = false;\n});\n\nfunction ensureAvatarNode(category) {\n if (!state.avatarNodes[category]) {\n state.avatarNodes[category] = new THREE.Group();\n state.avatarGroup.add(state.avatarNodes[category]);\n }\n}\n\nfunction resetView() {\n state.controls.reset();\n}\n\nfunction init() {\n THREE.Cache.enabled = !isThumbnailMode();\n\n const scene = new THREE.Scene();\n state.scene = scene;\n\n const skydome = createSkydome(isThumbnailMode() ? 2 : 400);\n scene.add(skydome);\n\n const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);\n camera.position.set(0, 0.6, 1);\n state.camera = camera;\n\n const directionalLight = new THREE.DirectionalLight(0xffffff, 4.0);\n directionalLight.position.set(10, 20, 5);\n scene.add(directionalLight);\n\n // TODO: Square this with react\n const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById(\"scene\"), antialias: true });\n renderer.physicallyCorrectLights = true;\n renderer.gammaOutput = true;\n state.renderer = renderer;\n\n state.clock = new THREE.Clock();\n\n const sky = createSky();\n state.envMap = generateEnvironmentMap(sky, renderer);\n\n const controls = new OrbitControls(camera, renderer.domElement);\n controls.target = new THREE.Vector3(0, 0.5, 0);\n controls.update();\n controls.saveState();\n state.controls = controls;\n state.currentCameraPosition = new THREE.Vector3();\n state.prevCameraPosition = new THREE.Vector3();\n\n // TODO Remove this test code\n state.testExportGroup = new THREE.Group();\n scene.add(state.testExportGroup);\n\n state.avatarGroup = new THREE.Group();\n scene.add(state.avatarGroup);\n}\n\nfunction playClips(scene, clips) {\n if (!scene.animations) return;\n\n const mixer = new THREE.AnimationMixer(scene);\n\n for (const clip of clips) {\n const animation = scene.animations.find(a => a.name === clip)\n if (animation) {\n const action = mixer.clipAction(animation);\n action.play();\n }\n }\n\n mixer.update(0);\n}\n\nfunction initializeGltf(key, gltf) {\n if (idleEyes.hasIdleEyes(gltf)) {\n state.idleEyesMixers[key] = idleEyes.mixerForGltf(gltf);\n }\n\n if (state.uvScrollMaps[key]) {\n state.uvScrollMaps[key].length = 0;\n }\n\n gltf.scene.traverse((obj) => {\n forEachMaterial(obj, (material) => {\n if (material.isMeshStandardMaterial) {\n material.envMap = state.envMap;\n material.envMapIntensity = 0.4;\n if (material.map) {\n material.map.anisotropy = state.renderer.capabilities.getMaxAnisotropy();\n }\n material.needsUpdate = true;\n }\n });\n\n if (uvScroll.isValidMesh(obj)) {\n state.uvScrollMaps[key] = state.uvScrollMaps[key] || [];\n state.uvScrollMaps[key].push(uvScroll.initialStateForMesh(obj));\n }\n });\n}\n\nfunction saveInitialMorphTargetInfluences(node) {\n node.traverse((obj) => {\n if (obj.morphTargetInfluences && !obj.userData.initialMorphTargetInfluences) {\n obj.userData.initialMorphTargetInfluences = obj.morphTargetInfluences.slice(0);\n }\n });\n}\n\nfunction resetMorphTargetInfluences(node) {\n for (const mesh of findChildrenByType(node, \"SkinnedMesh\")) {\n if (!mesh.morphTargetInfluences) continue;\n for (let i = 0; i < mesh.morphTargetInfluences.length; i++) {\n mesh.morphTargetInfluences[i] = mesh.userData.initialMorphTargetInfluences[i];\n }\n }\n}\n\nfunction applyMorphRelationships(part) {\n if (!part.morphRelationships) return;\n\n for (const { targetCategoryName, targetMorphName, targetMorphValue } of part.morphRelationships) {\n const mesh = state.avatarNodes[targetCategoryName].getObjectByProperty(\"type\", \"SkinnedMesh\");\n if (!mesh || !mesh.morphTargetDictionary) continue;\n\n const morphTargetIndex = mesh.morphTargetDictionary[targetMorphName];\n if (morphTargetIndex !== undefined) {\n mesh.morphTargetInfluences[morphTargetIndex] = targetMorphValue;\n }\n }\n}\n\nasync function loadIntoGroup({ category, part, group, cached = true }) {\n try {\n const load = cached ? loadGLTFCached : loadGLTF;\n const gltf = await load(urlFor(part));\n\n if (state.avatarConfig[category] !== part) return;\n\n // TODO Make sure we need to do this.\n // Stash animations on the Object3D so that we can use them during export.\n gltf.scene.animations = gltf.animations;\n\n saveInitialMorphTargetInfluences(gltf.scene);\n\n initializeGltf(category, gltf);\n\n group.clear();\n group.add(gltf.scene);\n state.shouldRenderInQuietMode = true;\n\n return gltf.scene;\n } catch (ex) {\n console.error(\"Failed to load avatar part\", category, part, ex);\n if (state.avatarConfig[category] !== part) return;\n group.clear();\n state.shouldRenderInQuietMode = true;\n return;\n }\n}\n\nfunction tick(time) {\n {\n if (state.reactIsLoaded && !state.didInit) {\n state.didInit = true;\n init();\n }\n if (!state.didInit) {\n requestAnimationFrame(tick);\n return;\n }\n }\n\n {\n state.delta = state.clock.getDelta();\n }\n\n {\n if (state.shouldResize) {\n state.shouldResize = false;\n const { renderer, camera } = state;\n\n const width = renderer.domElement.parentNode.clientWidth;\n const height = renderer.domElement.parentNode.clientHeight;\n renderer.setSize(width, height, false);\n camera.aspect = width / height;\n camera.updateProjectionMatrix();\n state.shouldRenderInQuietMode = true;\n }\n }\n\n {\n if (state.shouldApplyNewAvatarConfig) {\n state.shouldApplyNewAvatarConfig = false;\n\n const categories = new Set(Object.keys(state.newAvatarConfig).concat(Object.keys(state.avatarConfig)));\n\n for (const category of categories) {\n ensureAvatarNode(category);\n\n if (state.newAvatarConfig[category] !== state.avatarConfig[category]) {\n state.avatarConfig[category] = state.newAvatarConfig[category];\n if (state.newAvatarConfig[category] !== null) {\n loadIntoGroup({ category, part: state.newAvatarConfig[category], group: state.avatarNodes[category] }).then(\n () => {\n state.shouldApplyMorphRelationships = true;\n }\n );\n } else {\n state.avatarNodes[category].clear();\n state.shouldApplyMorphRelationships = true;\n state.shouldRenderInQuietMode = true;\n }\n }\n }\n }\n }\n\n {\n if (state.shouldApplyMorphRelationships) {\n state.shouldApplyMorphRelationships = false;\n\n for (const categoryName of Object.keys(state.avatarConfig)) {\n if (!state.avatarConfig[categoryName] || !assets[categoryName]) continue;\n\n resetMorphTargetInfluences(state.avatarNodes[categoryName]);\n\n const currentPart = assets[categoryName].parts.find((part) => part.value === state.avatarConfig[categoryName]);\n\n applyMorphRelationships(currentPart);\n }\n }\n }\n\n {\n if (state.shouldRenderThumbnail) {\n state.shouldRenderThumbnail = false;\n\n const { category, part } = state.thumbnailConfig;\n\n ensureAvatarNode(category);\n\n for (const category of Object.keys(state.avatarNodes)) {\n state.avatarNodes[category].clear();\n }\n\n state.avatarConfig[category] = part;\n\n loadIntoGroup({ category, part, group: state.avatarNodes[category], cached: false }).then((gltfScene) => {\n renderThumbnail(state.renderer, state.scene, gltfScene, category, part);\n });\n }\n }\n\n {\n if (state.shouldExportAvatar) {\n state.shouldExportAvatar = false;\n\n // Reset all idle eyes animations before cloning or exporting the avatar\n // so that we don't export it mid-blink.\n Object.values(state.idleEyesMixers).forEach(mixer => {\n mixer.setTime(0);\n });\n\n exportAvatar(state.avatarGroup).then(({ glb }) => {\n const blob = new Blob([glb], { type: \"application/octet-stream\" });\n const url = URL.createObjectURL(blob);\n\n if (!debugConfig.disableDownload) {\n const el = document.createElement(\"a\");\n el.style.display = \"none\";\n el.href = url;\n el.download = \"custom_avatar.glb\";\n el.click();\n el.remove();\n }\n\n if (debugConfig.debugExports) {\n loadGLTF(url).then((gltf) => {\n initializeGltf(\"testExportGroup\", gltf);\n state.testExportGroup.clear();\n state.testExportGroup.add(gltf.scene);\n gltf.scene.position.set(0.5, 0, 0);\n });\n }\n });\n }\n }\n\n {\n if (state.shouldResetView) {\n state.shouldResetView = false;\n resetView();\n }\n }\n\n {\n let speed = 0;\n if (state.shouldRotateLeft) {\n speed -= 30;\n }\n if (state.shouldRotateRight) {\n speed += 30;\n }\n const { controls } = state;\n controls.autoRotate = true;\n controls.autoRotateSpeed = speed;\n controls.update();\n }\n\n {\n for (const categoryName in state.idleEyesMixers) {\n if (!state.idleEyesMixers.hasOwnProperty(categoryName)) continue;\n const mixer = state.idleEyesMixers[categoryName];\n mixer.update(state.delta);\n }\n }\n\n {\n for (const categoryName in state.uvScrollMaps) {\n if (!state.uvScrollMaps.hasOwnProperty(categoryName)) continue;\n for (const uvScrollState of state.uvScrollMaps[categoryName]) {\n uvScroll.update(uvScrollState, state.delta);\n }\n }\n }\n\n {\n const { camera, prevCameraPosition, currentCameraPosition } = state;\n const didCameraMove = !prevCameraPosition.equals(currentCameraPosition.setFromMatrixPosition(camera.matrixWorld));\n prevCameraPosition.copy(currentCameraPosition);\n if (didCameraMove) {\n state.shouldRenderInQuietMode = true;\n }\n }\n\n {\n window.requestAnimationFrame(tick);\n }\n\n {\n const { renderer, scene, camera, controls } = state;\n if (!state.quietMode || state.shouldRenderInQuietMode) {\n state.shouldRenderInQuietMode = false;\n renderer.render(scene, camera);\n }\n }\n}\n\nwindow.requestAnimationFrame(tick);\n","export function urlFor(value) {\n if (value.startsWith(\"blob\")) {\n return value;\n } else {\n return `assets/models/${value}.glb`;\n }\n}\n","import * as THREE from \"three\";\n\nexport function createSkydome(radius) {\n const vertexShader = `\nvarying vec3 vWorldPosition;\n\nvoid main() {\n\n vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n vWorldPosition = worldPosition.xyz;\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n}\n`;\n const fragmentShader = `\nuniform vec3 topColor;\nuniform vec3 bottomColor;\nuniform float offset;\nuniform float exponent;\n\nvarying vec3 vWorldPosition;\n\nvoid main() {\n\n float h = normalize( vWorldPosition + offset ).y;\n gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );\n\n}\n`;\n\n const offset = radius / 12;\n\n const uniforms = {\n topColor: { value: new THREE.Color(0x0096db) }, // TODO: match primary color\n bottomColor: { value: new THREE.Color(0xc6dde5) },\n offset: { value: offset },\n exponent: { value: 1.0 },\n };\n\n // TODO Pixel push these values to perfection!!!\n const geometry = new THREE.SphereGeometry(radius, 16, 16);\n const material = new THREE.ShaderMaterial({\n uniforms: uniforms,\n vertexShader: vertexShader,\n fragmentShader: fragmentShader,\n side: THREE.BackSide,\n });\n\n return new THREE.Mesh(geometry, material);\n}\n","import * as THREE from \"three\";\nimport { findChildrenByType, findChildByType } from \"./utils\";\nimport constants from \"./constants\";\nimport assets from \"./assets\";\n\nfunction bisectGeometry(mesh) {\n const box = new THREE.Box3().setFromObject(mesh);\n const center = box.getCenter(new THREE.Vector3());\n\n // TODO: Could probably simplify this considerably by actually using indexed geometry\n // and removing indices of bisected attributes instead of the attribute values themselves.\n const geometry = mesh.geometry.toNonIndexed();\n\n const verts = geometry.getAttribute(\"position\");\n\n const attributeNames = Object.keys(geometry.attributes);\n const newAttributes = Object.fromEntries(\n attributeNames.map((name) => {\n const { itemSize } = geometry.getAttribute(name);\n return [name, new THREE.BufferAttribute(new Float32Array((verts.count / 2) * itemSize), itemSize)];\n })\n );\n\n for (let i = 0, j = 0; i < verts.count; i++) {\n if (verts.getX(i) > center.x) {\n for (const attributeName of attributeNames) {\n const oldAttr = geometry.getAttribute(attributeName);\n const { itemSize } = oldAttr;\n const offset = i * itemSize;\n const values = oldAttr.array.slice(offset, offset + itemSize);\n newAttributes[attributeName].set(values, j * itemSize);\n }\n j++;\n }\n }\n\n for (const attributeName of attributeNames) {\n geometry.setAttribute(attributeName, newAttributes[attributeName]);\n }\n\n mesh.geometry = geometry;\n}\n\nfunction shouldBisect(categoryName, partValue) {\n const part = assets[categoryName].parts.find((part) => part.value === partValue);\n return assets[categoryName].bisectInThumbnail || part.bisectInThumbnail;\n}\n\nexport function renderThumbnail(renderer, scene, gltfScene, categoryName, partValue) {\n const thumbnailSize = 128;\n renderer.setSize(thumbnailSize, thumbnailSize);\n\n const angle = -Math.PI / 6;\n const meshes = findChildrenByType(gltfScene, \"SkinnedMesh\");\n meshes.map((mesh, i) => {\n mesh.pose();\n if (shouldBisect(categoryName, partValue)) {\n bisectGeometry(mesh);\n }\n mesh.geometry.rotateY(angle);\n mesh.geometry.rotateX(-angle);\n });\n\n const box = new THREE.Box3().setFromObject(gltfScene);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const halfWidth = size.x / 2;\n const halfHeight = size.y / 2;\n const camSize = Math.max(halfWidth, halfHeight) * 1.1;\n const camera = new THREE.OrthographicCamera(-camSize, camSize, camSize, -camSize, 0.0001, 10);\n const unitZ = new THREE.Vector3(0, 0, 1);\n\n camera.position.copy(new THREE.Vector3().copy(center).add(unitZ.multiplyScalar(size.z)));\n\n renderer.render(scene, camera);\n\n renderer.domElement.toBlob((blob) => {\n const result = document.createElement(\"img\");\n result.id = constants.thumbnailResult;\n document.body.append(result);\n result.src = URL.createObjectURL(blob);\n });\n}\n","import React from \"react\";\n\nexport function Toolbar({children}) {\n return (\n
\n {children}\n
\n );\n}\n","import React from \"react\";\n\nexport function UploadButton({ onGLBUploaded }) {\n return (\n \n );\n}\n","import React, { useState } from \"react\";\n\nexport function MoreMenu({ items }) {\n const [menuVisible, setMenuVisible] = useState(false);\n return (\n
\n \n {menuVisible &&
{items}
}\n
\n );\n}\n","export function dispatch(eventName, detail) {\n document.dispatchEvent(new CustomEvent(eventName, { detail }));\n}\n","import React from \"react\";\nimport { Toolbar } from \"./Toolbar\";\nimport { UploadButton } from \"./UploadButton\";\nimport { MoreMenu } from \"./MoreMenu\";\nimport { dispatch } from \"../dispatch\";\nimport constants from \"../constants\";\n\nfunction dispatchResetView() {\n dispatch(constants.resetView);\n}\n\nfunction dispatchExportAvatar() {\n dispatch(constants.exportAvatar);\n}\n\nexport function ToolbarContainer({ onGLBUploaded, randomizeConfig }) {\n return (\n \n Hackweek Avatar Maker\n \n \n \n GitHub\n \n \n }\n >\n \n \n \n \n );\n}\n","import React from \"react\";\n\nexport function ButtonTip({ visible, top, left, text }) {\n return (\n
\n {text}\n
\n );\n}\n","import React from \"react\";\n\nexport function AvatarPreviewContainer({ thumbnailMode, canvasUrl }) {\n return (\n
\n {!thumbnailMode && (\n
\n )}\n \n
\n );\n}\n","import React from \"react\";\n\nexport const AvatarPartContainer = React.forwardRef(({ onKeyDown, isExpanded, children }, ref) => {\n return (\n \n {children}\n \n );\n});\n","import React from \"react\";\nimport cx from \"classnames\";\n\nexport const Thumbnail = React.forwardRef(({ as: Component = \"div\", image, className, children, ...props }, ref) => {\n return (\n \n {children}\n \n );\n});\n","import React, { useState, useEffect, useRef, useContext } from \"react\";\nimport { faChevronDown, faChevronRight } from \"@fortawesome/free-solid-svg-icons\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\n\nexport function Chevron({ isExpanded }) {\n return (\n
\n \n
\n );\n}\n","import React from \"react\";\n\nimport { Thumbnail } from \"./Thumbnail\";\nimport { Chevron } from \"./Chevron\";\n\nexport function CategoryHeading({ categoryName, onClick, isExpanded, selectedPartName, image }) {\n return (\n
\n

{categoryName}

\n \n

{selectedPartName}

\n \n
\n );\n}\n","import React from \"react\";\n\nexport function Collapsible({ children }) {\n return
{children}
;\n}\n","import React, { useEffect, useRef } from \"react\";\nimport { AvatarPartContainer } from \"./AvatarPartContainer\";\nimport { CategoryHeading } from \"./CategoryHeading\";\nimport { Collapsible } from \"./Collapsible\";\n\nexport function AvatarPartSelector({ setExpanded, isExpanded, expandedContent, currentSelection, categoryName }) {\n const containerEl = useRef(null);\n useEffect(() => {\n if (isExpanded) {\n containerEl.current.scrollIntoView({ behavior: \"smooth\", block: \"nearest\" });\n }\n }, [containerEl, isExpanded]);\n\n return (\n {\n if (e.target === e.currentTarget && (e.key === \"Enter\" || e.key === \" \")) {\n setExpanded(!isExpanded);\n e.preventDefault();\n e.stopPropagation();\n }\n },\n }}\n >\n setExpanded(!isExpanded),\n }}\n />\n {isExpanded && {expandedContent}}\n \n );\n}\n","import React from \"react\";\nimport { Thumbnail } from \"./Thumbnail\";\nimport cx from \"classnames\";\n\nexport const ThumbnailButton = React.forwardRef(({ tip, image, selected, onClick, onMouseOver, onMouseOut }, ref) => {\n return (\n \n );\n});\n","import React, { useRef, useContext } from \"react\";\nimport { ThumbnailButton } from \"./ThumbnailButton\";\nimport { TipContext } from \"./TipContext\";\n\nfunction AvatarPart({\n part,\n tip,\n isSelected,\n categoryName,\n onSelectAvatarPart,\n onHoverAvatarPart,\n onUnhoverAvatarPart,\n}) {\n const buttonRef = useRef(null);\n\n return (\n {\n onSelectAvatarPart({ categoryName, part });\n }}\n onMouseOver={() => {\n const [rect] = buttonRef.current.getClientRects();\n onHoverAvatarPart({ categoryName, part, tip, rect });\n }}\n onMouseOut={() => {\n onUnhoverAvatarPart();\n }}\n />\n );\n}\n\nfunction match({ description, part }) {\n if (!part.description) return false;\n for (const param of Object.keys(description)) {\n if (part.description[param] !== description[param]) {\n return false;\n }\n }\n return true;\n}\n\nfunction capitalize(str) {\n return str[0].toUpperCase() + str.substring(1);\n}\n\nfunction parseSubCategories({ category, currentSelection }) {\n const optionNames = Object.keys(category.description);\n\n return optionNames.map((optionName) => {\n if (currentSelection.value === null && !category.description[optionName].isPrimaryOption) {\n return { optionName, parts: [{part:{value: null, displayName: \"None\"}, tip: \"None\"}] }\n }\n const options = category.description[optionName].options;\n const parts = options\n .map((option) => {\n if (option === null) {\n const part = category.parts.find((part) => part.value === null);\n return { part, tip: \"None\" };\n }\n\n const description = Object.assign({}, currentSelection.description);\n description[optionName] = option;\n\n let part = category.parts.find((part) => {\n return match({ description, part });\n });\n\n if (!part && category.description[optionName].isPrimaryOption) {\n part = category.parts.find((part) => part.value !== null && part.description[optionName] === option);\n }\n\n const tip = option\n .split(\"-\")\n .map((p) => capitalize(p))\n .join(\" \");\n\n return { part, tip };\n })\n .filter(({ part }) => !!part);\n return { optionName, parts };\n });\n}\n\nexport function SubCategory({ name, parts }) {\n return (\n
\n

{name}

\n {parts}\n
\n );\n}\n\nexport function CategoryContainer({\n category,\n categoryName,\n currentSelection,\n onSelectAvatarPart,\n onHoverAvatarPart,\n onUnhoverAvatarPart,\n}) {\n if (category.description) {\n const subcategoryInfo = parseSubCategories({ category, currentSelection });\n return subcategoryInfo.map(({ optionName, parts }) => {\n return (\n (\n \n ))}\n />\n );\n });\n } else {\n return category.parts.map((part) => {\n const tip = part.displayName;\n return (\n \n );\n });\n }\n}\n","import React, { useState, useContext } from \"react\";\nimport SimpleBar from \"simplebar-react\";\nimport \"simplebar/dist/simplebar.min.css\";\nimport { AvatarPartSelector } from \"./AvatarPartSelector\";\nimport { CategoryContainer } from \"./CategoryContainer\";\nimport { TipContext } from \"./TipContext\";\n\nexport function AvatarConfigurationPanel({\n onScroll,\n avatarConfig,\n assets,\n onSelectAvatarPart,\n onHoverAvatarPart,\n onUnhoverAvatarPart,\n}) {\n const [expandedCategory, setExpandedCategory] = useState(null);\n const categoryNames = Object.keys(assets);\n\n const partSelectors = categoryNames.map((categoryName) => {\n const category = assets[categoryName];\n const currentSelection = category.parts.find((part) => part.value === avatarConfig[categoryName]);\n return (\n setExpandedCategory(expand ? categoryName : null)}\n categoryName={categoryName}\n currentSelection={currentSelection}\n expandedContent={\n \n }\n />\n );\n });\n\n return (\n
\n \n {partSelectors}\n \n
\n );\n}\n","import React from \"react\";\n\nexport function AvatarEditor({ thumbnailMode, leftPanel, rightPanel, buttonTip, toolbar }) {\n return (\n <>\n
\n {!thumbnailMode && leftPanel}\n {rightPanel}\n {buttonTip}\n
\n {!thumbnailMode && toolbar}\n \n );\n}\n","function chooseWeightedRandom(parts) {\n const partsWithWeightInfo = parts.reduce(\n (acc, part) => {\n const partWeight = part.randomizationWeight || 1;\n\n acc.parts.push({\n value: part.value,\n minValue: acc.sum,\n maxValue: acc.sum + partWeight,\n });\n\n acc.sum += partWeight;\n\n return acc;\n },\n { parts: [], sum: 0 }\n );\n\n const randomNum = Math.random() * partsWithWeightInfo.sum;\n\n return partsWithWeightInfo.parts.find((info) => randomNum >= info.minValue && randomNum < info.maxValue);\n}\n\nfunction maybeReplaceWithMatchingCategory(assets, newConfig, categoryName) {\n const category = assets[categoryName];\n\n if (newConfig[categoryName] === null || !category.matchRandomization) return;\n\n const categoryNameToMatch = category.matchRandomization.categoryName;\n\n const partToMatch = assets[categoryNameToMatch].parts.find((part) => part.value === newConfig[categoryNameToMatch]);\n\n // Some parts in the other category should never result in a random part chosen from this category\n if (partToMatch.matchRandomizationToNull) {\n newConfig[categoryName] = null;\n return;\n }\n\n if (!partToMatch.description) return;\n\n const currentPart = category.parts.find((part) => part.value === newConfig[categoryName]);\n\n const { primaryOption, secondaryOption } = category.matchRandomization;\n\n const matchingAsset = category.parts.find((part) => {\n return (\n part.description &&\n currentPart.description &&\n part.description[primaryOption] === partToMatch.description[primaryOption] &&\n part.description[secondaryOption] === currentPart.description[secondaryOption]\n );\n });\n\n if (matchingAsset) {\n newConfig[categoryName] = matchingAsset.value;\n } else {\n // If we don't find an exact match for the secondaryOption, \n // we should find a random part that matches the desired primaryOption.\n const randomMatchingAsset = chooseWeightedRandom(\n category.parts.filter((part) => {\n return (\n part.description &&\n part.description[primaryOption] === partToMatch.description[primaryOption]\n );\n })\n );\n if (randomMatchingAsset) {\n newConfig[categoryName] = randomMatchingAsset.value;\n }\n }\n}\n\nexport function generateRandomConfig(assets) {\n const categoryNames = Object.keys(assets);\n const newConfig = {};\n\n for (const categoryName of categoryNames) {\n const categoryAssets = assets[categoryName].parts.filter((part) => !part.excludeFromRandomize);\n if (categoryAssets.length === 0) continue;\n\n newConfig[categoryName] = chooseWeightedRandom(categoryAssets).value;\n }\n\n // We want to match some categories to the primary option choosen in another category.\n for (const categoryName of categoryNames) {\n maybeReplaceWithMatchingCategory(assets, newConfig, categoryName);\n }\n\n return newConfig;\n}\n","const storageKey = \"avatarMaker\";\n\nfunction getConfigFromLocalStorage() {\n const stored = localStorage.getItem(storageKey);\n if (stored) {\n return JSON.parse(stored);\n } else {\n return { avatars: {} };\n }\n}\n\nfunction persistToLocalStorage(config) {\n localStorage.setItem(storageKey, JSON.stringify(config))\n}\n\n/**\n * Saves an Avatar config object\n * @param {string} slotKey key to store under\n * @param {object} avatarConfig Avatar config object to store\n */\nexport function saveAvatarConfig(slotKey, avatarConfig) {\n if (!window.localStorage) {\n console.log(\"No localStorage...bailing.\");\n }\n\n const storedConfig = getConfigFromLocalStorage();\n\n storedConfig.avatars[slotKey] = avatarConfig;\n\n persistToLocalStorage(storedConfig);\n}\n\n/**\n * Returns the specified Avatar config object\n * @param {string} slotKey The key for the desired Avatar config\n * @returns {object} Avatar config\n */\nexport function getAvatarConfig(slotKey) {\n if (!window.localStorage) {\n console.log(\"No localStorage...bailing.\");\n }\n\n const storedConfig = getConfigFromLocalStorage();\n\n return storedConfig.avatars[slotKey];\n}\n\n/**\n * Returns list of the Avatar slotKeys\n * @returns {Array} List of Avatar slotKeys that have stored data.\n */\nexport function getAvatarConfigSlotKeys() {\n if (!window.localStorage) {\n console.log(\"No localStorage...bailing.\");\n }\n\n const storedConfig = getConfigFromLocalStorage();\n\n return Object.keys(storedConfig.avatars);\n}","import React, { useState, useEffect, useCallback } from \"react\";\nimport constants from \"../constants\";\nimport { generateWave } from \"../utils\";\nimport { ToolbarContainer } from \"./ToolbarContainer\";\nimport { ButtonTip } from \"./ButtonTip\";\nimport { AvatarPreviewContainer } from \"./AvatarPreviewContainer\";\nimport { AvatarConfigurationPanel } from \"./AvatarConfigurationPanel\";\nimport { AvatarEditor } from \"./AvatarEditor\";\nimport { dispatch } from \"../dispatch\";\nimport { generateRandomConfig } from \"../generate-random-config\";\nimport initialAssets from \"../assets\";\nimport { isThumbnailMode } from \"../utils\";\nimport debounce from \"../utils/debounce\";\nimport { saveAvatarConfig, getAvatarConfig, getAvatarConfigSlotKeys } from \"../persistence\";\n\n// Used externally by the generate-thumbnails script\nconst thumbnailMode = isThumbnailMode();\n\nexport function AvatarEditorContainer() {\n const [assets, setAssets] = useState(initialAssets);\n const [hoveredConfig, setHoveredConfig] = useState({});\n const debouncedSetHoveredConfig = useCallback(debounce(setHoveredConfig), [setHoveredConfig]);\n const [canvasUrl, setCanvasUrl] = useState(null);\n\n const initialConfig = generateRandomConfig(assets);\n const [avatarConfig, setAvatarConfig] = useState(initialConfig);\n const [tipState, setTipState] = useState({ visible: false, text: \"\", top: 0, left: 0 });\n\n useEffect(() => {\n if (!thumbnailMode) {\n dispatch(constants.avatarConfigChanged, { avatarConfig: { ...avatarConfig, ...hoveredConfig } });\n }\n dispatch(constants.reactIsLoaded);\n });\n\n // TODO: Save the wave to a static image, or actually do some interesting animation with it.\n useEffect(async () => {\n if (canvasUrl === null) {\n setCanvasUrl(await generateWave());\n }\n });\n\n function updateAvatarConfig(newConfig) {\n setAvatarConfig({ ...avatarConfig, ...newConfig });\n }\n\n function showTip(text, top, left) {\n setTipState({ visible: true, text, top, left });\n }\n\n function hideTip() {\n setTipState({ visible: false });\n }\n\n function capitalize(str) {\n if (!str) return \"\";\n return str[0].toUpperCase() + str.substring(1);\n }\n\n // TODO Share this code with the generate-assets script.\n function parseFilename(fullname, categoryNamePrefix, fallbackCategoryName) {\n const filename = fullname.substring(0, fullname.lastIndexOf(\".\"));\n\n let [hyphenatedCategory, hyphenatedName] = filename.split(\"_\");\n if (!hyphenatedName) {\n hyphenatedCategory = fallbackCategoryName;\n hyphenatedName = filename;\n } else {\n hyphenatedCategory = categoryNamePrefix + \"-\" + hyphenatedCategory;\n }\n const category = hyphenatedCategory\n .split(\"-\")\n .map((p) => capitalize(p))\n .join(\" \");\n const displayName = hyphenatedName\n .split(\"-\")\n .map((p) => capitalize(p))\n .join(\" \");\n return [category, displayName];\n }\n\n function onGLBUploaded(e) {\n const file = e.target.files[0];\n\n let [category, displayName] = parseFilename(file.name, \"Uploaded\", \"Uploads\");\n const url = URL.createObjectURL(file);\n\n const clone = { ...assets };\n\n clone[category] = clone[category] || {\n parts: [\n {\n displayName: \"None\",\n value: null,\n },\n ],\n };\n\n clone[category].parts.push({\n displayName,\n value: url,\n });\n\n setAssets(clone);\n\n updateAvatarConfig({ [category]: url });\n }\n\n function randomizeConfig() {\n setAvatarConfig(generateRandomConfig(assets));\n }\n\n function saveConfig(slotKey) {\n saveAvatarConfig(slotKey, avatarConfig);\n }\n\n function loadConfig(slotKey) {\n setAvatarConfig(getAvatarConfig(slotKey));\n }\n\n window.saveConfig = saveConfig; \n window.loadConfig = loadConfig;\n window.listStoredConfigs = getAvatarConfigSlotKeys;\n\n return (\n {\n hideTip();\n },\n onSelectAvatarPart: ({ categoryName, part }) => {\n updateAvatarConfig({ [categoryName]: part.value });\n },\n onHoverAvatarPart: ({ categoryName, part, tip, rect }) => {\n debouncedSetHoveredConfig({ [categoryName]: part.value });\n showTip(tip, rect.bottom, rect.left + rect.width / 2);\n },\n onUnhoverAvatarPart: () => {\n debouncedSetHoveredConfig({});\n hideTip();\n },\n }}\n />\n ),\n rightPanel: ,\n buttonTip: ,\n toolbar: ,\n }}\n />\n );\n}\n","export default function debounce(fn, wait = 30) {\n let timeoutId = null;\n return function (...args) {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), wait);\n };\n}\n","import \"./styles.css\";\nimport \"./game\";\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport { AvatarEditorContainer } from \"./react-components/AvatarEditorContainer\";\nimport { dispatch } from \"./dispatch\";\nimport constants from \"./constants\";\n\n// Used externally by the generate-thumbnails script\nwindow.renderThumbnail = (category, part) => {\n dispatch(constants.renderThumbnail, { thumbnailConfig: { category, part } });\n};\n\nReactDOM.render(, document.getElementById(\"root\"));\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/cssWithMappingToString.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nimport ___CSS_LOADER_GET_URL_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/getUrl.js\";\nimport ___CSS_LOADER_URL_IMPORT_0___ from \"./Poppins-Light.ttf\";\nimport ___CSS_LOADER_URL_IMPORT_1___ from \"./Poppins-Regular.ttf\";\nimport ___CSS_LOADER_URL_IMPORT_2___ from \"./Poppins-Medium.ttf\";\nimport ___CSS_LOADER_URL_IMPORT_3___ from \"./Poppins-SemiBold.ttf\";\nimport ___CSS_LOADER_URL_IMPORT_4___ from \"./Poppins-Bold.ttf\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\nvar ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);\nvar ___CSS_LOADER_URL_REPLACEMENT_1___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_1___);\nvar ___CSS_LOADER_URL_REPLACEMENT_2___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_2___);\nvar ___CSS_LOADER_URL_REPLACEMENT_3___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_3___);\nvar ___CSS_LOADER_URL_REPLACEMENT_4___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_4___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \"@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 300;\\n src: url(\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \") format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 400;\\n src: url(\" + ___CSS_LOADER_URL_REPLACEMENT_1___ + \") format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 500;\\n src: url(\" + ___CSS_LOADER_URL_REPLACEMENT_2___ + \") format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 600;\\n src: url(\" + ___CSS_LOADER_URL_REPLACEMENT_3___ + \") format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 700;\\n src: url(\" + ___CSS_LOADER_URL_REPLACEMENT_4___ + \") format('truetype');\\n}\\n\", \"\",{\"version\":3,\"sources\":[\"webpack://./assets/fonts/Poppins.css\"],\"names\":[],\"mappings\":\"AAAA;EACE,sBAAsB;EACtB,kBAAkB;EAClB,gBAAgB;EAChB,+DAAgD;AAClD;AACA;EACE,sBAAsB;EACtB,kBAAkB;EAClB,gBAAgB;EAChB,+DAAkD;AACpD;AACA;EACE,sBAAsB;EACtB,kBAAkB;EAClB,gBAAgB;EAChB,+DAAiD;AACnD;AACA;EACE,sBAAsB;EACtB,kBAAkB;EAClB,gBAAgB;EAChB,+DAAmD;AACrD;AACA;EACE,sBAAsB;EACtB,kBAAkB;EAClB,gBAAgB;EAChB,+DAA+C;AACjD\",\"sourcesContent\":[\"@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 300;\\n src: url(./Poppins-Light.ttf) format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 400;\\n src: url(./Poppins-Regular.ttf) format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 500;\\n src: url(./Poppins-Medium.ttf) format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 600;\\n src: url(./Poppins-SemiBold.ttf) format('truetype');\\n}\\n@font-face {\\n font-family: 'Poppins';\\n font-style: normal;\\n font-weight: 700;\\n src: url(./Poppins-Bold.ttf) format('truetype');\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../node_modules/css-loader/dist/runtime/cssWithMappingToString.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../node_modules/css-loader/dist/runtime/api.js\";\nimport ___CSS_LOADER_AT_RULE_IMPORT_0___ from \"-!../node_modules/css-loader/dist/cjs.js!../assets/fonts/Poppins.css\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n___CSS_LOADER_EXPORT___.i(___CSS_LOADER_AT_RULE_IMPORT_0___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \":root {\\n --main-bg-color: white;\\n --toolbar-bg-color: #f5f5f5;\\n --primary-blue: #00a5f4;\\n --thumbnail-bg-color: lightgray;\\n --button-border-color: white;\\n --hover-border-color: lightblue;\\n --button-selected-border-color: var(--primary-blue);\\n --thumbnail-size: 64px;\\n --border-radius: 16px;\\n --thumbnail-border-size: 4px;\\n\\n --outer-border-size: 4px;\\n --outer-border-offset: -6px;\\n --outer-border-radius: calc(var(--border-radius) * 1.1);\\n\\n --font-weight-not-bold-heading: 400;\\n --font-weight-bold-heading: 600;\\n}\\n\\nbody {\\n background-color: var(--main-bg-color);\\n}\\n\\nbody {\\n margin: 0;\\n}\\n\\n* {\\n font-family: Poppins, sans-serif;\\n font-size: 12pt;\\n box-sizing: border-box;\\n}\\n\\nhtml,\\nbody,\\n#root {\\n height: 100vh;\\n}\\n\\n#root {\\n display:flex;\\n flex-direction: column-reverse;\\n}\\n\\n.selector {\\n overflow: auto;\\n width: 45%;\\n background-color: var(--main-bg-color);\\n}\\n\\n.selector .simpleBar {\\n padding: 32px 64px;\\n}\\n\\n.main {\\n display: flex;\\n overflow: hidden;\\n flex: 1;\\n}\\n\\n#sceneContainer {\\n position: relative;\\n width: 55%;\\n}\\n\\nbutton,\\nlabel {\\n margin: 3px;\\n}\\n\\nlabel {\\n display: block;\\n}\\n\\n.categoryHeading {\\n display: flex;\\n flex-flow: row no-wrap;\\n align-items: center;\\n padding: 6px 24px;\\n}\\n\\n.categoryHeading h2, .categoryHeading .chevron {\\n margin-right: 12px;\\n}\\n.categoryHeading:hover .categoryName,\\n.categoryHeading:hover .chevron {\\n color: var(--primary-blue);\\n}\\n\\n.categoryHeading .chevron {\\n flex: 1;\\n text-align: left;\\n}\\n\\n.categoryHeading .categoryName {\\n font-weight: var(--font-weight-not-bold-heading);\\n white-space: nowrap;\\n}\\n.categoryHeading .selectedPartName {\\n font-weight: var(--font-weight-bold-heading);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.categoryHeading .chevron {\\n flex: 1;\\n text-align: left;\\n}\\n\\n.partSelector {\\n margin-bottom: 16px;\\n /* prevent margin collapse */\\n padding-bottom: 0.1px;\\n background-color: #f4f4f4;\\n border-radius: var(--border-radius);\\n position: relative;\\n outline: none;\\n}\\n.partSelector:after, .avatarPartButton:after {\\n content: '';\\n display: block;\\n position: absolute;\\n top: var(--outer-border-offset);\\n bottom: var(--outer-border-offset);\\n left: var(--outer-border-offset);\\n right: var(--outer-border-offset);\\n border-radius: var(--outer-border-radius);\\n border: none;\\n pointer-events: none;\\n}\\n.partSelector:focus:after,\\n.partSelector.expanded:after,\\n.partSelector.collapsed:hover:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--hover-border-color);\\n}\\n\\n.partSelector .collapsible {\\n overflow: hidden;\\n margin: 14px;\\n margin-top: 4px;\\n transform: scaleY(1);\\n transform-origin: top;\\n opacity: 1;\\n transition: transform 0.2s, opacity 0.2s;\\n}\\n\\n.partSelector.collapsed .collapsible {\\n transform: scaleY(0);\\n opacity: 0;\\n height: 0;\\n margin: 0;\\n}\\n\\n.partThumbnail, .avatarPartButton {\\n min-width: var(--thumbnail-size);\\n height: var(--thumbnail-size);\\n background-color: var(--thumbnail-bg-color);\\n border-radius: var(--border-radius);\\n border: var(--thumbnail-border-size) solid;\\n border-color: #f4f4f4;\\n background-size: contain;\\n}\\n\\n.partSelector.collapsed .avatarPartButton {\\n display: none;\\n}\\n\\n.avatarPartButton {\\n border-color: var(--button-border-color);\\n position: relative;\\n outline: none;\\n}\\n\\n.avatarPartButton:focus:after,\\n.avatarPartButton:hover:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--hover-border-color);\\n}\\n\\n.avatarPartButton.selected:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--button-selected-border-color);\\n}\\n\\n.buttonTip {\\n border-radius: 6px;\\n position: absolute;\\n background: var(--primary-blue);\\n white-space: nowrap;\\n padding: 3px 10px;\\n color: white;\\n font-weight: bold;\\n margin-top: 6px;\\n transform-origin: center center;\\n transform: translate(-50%, 0);\\n pointer-events: none;\\n}\\n\\n.toolbar {\\n padding: 20px 20px;\\n display: flex;\\n justify-content: flex-end;\\n align-items: center;\\n background-color: var(--toolbar-bg-color);\\n border-top: 2px solid lightgrey;\\n}\\n\\n.toolbar button, .toolbar .uploadButton {\\n display: inline;\\n background-color: white;\\n border-radius: var(--border-radius);\\n border: 2px solid grey;\\n color: grey;\\n font-size: 10pt;\\n padding: 22px;\\n font-weight: bold;\\n white-space: nowrap;\\n}\\n.toolbar button:hover,\\n.toolbar button:focus,\\n.toolbar .uploadButton:hover,\\n.toolbar .uploadButton:focus {\\n background-color: lightgrey;\\n}\\n\\nbutton.primary {\\n background-color: var(--primary-blue);\\n border-color: var(--primary-blue);\\n color: white;\\n}\\nbutton.primary:hover,\\nbutton.primary:focus {\\n background-color: lightblue;\\n border-color: lightblue;\\n}\\n\\n.toolbar .uploadButton input {\\n display: none;\\n}\\n\\n.appName {\\n flex: 1;\\n font-size: 12pt;\\n display: flex;\\n align-items: center;\\n}\\n\\n.menuContainer {\\n position: relative;\\n}\\n\\n.menuContainer .menuButton {\\n --button-size: 70px;\\n font-size: 20pt;\\n width: var(--button-size);\\n height: var(--button-size);\\n border-radius: var(--button-size);\\n padding: 0;\\n}\\n\\n.menu {\\n position: absolute;\\n z-index: 1;\\n background-color: var(--toolbar-bg-color);\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n padding: 4px;\\n border-radius: var(--border-radius);\\n}\\n\\n.menu a {\\n margin: 10px 0;\\n}\\n\\n@keyframes wave {\\n from { background-position-y: 0 }\\n to { background-position-y: 400px; }\\n}\\n\\n.waveContainer {\\n position: absolute;\\n width: 60px;\\n height: 100%;\\n pointer-events: none;\\n background-repeat: repeat-y;\\n animation: wave 3s infinite;\\n animation-timing-function: cubic-bezier(.2,.52,.79,.49);\\n /* Move 1 pixel to the left to workaround rendering issue in FF linux */\\n left: -1px;\\n}\\n\\n@media (min-width: 1200px) {\\n #root {\\n flex-direction: column;\\n }\\n .toolbar {\\n padding: 20px 40px;\\n }\\n .appName {\\n font-size: 24pt;\\n }\\n .menu {\\n bottom: 85px;\\n flex-direction: column-reverse;\\n }\\n}\\n\", \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles.css\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"@import url('../assets/fonts/Poppins.css');\\n\\n:root {\\n --main-bg-color: white;\\n --toolbar-bg-color: #f5f5f5;\\n --primary-blue: #00a5f4;\\n --thumbnail-bg-color: lightgray;\\n --button-border-color: white;\\n --hover-border-color: lightblue;\\n --button-selected-border-color: var(--primary-blue);\\n --thumbnail-size: 64px;\\n --border-radius: 16px;\\n --thumbnail-border-size: 4px;\\n\\n --outer-border-size: 4px;\\n --outer-border-offset: -6px;\\n --outer-border-radius: calc(var(--border-radius) * 1.1);\\n\\n --font-weight-not-bold-heading: 400;\\n --font-weight-bold-heading: 600;\\n}\\n\\nbody {\\n background-color: var(--main-bg-color);\\n}\\n\\nbody {\\n margin: 0;\\n}\\n\\n* {\\n font-family: Poppins, sans-serif;\\n font-size: 12pt;\\n box-sizing: border-box;\\n}\\n\\nhtml,\\nbody,\\n#root {\\n height: 100vh;\\n}\\n\\n#root {\\n display:flex;\\n flex-direction: column-reverse;\\n}\\n\\n.selector {\\n overflow: auto;\\n width: 45%;\\n background-color: var(--main-bg-color);\\n}\\n\\n.selector .simpleBar {\\n padding: 32px 64px;\\n}\\n\\n.main {\\n display: flex;\\n overflow: hidden;\\n flex: 1;\\n}\\n\\n#sceneContainer {\\n position: relative;\\n width: 55%;\\n}\\n\\nbutton,\\nlabel {\\n margin: 3px;\\n}\\n\\nlabel {\\n display: block;\\n}\\n\\n.categoryHeading {\\n display: flex;\\n flex-flow: row no-wrap;\\n align-items: center;\\n padding: 6px 24px;\\n}\\n\\n.categoryHeading h2, .categoryHeading .chevron {\\n margin-right: 12px;\\n}\\n.categoryHeading:hover .categoryName,\\n.categoryHeading:hover .chevron {\\n color: var(--primary-blue);\\n}\\n\\n.categoryHeading .chevron {\\n flex: 1;\\n text-align: left;\\n}\\n\\n.categoryHeading .categoryName {\\n font-weight: var(--font-weight-not-bold-heading);\\n white-space: nowrap;\\n}\\n.categoryHeading .selectedPartName {\\n font-weight: var(--font-weight-bold-heading);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.categoryHeading .chevron {\\n flex: 1;\\n text-align: left;\\n}\\n\\n.partSelector {\\n margin-bottom: 16px;\\n /* prevent margin collapse */\\n padding-bottom: 0.1px;\\n background-color: #f4f4f4;\\n border-radius: var(--border-radius);\\n position: relative;\\n outline: none;\\n}\\n.partSelector:after, .avatarPartButton:after {\\n content: '';\\n display: block;\\n position: absolute;\\n top: var(--outer-border-offset);\\n bottom: var(--outer-border-offset);\\n left: var(--outer-border-offset);\\n right: var(--outer-border-offset);\\n border-radius: var(--outer-border-radius);\\n border: none;\\n pointer-events: none;\\n}\\n.partSelector:focus:after,\\n.partSelector.expanded:after,\\n.partSelector.collapsed:hover:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--hover-border-color);\\n}\\n\\n.partSelector .collapsible {\\n overflow: hidden;\\n margin: 14px;\\n margin-top: 4px;\\n transform: scaleY(1);\\n transform-origin: top;\\n opacity: 1;\\n transition: transform 0.2s, opacity 0.2s;\\n}\\n\\n.partSelector.collapsed .collapsible {\\n transform: scaleY(0);\\n opacity: 0;\\n height: 0;\\n margin: 0;\\n}\\n\\n.partThumbnail, .avatarPartButton {\\n min-width: var(--thumbnail-size);\\n height: var(--thumbnail-size);\\n background-color: var(--thumbnail-bg-color);\\n border-radius: var(--border-radius);\\n border: var(--thumbnail-border-size) solid;\\n border-color: #f4f4f4;\\n background-size: contain;\\n}\\n\\n.partSelector.collapsed .avatarPartButton {\\n display: none;\\n}\\n\\n.avatarPartButton {\\n border-color: var(--button-border-color);\\n position: relative;\\n outline: none;\\n}\\n\\n.avatarPartButton:focus:after,\\n.avatarPartButton:hover:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--hover-border-color);\\n}\\n\\n.avatarPartButton.selected:after {\\n border: var(--outer-border-size) solid;\\n border-color: var(--button-selected-border-color);\\n}\\n\\n.buttonTip {\\n border-radius: 6px;\\n position: absolute;\\n background: var(--primary-blue);\\n white-space: nowrap;\\n padding: 3px 10px;\\n color: white;\\n font-weight: bold;\\n margin-top: 6px;\\n transform-origin: center center;\\n transform: translate(-50%, 0);\\n pointer-events: none;\\n}\\n\\n.toolbar {\\n padding: 20px 20px;\\n display: flex;\\n justify-content: flex-end;\\n align-items: center;\\n background-color: var(--toolbar-bg-color);\\n border-top: 2px solid lightgrey;\\n}\\n\\n.toolbar button, .toolbar .uploadButton {\\n display: inline;\\n background-color: white;\\n border-radius: var(--border-radius);\\n border: 2px solid grey;\\n color: grey;\\n font-size: 10pt;\\n padding: 22px;\\n font-weight: bold;\\n white-space: nowrap;\\n}\\n.toolbar button:hover,\\n.toolbar button:focus,\\n.toolbar .uploadButton:hover,\\n.toolbar .uploadButton:focus {\\n background-color: lightgrey;\\n}\\n\\nbutton.primary {\\n background-color: var(--primary-blue);\\n border-color: var(--primary-blue);\\n color: white;\\n}\\nbutton.primary:hover,\\nbutton.primary:focus {\\n background-color: lightblue;\\n border-color: lightblue;\\n}\\n\\n.toolbar .uploadButton input {\\n display: none;\\n}\\n\\n.appName {\\n flex: 1;\\n font-size: 12pt;\\n display: flex;\\n align-items: center;\\n}\\n\\n.menuContainer {\\n position: relative;\\n}\\n\\n.menuContainer .menuButton {\\n --button-size: 70px;\\n font-size: 20pt;\\n width: var(--button-size);\\n height: var(--button-size);\\n border-radius: var(--button-size);\\n padding: 0;\\n}\\n\\n.menu {\\n position: absolute;\\n z-index: 1;\\n background-color: var(--toolbar-bg-color);\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n padding: 4px;\\n border-radius: var(--border-radius);\\n}\\n\\n.menu a {\\n margin: 10px 0;\\n}\\n\\n@keyframes wave {\\n from { background-position-y: 0 }\\n to { background-position-y: 400px; }\\n}\\n\\n.waveContainer {\\n position: absolute;\\n width: 60px;\\n height: 100%;\\n pointer-events: none;\\n background-repeat: repeat-y;\\n animation: wave 3s infinite;\\n animation-timing-function: cubic-bezier(.2,.52,.79,.49);\\n /* Move 1 pixel to the left to workaround rendering issue in FF linux */\\n left: -1px;\\n}\\n\\n@media (min-width: 1200px) {\\n #root {\\n flex-direction: column;\\n }\\n .toolbar {\\n padding: 20px 40px;\\n }\\n .appName {\\n font-size: 24pt;\\n }\\n .menu {\\n bottom: 85px;\\n flex-direction: column-reverse;\\n }\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tif(__webpack_module_cache__[moduleId]) {\n\t\treturn __webpack_module_cache__[moduleId].exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n// the startup function\n// It's empty as some runtime module handles the default behavior\n__webpack_require__.x = x => {}\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => module['default'] :\n\t\t() => module;\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)","__webpack_require__.p = \"dist/\";","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// Promise = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t179: 0\n};\n\nvar deferredModules = [\n\t[7626,779]\n];\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\nvar checkDeferredModules = x => {};\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = (parentChunkLoadingFunction, data) => {\n\tvar [chunkIds, moreModules, runtime, executeModules] = data;\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0, resolves = [];\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tresolves.push(installedChunks[chunkId][0]);\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\tfor(moduleId in moreModules) {\n\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t}\n\t}\n\tif(runtime) runtime(__webpack_require__);\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\twhile(resolves.length) {\n\t\tresolves.shift()();\n\t}\n\n\t// add entry modules from loaded chunk to deferred list\n\tif(executeModules) deferredModules.push.apply(deferredModules, executeModules);\n\n\t// run deferred modules when all chunks ready\n\treturn checkDeferredModules();\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunk\"] = self[\"webpackChunk\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));\n\nfunction checkDeferredModulesImpl() {\n\tvar result;\n\tfor(var i = 0; i < deferredModules.length; i++) {\n\t\tvar deferredModule = deferredModules[i];\n\t\tvar fulfilled = true;\n\t\tfor(var j = 1; j < deferredModule.length; j++) {\n\t\t\tvar depId = deferredModule[j];\n\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferredModules.splice(i--, 1);\n\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n\t\t}\n\t}\n\tif(deferredModules.length === 0) {\n\t\t__webpack_require__.x();\n\t\t__webpack_require__.x = x => {};\n\t}\n\treturn result;\n}\nvar startup = __webpack_require__.x;\n__webpack_require__.x = () => {\n\t// reset startup function so it can be called again when more startup code is added\n\t__webpack_require__.x = startup || (x => {});\n\treturn (checkDeferredModules = checkDeferredModulesImpl)();\n};","// run startup\n__webpack_require__.x();\n"],"sourceRoot":""} \ No newline at end of file diff --git a/index.html b/index.html index 6274fa0..dc31987 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -Hackweek Avatar Maker
\ No newline at end of file +Hackweek Avatar Maker
diff --git a/package.json b/package.json index d93e34b..81d9d66 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,10 @@ "start": "webpack serve", "build": "NODE_ENV=production webpack", "gen-assets": "node scripts/generate-assets.js", - "fix-assets": "node scripts/fix-assets.js" + "fix-assets": "node scripts/fix-assets.js", + "clean-public": "rm -r -f public", + "package-to-public": "npm run clean-public && mkdir public && cp -R dist/ public && cp -R assets public && cp index.html public/", + "build-for-netlify": "npm run build && npm run package-to-public" }, "devDependencies": { "@babel/core": "^7.12.10", diff --git a/src/persistence.js b/src/persistence.js new file mode 100644 index 0000000..c525ece --- /dev/null +++ b/src/persistence.js @@ -0,0 +1,127 @@ +import { useState, useEffect } from 'react' +import { simplePubSub } from "./utils/pub-sub"; + +const storageKey = "avatarMaker"; + +const slotKeyChange = simplePubSub(); + +function getConfigFromLocalStorage() { + const stored = localStorage.getItem(storageKey); + if (stored) { + return JSON.parse(stored); + } else { + return { avatars: {}, uiEnabled: false }; + } +} + +function persistToLocalStorage(config) { + localStorage.setItem(storageKey, JSON.stringify(config)) +} + +/** + * Saves an Avatar config object + * @param {string} slotKey key to store under + * @param {object} avatarConfig Avatar config object to store + */ +export function saveAvatarConfig(slotKey, avatarConfig) { + if (!window.localStorage) { + console.log("No localStorage...bailing."); + } + + const storedConfig = getConfigFromLocalStorage(); + + storedConfig.avatars[slotKey] = avatarConfig; + + persistToLocalStorage(storedConfig); + slotKeyChange.publish(); +} + +/** + * Returns the specified Avatar config object + * @param {string} slotKey The key for the desired Avatar config + * @returns {object} Avatar config + */ +export function getAvatarConfig(slotKey) { + if (!window.localStorage) { + console.log("No localStorage...bailing."); + return {}; + } + + const storedConfig = getConfigFromLocalStorage(); + + return storedConfig.avatars[slotKey]; +} + +/** + * Deletes the specified Avatar config object + * @param {string} slotKey The key for the desired Avatar config + */ +export function deleteAvatarConfig(slotKey) { + if (!window.localStorage) { + console.log("No localStorage...bailing."); + return; + } + + const storedConfig = getConfigFromLocalStorage(); + + delete storedConfig.avatars[slotKey]; + persistToLocalStorage(storedConfig); + slotKeyChange.publish(); +} + +/** + * Returns list of the Avatar slotKeys + * @returns {Array} List of Avatar slotKeys that have stored data. + */ +export function getAvatarConfigSlotKeys() { + if (!window.localStorage) { + console.log("No localStorage...bailing."); + return []; + } + + const storedConfig = getConfigFromLocalStorage(); + + return Object.keys(storedConfig.avatars); +} + +export function avatarPersistenceUIEnabled(newValue) { + + const storedConfig = getConfigFromLocalStorage(); + + if (newValue !== undefined) { + storedConfig.uiEnabled = newValue; + persistToLocalStorage(storedConfig); + } else { + return storedConfig.uiEnabled || true; + } +} + + +// Expose the pieces that need to be reactive +export function usePersistenceUIEnabled() { + const [storedValue, setStoredValue] = useState(avatarPersistenceUIEnabled()); + + const setValue = (value) => { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + avatarPersistenceUIEnabled(valueToStore); + }; + + return [storedValue, setValue]; +} + +export function useAvatarConfigSlotKeys() { + const [slotKeys, setSlotKeys] = useState(getAvatarConfigSlotKeys); + + useEffect(() => { + //Subscribe to changes + const subscriptionId = slotKeyChange + .subscribe(() => setSlotKeys(getAvatarConfigSlotKeys())); + + return function cleanup() { + slotKeyChange.unsubscribe(subscriptionId); + } + }); + + return slotKeys; +} diff --git a/src/react-components/AvatarEditorContainer.js b/src/react-components/AvatarEditorContainer.js index 8fae5f9..07fad9f 100644 --- a/src/react-components/AvatarEditorContainer.js +++ b/src/react-components/AvatarEditorContainer.js @@ -11,6 +11,7 @@ import { generateRandomConfig } from "../generate-random-config"; import initialAssets from "../assets"; import { isThumbnailMode } from "../utils"; import debounce from "../utils/debounce"; +import { avatarPersistenceUIEnabled } from "../persistence"; // Used externally by the generate-thumbnails script const thumbnailMode = isThumbnailMode(); @@ -109,6 +110,9 @@ export function AvatarEditorContainer() { setAvatarConfig(generateRandomConfig(assets)); } + //Ideally this doesn't belong here. Is just here to allow the Saved Avatar display to be disabled. + window.avatarPersistenceUIEnabled = avatarPersistenceUIEnabled; + return ( , buttonTip: , - toolbar: , + toolbar: , }} /> ); diff --git a/src/react-components/AvatarPersistenceContainer.js b/src/react-components/AvatarPersistenceContainer.js new file mode 100644 index 0000000..b46a3de --- /dev/null +++ b/src/react-components/AvatarPersistenceContainer.js @@ -0,0 +1,21 @@ +import React from "react"; +import { usePersistenceUIEnabled } from "../persistence"; + +import { AvatarPersistenceSaved } from "./AvatarPersistenceSaved"; + +export function AvatarPersistenceContainer({ setAvatarConfig, avatarConfig }) { + const [uiEnabled, setUIEnabled] = usePersistenceUIEnabled(); + + if (uiEnabled) { + return ( +
+

Saved Avatars

+ +
+ ) + } else { + return ( + <> + ) + } +} \ No newline at end of file diff --git a/src/react-components/AvatarPersistenceSaveAs.js b/src/react-components/AvatarPersistenceSaveAs.js new file mode 100644 index 0000000..f7e5f47 --- /dev/null +++ b/src/react-components/AvatarPersistenceSaveAs.js @@ -0,0 +1,61 @@ +import React, { useState } from "react"; +import { faSave, faWindowClose } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { saveAvatarConfig } from "../persistence"; + +export function AvatarPersistenceSaveAs({ avatarConfig }) { + const [adding, setAdding] = useState(false); + const [name, setName] = useState(''); + + function openSaveAs() { + setAdding(true); + } + + function cancel() { + setAdding(false); + setName(''); + } + + function cancelOnEscape(e) { + if (e.keyCode === 27) { + cancel(); + } + } + + function save() { + saveAvatarConfig(name, avatarConfig); + setAdding(false); + setName(''); + } + + function saveDisabled() { + return name === ""; + } + + if (adding) { + return ( +
  • +
    + setName(e.target.value)} + onKeyDown={cancelOnEscape} + placeholder="Save Current Avatar as ..."/> +
    +
    + + +
    +
  • + ) + } else { + return ( +
  • + +
  • + ) + } +} \ No newline at end of file diff --git a/src/react-components/AvatarPersistenceSaved.js b/src/react-components/AvatarPersistenceSaved.js new file mode 100644 index 0000000..d89d567 --- /dev/null +++ b/src/react-components/AvatarPersistenceSaved.js @@ -0,0 +1,18 @@ +import React from "react"; +import { useAvatarConfigSlotKeys } from "../persistence"; +import { AvatarPersistenceSavedItem } from "./AvatarPersistenceSavedItem"; +import { AvatarPersistenceSaveAs } from "./AvatarPersistenceSaveAs"; + +export function AvatarPersistenceSaved({ setAvatarConfig, avatarConfig }) { + const avatarConfigSlotKeys = useAvatarConfigSlotKeys(); + const listItems = avatarConfigSlotKeys.map((key) => ( + + )); + + return ( +
      + {listItems} + +
    + ) +} \ No newline at end of file diff --git a/src/react-components/AvatarPersistenceSavedItem.js b/src/react-components/AvatarPersistenceSavedItem.js new file mode 100644 index 0000000..547d9a3 --- /dev/null +++ b/src/react-components/AvatarPersistenceSavedItem.js @@ -0,0 +1,30 @@ +import React, { useLayoutEffect } from "react"; +import { faArrowAltCircleRight, faTrashAlt } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { deleteAvatarConfig, getAvatarConfig } from "../persistence"; + +export function AvatarPersistenceSavedItem({ slotKey, setAvatarConfig }) { + + function loadAvatar() { + setAvatarConfig(getAvatarConfig(slotKey)); + } + + function deleteAvatar() { + deleteAvatarConfig(slotKey); + } + + return ( +
  • +
    {slotKey}
    +
    + + +
    +
  • + ) + +} \ No newline at end of file diff --git a/src/react-components/ToolbarContainer.js b/src/react-components/ToolbarContainer.js index 8aeabed..616abc1 100644 --- a/src/react-components/ToolbarContainer.js +++ b/src/react-components/ToolbarContainer.js @@ -2,6 +2,7 @@ import React from "react"; import { Toolbar } from "./Toolbar"; import { UploadButton } from "./UploadButton"; import { MoreMenu } from "./MoreMenu"; +import { AvatarPersistenceContainer } from "./AvatarPersistenceContainer"; import { dispatch } from "../dispatch"; import constants from "../constants"; @@ -13,7 +14,7 @@ function dispatchExportAvatar() { dispatch(constants.exportAvatar); } -export function ToolbarContainer({ onGLBUploaded, randomizeConfig }) { +export function ToolbarContainer({ onGLBUploaded, randomizeConfig, setAvatarConfig, avatarConfig }) { return ( Hackweek Avatar Maker @@ -21,6 +22,7 @@ export function ToolbarContainer({ onGLBUploaded, randomizeConfig }) { items={ <> + GitHub diff --git a/src/styles.css b/src/styles.css index fcd7056..63b02d1 100644 --- a/src/styles.css +++ b/src/styles.css @@ -278,6 +278,74 @@ button.primary:focus { margin: 10px 0; } +.peristenceContainer { + display: flex; + flex-direction: column; + border-radius: var(--border-radius); + border: 2px solid grey; + width: calc(100% - 6px); + margin-bottom: 8px; + padding: 4px; +} + +.peristenceContainer h2 { + color: grey; + text-align: center; + margin-bottom: 4px; +} + +.peristenceContainer ul { + margin-top: 0; + margin-bottom: 4px; + list-style: none; + padding: 0; + width: 250px; +} + +.peristenceContainer ul li { + display: flex; + justify-content: space-between; + align-items: center; + text-decoration: none; + padding: 4px; + margin-left: -4px; + margin-right: 2px; +} + +.peristenceContainer ul li.saveAs input { + width: 150px; +} + +.peristenceContainer ul li:not(.saveAs):hover { + background-color: lightgrey; +} + +.peristenceContainer ul li .savedItemAction { + padding: 4px 8px; +} + +.peristenceContainer ul li .savedItemAction:last-of-type { + margin-right: 0; +} + +.peristenceContainer ul li.saveAs.closed { + justify-content: center; +} + +.peristenceContainer ul li.saveAs.closed button { + border-radius: 8px; + padding: 4px 22px; +} + +.peristenceContainer button:disabled { + border-color: #d3d3d3a4; + color: #d3d3d3a4; +} + +.peristenceContainer button:disabled:hover { + background-color: white; +} + @keyframes wave { from { background-position-y: 0 } to { background-position-y: 400px; } diff --git a/src/utils/pub-sub.js b/src/utils/pub-sub.js new file mode 100644 index 0000000..74f069a --- /dev/null +++ b/src/utils/pub-sub.js @@ -0,0 +1,36 @@ + +/** + * Super simple PubSub construct with no topics and no value passing (because they weren't required) + * @returns PubSub instance + */ + export function simplePubSub() { + const subs = []; + var currSubIndex = -1; + + return { + /** + * Registers a handler to be fired by publish + * @param {Function} handler to be called + * @returns index to use to unsubscribe + */ + subscribe(handler) { + subs[++currSubIndex] = handler; + return currSubIndex; + }, + + /** + * Fire all subscription handlers + */ + publish() { + subs.forEach((sub) => sub()); + }, + + /** + * Removes specified handler + * @param {number} index provided by subscribe + */ + unsubscribe(index) { + delete subs[index]; + } + } +} \ No newline at end of file