roavatar-renderer 1.6.3 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,7 @@ Basic example on how to load an avatar using OutfitRenderer (to make it simpler)
27
27
  FLAGS.RIG_PATH = chrome.runtime.getURL("assets/")
28
28
  }
29
29
  //if layered assets dont work set this to false (workers improve performance)
30
+ //or set FLAGS.GET_WORKER_FUNC to a working function, check source for example
30
31
  FLAGS.USE_WORKERS = true
31
32
 
32
33
  //setup RBXRenderer
@@ -44,19 +45,23 @@ Basic example on how to load an avatar using OutfitRenderer (to make it simpler)
44
45
  //add renderer to document
45
46
  document.body.appendChild(RBXRenderer.getRendererElement())
46
47
 
47
- //get avatar data for the user with id 1
48
- const outfit = await API.Avatar.GetAvatarDetails(1)
49
- if (!(outfit instanceof Outfit)) throw new Error("Failed to get outfit")
48
+ //get the OutfitModel for the user with id 1
49
+ const outfitModel = await API.Avatar.GetUserAvatarModel(1)
50
+ if (!(outfitModel instanceof OutfitModel)) throw new Error("Failed to get outfitModel")
50
51
 
51
52
  //create renderer for outfit
52
53
  //used by api
53
54
  const auth = new Authentication()
54
55
  //manages outfit rendering for you
55
- const outfitRenderer = new OutfitRenderer(auth, outfit)
56
+ const outfitRenderer = new OutfitRenderer(auth, outfitModel)
56
57
  outfitRenderer.startAnimating()
57
58
  outfitRenderer.setMainAnimation("idle")
