roavatar-renderer 1.6.3 → 1.6.4

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,20 @@ 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 examples check out the OutfitRenderer, BackgroundRenderer, RoAvatar (avatarPreview.tsx) or RoValra (ItemRender.ts) source code
64
+ 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
@@ -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>;
@@ -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": {
@@ -52774,11 +52809,11 @@ class LightDesc extends RenderDesc {
52774
52809
  if (light instanceof PointLight || light instanceof SpotLight) {
52775
52810
  light.decay = 0.4;
52776
52811
  light.visible = this.enabled;
52777
- light.intensity = this.brightness;
52812
+ light.intensity = this.brightness * 4;
52778
52813
  light.distance = this.range + 0.5;
52779
52814
  light.castShadow = this.shadows;
52780
52815
  light.shadow.intensity = 0.5;
52781
- light.color = new Color().setRGB(this.color.R, this.color.G, this.color.B);
52816
+ light.color = new Color().setRGB(this.color.R, this.color.G, this.color.B, SRGBColorSpace);
52782
52817
  const resultCF = this.cframe;
52783
52818
  const targetCF = new CFrame();
52784
52819
  if (light instanceof SpotLight) {
@@ -59383,7 +59418,7 @@ class OutfitRenderer {
59383
59418
  if (animatorW) {
59384
59419
  animatorW.data.forceTransitionTime = 0;
59385
59420
  }
59386
- if (!this.outfit.containsAssetType("Gear")) {
59421
+ if (!this.outfit.containsAssetType("Gear") || this.outfit.playerAvatarType === AvatarType.R15 && !this.hasAnimationSetAnimation("pose")) {
59387
59422
  if (this.outfit.playerAvatarType === AvatarType.R15) {
59388
59423
  if (this.hasAnimationSetAnimation("pose")) {
59389
59424
  this.setMainAnimation("pose").then(() => {
@@ -59556,12 +59591,8 @@ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "
59556
59591
  }
59557
59592
  if (outfitRenderer.backgroundRenderer.backgroundId) {
59558
59593
  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
- }));
59594
+ renderScene.directionalLight.position.set(-0.55828 * 10, 0.72756 * 10, -0.39873 * 10);
59595
+ renderScene.directionalLight2.position.set(0.55828 * 10, -0.72756 * 10, 0.39873 * 10);
59565
59596
  }
59566
59597
  if (outfitRenderer.currentRig) {
59567
59598
  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.4",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",