58
59
  ```
59
60
  **RESULT:**
60
61
  <img src="https://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/5X/9/f/a/d/9fadf25d9770b63e8a2e480369930cad94ad04aa.png">
61
62
 
62
- Also the OutfitRenderer code or RoAvatar source code is useful, especially ```avatarPreview.ts```
63
+ For more code examples check out the OutfitRenderer, BackgroundRenderer, RoAvatar (avatarPreview.tsx) or RoValra (ItemRender.ts) source code
64
+
65
+ For a live renderer example on a website check out https://roavatar.net
66
+
67
+ There is also a discord server you can ask for help in: https://discord.gg/PHa5Vgtbva
package/dist/index.d.ts CHANGED
@@ -404,6 +404,7 @@ export declare const API: {
404
404
  GetUserLooks: (userId: number, cursor?: string) => Promise<Response | UserLooks_Result>;
405
405
  CreateLook: (auth: Authentication, outfit: Outfit, name: string, description: string) => Promise<Response>;
406
406
  DeleteLook: (auth: Authentication, lookId: string) => Promise<Response>;
407
+ PatchLook: (auth: Authentication, lookId: string, data: Partial<Look_Result["look"]>) => Promise<Response>;
407
408
  };
408
409
  PremiumFeatures: {
409
410
  GetSubscription: (userId: number) => Promise<Response | GetSubscription_Result>;
@@ -685,6 +686,10 @@ export declare function awaitTimeout<T>(promise: Promise<T>, time?: number): Pro
685
686
  */
686
687
  export declare function awaitTimeoutThrows<T>(promise: Promise<T>, time?: number): Promise<T>;
687
688
 
689
+ /**
690
+ * Used internally by OutfitRenderer to render backgrounds
691
+ * @category Renderer
692
+ */
688
693
  export declare class BackgroundRenderer {
689
694
  auth: Authentication;
690
695
  avatarCyclorama?: Instance;
@@ -1576,6 +1581,8 @@ export declare const FLAGS: {
1576
1581
  API_REQUEST_RETRY: boolean;
1577
1582
  /**the fetch function the api will use */
1578
1583
  FETCH_FUNC: ((input: URL | RequestInfo, init?: RequestInit) => Promise<Response>) | undefined;
1584
+ /**a function all image urls will go through before being loaded, the return value is the new image url */
1585
+ IMAGE_FUNC: ((input: string) => Promise<string>) | undefined;
1579
1586
  /**loads assets from assetdelivery instead of local files */
1580
1587
  ONLINE_ASSETS: boolean;
1581
1588
  /**path to rbxasset:// local files*/
@@ -1739,6 +1746,14 @@ export declare function gaussian_rbf(v0: Vec3, v1: Vec3, sigma?: number): number
1739
1746
  */
1740
1747
  export declare function generateModelThumbnail(auth: Authentication, renderScene: RBXRendererScene, model: Instance, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean, includeAnimations?: boolean): Promise<ThumbnailResult>;
1741
1748
 
1749
+ /**
1750
+ * @deprecated This has the exact same behavior as generateOutfitThumbnail which also supports outfitModels
1751
+ * @category ThumbnailGenerator
1752
+ * @param auth
1753
+ * @param outfitModel
1754
+ * @param options
1755
+ * @returns
1756
+ */
1742
1757
  export declare function generateOutfitModelThumbnail(auth: Authentication, outfitModel: OutfitModel, options: Partial<OutfitModelThumbnailOptions>): Promise<ThumbnailResult>;
1743
1758
 
1744
1759
  /**
@@ -1751,7 +1766,6 @@ export declare function generateOutfitModelThumbnail(auth: Authentication, outfi
1751
1766
  * @param gltfAutoDownload Automatically download gltf file
1752
1767
  * @returns ThumbnailResult, always a string for 2d thumbnails, 3d can be ArrayBuffer (glb, binary) or {[key: string]: unknown} (gltf, json)
1753
1768
  *
1754
- * @deprecated Use new Thumbnails category instead
1755
1769
  * @category ThumbnailGenerator
1756
1770
  *
1757
1771
  * @example
@@ -2012,7 +2026,7 @@ export declare class HumanoidDescriptionWrapper extends InstanceWrapper {
2012
2026
  getAccessoryIds(): bigint[];
2013
2027
  getAccessoryDescriptionWithId(id: bigint): Instance | undefined;
2014
2028
  getBodyPartDescription(bodyPart: number): Instance | undefined;
2015
- getBodyPartColor(bodyPart: number): Color3;
2029
+ getBodyPartColor(bodyPart: number): Color3 | undefined;
2016
2030
  setBodyPartId(bodyPart: number, id: bigint): void;
2017
2031
  setBodyPartHeadShape(bodyPart: number, headShape: string): void;
2018
2032
  getBodyPartId(bodyPart: number): bigint;
@@ -2892,6 +2906,8 @@ export declare function offsetMesh(mesh: FileMesh, cframe: CFrame): void;
2892
2906
  export declare function offsetMeshWithRotation(mesh: FileMesh, cframe: CFrame): void;
2893
2907
 
2894
2908
  /**
2909
+ * It is recommended to use an OutfitModel that contains an Outfit instead of using an Outfit directly as they cannot contain things such as avatar backgrounds
2910
+ *
2895
2911
  * Usually obtained from API
2896
2912
  * @category Outfit
2897
2913
  */
@@ -2955,7 +2971,7 @@ export declare class Outfit {
2955
2971
  getNextOrder(order: number): number;
2956
2972
  addAssetId(assetId: number, auth: Authentication): Promise<boolean>;
2957
2973
  addAssetIdEconomy(assetId: number): Promise<boolean>;
2958
- addBundleId(bundleId: number): Promise<boolean>;
2974
+ addBundleId(bundleId: number, auth?: Authentication): Promise<boolean>;
2959
2975
  getAssetId(assetId: number): Asset | undefined;
2960
2976
  fromLook(look: Look_Result["look"], auth: Authentication): Promise<boolean>;
2961
2977
  fromBuffer(buffer: ArrayBuffer, auth: Authentication): Promise<Response | Outfit>;
@@ -2979,6 +2995,10 @@ export declare type OutfitJson = {
2979
2995
  scales?: ScaleJson;
2980
2996
  };
2981
2997
 
2998
+ /**
2999
+ * Usually obtained from API, not to be confused with Outfit which cannot contain things such as backgrounds
3000
+ * @category Outfit
3001
+ */
2982
3002
  export declare class OutfitModel {
2983
3003
  outfit: Outfit;
2984
3004
  emotes: Map<number, Asset>;
@@ -3658,12 +3678,12 @@ declare class RenderDesc extends DisposableDesc {
3658
3678
  compiled: boolean;
3659
3679
  failed: boolean;
3660
3680
  constructor(renderScene: RBXRendererScene);
3661
- isSame(_other: RenderDesc): boolean;
3662
- needsRegeneration(_other: RenderDesc): boolean;
3663
- fromRenderDesc(other: RenderDesc): void;
3664
- transferFrom(other: RenderDesc): void;
3665
- virtualTransferFrom(_other: RenderDesc): void;
3666
- virtualFromRenderDesc(_other: RenderDesc): void;
3681
+ isSame(_newDesc: RenderDesc): boolean;
3682
+ needsRegeneration(_newDesc: RenderDesc): boolean;
3683
+ fromRenderDesc(newDesc: RenderDesc): void;
3684
+ transferFrom(oldDesc: RenderDesc): void;
3685
+ virtualTransferFrom(_oldDesc: RenderDesc): void;
3686
+ virtualFromRenderDesc(_newDesc: RenderDesc): void;
3667
3687
  fromInstance(_child: Instance): void;
3668
3688
  compileResults(_renderer: THREE.WebGLRenderer, _scene: THREE.Scene): Promise<THREE.Object3D[] | Response | undefined>;
3669
3689
  updateResults(): void;
@@ -3985,6 +4005,9 @@ declare type ThreePoseCorrective = Vec3;
3985
4005
  * @category ThumbnailGenerator */
3986
4006
  export declare type ThumbnailCameraType = "default" | "avatarHeadshot" | "avatarFullbody" | "fullbody";
3987
4007
 
4008
+ /**
4009
+ * @category Outfit
4010
+ */
3988
4011
  export declare class ThumbnailCustomization {
3989
4012
  thumbnailType: number;
3990
4013
  emoteAssetId: number;
package/dist/index.js CHANGED
@@ -22,6 +22,275 @@ function cloneSearch_Payload(data) {
22
22
  return newData;
23
23
  }
24
24
  const AllAvatarModelOutfitUpdateTypes = ["UpdateBodyColors", "UpdateAssets", "UpdateAvatarType", "UpdateScales", "UpdateBackground"];
25
+ const AssetTypes = [
26
+ "",
27
+ "Image",
28
+ "TShirt",
29
+ "Audio",
30
+ "Mesh",
31
+ "Lua",
32
+ "HTML",
33
+ "Text",
34
+ "Hat",
35
+ "Place",
36
+ "Model",
37
+ "Shirt",
38
+ "Pants",
39
+ "Decal",
40
+ "",
41
+ "",
42
+ "Avatar",
43
+ "Head",
44
+ "Face",
45
+ "Gear",
46
+ "",
47
+ "Badge",
48
+ "GroupEmblem",
49
+ "",
50
+ "Animation",
51
+ "Arms",
52
+ "Legs",
53
+ "Torso",
54
+ "RightArm",
55
+ "LeftArm",
56
+ "LeftLeg",
57
+ "RightLeg",
58
+ "Package",
59
+ "YouTubeVideo",
60
+ "GamePass",
61
+ "App",
62
+ "",
63
+ "Code",
64
+ "Plugin",
65
+ "SolidModel",
66
+ "MeshPart",
67
+ "HairAccessory",
68
+ "FaceAccessory",
69
+ "NeckAccessory",
70
+ "ShoulderAccessory",
71
+ "FrontAccessory",
72
+ "BackAccessory",
73
+ "WaistAccessory",
74
+ "ClimbAnimation",
75
+ "DeathAnimation",
76
+ "FallAnimation",
77
+ "IdleAnimation",
78
+ "JumpAnimation",
79
+ "RunAnimation",
80
+ "SwimAnimation",
81
+ "WalkAnimation",
82
+ "PoseAnimation",
83
+ "",
84
+ "",
85
+ "LocalizationTableManifest",
86
+ "LocalizationTableTranslation",
87
+ "EmoteAnimation",
88
+ "Video",
89
+ "TexturePack",
90
+ "TShirtAccessory",
91
+ "ShirtAccessory",
92
+ "PantsAccessory",
93
+ "JacketAccessory",
94
+ "SweaterAccessory",
95
+ "ShortsAccessory",
96
+ "LeftShoeAccessory",
97
+ "RightShoeAccessory",
98
+ "DressSkirtAccessory",
99
+ "FontFamily",
100
+ "FontFace",
101
+ "MeshHiddenSurfaceRemoval",
102
+ "EyebrowAccessory",
103
+ "EyelashAccessory",
104
+ "MoodAnimation",
105
+ "DynamicHead",
106
+ //79
107
+ "CodeSnippet",
108
+ "AdsVideo",
109
+ "OtaUpdate",
110
+ "Screenshot",
111
+ "RuntimePropertySet",
112
+ "StorePreviewVideo",
113
+ "GamePreviewVideo",
114
+ "CreatorExperienceConfig",
115
+ "FaceMakeup",
116
+ "LipMakeup",
117
+ "EyeMakeup",
118
+ "VoxelFragment",
119
+ "AvatarBackground",
120
+ "TextDocument"
121
+ ];
122
+ const WearableAssetTypes = [
123
+ "TShirt",
124
+ "Hat",
125
+ "Shirt",
126
+ "Pants",
127
+ "Head",
128
+ "Face",
129
+ "Gear",
130
+ "Torso",
131
+ "RightArm",
132
+ "LeftArm",
133
+ "LeftLeg",
134
+ "RightLeg",
135
+ "HairAccessory",
136
+ "FaceAccessory",
137
+ "NeckAccessory",
138
+ "ShoulderAccessory",
139
+ "FrontAccessory",
140
+ "BackAccessory",
141
+ "WaistAccessory",
142
+ "ClimbAnimation",
143
+ "FallAnimation",
144
+ "IdleAnimation",
145
+ "JumpAnimation",
146
+ "RunAnimation",
147
+ "SwimAnimation",
148
+ "WalkAnimation",
149
+ "TShirtAccessory",
150
+ "ShirtAccessory",
151
+ "PantsAccessory",
152
+ "JacketAccessory",
153
+ "SweaterAccessory",
154
+ "ShortsAccessory",
155
+ "LeftShoeAccessory",
156
+ "RightShoeAccessory",
157
+ "DressSkirtAccessory",
158
+ "EyebrowAccessory",
159
+ "EyelashAccessory",
160
+ "MoodAnimation",
161
+ "DynamicHead",
162
+ "FaceMakeup",
163
+ "LipMakeup",
164
+ "EyeMakeup",
165
+ "PoseAnimation",
166
+ "EarAccessory",
167
+ "EyeAccessory",
168
+ "DeathAnimation"
169
+ ];
170
+ const AccessoryAssetTypes = [
171
+ "Hat",
172
+ "HairAccessory",
173
+ "FaceAccessory",
174
+ "NeckAccessory",
175
+ "ShoulderAccessory",
176
+ "FrontAccessory",
177
+ "BackAccessory",
178
+ "WaistAccessory"
179
+ ];
180
+ const LayeredAssetTypes = [
181
+ "TShirtAccessory",
182
+ "ShirtAccessory",
183
+ "PantsAccessory",
184
+ "JacketAccessory",
185
+ "SweaterAccessory",
186
+ "ShortsAccessory",
187
+ "LeftShoeAccessory",
188
+ "RightShoeAccessory",
189
+ "DressSkirtAccessory",
190
+ "EyebrowAccessory",
191
+ "EyelashAccessory",
192
+ "HairAccessory",
193
+ "FaceMakeup",
194
+ "LipMakeup",
195
+ "EyeMakeup"
196
+ ];
197
+ const SpecialLayeredAssetTypes = [
198
+ "EyebrowAccessory",
199
+ "EyelashAccessory",
200
+ "HairAccessory"
201
+ ];
202
+ const MaxOneOfAssetTypes = [
203
+ "TShirt",
204
+ "Shirt",
205
+ "Pants",
206
+ "Head",
207
+ "Face",
208
+ "Gear",
209
+ "Torso",
210
+ "RightArm",
211
+ "LeftArm",
212
+ "LeftLeg",
213
+ "RightLeg",
214
+ "ClimbAnimation",
215
+ "DeathAnimation",
216
+ "FallAnimation",
217
+ "IdleAnimation",
218
+ "JumpAnimation",
219
+ "RunAnimation",
220
+ "SwimAnimation",
221
+ "WalkAnimation",
222
+ "PoseAnimation",
223
+ "MoodAnimation",
224
+ "DynamicHead",
225
+ "EyebrowAccessory",
226
+ "EyelashAccessory"
227
+ ];
228
+ const ToRemoveBeforeBundleType = {
229
+ "DynamicHead": ["MoodAnimation", "DynamicHead", "EyebrowAccessory", "EyelashAccessory", "Head"],
230
+ "Shoes": ["LeftShoeAccessory", "RightShoeAccessory"],
231
+ "AnimationPack": [
232
+ "ClimbAnimation",
233
+ "DeathAnimation",
234
+ "FallAnimation",
235
+ "IdleAnimation",
236
+ "JumpAnimation",
237
+ "RunAnimation",
238
+ "SwimAnimation",
239
+ "WalkAnimation",
240
+ "PoseAnimation",
241
+ "MoodAnimation"
242
+ ],
243
+ "Character": [
244
+ "DynamicHead",
245
+ "Head",
246
+ "Torso",
247
+ "LeftArm",
248
+ "RightArm",
249
+ "LeftLeg",
250
+ "RightLeg"
251
+ ],
252
+ "MakeupLook": [
253
+ "FaceMakeup",
254
+ "EyeMakeup",
255
+ "LipMakeup",
256
+ "EyebrowAccessory",
257
+ "EyelashAccessory"
258
+ ]
259
+ };
260
+ const AssetTypeNameToId = /* @__PURE__ */ new Map();
261
+ for (let i = 0; i < AssetTypes.length; i++) {
262
+ const name = AssetTypes[i];
263
+ AssetTypeNameToId.set(name, i);
264
+ }
265
+ const ActualBundleTypes = [
266
+ //names used by Roblox
267
+ "",
268
+ "Avatar",
269
+ //traditional bundle
270
+ "DynamicHead",
271
+ "Avatar",
272
+ //outfit
273
+ "Shoes",
274
+ "Avatar"
275
+ //animation pack
276
+ ];
277
+ const BundleTypes = [
278
+ "",
279
+ "Character",
280
+ "DynamicHead",
281
+ "Outfit",
282
+ "Shoes",
283
+ "AnimationPack",
284
+ "",
285
+ "MakeupLook"
286
+ ];
287
+ const CatalogBundleTypes = [
288
+ "",
289
+ "Character",
290
+ "AnimationPack",
291
+ "Shoes",
292
+ "DynamicHead"
293
+ ];
25
294
  const BrickColors = {
26
295
  1: "#F2F3F3",
27
296
  2: "#A1A5A2",
@@ -338,7 +607,9 @@ const MaxPerAsset = {
338
607
  "WalkAnimation": 1,
339
608
  "LayeredClothing": 5,
340
609
  //group type
341
- "MoodAnimation": 1
610
+ "MoodAnimation": 1,
611
+ "EyebrowAccessory": 1,
612
+ "EyelashAccessory": 1
342
613
  };
343
614
  const OutfitOrigin = {
344
615
  "WebAvatar": "WebAvatar",
@@ -32408,7 +32679,7 @@ function nearestSearch(node, target, best = { dist: Infinity, index: -1 }) {
32408
32679
  }
32409
32680
  return best;
32410
32681
  }
32411
- const jsContent = '(function() {\n "use strict";\n new TextDecoder();\n new TextDecoder();\n const FullBodyColorPalette = [\n {\n "brickColorId": 361,\n "hexColor": "#564236",\n "name": "Dirt brown"\n },\n {\n "brickColorId": 192,\n "hexColor": "#694028",\n "name": "Reddish brown"\n },\n {\n "brickColorId": 217,\n "hexColor": "#7C5C46",\n "name": "Brown"\n },\n {\n "brickColorId": 153,\n "hexColor": "#957977",\n "name": "Sand red"\n },\n {\n "brickColorId": 359,\n "hexColor": "#AF9483",\n "name": "Linen"\n },\n {\n "brickColorId": 352,\n "hexColor": "#C7AC78",\n "name": "Burlap"\n },\n {\n "brickColorId": 5,\n "hexColor": "#D7C59A",\n "name": "Brick yellow"\n },\n {\n "brickColorId": 101,\n "hexColor": "#DA867A",\n "name": "Medium red"\n },\n {\n "brickColorId": 1007,\n "hexColor": "#A34B4B",\n "name": "Dusty Rose"\n },\n {\n "brickColorId": 1014,\n "hexColor": "#AA5500",\n "name": "CGA brown"\n },\n {\n "brickColorId": 38,\n "hexColor": "#A05F35",\n "name": "Dark orange"\n },\n {\n "brickColorId": 18,\n "hexColor": "#CC8E69",\n "name": "Nougat"\n },\n {\n "brickColorId": 125,\n "hexColor": "#EAB892",\n "name": "Light orange"\n },\n {\n "brickColorId": 1030,\n "hexColor": "#FFCC99",\n "name": "Pastel brown"\n },\n {\n "brickColorId": 133,\n "hexColor": "#D5733D",\n "name": "Neon orange"\n },\n {\n "brickColorId": 106,\n "hexColor": "#DA8541",\n "name": "Bright orange"\n },\n {\n "brickColorId": 105,\n "hexColor": "#E29B40",\n "name": "Br. yellowish orange"\n },\n {\n "brickColorId": 1017,\n "hexColor": "#FFAF00",\n "name": "Deep orange"\n },\n {\n "brickColorId": 24,\n "hexColor": "#F5CD30",\n "name": "Bright yellow"\n },\n {\n "brickColorId": 334,\n "hexColor": "#F8D96D",\n "name": "Daisy orange"\n },\n {\n "brickColorId": 226,\n "hexColor": "#FDEA8D",\n "name": "Cool yellow"\n },\n {\n "brickColorId": 141,\n "hexColor": "#27462D",\n "name": "Earth green"\n },\n {\n "brickColorId": 1021,\n "hexColor": "#3A7D15",\n "name": "Camo"\n },\n {\n "brickColorId": 28,\n "hexColor": "#287F47",\n "name": "Dark green"\n },\n {\n "brickColorId": 37,\n "hexColor": "#4B974B",\n "name": "Bright green"\n },\n {\n "brickColorId": 310,\n "hexColor": "#5B9A4C",\n "name": "Shamrock"\n },\n {\n "brickColorId": 317,\n "hexColor": "#7C9C6B",\n "name": "Moss"\n },\n {\n "brickColorId": 119,\n "hexColor": "#A4BD47",\n "name": "Br. yellowish green"\n },\n {\n "brickColorId": 1011,\n "hexColor": "#002060",\n "name": "Navy blue"\n },\n {\n "brickColorId": 1012,\n "hexColor": "#2154B9",\n "name": "Deep blue"\n },\n {\n "brickColorId": 1010,\n "hexColor": "#0000FF",\n "name": "Really blue"\n },\n {\n "brickColorId": 23,\n "hexColor": "#0D69AC",\n "name": "Bright blue"\n },\n {\n "brickColorId": 305,\n "hexColor": "#527CAE",\n "name": "Steel blue"\n },\n {\n "brickColorId": 102,\n "hexColor": "#6E99CA",\n "name": "Medium blue"\n },\n {\n "brickColorId": 45,\n "hexColor": "#B4D2E4",\n "name": "Light blue"\n },\n {\n "brickColorId": 107,\n "hexColor": "#008F9C",\n "name": "Bright bluish green"\n },\n {\n "brickColorId": 1018,\n "hexColor": "#12EED4",\n "name": "Teal"\n },\n {\n "brickColorId": 1027,\n "hexColor": "#9FF3E9",\n "name": "Pastel blue-green"\n },\n {\n "brickColorId": 1019,\n "hexColor": "#00FFFF",\n "name": "Toothpaste"\n },\n {\n "brickColorId": 1013,\n "hexColor": "#04AFEC",\n "name": "Cyan"\n },\n {\n "brickColorId": 11,\n "hexColor": "#80BBDC",\n "name": "Pastel Blue"\n },\n {\n "brickColorId": 1024,\n "hexColor": "#AFDDFF",\n "name": "Pastel light blue"\n },\n {\n "brickColorId": 104,\n "hexColor": "#6B327C",\n "name": "Bright violet"\n },\n {\n "brickColorId": 1023,\n "hexColor": "#8C5B9F",\n "name": "Lavender"\n },\n {\n "brickColorId": 321,\n "hexColor": "#A75E9B",\n "name": "Lilac"\n },\n {\n "brickColorId": 1015,\n "hexColor": "#AA00AA",\n "name": "Magenta"\n },\n {\n "brickColorId": 1031,\n "hexColor": "#6225D1",\n "name": "Royal purple"\n },\n {\n "brickColorId": 1006,\n "hexColor": "#B480FF",\n "name": "Alder"\n },\n {\n "brickColorId": 1026,\n "hexColor": "#B1A7FF",\n "name": "Pastel violet"\n },\n {\n "brickColorId": 21,\n "hexColor": "#C4281C",\n "name": "Bright red"\n },\n {\n "brickColorId": 1004,\n "hexColor": "#FF0000",\n "name": "Really red"\n },\n {\n "brickColorId": 1032,\n "hexColor": "#FF00BF",\n "name": "Hot pink"\n },\n {\n "brickColorId": 1016,\n "hexColor": "#FF66CC",\n "name": "Pink"\n },\n {\n "brickColorId": 330,\n "hexColor": "#FF98DC",\n "name": "Carnation pink"\n },\n {\n "brickColorId": 9,\n "hexColor": "#E8BAC8",\n "name": "Light reddish violet"\n },\n {\n "brickColorId": 1025,\n "hexColor": "#FFC9C9",\n "name": "Pastel orange"\n },\n {\n "brickColorId": 364,\n "hexColor": "#5A4C42",\n "name": "Dark taupe"\n },\n {\n "brickColorId": 351,\n "hexColor": "#BC9B5D",\n "name": "Cork"\n },\n {\n "brickColorId": 1008,\n "hexColor": "#C1BE42",\n "name": "Olive"\n },\n {\n "brickColorId": 29,\n "hexColor": "#A1C48C",\n "name": "Medium green"\n },\n {\n "brickColorId": 1022,\n "hexColor": "#7F8E64",\n "name": "Grime"\n },\n {\n "brickColorId": 151,\n "hexColor": "#789082",\n "name": "Sand green"\n },\n {\n "brickColorId": 135,\n "hexColor": "#74869D",\n "name": "Sand blue"\n },\n {\n "brickColorId": 1020,\n "hexColor": "#00FF00",\n "name": "Lime green"\n },\n {\n "brickColorId": 1028,\n "hexColor": "#CCFFCC",\n "name": "Pastel green"\n },\n {\n "brickColorId": 1009,\n "hexColor": "#FFFF00",\n "name": "New Yeller"\n },\n {\n "brickColorId": 1029,\n "hexColor": "#FFFFCC",\n "name": "Pastel yellow"\n },\n {\n "brickColorId": 1003,\n "hexColor": "#111111",\n "name": "Really black"\n },\n {\n "brickColorId": 26,\n "hexColor": "#1B2A35",\n "name": "Black"\n },\n {\n "brickColorId": 199,\n "hexColor": "#635F62",\n "name": "Dark stone grey"\n },\n {\n "brickColorId": 194,\n "hexColor": "#A3A2A5",\n "name": "Medium stone grey"\n },\n {\n "brickColorId": 1002,\n "hexColor": "#CDCDCD",\n "name": "Mid gray"\n },\n {\n "brickColorId": 208,\n "hexColor": "#E5E4DF",\n "name": "Light stone grey"\n },\n {\n "brickColorId": 1,\n "hexColor": "#F2F3F3",\n "name": "White"\n },\n {\n "brickColorId": 1001,\n "hexColor": "#F8F8F8",\n "name": "Institutional white"\n }\n ];\n const RegularBodyColors = [\n "5A4C42",\n "7C5C46",\n "AF9483",\n "CC8E69",\n "EAB892",\n "564236",\n "694028",\n "BC9B5D",\n "c7ac78",\n "d7c59a",\n "957977",\n "a34b4b",\n "da867a",\n "ffc9c9",\n "ff98dc",\n "74869d",\n "527cae",\n "80bbdc",\n "b1a7ff",\n "a75e9b",\n "008f9c",\n "5b9a4c",\n "7c9c6b",\n "a1c48c",\n "e29b40",\n "f5cd30",\n "f8d96d",\n "635f62",\n "cdcdcd",\n "f8f8f8"\n ];\n for (let i = 0; i < RegularBodyColors.length; i++) {\n const color = RegularBodyColors[i];\n RegularBodyColors[i] = color.toUpperCase();\n }\n const FullBodyColors = [];\n for (const colorDetails of FullBodyColorPalette) {\n FullBodyColors.push(colorDetails.hexColor.substring(1));\n }\n function calculateMagnitude3D(x, y, z) {\n return Math.sqrt(x * x + y * y + z * z);\n }\n function magnitude(v) {\n return calculateMagnitude3D(v[0], v[1], v[2]);\n }\n function minus(v0, v1) {\n return [v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2]];\n }\n function distance(v0, v1) {\n return magnitude(minus(v1, v0));\n }\n class KDNode {\n point;\n index;\n axis;\n left = null;\n right = null;\n constructor(point, index, axis) {\n this.point = point;\n this.index = index;\n this.axis = axis;\n }\n }\n function buildKDTree(points, indices, depth = 0) {\n if (points.length === 0) return null;\n const axis = depth % 3;\n const sorted = points.map((p, i) => ({ p, index: indices[i] })).sort((a, b) => a.p[axis] - b.p[axis]);\n const mid = Math.floor(sorted.length / 2);\n const node = new KDNode(sorted[mid].p, sorted[mid].index, axis);\n const leftPoints = sorted.slice(0, mid).map((x) => x.p);\n const leftIndices = sorted.slice(0, mid).map((x) => x.index);\n const rightPoints = sorted.slice(mid + 1).map((x) => x.p);\n const rightIndices = sorted.slice(mid + 1).map((x) => x.index);\n node.left = buildKDTree(leftPoints, leftIndices, depth + 1);\n node.right = buildKDTree(rightPoints, rightIndices, depth + 1);\n return node;\n }\n function siftUp(heap, i) {\n while (i > 0) {\n const p = i - 1 >> 1;\n if (heap[p].dist >= heap[i].dist) break;\n const tmp = heap[p];\n heap[p] = heap[i];\n heap[i] = tmp;\n i = p;\n }\n }\n function siftDown(heap, i) {\n const n = heap.length;\n while (true) {\n let largest = i;\n const l = (i << 1) + 1;\n const r = l + 1;\n if (l < n && heap[l].dist > heap[largest].dist) largest = l;\n if (r < n && heap[r].dist > heap[largest].dist) largest = r;\n if (largest === i) break;\n const tmp = heap[i];\n heap[i] = heap[largest];\n heap[largest] = tmp;\n i = largest;\n }\n }\n function heapPushMax(heap, item, k) {\n if (heap.length < k) {\n heap.push(item);\n siftUp(heap, heap.length - 1);\n return;\n }\n if (item.dist >= heap[0].dist) return;\n heap[0] = item;\n siftDown(heap, 0);\n }\n function distSq(a, b) {\n const dx = a[0] - b[0];\n const dy = a[1] - b[1];\n const dz = a[2] - b[2];\n return dx * dx + dy * dy + dz * dz;\n }\n function knnSearch(node, target, k, heap = []) {\n if (!node) return heap;\n const axis = node.axis;\n const dist = distSq(target, node.point);\n heapPushMax(heap, { dist, index: node.index }, k);\n const diff = target[axis] - node.point[axis];\n const primary = diff < 0 ? node.left : node.right;\n const secondary = diff < 0 ? node.right : node.left;\n knnSearch(primary, target, k, heap);\n const worstDist = heap.length < k ? Infinity : heap[0].dist;\n if (diff * diff < worstDist) {\n knnSearch(secondary, target, k, heap);\n }\n if (node === null) {\n heap.sort((a, b) => a.dist - b.dist);\n }\n return heap;\n }\n function nearestSearch(node, target, best = { dist: Infinity, index: -1 }) {\n if (!node) return best;\n const dist = distance(target, node.point);\n if (dist < best.dist) {\n best = { dist, index: node.index };\n }\n const axis = node.axis;\n const diff = target[axis] - node.point[axis];\n const primary = diff < 0 ? node.left : node.right;\n const secondary = diff < 0 ? node.right : node.left;\n best = nearestSearch(primary, target, best);\n if (Math.abs(diff) < best.dist) {\n best = nearestSearch(secondary, target, best);\n }\n return best;\n }\n function luDecompose(A) {\n const n = A.length;\n const LU = A;\n const P = new Int32Array(n);\n for (let i = 0; i < n; i++) P[i] = i;\n for (let k = 0; k < n; k++) {\n let pivot = k;\n for (let i = k + 1; i < n; i++) {\n if (Math.abs(LU[i][k]) > Math.abs(LU[pivot][k])) {\n pivot = i;\n }\n }\n if (pivot !== k) {\n const tmpRow = LU[k];\n LU[k] = LU[pivot];\n LU[pivot] = tmpRow;\n const tmpP = P[k];\n P[k] = P[pivot];\n P[pivot] = tmpP;\n }\n const pivotVal = LU[k][k];\n for (let i = k + 1; i < n; i++) {\n LU[i][k] /= pivotVal;\n const mult = LU[i][k];\n const rowI = LU[i];\n const rowK = LU[k];\n for (let j = k + 1; j < n; j++) {\n rowI[j] -= mult * rowK[j];\n }\n }\n }\n return { LU, P };\n }\n function luSolve({ LU, P }, b) {\n const n = LU.length;\n const x = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n x[i] = b[P[i]];\n }\n for (let i = 0; i < n; i++) {\n const row = LU[i];\n let sum = x[i];\n for (let j = 0; j < i; j++) {\n sum -= row[j] * x[j];\n }\n x[i] = sum;\n }\n for (let i = n - 1; i >= 0; i--) {\n const row = LU[i];\n let sum = x[i];\n for (let j = i + 1; j < n; j++) {\n sum -= row[j] * x[j];\n }\n x[i] = sum / row[i];\n }\n return x;\n }\n function patchRBFWorkerFunc([_A, _bx, _by, _bz]) {\n const A = _A.map((r) => new Float32Array(r));\n const bx = new Float32Array(_bx);\n const by = new Float32Array(_by);\n const bz = new Float32Array(_bz);\n const LU = luDecompose(A);\n const wx = luSolve(LU, bx);\n const wy = luSolve(LU, by);\n const wz = luSolve(LU, bz);\n const n = wx.length;\n const result = new Float32Array(n * 3);\n for (let i = 0; i < n; i++) {\n result[i * 3 + 0] = wx[i];\n result[i * 3 + 1] = wy[i];\n result[i * 3 + 2] = wz[i];\n }\n return result.buffer;\n }\n function RBFDeformerSolveAsync([patchCount, detailsCount, epsilon, importantIndicesBuf, refVertsBuf, distVertsBuf, meshVertsBuf, meshBonesBuf]) {\n const importantIndices = new Uint16Array(importantIndicesBuf);\n const refVerts = new Float32Array(refVertsBuf);\n const distVerts = new Float32Array(distVertsBuf);\n const meshVerts = new Float32Array(meshVertsBuf);\n const meshBones = new Float32Array(meshBonesBuf);\n const refCount = refVerts.length / 3;\n const meshVertCount = meshVerts.length / 3;\n const meshBoneCount = meshBones.length / 3;\n const points = new Array(refCount);\n const indices = new Array(refCount);\n for (let i = 0; i < refCount; i++) {\n const refPos = [refVerts[i * 3 + 0], refVerts[i * 3 + 1], refVerts[i * 3 + 2]];\n points[i] = refPos;\n indices[i] = i;\n }\n const controlKD = buildKDTree(points, indices);\n const step = Math.max(1, Math.floor(refCount / patchCount));\n const patchCenters = [];\n for (let i = 0; i < refCount; i += step) {\n const refPos = [refVerts[i * 3 + 0], refVerts[i * 3 + 1], refVerts[i * 3 + 2]];\n patchCenters.push(refPos);\n if (patchCenters.length >= patchCount) break;\n }\n const neighborIndices = new Array(patchCenters.length);\n const weights = new Array(patchCenters.length);\n const patchIndices = patchCenters.map((_, i) => i);\n const patchKD = buildKDTree(patchCenters, patchIndices);\n const isUsedArr = new Array(patchCenters.length).fill(false);\n const nearestPatch = new Uint16Array(meshVertCount + meshBoneCount);\n for (let i = 0; i < meshVertCount; i++) {\n const vec = [meshVerts[i * 3 + 0], meshVerts[i * 3 + 1], meshVerts[i * 3 + 2]];\n const nearestPatchNode = nearestSearch(patchKD, vec);\n isUsedArr[nearestPatchNode.index] = true;\n nearestPatch[i] = nearestPatchNode.index;\n }\n for (let i = 0; i < meshBoneCount; i++) {\n const vec = [meshBones[i * 3 + 0], meshBones[i * 3 + 1], meshBones[i * 3 + 2]];\n const nearestPatchNode = nearestSearch(patchKD, vec);\n isUsedArr[nearestPatchNode.index] = true;\n nearestPatch[i + meshVertCount] = nearestPatchNode.index;\n }\n for (let i = 0; i < patchCenters.length; i++) {\n if (!isUsedArr[i]) {\n continue;\n }\n const centerPos = patchCenters[i];\n const neighbors = knnSearch(controlKD, centerPos, detailsCount);\n const foundNeighborIndices = neighbors.map((n) => n.index);\n for (const important of importantIndices) {\n if (!foundNeighborIndices.includes(important)) {\n foundNeighborIndices.push(important);\n }\n }\n neighborIndices[i] = new Uint16Array(foundNeighborIndices);\n }\n const A_array = new Array(patchCenters.length);\n for (let p = 0; p < patchCenters.length; p++) {\n const patchNeighborIndices = neighborIndices[p];\n if (!patchNeighborIndices) continue;\n const K = patchNeighborIndices.length;\n const positions = new Array(patchNeighborIndices.length);\n for (let i = 0; i < patchNeighborIndices.length; i++) {\n const j = patchNeighborIndices[i];\n const refPos = [refVerts[j * 3 + 0], refVerts[j * 3 + 1], refVerts[j * 3 + 2]];\n positions[i] = refPos;\n }\n const A = new Array(K);\n for (let i = 0; i < K; i++) {\n A[i] = new Float32Array(K);\n }\n for (let i = 0; i < K; i++) {\n const [pix, piy, piz] = positions[i];\n for (let j = i + 1; j < K; j++) {\n const [pjx, pjy, pjz] = positions[j];\n const dist = Math.sqrt((pix - pjx) * (pix - pjx) + (piy - pjy) * (piy - pjy) + (piz - pjz) * (piz - pjz));\n A[i][j] = dist;\n A[j][i] = dist;\n }\n A[i][i] = epsilon;\n }\n A_array[p] = A;\n }\n for (let p = 0; p < patchCenters.length; p++) {\n if (!isUsedArr[p]) {\n continue;\n }\n const patchNeighborIndices = neighborIndices[p];\n const K = patchNeighborIndices.length;\n const usedRef = new Array(K);\n const usedDist = new Array(K);\n for (let i = 0; i < K; i++) {\n const idx = patchNeighborIndices[i];\n const j = idx;\n const refPos = [refVerts[j * 3 + 0], refVerts[j * 3 + 1], refVerts[j * 3 + 2]];\n const distPos = [distVerts[j * 3 + 0], distVerts[j * 3 + 1], distVerts[j * 3 + 2]];\n usedRef[i] = refPos;\n usedDist[i] = distPos;\n }\n const A = A_array[p];\n const bx = new Float32Array(K);\n const by = new Float32Array(K);\n const bz = new Float32Array(K);\n for (let i = 0; i < K; i++) {\n const dr = usedDist[i];\n const rr = usedRef[i];\n bx[i] = dr[0] - rr[0];\n by[i] = dr[1] - rr[1];\n bz[i] = dr[2] - rr[2];\n }\n const Abuffers = A.map((r) => r.buffer);\n weights[p] = new Float32Array(patchRBFWorkerFunc([Abuffers, bx.buffer, by.buffer, bz.buffer]));\n }\n const neighborIndicesBuf = neighborIndices.map((a) => {\n return a.buffer;\n });\n const weightsBuf = weights.map((a) => {\n return a.buffer;\n });\n return [neighborIndicesBuf, weightsBuf, nearestPatch.buffer];\n }\n const WorkerTypeToFunction = {\n "patchRBF": patchRBFWorkerFunc,\n "RBFDeformerSolveAsync": RBFDeformerSolveAsync\n };\n function getWorkerOnMessage() {\n return function(event) {\n const [id, type, data] = event.data;\n const func = WorkerTypeToFunction[type];\n self.postMessage([id, func(data)]);\n };\n }\n onmessage = getWorkerOnMessage();\n})();\n';
32682
+ const jsContent = '(function() {\n "use strict";\n new TextDecoder();\n new TextDecoder();\n const AssetTypes = [\n "",\n "Image",\n "TShirt",\n "Audio",\n "Mesh",\n "Lua",\n "HTML",\n "Text",\n "Hat",\n "Place",\n "Model",\n "Shirt",\n "Pants",\n "Decal",\n "",\n "",\n "Avatar",\n "Head",\n "Face",\n "Gear",\n "",\n "Badge",\n "GroupEmblem",\n "",\n "Animation",\n "Arms",\n "Legs",\n "Torso",\n "RightArm",\n "LeftArm",\n "LeftLeg",\n "RightLeg",\n "Package",\n "YouTubeVideo",\n "GamePass",\n "App",\n "",\n "Code",\n "Plugin",\n "SolidModel",\n "MeshPart",\n "HairAccessory",\n "FaceAccessory",\n "NeckAccessory",\n "ShoulderAccessory",\n "FrontAccessory",\n "BackAccessory",\n "WaistAccessory",\n "ClimbAnimation",\n "DeathAnimation",\n "FallAnimation",\n "IdleAnimation",\n "JumpAnimation",\n "RunAnimation",\n "SwimAnimation",\n "WalkAnimation",\n "PoseAnimation",\n "",\n "",\n "LocalizationTableManifest",\n "LocalizationTableTranslation",\n "EmoteAnimation",\n "Video",\n "TexturePack",\n "TShirtAccessory",\n "ShirtAccessory",\n "PantsAccessory",\n "JacketAccessory",\n "SweaterAccessory",\n "ShortsAccessory",\n "LeftShoeAccessory",\n "RightShoeAccessory",\n "DressSkirtAccessory",\n "FontFamily",\n "FontFace",\n "MeshHiddenSurfaceRemoval",\n "EyebrowAccessory",\n "EyelashAccessory",\n "MoodAnimation",\n "DynamicHead",\n //79\n "CodeSnippet",\n "AdsVideo",\n "OtaUpdate",\n "Screenshot",\n "RuntimePropertySet",\n "StorePreviewVideo",\n "GamePreviewVideo",\n "CreatorExperienceConfig",\n "FaceMakeup",\n "LipMakeup",\n "EyeMakeup",\n "VoxelFragment",\n "AvatarBackground",\n "TextDocument"\n ];\n const AssetTypeNameToId = /* @__PURE__ */ new Map();\n for (let i = 0; i < AssetTypes.length; i++) {\n const name = AssetTypes[i];\n AssetTypeNameToId.set(name, i);\n }\n const FullBodyColorPalette = [\n {\n "brickColorId": 361,\n "hexColor": "#564236",\n "name": "Dirt brown"\n },\n {\n "brickColorId": 192,\n "hexColor": "#694028",\n "name": "Reddish brown"\n },\n {\n "brickColorId": 217,\n "hexColor": "#7C5C46",\n "name": "Brown"\n },\n {\n "brickColorId": 153,\n "hexColor": "#957977",\n "name": "Sand red"\n },\n {\n "brickColorId": 359,\n "hexColor": "#AF9483",\n "name": "Linen"\n },\n {\n "brickColorId": 352,\n "hexColor": "#C7AC78",\n "name": "Burlap"\n },\n {\n "brickColorId": 5,\n "hexColor": "#D7C59A",\n "name": "Brick yellow"\n },\n {\n "brickColorId": 101,\n "hexColor": "#DA867A",\n "name": "Medium red"\n },\n {\n "brickColorId": 1007,\n "hexColor": "#A34B4B",\n "name": "Dusty Rose"\n },\n {\n "brickColorId": 1014,\n "hexColor": "#AA5500",\n "name": "CGA brown"\n },\n {\n "brickColorId": 38,\n "hexColor": "#A05F35",\n "name": "Dark orange"\n },\n {\n "brickColorId": 18,\n "hexColor": "#CC8E69",\n "name": "Nougat"\n },\n {\n "brickColorId": 125,\n "hexColor": "#EAB892",\n "name": "Light orange"\n },\n {\n "brickColorId": 1030,\n "hexColor": "#FFCC99",\n "name": "Pastel brown"\n },\n {\n "brickColorId": 133,\n "hexColor": "#D5733D",\n "name": "Neon orange"\n },\n {\n "brickColorId": 106,\n "hexColor": "#DA8541",\n "name": "Bright orange"\n },\n {\n "brickColorId": 105,\n "hexColor": "#E29B40",\n "name": "Br. yellowish orange"\n },\n {\n "brickColorId": 1017,\n "hexColor": "#FFAF00",\n "name": "Deep orange"\n },\n {\n "brickColorId": 24,\n "hexColor": "#F5CD30",\n "name": "Bright yellow"\n },\n {\n "brickColorId": 334,\n "hexColor": "#F8D96D",\n "name": "Daisy orange"\n },\n {\n "brickColorId": 226,\n "hexColor": "#FDEA8D",\n "name": "Cool yellow"\n },\n {\n "brickColorId": 141,\n "hexColor": "#27462D",\n "name": "Earth green"\n },\n {\n "brickColorId": 1021,\n "hexColor": "#3A7D15",\n "name": "Camo"\n },\n {\n "brickColorId": 28,\n "hexColor": "#287F47",\n "name": "Dark green"\n },\n {\n "brickColorId": 37,\n "hexColor": "#4B974B",\n "name": "Bright green"\n },\n {\n "brickColorId": 310,\n "hexColor": "#5B9A4C",\n "name": "Shamrock"\n },\n {\n "brickColorId": 317,\n "hexColor": "#7C9C6B",\n "name": "Moss"\n },\n {\n "brickColorId": 119,\n "hexColor": "#A4BD47",\n "name": "Br. yellowish green"\n },\n {\n "brickColorId": 1011,\n "hexColor": "#002060",\n "name": "Navy blue"\n },\n {\n "brickColorId": 1012,\n "hexColor": "#2154B9",\n "name": "Deep blue"\n },\n {\n "brickColorId": 1010,\n "hexColor": "#0000FF",\n "name": "Really blue"\n },\n {\n "brickColorId": 23,\n "hexColor": "#0D69AC",\n "name": "Bright blue"\n },\n {\n "brickColorId": 305,\n "hexColor": "#527CAE",\n "name": "Steel blue"\n },\n {\n "brickColorId": 102,\n "hexColor": "#6E99CA",\n "name": "Medium blue"\n },\n {\n "brickColorId": 45,\n "hexColor": "#B4D2E4",\n "name": "Light blue"\n },\n {\n "brickColorId": 107,\n "hexColor": "#008F9C",\n "name": "Bright bluish green"\n },\n {\n "brickColorId": 1018,\n "hexColor": "#12EED4",\n "name": "Teal"\n },\n {\n "brickColorId": 1027,\n "hexColor": "#9FF3E9",\n "name": "Pastel blue-green"\n },\n {\n "brickColorId": 1019,\n "hexColor": "#00FFFF",\n "name": "Toothpaste"\n },\n {\n "brickColorId": 1013,\n "hexColor": "#04AFEC",\n "name": "Cyan"\n },\n {\n "brickColorId": 11,\n "hexColor": "#80BBDC",\n "name": "Pastel Blue"\n },\n {\n "brickColorId": 1024,\n "hexColor": "#AFDDFF",\n "name": "Pastel light blue"\n },\n {\n "brickColorId": 104,\n "hexColor": "#6B327C",\n "name": "Bright violet"\n },\n {\n "brickColorId": 1023,\n "hexColor": "#8C5B9F",\n "name": "Lavender"\n },\n {\n "brickColorId": 321,\n "hexColor": "#A75E9B",\n "name": "Lilac"\n },\n {\n "brickColorId": 1015,\n "hexColor": "#AA00AA",\n "name": "Magenta"\n },\n {\n "brickColorId": 1031,\n "hexColor": "#6225D1",\n "name": "Royal purple"\n },\n {\n "brickColorId": 1006,\n "hexColor": "#B480FF",\n "name": "Alder"\n },\n {\n "brickColorId": 1026,\n "hexColor": "#B1A7FF",\n "name": "Pastel violet"\n },\n {\n "brickColorId": 21,\n "hexColor": "#C4281C",\n "name": "Bright red"\n },\n {\n "brickColorId": 1004,\n "hexColor": "#FF0000",\n "name": "Really red"\n },\n {\n "brickColorId": 1032,\n "hexColor": "#FF00BF",\n "name": "Hot pink"\n },\n {\n "brickColorId": 1016,\n "hexColor": "#FF66CC",\n "name": "Pink"\n },\n {\n "brickColorId": 330,\n "hexColor": "#FF98DC",\n "name": "Carnation pink"\n },\n {\n "brickColorId": 9,\n "hexColor": "#E8BAC8",\n "name": "Light reddish violet"\n },\n {\n "brickColorId": 1025,\n "hexColor": "#FFC9C9",\n "name": "Pastel orange"\n },\n {\n "brickColorId": 364,\n "hexColor": "#5A4C42",\n "name": "Dark taupe"\n },\n {\n "brickColorId": 351,\n "hexColor": "#BC9B5D",\n "name": "Cork"\n },\n {\n "brickColorId": 1008,\n "hexColor": "#C1BE42",\n "name": "Olive"\n },\n {\n "brickColorId": 29,\n "hexColor": "#A1C48C",\n "name": "Medium green"\n },\n {\n "brickColorId": 1022,\n "hexColor": "#7F8E64",\n "name": "Grime"\n },\n {\n "brickColorId": 151,\n "hexColor": "#789082",\n "name": "Sand green"\n },\n {\n "brickColorId": 135,\n "hexColor": "#74869D",\n "name": "Sand blue"\n },\n {\n "brickColorId": 1020,\n "hexColor": "#00FF00",\n "name": "Lime green"\n },\n {\n "brickColorId": 1028,\n "hexColor": "#CCFFCC",\n "name": "Pastel green"\n },\n {\n "brickColorId": 1009,\n "hexColor": "#FFFF00",\n "name": "New Yeller"\n },\n {\n "brickColorId": 1029,\n "hexColor": "#FFFFCC",\n "name": "Pastel yellow"\n },\n {\n "brickColorId": 1003,\n "hexColor": "#111111",\n "name": "Really black"\n },\n {\n "brickColorId": 26,\n "hexColor": "#1B2A35",\n "name": "Black"\n },\n {\n "brickColorId": 199,\n "hexColor": "#635F62",\n "name": "Dark stone grey"\n },\n {\n "brickColorId": 194,\n "hexColor": "#A3A2A5",\n "name": "Medium stone grey"\n },\n {\n "brickColorId": 1002,\n "hexColor": "#CDCDCD",\n "name": "Mid gray"\n },\n {\n "brickColorId": 208,\n "hexColor": "#E5E4DF",\n "name": "Light stone grey"\n },\n {\n "brickColorId": 1,\n "hexColor": "#F2F3F3",\n "name": "White"\n },\n {\n "brickColorId": 1001,\n "hexColor": "#F8F8F8",\n "name": "Institutional white"\n }\n ];\n const RegularBodyColors = [\n "5A4C42",\n "7C5C46",\n "AF9483",\n "CC8E69",\n "EAB892",\n "564236",\n "694028",\n "BC9B5D",\n "c7ac78",\n "d7c59a",\n "957977",\n "a34b4b",\n "da867a",\n "ffc9c9",\n "ff98dc",\n "74869d",\n "527cae",\n "80bbdc",\n "b1a7ff",\n "a75e9b",\n "008f9c",\n "5b9a4c",\n "7c9c6b",\n "a1c48c",\n "e29b40",\n "f5cd30",\n "f8d96d",\n "635f62",\n "cdcdcd",\n "f8f8f8"\n ];\n for (let i = 0; i < RegularBodyColors.length; i++) {\n const color = RegularBodyColors[i];\n RegularBodyColors[i] = color.toUpperCase();\n }\n const FullBodyColors = [];\n for (const colorDetails of FullBodyColorPalette) {\n FullBodyColors.push(colorDetails.hexColor.substring(1));\n }\n function calculateMagnitude3D(x, y, z) {\n return Math.sqrt(x * x + y * y + z * z);\n }\n function magnitude(v) {\n return calculateMagnitude3D(v[0], v[1], v[2]);\n }\n function minus(v0, v1) {\n return [v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2]];\n }\n function distance(v0, v1) {\n return magnitude(minus(v1, v0));\n }\n class KDNode {\n point;\n index;\n axis;\n left = null;\n right = null;\n constructor(point, index, axis) {\n this.point = point;\n this.index = index;\n this.axis = axis;\n }\n }\n function buildKDTree(points, indices, depth = 0) {\n if (points.length === 0) return null;\n const axis = depth % 3;\n const sorted = points.map((p, i) => ({ p, index: indices[i] })).sort((a, b) => a.p[axis] - b.p[axis]);\n const mid = Math.floor(sorted.length / 2);\n const node = new KDNode(sorted[mid].p, sorted[mid].index, axis);\n const leftPoints = sorted.slice(0, mid).map((x) => x.p);\n const leftIndices = sorted.slice(0, mid).map((x) => x.index);\n const rightPoints = sorted.slice(mid + 1).map((x) => x.p);\n const rightIndices = sorted.slice(mid + 1).map((x) => x.index);\n node.left = buildKDTree(leftPoints, leftIndices, depth + 1);\n node.right = buildKDTree(rightPoints, rightIndices, depth + 1);\n return node;\n }\n function siftUp(heap, i) {\n while (i > 0) {\n const p = i - 1 >> 1;\n if (heap[p].dist >= heap[i].dist) break;\n const tmp = heap[p];\n heap[p] = heap[i];\n heap[i] = tmp;\n i = p;\n }\n }\n function siftDown(heap, i) {\n const n = heap.length;\n while (true) {\n let largest = i;\n const l = (i << 1) + 1;\n const r = l + 1;\n if (l < n && heap[l].dist > heap[largest].dist) largest = l;\n if (r < n && heap[r].dist > heap[largest].dist) largest = r;\n if (largest === i) break;\n const tmp = heap[i];\n heap[i] = heap[largest];\n heap[largest] = tmp;\n i = largest;\n }\n }\n function heapPushMax(heap, item, k) {\n if (heap.length < k) {\n heap.push(item);\n siftUp(heap, heap.length - 1);\n return;\n }\n if (item.dist >= heap[0].dist) return;\n heap[0] = item;\n siftDown(heap, 0);\n }\n function distSq(a, b) {\n const dx = a[0] - b[0];\n const dy = a[1] - b[1];\n const dz = a[2] - b[2];\n return dx * dx + dy * dy + dz * dz;\n }\n function knnSearch(node, target, k, heap = []) {\n if (!node) return heap;\n const axis = node.axis;\n const dist = distSq(target, node.point);\n heapPushMax(heap, { dist, index: node.index }, k);\n const diff = target[axis] - node.point[axis];\n const primary = diff < 0 ? node.left : node.right;\n const secondary = diff < 0 ? node.right : node.left;\n knnSearch(primary, target, k, heap);\n const worstDist = heap.length < k ? Infinity : heap[0].dist;\n if (diff * diff < worstDist) {\n knnSearch(secondary, target, k, heap);\n }\n if (node === null) {\n heap.sort((a, b) => a.dist - b.dist);\n }\n return heap;\n }\n function nearestSearch(node, target, best = { dist: Infinity, index: -1 }) {\n if (!node) return best;\n const dist = distance(target, node.point);\n if (dist < best.dist) {\n best = { dist, index: node.index };\n }\n const axis = node.axis;\n const diff = target[axis] - node.point[axis];\n const primary = diff < 0 ? node.left : node.right;\n const secondary = diff < 0 ? node.right : node.left;\n best = nearestSearch(primary, target, best);\n if (Math.abs(diff) < best.dist) {\n best = nearestSearch(secondary, target, best);\n }\n return best;\n }\n function luDecompose(A) {\n const n = A.length;\n const LU = A;\n const P = new Int32Array(n);\n for (let i = 0; i < n; i++) P[i] = i;\n for (let k = 0; k < n; k++) {\n let pivot = k;\n for (let i = k + 1; i < n; i++) {\n if (Math.abs(LU[i][k]) > Math.abs(LU[pivot][k])) {\n pivot = i;\n }\n }\n if (pivot !== k) {\n const tmpRow = LU[k];\n LU[k] = LU[pivot];\n LU[pivot] = tmpRow;\n const tmpP = P[k];\n P[k] = P[pivot];\n P[pivot] = tmpP;\n }\n const pivotVal = LU[k][k];\n for (let i = k + 1; i < n; i++) {\n LU[i][k] /= pivotVal;\n const mult = LU[i][k];\n const rowI = LU[i];\n const rowK = LU[k];\n for (let j = k + 1; j < n; j++) {\n rowI[j] -= mult * rowK[j];\n }\n }\n }\n return { LU, P };\n }\n function luSolve({ LU, P }, b) {\n const n = LU.length;\n const x = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n x[i] = b[P[i]];\n }\n for (let i = 0; i < n; i++) {\n const row = LU[i];\n let sum = x[i];\n for (let j = 0; j < i; j++) {\n sum -= row[j] * x[j];\n }\n x[i] = sum;\n }\n for (let i = n - 1; i >= 0; i--) {\n const row = LU[i];\n let sum = x[i];\n for (let j = i + 1; j < n; j++) {\n sum -= row[j] * x[j];\n }\n x[i] = sum / row[i];\n }\n return x;\n }\n function patchRBFWorkerFunc([_A, _bx, _by, _bz]) {\n const A = _A.map((r) => new Float32Array(r));\n const bx = new Float32Array(_bx);\n const by = new Float32Array(_by);\n const bz = new Float32Array(_bz);\n const LU = luDecompose(A);\n const wx = luSolve(LU, bx);\n const wy = luSolve(LU, by);\n const wz = luSolve(LU, bz);\n const n = wx.length;\n const result = new Float32Array(n * 3);\n for (let i = 0; i < n; i++) {\n result[i * 3 + 0] = wx[i];\n result[i * 3 + 1] = wy[i];\n result[i * 3 + 2] = wz[i];\n }\n return result.buffer;\n }\n function RBFDeformerSolveAsync([patchCount, detailsCount, epsilon, importantIndicesBuf, refVertsBuf, distVertsBuf, meshVertsBuf, meshBonesBuf]) {\n const importantIndices = new Uint16Array(importantIndicesBuf);\n const refVerts = new Float32Array(refVertsBuf);\n const distVerts = new Float32Array(distVertsBuf);\n const meshVerts = new Float32Array(meshVertsBuf);\n const meshBones = new Float32Array(meshBonesBuf);\n const refCount = refVerts.length / 3;\n const meshVertCount = meshVerts.length / 3;\n const meshBoneCount = meshBones.length / 3;\n const points = new Array(refCount);\n const indices = new Array(refCount);\n for (let i = 0; i < refCount; i++) {\n const refPos = [refVerts[i * 3 + 0], refVerts[i * 3 + 1], refVerts[i * 3 + 2]];\n points[i] = refPos;\n indices[i] = i;\n }\n const controlKD = buildKDTree(points, indices);\n const step = Math.max(1, Math.floor(refCount / patchCount));\n const patchCenters = [];\n for (let i = 0; i < refCount; i += step) {\n const refPos = [refVerts[i * 3 + 0], refVerts[i * 3 + 1], refVerts[i * 3 + 2]];\n patchCenters.push(refPos);\n if (patchCenters.length >= patchCount) break;\n }\n const neighborIndices = new Array(patchCenters.length);\n const weights = new Array(patchCenters.length);\n const patchIndices = patchCenters.map((_, i) => i);\n const patchKD = buildKDTree(patchCenters, patchIndices);\n const isUsedArr = new Array(patchCenters.length).fill(false);\n const nearestPatch = new Uint16Array(meshVertCount + meshBoneCount);\n for (let i = 0; i < meshVertCount; i++) {\n const vec = [meshVerts[i * 3 + 0], meshVerts[i * 3 + 1], meshVerts[i * 3 + 2]];\n const nearestPatchNode = nearestSearch(patchKD, vec);\n isUsedArr[nearestPatchNode.index] = true;\n nearestPatch[i] = nearestPatchNode.index;\n }\n for (let i = 0; i < meshBoneCount; i++) {\n const vec = [meshBones[i * 3 + 0], meshBones[i * 3 + 1], meshBones[i * 3 + 2]];\n const nearestPatchNode = nearestSearch(patchKD, vec);\n isUsedArr[nearestPatchNode.index] = true;\n nearestPatch[i + meshVertCount] = nearestPatchNode.index;\n }\n for (let i = 0; i < patchCenters.length; i++) {\n if (!isUsedArr[i]) {\n continue;\n }\n const centerPos = patchCenters[i];\n const neighbors = knnSearch(controlKD, centerPos, detailsCount);\n const foundNeighborIndices = neighbors.map((n) => n.index);\n for (const important of importantIndices) {\n if (!foundNeighborIndices.includes(important)) {\n foundNeighborIndices.push(important);\n }\n }\n neighborIndices[i] = new Uint16Array(foundNeighborIndices);\n }\n const A_array = new Array(patchCenters.length);\n for (let p = 0; p < patchCenters.length; p++) {\n const patchNeighborIndices = neighborIndices[p];\n if (!patchNeighborIndices) continue;\n const K = patchNeighborIndices.length;\n const positions = new Array(patchNeighborIndices.length);\n for (let i = 0; i < patchNeighborIndices.length; i++) {\n const j = patchNeighborIndices[i];\n const refPos = [refVerts[j * 3 + 0], refVerts[j * 3 + 1], refVerts[j * 3 + 2]];\n positions[i] = refPos;\n }\n const A = new Array(K);\n for (let i = 0; i < K; i++) {\n A[i] = new Float32Array(K);\n }\n for (let i = 0; i < K; i++) {\n const [pix, piy, piz] = positions[i];\n for (let j = i + 1; j < K; j++) {\n const [pjx, pjy, pjz] = positions[j];\n const dist = Math.sqrt((pix - pjx) * (pix - pjx) + (piy - pjy) * (piy - pjy) + (piz - pjz) * (piz - pjz));\n A[i][j] = dist;\n A[j][i] = dist;\n }\n A[i][i] = epsilon;\n }\n A_array[p] = A;\n }\n for (let p = 0; p < patchCenters.length; p++) {\n if (!isUsedArr[p]) {\n continue;\n }\n const patchNeighborIndices = neighborIndices[p];\n const K = patchNeighborIndices.length;\n const usedRef = new Array(K);\n const usedDist = new Array(K);\n for (let i = 0; i < K; i++) {\n const idx = patchNeighborIndices[i];\n const j = idx;\n const refPos = [refVerts[j * 3 + 0], refVerts[j * 3 + 1], refVerts[j * 3 + 2]];\n const distPos = [distVerts[j * 3 + 0], distVerts[j * 3 + 1], distVerts[j * 3 + 2]];\n usedRef[i] = refPos;\n usedDist[i] = distPos;\n }\n const A = A_array[p];\n const bx = new Float32Array(K);\n const by = new Float32Array(K);\n const bz = new Float32Array(K);\n for (let i = 0; i < K; i++) {\n const dr = usedDist[i];\n const rr = usedRef[i];\n bx[i] = dr[0] - rr[0];\n by[i] = dr[1] - rr[1];\n bz[i] = dr[2] - rr[2];\n }\n const Abuffers = A.map((r) => r.buffer);\n weights[p] = new Float32Array(patchRBFWorkerFunc([Abuffers, bx.buffer, by.buffer, bz.buffer]));\n }\n const neighborIndicesBuf = neighborIndices.map((a) => {\n return a.buffer;\n });\n const weightsBuf = weights.map((a) => {\n return a.buffer;\n });\n return [neighborIndicesBuf, weightsBuf, nearestPatch.buffer];\n }\n const WorkerTypeToFunction = {\n "patchRBF": patchRBFWorkerFunc,\n "RBFDeformerSolveAsync": RBFDeformerSolveAsync\n };\n function getWorkerOnMessage() {\n return function(event) {\n const [id, type, data] = event.data;\n const func = WorkerTypeToFunction[type];\n self.postMessage([id, func(data)]);\n };\n }\n onmessage = getWorkerOnMessage();\n})();\n';
32412
32683
  const blob = typeof self !== "undefined" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", jsContent], { type: "text/javascript;charset=utf-8" });
32413
32684
  function WorkerWrapper(options) {
32414
32685
  let objURL;
@@ -32664,6 +32935,7 @@ const FLAGS = {
32664
32935
  INCLUDE_REQUEST_CREDENTIALS_OVERRIDE: "include",
32665
32936
  API_REQUEST_RETRY: true,
32666
32937
  FETCH_FUNC: void 0,
32938
+ IMAGE_FUNC: void 0,
32667
32939
  //assets
32668
32940
  ONLINE_ASSETS: false,
32669
32941
  ASSETS_PATH: "../assets/rbxasset/",
@@ -35126,275 +35398,6 @@ function toVecXYZ(vec) {
35126
35398
  Z: vec.z
35127
35399
  };
35128
35400
  }
35129
- const AssetTypes = [
35130
- "",
35131
- "Image",
35132
- "TShirt",
35133
- "Audio",
35134
- "Mesh",
35135
- "Lua",
35136
- "HTML",
35137
- "Text",
35138
- "Hat",
35139
- "Place",
35140
- "Model",
35141
- "Shirt",
35142
- "Pants",
35143
- "Decal",
35144
- "",
35145
- "",
35146
- "Avatar",
35147
- "Head",
35148
- "Face",
35149
- "Gear",
35150
- "",
35151
- "Badge",
35152
- "GroupEmblem",
35153
- "",
35154
- "Animation",
35155
- "Arms",
35156
- "Legs",
35157
- "Torso",
35158
- "RightArm",
35159
- "LeftArm",
35160
- "LeftLeg",
35161
- "RightLeg",
35162
- "Package",
35163
- "YouTubeVideo",
35164
- "GamePass",
35165
- "App",
35166
- "",
35167
- "Code",
35168
- "Plugin",
35169
- "SolidModel",
35170
- "MeshPart",
35171
- "HairAccessory",
35172
- "FaceAccessory",
35173
- "NeckAccessory",
35174
- "ShoulderAccessory",
35175
- "FrontAccessory",
35176
- "BackAccessory",
35177
- "WaistAccessory",
35178
- "ClimbAnimation",
35179
- "DeathAnimation",
35180
- "FallAnimation",
35181
- "IdleAnimation",
35182
- "JumpAnimation",
35183
- "RunAnimation",
35184
- "SwimAnimation",
35185
- "WalkAnimation",
35186
- "PoseAnimation",
35187
- "",
35188
- "",
35189
- "LocalizationTableManifest",
35190
- "LocalizationTableTranslation",
35191
- "EmoteAnimation",
35192
- "Video",
35193
- "TexturePack",
35194
- "TShirtAccessory",
35195
- "ShirtAccessory",
35196
- "PantsAccessory",
35197
- "JacketAccessory",
35198
- "SweaterAccessory",
35199
- "ShortsAccessory",
35200
- "LeftShoeAccessory",
35201
- "RightShoeAccessory",
35202
- "DressSkirtAccessory",
35203
- "FontFamily",
35204
- "FontFace",
35205
- "MeshHiddenSurfaceRemoval",
35206
- "EyebrowAccessory",
35207
- "EyelashAccessory",
35208
- "MoodAnimation",
35209
- "DynamicHead",
35210
- //79
35211
- "CodeSnippet",
35212
- "AdsVideo",
35213
- "OtaUpdate",
35214
- "Screenshot",
35215
- "RuntimePropertySet",
35216
- "StorePreviewVideo",
35217
- "GamePreviewVideo",
35218
- "CreatorExperienceConfig",
35219
- "FaceMakeup",
35220
- "LipMakeup",
35221
- "EyeMakeup",
35222
- "VoxelFragment",
35223
- "AvatarBackground",
35224
- "TextDocument"
35225
- ];
35226
- const WearableAssetTypes = [
35227
- "TShirt",
35228
- "Hat",
35229
- "Shirt",
35230
- "Pants",
35231
- "Head",
35232
- "Face",
35233
- "Gear",
35234
- "Torso",
35235
- "RightArm",
35236
- "LeftArm",
35237
- "LeftLeg",
35238
- "RightLeg",
35239
- "HairAccessory",
35240
- "FaceAccessory",
35241
- "NeckAccessory",
35242
- "ShoulderAccessory",
35243
- "FrontAccessory",
35244
- "BackAccessory",
35245
- "WaistAccessory",
35246
- "ClimbAnimation",
35247
- "FallAnimation",
35248
- "IdleAnimation",
35249
- "JumpAnimation",
35250
- "RunAnimation",
35251
- "SwimAnimation",
35252
- "WalkAnimation",
35253
- "TShirtAccessory",
35254
- "ShirtAccessory",
35255
- "PantsAccessory",
35256
- "JacketAccessory",
35257
- "SweaterAccessory",
35258
- "ShortsAccessory",
35259
- "LeftShoeAccessory",
35260
- "RightShoeAccessory",
35261
- "DressSkirtAccessory",
35262
- "EyebrowAccessory",
35263
- "EyelashAccessory",
35264
- "MoodAnimation",
35265
- "DynamicHead",
35266
- "FaceMakeup",
35267
- "LipMakeup",
35268
- "EyeMakeup",
35269
- "PoseAnimation",
35270
- "EarAccessory",
35271
- "EyeAccessory",
35272
- "DeathAnimation"
35273
- ];
35274
- const AccessoryAssetTypes = [
35275
- "Hat",
35276
- "HairAccessory",
35277
- "FaceAccessory",
35278
- "NeckAccessory",
35279
- "ShoulderAccessory",
35280
- "FrontAccessory",
35281
- "BackAccessory",
35282
- "WaistAccessory"
35283
- ];
35284
- const LayeredAssetTypes = [
35285
- "TShirtAccessory",
35286
- "ShirtAccessory",
35287
- "PantsAccessory",
35288
- "JacketAccessory",
35289
- "SweaterAccessory",
35290
- "ShortsAccessory",
35291
- "LeftShoeAccessory",
35292
- "RightShoeAccessory",
35293
- "DressSkirtAccessory",
35294
- "EyebrowAccessory",
35295
- "EyelashAccessory",
35296
- "HairAccessory",
35297
- "FaceMakeup",
35298
- "LipMakeup",
35299
- "EyeMakeup"
35300
- ];
35301
- const SpecialLayeredAssetTypes = [
35302
- "EyebrowAccessory",
35303
- "EyelashAccessory",
35304
- "HairAccessory"
35305
- ];
35306
- const MaxOneOfAssetTypes = [
35307
- "TShirt",
35308
- "Shirt",
35309
- "Pants",
35310
- "Head",
35311
- "Face",
35312
- "Gear",
35313
- "Torso",
35314
- "RightArm",
35315
- "LeftArm",
35316
- "LeftLeg",
35317
- "RightLeg",
35318
- "ClimbAnimation",
35319
- "DeathAnimation",
35320
- "FallAnimation",
35321
- "IdleAnimation",
35322
- "JumpAnimation",
35323
- "RunAnimation",
35324
- "SwimAnimation",
35325
- "WalkAnimation",
35326
- "PoseAnimation",
35327
- "MoodAnimation",
35328
- "DynamicHead",
35329
- "EyebrowAccessory",
35330
- "EyelashAccessory"
35331
- ];
35332
- const ToRemoveBeforeBundleType = {
35333
- "DynamicHead": ["MoodAnimation", "DynamicHead", "EyebrowAccessory", "EyelashAccessory", "Head"],
35334
- "Shoes": ["LeftShoeAccessory", "RightShoeAccessory"],
35335
- "AnimationPack": [
35336
- "ClimbAnimation",
35337
- "DeathAnimation",
35338
- "FallAnimation",
35339
- "IdleAnimation",
35340
- "JumpAnimation",
35341
- "RunAnimation",
35342
- "SwimAnimation",
35343
- "WalkAnimation",
35344
- "PoseAnimation",
35345
- "MoodAnimation"
35346
- ],
35347
- "Character": [
35348
- "DynamicHead",
35349
- "Head",
35350
- "Torso",
35351
- "LeftArm",
35352
- "RightArm",
35353
- "LeftLeg",
35354
- "RightLeg"
35355
- ],
35356
- "MakeupLook": [
35357
- "FaceMakeup",
35358
- "EyeMakeup",
35359
- "LipMakeup",
35360
- "EyebrowAccessory",
35361
- "EyelashAccessory"
35362
- ]
35363
- };
35364
- const AssetTypeNameToId = /* @__PURE__ */ new Map();
35365
- for (let i = 0; i < AssetTypes.length; i++) {
35366
- const name = AssetTypes[i];
35367
- AssetTypeNameToId.set(name, i);
35368
- }
35369
- const ActualBundleTypes = [
35370
- //names used by Roblox
35371
- "",
35372
- "Avatar",
35373
- //traditional bundle
35374
- "DynamicHead",
35375
- "Avatar",
35376
- //outfit
35377
- "Shoes",
35378
- "Avatar"
35379
- //animation pack
35380
- ];
35381
- const BundleTypes = [
35382
- "",
35383
- "Character",
35384
- "DynamicHead",
35385
- "Outfit",
35386
- "Shoes",
35387
- "AnimationPack",
35388
- "",
35389
- "MakeupLook"
35390
- ];
35391
- const CatalogBundleTypes = [
35392
- "",
35393
- "Character",
35394
- "AnimationPack",
35395
- "Shoes",
35396
- "DynamicHead"
35397
- ];
35398
35401
  class ItemInfo {
35399
35402
  itemType;
35400
35403
  type;
@@ -36037,7 +36040,7 @@ class Outfit {
36037
36040
  });
36038
36041
  }
36039
36042
  }
36040
- if (LayeredAssetTypes.includes(asset.assetType.name) && !MakeupAssetTypes.includes(asset.assetType.name)) {
36043
+ if (LayeredAssetTypes.includes(asset.assetType.name) && !MakeupAssetTypes.includes(asset.assetType.name) && !MaxOneOfAssetTypes.includes(asset.assetType.name)) {
36041
36044
  totalLayered += 1;
36042
36045
  if (totalLayered > 10) {
36043
36046
  issues.push({
@@ -36491,7 +36494,7 @@ class Outfit {
36491
36494
  this.addAsset(assetId, assetDetails.AssetTypeId, assetDetails.Name);
36492
36495
  return true;
36493
36496
  }
36494
- async addBundleId(bundleId) {
36497
+ async addBundleId(bundleId, auth) {
36495
36498
  const bundleDetails = await API.Catalog.GetBundleDetails(bundleId);
36496
36499
  if (!(bundleDetails instanceof Response)) {
36497
36500
  const bundleType = CatalogBundleTypes[bundleDetails.bundleType];
@@ -36510,6 +36513,18 @@ class Outfit {
36510
36513
  break;
36511
36514
  }
36512
36515
  }
36516
+ if (!bundleDetails.bundledItems.find((v) => {
36517
+ return v.type === "UserOutfit";
36518
+ })) {
36519
+ const promises = [];
36520
+ for (const item of bundleDetails.bundledItems) {
36521
+ if (item.type !== "Asset") continue;
36522
+ const promise = auth ? this.addAssetId(item.id, auth) : this.addAssetIdEconomy(item.id);
36523
+ promises.push(promise);
36524
+ }
36525
+ await Promise.all(promises);
36526
+ return true;
36527
+ }
36513
36528
  } else {
36514
36529
  warn(true, "Failed to get bundleDetails", bundleDetails);
36515
36530
  }
@@ -39061,7 +39076,13 @@ const API = {
39061
39076
  CACHE.Image.set(cacheURL, void 0);
39062
39077
  };
39063
39078
  image.crossOrigin = "anonymous";
39064
- image.src = fetchStr;
39079
+ if (FLAGS.IMAGE_FUNC) {
39080
+ FLAGS.IMAGE_FUNC(fetchStr).then((str) => {
39081
+ image.src = str;
39082
+ });
39083
+ } else {
39084
+ image.src = fetchStr;
39085
+ }
39065
39086
  });
39066
39087
  }));
39067
39088
  }
@@ -39206,13 +39227,19 @@ const API = {
39206
39227
  if (response.status !== 200) return response;
39207
39228
  const body = await response.json();
39208
39229
  const outfitModel = new OutfitModel().fromJson(body);
39230
+ outfitModel.outfit.creatorId = userId;
39231
+ outfitModel.outfit.origin = OutfitOrigin.WebAvatar;
39209
39232
  return outfitModel;
39210
39233
  },
39211
39234
  GetAvatarModel: async function() {
39235
+ const userInfoPromise = API.Users.GetUserInfo();
39212
39236
  const response = await RBLXGet("https://avatar.roblox.com/v4/avatar?selectionTypes=0&selectionTypes=1&selectionTypes=2&selectionTypes=3&selectionTypes=4&selectionTypes=5&selectionTypes=6");
39213
39237
  if (response.status !== 200) return response;
39214
39238
  const body = await response.json();
39215
39239
  const outfitModel = new OutfitModel().fromJson(body);
39240
+ const userInfo = await userInfoPromise;
39241
+ if (userInfo) outfitModel.outfit.creatorId = userInfo.id;
39242
+ outfitModel.outfit.origin = OutfitOrigin.WebAvatar;
39216
39243
  return outfitModel;
39217
39244
  },
39218
39245
  UpdateAvatarModel: async function(auth, model, updateTypes = AllAvatarModelOutfitUpdateTypes) {
@@ -39464,7 +39491,11 @@ const API = {
39464
39491
  if (response instanceof ArrayBuffer) {
39465
39492
  const buffer2 = response;
39466
39493
  const rbx = new RBX();
39467
- rbx.fromBuffer(buffer2);
39494
+ try {
39495
+ rbx.fromBuffer(buffer2);
39496
+ } catch {
39497
+ return new Response();
39498
+ }
39468
39499
  if (FLAGS.ENABLE_API_CACHE && FLAGS.ENABLE_API_RBX_CACHE) {
39469
39500
  CACHE.RBX.set(cacheStr, rbx.clone());
39470
39501
  }
@@ -39676,7 +39707,7 @@ const API = {
39676
39707
  },
39677
39708
  "Users": {
39678
39709
  GetUserInfo: async function() {
39679
- if (CACHE.UserInfo) {
39710
+ if (CACHE.UserInfo !== void 0) {
39680
39711
  return CACHE.UserInfo;
39681
39712
  }
39682
39713
  const response = await RBLXGet("https://users.roblox.com/v1/users/authenticated");
@@ -39856,6 +39887,10 @@ const API = {
39856
39887
  DeleteLook: async function(auth, lookId) {
39857
39888
  const response = await RBLXDelete(`https://apis.roblox.com/look-api/v1/looks/${lookId}`, auth, {});
39858
39889
  return response;
39890
+ },
39891
+ PatchLook: async function(auth, lookId, data) {
39892
+ const response = await RBLXPatch(`https://apis.roblox.com/look-api/v1/looks/${lookId}`, auth, data);
39893
+ return response;
39859
39894
  }
39860
39895
  },
39861
39896
  "PremiumFeatures": {
@@ -43243,27 +43278,27 @@ class RenderDesc extends DisposableDesc {
43243
43278
  this.renderScene = renderScene;
43244
43279
  }
43245
43280
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
43246
- isSame(_other) {
43281
+ isSame(_newDesc) {
43247
43282
  throw new Error("Virtual method isSame called");
43248
43283
  }
43249
43284
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
43250
- needsRegeneration(_other) {
43285
+ needsRegeneration(_newDesc) {
43251
43286
  throw new Error("Virtual method needsRegeneration called");
43252
43287
  }
43253
- fromRenderDesc(other) {
43254
- if (this.needsRegeneration(other)) {
43288
+ fromRenderDesc(newDesc) {
43289
+ if (this.needsRegeneration(newDesc)) {
43255
43290
  throw new Error("These RenderableDesc objects have differences that require recompilation");
43256
43291
  }
43257
- this.virtualFromRenderDesc(other);
43292
+ this.virtualFromRenderDesc(newDesc);
43258
43293
  }
43259
- transferFrom(other) {
43260
- this.virtualTransferFrom(other);
43294
+ transferFrom(oldDesc) {
43295
+ this.virtualTransferFrom(oldDesc);
43261
43296
  }
43262
43297
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
43263
- virtualTransferFrom(_other) {
43298
+ virtualTransferFrom(_oldDesc) {
43264
43299
  }
43265
43300
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
43266
- virtualFromRenderDesc(_other) {
43301
+ virtualFromRenderDesc(_newDesc) {
43267
43302
  throw new Error("Virtual method virtualFromRenderDesc called");
43268
43303
  }
43269
43304
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -46498,20 +46533,20 @@ class MaterialDesc {
46498
46533
  }
46499
46534
  return propertiesSame && layersSame;
46500
46535
  }
46501
- needsRegeneration(other) {
46502
- if (this.dirty || other.dirty) return true;
46503
- const propertiesSame = this.isDecal === other.isDecal && this.doubleSided === other.doubleSided && this.visible === other.visible && this.canHaveMipmaps === other.canHaveMipmaps && this.resampleMode === other.resampleMode;
46536
+ needsRegeneration(newDesc) {
46537
+ if (this.dirty || newDesc.dirty) return true;
46538
+ const propertiesSame = this.isDecal === newDesc.isDecal && this.doubleSided === newDesc.doubleSided && this.canHaveMipmaps === newDesc.canHaveMipmaps && this.resampleMode === newDesc.resampleMode;
46504
46539
  let layersSame = true;
46505
- if (this.layers.length !== other.layers.length) {
46540
+ if (this.layers.length !== newDesc.layers.length) {
46506
46541
  layersSame = false;
46507
46542
  } else {
46508
46543
  for (let i = 0; i < this.layers.length; i++) {
46509
46544
  const thisLayer = this.layers[i];
46510
- const otherLayer = other.layers[i];
46545
+ const otherLayer = newDesc.layers[i];
46511
46546
  layersSame = layersSame && thisLayer.isSame(otherLayer);
46512
46547
  }
46513
46548
  }
46514
- return !propertiesSame || !layersSame;
46549
+ return (!propertiesSame || !layersSame) && newDesc.visible;
46515
46550
  }
46516
46551
  getTexturesOfType(textureType) {
46517
46552
  const urls = [];
@@ -47049,6 +47084,7 @@ class MaterialDesc {
47049
47084
  fromMaterialDesc(other) {
47050
47085
  this.transparency = other.transparency;
47051
47086
  this.transparent = other.transparent;
47087
+ this.visible = other.visible;
47052
47088
  }
47053
47089
  updateTransparency() {
47054
47090
  if (this.result) {
@@ -47061,8 +47097,14 @@ class MaterialDesc {
47061
47097
  }
47062
47098
  }
47063
47099
  }
47100
+ updateVisibility() {
47101
+ if (this.result) {
47102
+ this.result.visible = this.visible;
47103
+ }
47104
+ }
47064
47105
  updateResult() {
47065
47106
  this.updateTransparency();
47107
+ this.updateVisibility();
47066
47108
  }
47067
47109
  addClothingLayers(parent) {
47068
47110
  const pants = parent.FindFirstChildOfClass("Pants");
@@ -47767,13 +47809,13 @@ class ObjectDesc extends RenderDesc {
47767
47809
  isSame(other) {
47768
47810
  return this.cframe.isSame(other.cframe) && this.meshDesc.isSame(other.meshDesc) && this.materialDesc.isSame(other.materialDesc) && this.isBodyPart === other.isBodyPart && this.size.isSame(other.size) && this.skeletonDesc === other.skeletonDesc;
47769
47811
  }
47770
- needsRegeneration(other) {
47812
+ needsRegeneration(newDesc) {
47771
47813
  if (!this.renderScene.forceAccurateNeedsRegeneration) {
47772
47814
  if (this.meshDesc.layerDesc && Date.now() / 1e3 - this.meshDesc.compilationTimestamp < FLAGS.LAYERED_CLOTHING_COOLDOWN) {
47773
47815
  return false;
47774
47816
  }
47775
47817
  }
47776
- return !this.meshDesc.isSame(other.meshDesc) || this.materialDesc.needsRegeneration(other.materialDesc);
47818
+ return !this.meshDesc.isSame(newDesc.meshDesc) || this.materialDesc.needsRegeneration(newDesc.materialDesc);
47777
47819
  }
47778
47820
  virtualFromRenderDesc(other) {
47779
47821
  this.cframe = other.cframe;
@@ -49804,7 +49846,9 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
49804
49846
  let bodyColorsSame = true;
49805
49847
  let bodyPartsSame = true;
49806
49848
  for (const bodyPart of AllBodyParts) {
49807
- if (!isSameColor(this.getBodyPartColor(bodyPart), originalW.getBodyPartColor(bodyPart))) {
49849
+ const originalBodyPartColor = originalW.getBodyPartColor(bodyPart);
49850
+ const newBodyPartColor = this.getBodyPartColor(bodyPart);
49851
+ if (!originalBodyPartColor || !newBodyPartColor || !isSameColor(originalBodyPartColor, newBodyPartColor)) {
49808
49852
  bodyColorsSame = false;
49809
49853
  }
49810
49854
  if (this.getBodyPartId(bodyPart) !== originalW.getBodyPartId(bodyPart)) {
@@ -49975,7 +50019,6 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
49975
50019
  if (bodyPartDesc) {
49976
50020
  return bodyPartDesc.Prop("Color");
49977
50021
  }
49978
- return new Color3(0, 0, 0);
49979
50022
  }
49980
50023
  setBodyPartId(bodyPart, id) {
49981
50024
  const bodyPartDesc = this.getBodyPartDescription(bodyPart);
@@ -51034,6 +51077,7 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
51034
51077
  this._applyScale(humanoid);
51035
51078
  this._applyScale(humanoid);
51036
51079
  }
51080
+ console.log(diffs);
51037
51081
  }
51038
51082
  const values = await Promise.all(promises);
51039
51083
  if (this.cancelApply) return void 0;
@@ -51569,11 +51613,11 @@ class EmitterDesc extends DisposableDesc {
51569
51613
  const particleMax = this.initialParticleCount + calculatedMax;
51570
51614
  return particleMax;
51571
51615
  }
51572
- needsRegeneration(other) {
51573
- return this.texture === other.texture && this.alphaTexture === other.alphaTexture && this.colorTexture === other.colorTexture && this.rate === other.rate;
51616
+ needsRegeneration(newDesc) {
51617
+ return this.texture === newDesc.texture && this.alphaTexture === newDesc.alphaTexture && this.colorTexture === newDesc.colorTexture && this.rate === newDesc.rate;
51574
51618
  }
51575
- isSame(other) {
51576
- return !this.needsRegeneration(other) && this.lockedToPart === other.lockedToPart && this.lifetime.isSame(other.lifetime) && this.spreadAngle.isSame(other.spreadAngle) && this.speed.isSame(other.speed) && this.rotation.isSame(other.rotation) && this.rotationSpeed.isSame(other.rotationSpeed) && this.localAcceleration.isSame(other.localAcceleration) && this.acceleration.isSame(other.acceleration) && this.drag === other.drag && this.timeScale === other.timeScale && this.orientation === other.orientation && this.zOffset === other.zOffset && this.offset.isSame(other.offset) && this.shapeInOut === other.shapeInOut && this.opacity === other.opacity && this.lightEmission === other.lightEmission && this.lightInfluence === other.lightInfluence && this.blending === other.blending && this.color.isSame(other.color) && this.size.isSame(other.size) && this.squash.isSame(other.squash) && this.transparency.isSame(other.transparency) && this.normalizeSizeKeypointTime === other.normalizeSizeKeypointTime && this.flipbookLayout === other.flipbookLayout && this.flipbookBlendFrames === other.flipbookBlendFrames && this.flipbookFramerate.isSame(other.flipbookFramerate) && this.flipbookMode === other.flipbookMode && this.flipbookSizeX === other.flipbookSizeX && this.flipbookSizeY === other.flipbookSizeY && this.flipbookStartRandom === other.flipbookStartRandom;
51619
+ isSame(newDesc) {
51620
+ return !this.needsRegeneration(newDesc) && this.lockedToPart === newDesc.lockedToPart && this.lifetime.isSame(newDesc.lifetime) && this.spreadAngle.isSame(newDesc.spreadAngle) && this.speed.isSame(newDesc.speed) && this.rotation.isSame(newDesc.rotation) && this.rotationSpeed.isSame(newDesc.rotationSpeed) && this.localAcceleration.isSame(newDesc.localAcceleration) && this.acceleration.isSame(newDesc.acceleration) && this.drag === newDesc.drag && this.timeScale === newDesc.timeScale && this.orientation === newDesc.orientation && this.zOffset === newDesc.zOffset && this.offset.isSame(newDesc.offset) && this.shapeInOut === newDesc.shapeInOut && this.opacity === newDesc.opacity && this.lightEmission === newDesc.lightEmission && this.lightInfluence === newDesc.lightInfluence && this.blending === newDesc.blending && this.color.isSame(newDesc.color) && this.size.isSame(newDesc.size) && this.squash.isSame(newDesc.squash) && this.transparency.isSame(newDesc.transparency) && this.normalizeSizeKeypointTime === newDesc.normalizeSizeKeypointTime && this.flipbookLayout === newDesc.flipbookLayout && this.flipbookBlendFrames === newDesc.flipbookBlendFrames && this.flipbookFramerate.isSame(newDesc.flipbookFramerate) && this.flipbookMode === newDesc.flipbookMode && this.flipbookSizeX === newDesc.flipbookSizeX && this.flipbookSizeY === newDesc.flipbookSizeY && this.flipbookStartRandom === newDesc.flipbookStartRandom;
51577
51621
  }
51578
51622
  fromEmitterDesc(other) {
51579
51623
  this.lockedToPart = other.lockedToPart;
@@ -51893,18 +51937,18 @@ class EmitterGroupDesc extends RenderDesc {
51893
51937
  return emitter;
51894
51938
  }
51895
51939
  //inherited from RenderDesc
51896
- isSame(other) {
51897
- if (this.needsRegeneration(other)) {
51940
+ isSame(newDesc) {
51941
+ if (this.needsRegeneration(newDesc)) {
51898
51942
  return false;
51899
51943
  }
51900
- return this.time === other.time;
51944
+ return this.time === newDesc.time;
51901
51945
  }
51902
- needsRegeneration(other) {
51903
- if (this.emitterDescs.length !== other.emitterDescs.length) {
51946
+ needsRegeneration(newDesc) {
51947
+ if (this.emitterDescs.length !== newDesc.emitterDescs.length) {
51904
51948
  return true;
51905
51949
  }
51906
51950
  for (let i = 0; i < this.emitterDescs.length; i++) {
51907
- if (!this.emitterDescs[i].needsRegeneration(other.emitterDescs[i])) {
51951
+ if (!this.emitterDescs[i].needsRegeneration(newDesc.emitterDescs[i])) {
51908
51952
  return true;
51909
51953
  }
51910
51954
  }
@@ -52639,8 +52683,8 @@ class AttachmentDesc extends RenderDesc {
52639
52683
  isSame(other) {
52640
52684
  return this.visible === other.visible && this.cframe.isSame(other.cframe);
52641
52685
  }
52642
- needsRegeneration(other) {
52643
- return this.visible !== other.visible;
52686
+ needsRegeneration(newDesc) {
52687
+ return this.visible !== newDesc.visible;
52644
52688
  }
52645
52689
  virtualFromRenderDesc(other) {
52646
52690
  this.cframe = other.cframe.clone();
@@ -52699,8 +52743,8 @@ class LightDesc extends RenderDesc {
52699
52743
  isSame(other) {
52700
52744
  return this.enabled === other.enabled && this.shadows === other.shadows && this.color.isSame(other.color) && this.brightness === other.brightness && this.range === other.range && this.lightType === other.lightType && this.angle === other.angle && this.face === other.face && this.cframe.isSame(other.cframe);
52701
52745
  }
52702
- needsRegeneration(other) {
52703
- return this.lightType !== other.lightType;
52746
+ needsRegeneration(newDesc) {
52747
+ return this.lightType !== newDesc.lightType;
52704
52748
  }
52705
52749
  virtualFromRenderDesc(other) {
52706
52750
  this.enabled = other.enabled;
@@ -52774,11 +52818,11 @@ class LightDesc extends RenderDesc {
52774
52818
  if (light instanceof PointLight || light instanceof SpotLight) {
52775
52819
  light.decay = 0.4;
52776
52820
  light.visible = this.enabled;
52777
- light.intensity = this.brightness;
52821
+ light.intensity = this.brightness * 4;
52778
52822
  light.distance = this.range + 0.5;
52779
52823
  light.castShadow = this.shadows;
52780
52824
  light.shadow.intensity = 0.5;
52781
- light.color = new Color().setRGB(this.color.R, this.color.G, this.color.B);
52825
+ light.color = new Color().setRGB(this.color.R, this.color.G, this.color.B, SRGBColorSpace);
52782
52826
  const resultCF = this.cframe;
52783
52827
  const targetCF = new CFrame();
52784
52828
  if (light instanceof SpotLight) {
@@ -59383,7 +59427,7 @@ class OutfitRenderer {
59383
59427
  if (animatorW) {
59384
59428
  animatorW.data.forceTransitionTime = 0;
59385
59429
  }
59386
- if (!this.outfit.containsAssetType("Gear")) {
59430
+ if (!this.outfit.containsAssetType("Gear") || this.outfit.playerAvatarType === AvatarType.R15 && !this.hasAnimationSetAnimation("pose")) {
59387
59431
  if (this.outfit.playerAvatarType === AvatarType.R15) {
59388
59432
  if (this.hasAnimationSetAnimation("pose")) {
59389
59433
  this.setMainAnimation("pose").then(() => {
@@ -59556,12 +59600,8 @@ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "
59556
59600
  }
59557
59601
  if (outfitRenderer.backgroundRenderer.backgroundId) {
59558
59602
  renderScene.directionalLight.castShadow = true;
59559
- renderScene.directionalLight.position.set(...renderScene.directionalLight.position.toArray().map((v, i) => {
59560
- return i === 2 ? -v : v;
59561
- }));
59562
- renderScene.directionalLight2.position.set(...renderScene.directionalLight2.position.toArray().map((v, i) => {
59563
- return i === 2 ? -v : v;
59564
- }));
59603
+ renderScene.directionalLight.position.set(-0.55828 * 10, 0.72756 * 10, -0.39873 * 10);
59604
+ renderScene.directionalLight2.position.set(0.55828 * 10, -0.72756 * 10, 0.39873 * 10);
59565
59605
  }
59566
59606
  if (outfitRenderer.currentRig) {
59567
59607
  let cameraCFrame = new CFrame();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",