roavatar-renderer 1.5.17 → 1.5.18

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +119 -16
  2. package/dist/index.js +375 -45
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -88,6 +88,8 @@ export declare const AllAnimations: AnimationProp[];
88
88
 
89
89
  export declare const AllAnimationSorts: ItemSort[];
90
90
 
91
+ export declare const AllAvatarModelOutfitUpdateTypes: AvatarModelUpdateType[];
92
+
91
93
  export declare const AllBodyParts: number[];
92
94
 
93
95
  export declare const AllBodyPartsSorts: ItemSort[];
@@ -313,11 +315,28 @@ export declare const API: {
313
315
  WearOutfit: (auth: Authentication, outfit: Outfit, onlyItems: boolean) => Promise<[boolean, boolean]>;
314
316
  SaveOutfitNoRetry: (auth: Authentication, outfit: Outfit) => Promise<Response>;
315
317
  GetAvatarDetails: (userId: number) => Promise<Response | Outfit>;
318
+ GetAvatarModel: () => Promise<Response | OutfitModel>;
319
+ UpdateAvatarModel: (auth: Authentication, model: OutfitModel, updateTypes?: AvatarModelUpdateType[]) => Promise<Response>;
320
+ GetOutfitModel: (id: number | string, creatorId: number) => Promise<Response | OutfitModel>;
321
+ CreateOutfitModel: (auth: Authentication, model: OutfitModel) => Promise<Response>;
322
+ UpdateOutfitModel: (auth: Authentication, model: OutfitModel, id: number, updateTypes?: AvatarModelUpdateType[]) => Promise<Response>;
316
323
  GetHeadShapes: (pageToken: string | null | undefined) => Promise<AvatarInventory_Result | Response>;
317
324
  GetAvatarInventory: (sortOption: string, pageToken: string | null | undefined, itemInfos?: ItemSort[]) => Promise<AvatarInventory_Result | Response>;
325
+ /**
326
+ * @deprecated Use GetOutfitModel instead
327
+ */
318
328
  GetOutfitDetails: (outfitId: number | string, userId: number) => Promise<Response | Outfit>;
329
+ /**
330
+ * @deprecated Use CreateOutfitModel instead
331
+ */
319
332
  SaveOutfit: (auth: Authentication, outfit: Outfit) => Promise<Response>;
333
+ /**
334
+ * @deprecated Use UpdateOutfitModel instead
335
+ */
320
336
  UpdateOutfit: (auth: Authentication, outfitId: number | string, newOutfit: Outfit) => Promise<Response>;
337
+ /**
338
+ * @deprecated Use UpdateOutfitModel instead
339
+ */
321
340
  PatchOutfit: (auth: Authentication, outfitId: number | string, patchData: any) => Promise<Response>;
322
341
  DeleteOutfit: (auth: Authentication, outfitId: number | string) => Promise<Response>;
323
342
  GetUserOutfits: (userId: number) => Promise<Response | GetUserOutfits_Result>;
@@ -345,16 +364,16 @@ export declare const API: {
345
364
  IsLayered: (id: number) => Promise<boolean | Response>;
346
365
  };
347
366
  Catalog: {
348
- GetNavigationMenuItems: () => Promise<NavigationMenuItems | Response>;
349
- GetTopics: (auth: Authentication, body: GetTopics_Payload) => Promise<GetTopics_Result | Response>;
350
- Search: ({ taxonomy, salesTypeFilter, sortType, categoryFilter, keyword, topics, creatorName, minPrice, maxPrice, includeNotForSale, limit }: Search_Payload, cursor?: string) => Promise<Search_Result | Response>;
351
- GetBundleDetails: (bundleId: number | string) => Promise<BundleDetails_Result | Response>;
367
+ GetNavigationMenuItems: () => Promise<Response | NavigationMenuItems>;
368
+ GetTopics: (auth: Authentication, body: GetTopics_Payload) => Promise<Response | GetTopics_Result>;
369
+ Search: ({ taxonomy, salesTypeFilter, sortType, categoryFilter, keyword, topics, creatorName, minPrice, maxPrice, includeNotForSale, limit }: Search_Payload, cursor?: string) => Promise<Response | Search_Result>;
370
+ GetBundleDetails: (bundleId: number | string) => Promise<Response | BundleDetails_Result>;
352
371
  GetItemDetails: (auth: Authentication, items: {
353
372
  itemType: "Asset" | "Bundle";
354
373
  id: number;
355
- }[]) => Promise<ItemDetails_Result | Response>;
356
- GetMarketplaceWidgetsSearch: (query: string) => Promise<MarketplaceWidgets_Result | Response>;
357
- GetMarketplaceWidgets: (context?: string) => Promise<MarketplaceWidgets_Result | Response>;
374
+ }[]) => Promise<Response | ItemDetails_Result>;
375
+ GetMarketplaceWidgetsSearch: (query: string) => Promise<Response | MarketplaceWidgets_Result>;
376
+ GetMarketplaceWidgets: (context?: string) => Promise<Response | MarketplaceWidgets_Result>;
358
377
  };
359
378
  Develop: {
360
379
  GetLatestVersions: (auth: Authentication, assetIds: number[]) => Promise<Response | LatestVersions_Result>;
@@ -366,7 +385,7 @@ export declare const API: {
366
385
  Users: {
367
386
  GetUserInfo: () => Promise<UserInfo | undefined>;
368
387
  GetIdsFromUsernames: (usernames: string[]) => Promise<any>;
369
- GetInfoForId: (userId: number) => Promise<GetInfoForId_Result | Response>;
388
+ GetInfoForId: (userId: number) => Promise<Response | GetInfoForId_Result>;
370
389
  UserOmniSearch: (query: string, cursor?: string) => Promise<Response | UserOmniSearch_Result>;
371
390
  };
372
391
  Thumbnails: {
@@ -576,6 +595,19 @@ export declare class Authentication {
576
595
  getSessionUUID(): string;
577
596
  }
578
597
 
598
+ declare interface AvatarConfigurations {
599
+ emotes?: {
600
+ assetId: number;
601
+ assetName: string;
602
+ position: number;
603
+ }[];
604
+ background?: {
605
+ backgroundAsset: AssetJson;
606
+ };
607
+ thumbnailCustomizations?: ThumbnailsCustomization_Payload[];
608
+ profileFrame: null;
609
+ }
610
+
579
611
  /**@category API */
580
612
  export declare interface AvatarInventory_Result {
581
613
  avatarInventoryItems: {
@@ -616,6 +648,13 @@ export declare interface AvatarInventory_Result {
616
648
  nextPageToken: string | null;
617
649
  }
618
650
 
651
+ export declare interface AvatarModel_Result {
652
+ avatarModel: OutfitJson;
653
+ avatarConfigurations: AvatarConfigurations | null;
654
+ }
655
+
656
+ export declare type AvatarModelUpdateType = "UpdateName" | "UpdateBodyColors" | "UpdateAssets" | "UpdateScales" | "UpdateBackground";
657
+
619
658
  /** @category Outfit */
620
659
  export declare type AvatarType = "R6" | "R15";
621
660
 
@@ -719,6 +758,12 @@ export declare type BodyColor3sJson = {
719
758
  leftArmColor3?: string;
720
759
  rightLegColor3?: string;
721
760
  leftLegColor3?: string;
761
+ headColor?: string;
762
+ torsoColor?: string;
763
+ rightArmColor?: string;
764
+ leftArmColor?: string;
765
+ rightLegColor?: string;
766
+ leftLegColor?: string;
722
767
  };
723
768
 
724
769
  /**@category Outfit */
@@ -929,6 +974,7 @@ export declare class CFrame {
929
974
  fromMatrix(m: Mat4x4): this;
930
975
  fromRotationMatrix(r00: number, r01: number, r02: number, r10: number, r11: number, r12: number, r20: number, r21: number, r22: number, order?: string): void;
931
976
  lookVector(): Vec3;
977
+ upVector(): Vec3;
932
978
  static lookAt(eye: Vec3, target: Vec3, up?: Vec3): CFrame;
933
979
  static fromEulerAngles(rx: number, ry: number, rz: number, order?: THREE.EulerOrder): CFrame;
934
980
  inverse(): CFrame;
@@ -1527,6 +1573,7 @@ export declare function gaussian_rbf(v0: Vec3, v1: Vec3, sigma?: number): number
1527
1573
  * @param gltfAutoDownload Automatically download gltf file
1528
1574
  * @returns ThumbnailResult, always a string for 2d thumbnails, 3d can be ArrayBuffer (glb, binary) or {[key: string]: unknown} (gltf, json)
1529
1575
  *
1576
+ * @deprecated Use new Thumbnails category instead
1530
1577
  * @category ThumbnailGenerator
1531
1578
  *
1532
1579
  * @example
@@ -1555,6 +1602,8 @@ export declare function gaussian_rbf(v0: Vec3, v1: Vec3, sigma?: number): number
1555
1602
  */
1556
1603
  export declare function generateModelThumbnail(auth: Authentication, renderScene: RBXRendererScene, model: Instance, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean, includeAnimations?: boolean): Promise<ThumbnailResult>;
1557
1604
 
1605
+ export declare function generateOutfitModelThumbnail(auth: Authentication, outfitModel: OutfitModel, options: Partial<OutfitModelThumbnailOptions>): Promise<ThumbnailResult>;
1606
+
1558
1607
  /**
1559
1608
  * Generates a 2d or 3d thumbnail of an outfit
1560
1609
  * @param auth Authentication
@@ -1565,6 +1614,7 @@ export declare function generateModelThumbnail(auth: Authentication, renderScene
1565
1614
  * @param gltfAutoDownload Automatically download gltf file
1566
1615
  * @returns ThumbnailResult, always a string for 2d thumbnails, 3d can be ArrayBuffer (glb, binary) or {[key: string]: unknown} (gltf, json)
1567
1616
  *
1617
+ * @deprecated Use new Thumbnails category instead
1568
1618
  * @category ThumbnailGenerator
1569
1619
  *
1570
1620
  * @example
@@ -1580,7 +1630,7 @@ export declare function generateModelThumbnail(auth: Authentication, renderScene
1580
1630
  * console.log(result)
1581
1631
  * ```
1582
1632
  */
1583
- export declare function generateOutfitThumbnail(auth: Authentication, outfit: Outfit, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean, includeAnimations?: boolean): Promise<ThumbnailResult>;
1633
+ export declare function generateOutfitThumbnail(auth: Authentication, outfit: Outfit, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean, includeAnimations?: boolean, renderSceneParam?: RBXRendererScene): Promise<ThumbnailResult>;
1584
1634
 
1585
1635
  export declare function generateUUIDv4(): string;
1586
1636
 
@@ -1600,6 +1650,7 @@ export declare function getCameraCFrameForAvatarNonCustomized(rig: Instance): CF
1600
1650
  * @param yRot Customized yRot
1601
1651
  * @param distance Customized distanceScale
1602
1652
  * @returns Thumbnail camera cframe
1653
+ * @deprecated Use new Thumbnails category instead
1603
1654
  * @category ThumbnailGenerator
1604
1655
  */
1605
1656
  export declare function getCameraCFrameForHeadshotCustomized(rig: Instance, fov: number, yRot: number, distance: number): CFrame | undefined;
@@ -1609,14 +1660,18 @@ export declare function getCameraCFrameForHeadshotCustomized(rig: Instance, fov:
1609
1660
  */
1610
1661
  export declare function getDistIndexArray(ref: FileMesh, dist: FileMesh): (number | undefined)[];
1611
1662
 
1612
- /**@category ThumbnailGenerator */
1663
+ /**
1664
+ * @deprecated Use new Thumbnails category instead
1665
+ * @category ThumbnailGenerator */
1613
1666
  export declare function getExtents(cframe: CFrame, parts: Instance[]): [Vector3, Vector3];
1614
1667
 
1615
- /**@category ThumbnailGenerator */
1668
+ /**
1669
+ * @deprecated Use new Thumbnails category instead
1670
+ * @category ThumbnailGenerator */
1616
1671
  export declare function getExtentsCenter(extents: [Vector3, Vector3]): Vector3;
1617
1672
 
1618
1673
  /**
1619
- * @deprecated this is SO broken
1674
+ * @deprecated Use new Thumbnails category instead
1620
1675
  * @category ThumbnailGenerator
1621
1676
  * */
1622
1677
  export declare function getExtentsForParts(parts: Instance[], includeTransform?: boolean): [Vector3, Vector3];
@@ -1676,9 +1731,10 @@ export declare interface GetSubscription_Result {
1676
1731
  * Calculates the CFrame the camera should be at when generating a thumbnail
1677
1732
  * @param model The model-like instance to get thumbnail camera for
1678
1733
  * @returns Thumbnail camera cframe
1734
+ * @deprecated Use new Thumbnails category instead
1679
1735
  * @category ThumbnailGenerator
1680
1736
  */
1681
- export declare function getThumbnailCameraCFrame(model: Instance): CFrame | undefined;
1737
+ export declare function getThumbnailCameraCFrame(model: Instance, fov: number, forceAngle?: Vec3): CFrame | undefined;
1682
1738
 
1683
1739
  /**@category API */
1684
1740
  export declare interface GetTopics_Payload {
@@ -2158,11 +2214,16 @@ export declare class LocalOutfit {
2158
2214
  date: number;
2159
2215
  image?: string;
2160
2216
  buffer: string;
2217
+ bg: number;
2161
2218
  constructor(outfit: Outfit);
2162
2219
  toJson(): LocalOutfitJson;
2163
2220
  fromJson(data: LocalOutfitJson): this;
2164
2221
  update(outfit: Outfit): void;
2222
+ /**
2223
+ * @deprecated Use toOutfitModel() instead
2224
+ */
2165
2225
  toOutfit(auth: Authentication): Promise<Outfit>;
2226
+ toOutfitModel(auth: Authentication): Promise<OutfitModel>;
2166
2227
  }
2167
2228
 
2168
2229
  export declare interface LocalOutfitJson {
@@ -2172,6 +2233,7 @@ export declare interface LocalOutfitJson {
2172
2233
  date: number;
2173
2234
  image: string | undefined;
2174
2235
  buffer: string;
2236
+ bg?: number;
2175
2237
  }
2176
2238
 
2177
2239
  /**
@@ -2660,6 +2722,7 @@ export declare class Outfit {
2660
2722
  clone(): Outfit;
2661
2723
  toJson(removeNotOwnedAssets?: boolean): OutfitJson;
2662
2724
  toCleanJson(removeNotOwnedAssets?: boolean): OutfitJson;
2725
+ toCleanJsonV4(removeNotOwnedAssets?: boolean): OutfitJson;
2663
2726
  fromJson(outfitJson: OutfitJson): void;
2664
2727
  /**
2665
2728
  * @deprecated Incorrect, use getValidationIssues() instead
@@ -2715,6 +2778,29 @@ export declare type OutfitJson = {
2715
2778
  scales?: ScaleJson;
2716
2779
  };
2717
2780
 
2781
+ export declare class OutfitModel {
2782
+ outfit: Outfit;
2783
+ emotes: Map<number, Asset>;
2784
+ background?: Asset;
2785
+ thumbnailCustomizations?: ThumbnailCustomization[];
2786
+ profileFrame: undefined;
2787
+ fromJson(outfitModel: AvatarModel_Result | OutfitModel_Result): OutfitModel;
2788
+ clone(): OutfitModel;
2789
+ }
2790
+
2791
+ export declare interface OutfitModel_Result {
2792
+ outfitModel: OutfitJson;
2793
+ outfitConfigurations: AvatarConfigurations | null;
2794
+ }
2795
+
2796
+ export declare type OutfitModelThumbnailOptions = {
2797
+ size: Vec2;
2798
+ type: ThumbnailType;
2799
+ quality: number;
2800
+ gltfAutoDownload: boolean;
2801
+ includeAnimations: boolean;
2802
+ };
2803
+
2718
2804
  /** @category Outfit */
2719
2805
  export declare type OutfitOrigin = "WebAvatar" | "WebOutfit" | "Other" | "Look";
2720
2806
 
@@ -2761,7 +2847,7 @@ export declare class OutfitRenderer {
2761
2847
  /**
2762
2848
  * Updates the current rig, called internally by _updateOutfit()
2763
2849
  */
2764
- _setRigTo(newRigType: AvatarType): Promise<Response | Instance>;
2850
+ _setRigTo(newRigType: AvatarType): Promise<Instance | Response>;
2765
2851
  /**
2766
2852
  * Rerenders the current outfit, called internally by setOutfit() and constructor
2767
2853
  */
@@ -3458,6 +3544,7 @@ export declare interface Search_Result {
3458
3544
  * Gives a scene the default appearance for thumbnails
3459
3545
  * @param renderScene RBXRenderScene to setup
3460
3546
  *
3547
+ * @deprecated Use new Thumbnails category instead
3461
3548
  * @category ThumbnailGenerator
3462
3549
  */
3463
3550
  export declare function setupThumbnailScene(renderScene: RBXRendererScene): void;
@@ -3564,6 +3651,18 @@ export declare const StringBufferProperties: string[];
3564
3651
 
3565
3652
  declare type ThreePoseCorrective = Vec3;
3566
3653
 
3654
+ export declare class ThumbnailCustomization {
3655
+ thumbnailType: number;
3656
+ emoteAssetId: number;
3657
+ fieldOfViewDeg: number;
3658
+ yRotDeg: number;
3659
+ distanceScale: number;
3660
+ constructor(thumbnailType: number);
3661
+ fromJson(json: ThumbnailsCustomization_Payload): this;
3662
+ toJson(): ThumbnailsCustomization_Payload;
3663
+ clone(): ThumbnailCustomization;
3664
+ }
3665
+
3567
3666
  /**@category API */
3568
3667
  export declare interface ThumbnailCustomizations_Result {
3569
3668
  "avatarThumbnailCustomizations": {
@@ -3577,7 +3676,9 @@ export declare interface ThumbnailCustomizations_Result {
3577
3676
  }[];
3578
3677
  }
3579
3678
 
3580
- /**@category ThumbnailGenerator */
3679
+ /**
3680
+ * @deprecated Use new Thumbnails category instead
3681
+ * @category ThumbnailGenerator */
3581
3682
  export declare type ThumbnailResult = ArrayBuffer | {
3582
3683
  [key: string]: unknown;
3583
3684
  } | string | undefined;
@@ -3593,7 +3694,9 @@ export declare interface ThumbnailsCustomization_Payload {
3593
3694
  };
3594
3695
  }
3595
3696
 
3596
- /**@category ThumbnailGenerator */
3697
+ /**
3698
+ * @deprecated Use new Thumbnails category instead
3699
+ * @category ThumbnailGenerator */
3597
3700
  export declare type ThumbnailType = "png" | "webp" | "gltf" | "glb";
3598
3701
 
3599
3702
  /**
package/dist/index.js CHANGED
@@ -1,3 +1,26 @@
1
+ function cloneSearch_Payload(data) {
2
+ const newData = {
3
+ taxonomy: data.taxonomy,
4
+ salesTypeFilter: data.salesTypeFilter,
5
+ categoryFilter: data.categoryFilter,
6
+ sortType: data.sortType,
7
+ keyword: data.keyword,
8
+ topics: void 0,
9
+ creatorName: data.creatorName,
10
+ minPrice: data.minPrice,
11
+ maxPrice: data.maxPrice,
12
+ includeNotForSale: data.includeNotForSale,
13
+ limit: data.limit
14
+ };
15
+ if (data.topics) {
16
+ newData.topics = [];
17
+ for (const topic of data.topics) {
18
+ newData.topics.push(topic);
19
+ }
20
+ }
21
+ return newData;
22
+ }
23
+ const AllAvatarModelOutfitUpdateTypes = ["UpdateBodyColors", "UpdateAssets", "UpdateScales", "UpdateBackground"];
1
24
  const BrickColors = {
2
25
  1: "#F2F3F3",
3
26
  2: "#A1A5A2",
@@ -31497,6 +31520,16 @@ class CFrame {
31497
31520
  lookVector.applyQuaternion(quat);
31498
31521
  return lookVector.toArray();
31499
31522
  }
31523
+ upVector() {
31524
+ const matrix = this.getTHREEMatrix();
31525
+ const pos = new Vector3$1();
31526
+ const quat = new Quaternion();
31527
+ const scale = new Vector3$1();
31528
+ matrix.decompose(pos, quat, scale);
31529
+ const upVector = new Vector3$1(0, 1, 0);
31530
+ upVector.applyQuaternion(quat);
31531
+ return upVector.toArray();
31532
+ }
31500
31533
  static lookAt(eye, target, up = [0, 1, 0]) {
31501
31534
  const matrix = new Matrix4().lookAt(new Vector3$1(...eye), new Vector3$1(...target), new Vector3$1(...up));
31502
31535
  const newCFrame = new CFrame();
@@ -31750,6 +31783,9 @@ class Instance {
31750
31783
  if (value && value.toLowerCase().includes(FLAGS.SEARCH_FOR_STRING)) {
31751
31784
  log(true, this.GetFullName());
31752
31785
  log(true, value);
31786
+ if (value.length > 1e4) {
31787
+ download(this.GetFullName(), value);
31788
+ }
31753
31789
  }
31754
31790
  }
31755
31791
  }
@@ -33441,7 +33477,8 @@ const AssetTypes = [
33441
33477
  "LipMakeup",
33442
33478
  "EyeMakeup",
33443
33479
  "VoxelFragment",
33444
- "AvatarBackground"
33480
+ "AvatarBackground",
33481
+ "TextDocument"
33445
33482
  ];
33446
33483
  const WearableAssetTypes = [
33447
33484
  "TShirt",
@@ -33934,6 +33971,18 @@ class BodyColor3s {
33934
33971
  this.rightLegColor3 = bodyColorsJson.rightLegColor3;
33935
33972
  if (bodyColorsJson.leftLegColor3)
33936
33973
  this.leftLegColor3 = bodyColorsJson.leftLegColor3;
33974
+ if (bodyColorsJson.headColor)
33975
+ this.headColor3 = bodyColorsJson.headColor;
33976
+ if (bodyColorsJson.torsoColor)
33977
+ this.torsoColor3 = bodyColorsJson.torsoColor;
33978
+ if (bodyColorsJson.rightArmColor)
33979
+ this.rightArmColor3 = bodyColorsJson.rightArmColor;
33980
+ if (bodyColorsJson.leftArmColor)
33981
+ this.leftArmColor3 = bodyColorsJson.leftArmColor;
33982
+ if (bodyColorsJson.rightLegColor)
33983
+ this.rightLegColor3 = bodyColorsJson.rightLegColor;
33984
+ if (bodyColorsJson.leftLegColor)
33985
+ this.leftLegColor3 = bodyColorsJson.leftLegColor;
33937
33986
  }
33938
33987
  }
33939
33988
  class BodyColors {
@@ -34109,6 +34158,15 @@ class Outfit {
34109
34158
  ogJson.collections = void 0;
34110
34159
  return ogJson;
34111
34160
  }
34161
+ toCleanJsonV4(removeNotOwnedAssets = false) {
34162
+ const ogJson = this.toJson(removeNotOwnedAssets);
34163
+ ogJson.creatorId = void 0;
34164
+ ogJson.outfitType = void 0;
34165
+ ogJson.collections = void 0;
34166
+ ogJson.bodyColor3s = void 0;
34167
+ ogJson.bodyColors = this.bodyColors.toHexJson();
34168
+ return ogJson;
34169
+ }
34112
34170
  fromJson(outfitJson) {
34113
34171
  this.scale = new Scale();
34114
34172
  if (outfitJson.scale) {
@@ -34117,7 +34175,7 @@ class Outfit {
34117
34175
  this.scale.fromJson(outfitJson.scales);
34118
34176
  }
34119
34177
  const bodyColorsJson = outfitJson.bodyColors;
34120
- if (bodyColorsJson && !("headColor3" in bodyColorsJson)) {
34178
+ if (bodyColorsJson && !("headColor3" in bodyColorsJson) && !("headColor" in bodyColorsJson)) {
34121
34179
  const oldBodyColors = new BodyColors();
34122
34180
  oldBodyColors.fromJson(bodyColorsJson);
34123
34181
  if (FLAGS.BODYCOLOR3) {
@@ -35071,6 +35129,92 @@ class Outfit {
35071
35129
  return view.buffer;
35072
35130
  }
35073
35131
  }
35132
+ class ThumbnailCustomization {
35133
+ thumbnailType;
35134
+ emoteAssetId = 0;
35135
+ fieldOfViewDeg = 28.751935958862305;
35136
+ yRotDeg = 0;
35137
+ distanceScale = 1;
35138
+ constructor(thumbnailType) {
35139
+ this.thumbnailType = thumbnailType;
35140
+ }
35141
+ fromJson(json) {
35142
+ this.emoteAssetId = json.emoteAssetId;
35143
+ this.fieldOfViewDeg = json.camera.fieldOfViewDeg;
35144
+ this.yRotDeg = json.camera.yRotDeg;
35145
+ this.distanceScale = json.camera.distanceScale;
35146
+ return this;
35147
+ }
35148
+ toJson() {
35149
+ return {
35150
+ thumbnailType: this.thumbnailType,
35151
+ emoteAssetId: this.emoteAssetId,
35152
+ camera: {
35153
+ fieldOfViewDeg: this.fieldOfViewDeg,
35154
+ yRotDeg: this.yRotDeg,
35155
+ distanceScale: this.distanceScale
35156
+ }
35157
+ };
35158
+ }
35159
+ clone() {
35160
+ const copy = new ThumbnailCustomization(this.thumbnailType);
35161
+ copy.emoteAssetId = this.emoteAssetId;
35162
+ copy.fieldOfViewDeg = this.fieldOfViewDeg;
35163
+ copy.yRotDeg = this.yRotDeg;
35164
+ copy.distanceScale = this.distanceScale;
35165
+ return copy;
35166
+ }
35167
+ }
35168
+ class OutfitModel {
35169
+ outfit = new Outfit();
35170
+ emotes = /* @__PURE__ */ new Map();
35171
+ background;
35172
+ thumbnailCustomizations;
35173
+ profileFrame;
35174
+ fromJson(outfitModel) {
35175
+ const config = "avatarConfigurations" in outfitModel ? outfitModel.avatarConfigurations : outfitModel.outfitConfigurations;
35176
+ this.outfit.fromJson("avatarModel" in outfitModel ? outfitModel.avatarModel : outfitModel.outfitModel);
35177
+ if (config) {
35178
+ if (config.emotes) {
35179
+ for (const emote of config.emotes) {
35180
+ const asset = new Asset();
35181
+ asset.id = emote.assetId;
35182
+ asset.name = emote.assetName;
35183
+ this.emotes.set(emote.position, asset);
35184
+ }
35185
+ }
35186
+ if (config.background) {
35187
+ const asset = new Asset();
35188
+ asset.fromJson(config.background.backgroundAsset);
35189
+ this.background = asset;
35190
+ }
35191
+ if (config.thumbnailCustomizations) {
35192
+ this.thumbnailCustomizations = [];
35193
+ for (const json of config.thumbnailCustomizations) {
35194
+ this.thumbnailCustomizations.push(new ThumbnailCustomization(json.thumbnailType).fromJson(json));
35195
+ }
35196
+ }
35197
+ }
35198
+ return this;
35199
+ }
35200
+ clone() {
35201
+ const copy = new OutfitModel();
35202
+ copy.outfit = this.outfit.clone();
35203
+ copy.emotes = /* @__PURE__ */ new Map();
35204
+ for (const key of this.emotes.keys()) {
35205
+ copy.emotes.set(key, this.emotes.get(key));
35206
+ }
35207
+ copy.background = this.background?.clone();
35208
+ if (this.thumbnailCustomizations) {
35209
+ copy.thumbnailCustomizations = [];
35210
+ for (const customization of this.thumbnailCustomizations) {
35211
+ copy.thumbnailCustomizations.push(customization.clone());
35212
+ }
35213
+ }
35214
+ copy.profileFrame = this.profileFrame;
35215
+ return copy;
35216
+ }
35217
+ }
35074
35218
  class LocalOutfit {
35075
35219
  name;
35076
35220
  id;
@@ -35078,6 +35222,7 @@ class LocalOutfit {
35078
35222
  date;
35079
35223
  image;
35080
35224
  buffer;
35225
+ bg = 0;
35081
35226
  constructor(outfit) {
35082
35227
  this.name = outfit.name;
35083
35228
  this.id = outfit.id;
@@ -35092,7 +35237,8 @@ class LocalOutfit {
35092
35237
  creator: this.creator,
35093
35238
  date: this.date,
35094
35239
  image: this.image,
35095
- buffer: this.buffer
35240
+ buffer: this.buffer,
35241
+ bg: this.bg
35096
35242
  };
35097
35243
  }
35098
35244
  fromJson(data) {
@@ -35101,12 +35247,16 @@ class LocalOutfit {
35101
35247
  this.creator = data.creator;
35102
35248
  this.image = data.image;
35103
35249
  this.buffer = data.buffer;
35250
+ this.bg = data.bg || 0;
35104
35251
  return this;
35105
35252
  }
35106
35253
  update(outfit) {
35107
35254
  this.buffer = arrayBufferToBase64(outfit.toBuffer());
35108
35255
  this.image = void 0;
35109
35256
  }
35257
+ /**
35258
+ * @deprecated Use toOutfitModel() instead
35259
+ */
35110
35260
  async toOutfit(auth) {
35111
35261
  const outfit = new Outfit();
35112
35262
  outfit.name = this.name;
@@ -35115,6 +35265,26 @@ class LocalOutfit {
35115
35265
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
35116
35266
  return outfit;
35117
35267
  }
35268
+ async toOutfitModel(auth) {
35269
+ const outfitModel = new OutfitModel();
35270
+ const outfit = outfitModel.outfit;
35271
+ outfit.name = this.name;
35272
+ outfit.id = this.id;
35273
+ outfit.creatorId = this.creator;
35274
+ await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
35275
+ if (this.bg) {
35276
+ await outfit.addAssetId(this.bg, auth);
35277
+ const assetIndex = outfit.assets.findIndex((v) => {
35278
+ return v.id === this.bg;
35279
+ });
35280
+ if (assetIndex >= 0) {
35281
+ const asset = outfit.assets[assetIndex];
35282
+ outfitModel.background = asset;
35283
+ outfit.removeAsset(this.bg);
35284
+ }
35285
+ }
35286
+ return outfitModel;
35287
+ }
35118
35288
  }
35119
35289
  class ItemSort {
35120
35290
  subType;
@@ -35274,6 +35444,9 @@ const CategoryDictionary = {
35274
35444
  "Swim": new SortInfo([new ItemSort(54)]),
35275
35445
  "Climb": new SortInfo([new ItemSort(48)]),
35276
35446
  "Mood": new SortInfo([new ItemSort(AssetTypeNameToId.get("MoodAnimation") || 0)], "inventory")
35447
+ },
35448
+ "Profile": {
35449
+ "Backgrounds": new SortInfo([new ItemSort(AssetTypeNameToId.get("AvatarBackground") || 0)])
35277
35450
  }
35278
35451
  }
35279
35452
  };
@@ -37025,6 +37198,7 @@ function createContentMap() {
37025
37198
  }
37026
37199
  ContentMap.set("roavatar://AvatarEditorScene.rbxm", "74148511291027");
37027
37200
  ContentMap.set("roavatar://AvatarSceneNew.rbxm", "130507237273896");
37201
+ ContentMap.set("roavatar://AvatarCyclorama.rbxm", "79116945688799");
37028
37202
  }
37029
37203
  let CachedRoAvatarData = void 0;
37030
37204
  let ThumbnailsToBatch = [];
@@ -37281,6 +37455,64 @@ const API = {
37281
37455
  return response;
37282
37456
  }
37283
37457
  },
37458
+ GetAvatarModel: async function() {
37459
+ const response = await RBLXGet("https://avatar.roblox.com/v4/avatar?selectionTypes=0&selectionTypes=1&selectionTypes=2&selectionTypes=3&selectionTypes=4&selectionTypes=5");
37460
+ if (response.status !== 200) return response;
37461
+ const body = await response.json();
37462
+ const outfitModel = new OutfitModel().fromJson(body);
37463
+ return outfitModel;
37464
+ },
37465
+ UpdateAvatarModel: async function(auth, model, updateTypes = AllAvatarModelOutfitUpdateTypes) {
37466
+ const response = await RBLXPatch("https://avatar.roblox.com/v4/avatar", auth, {
37467
+ updateTypes,
37468
+ avatarDefinition: {
37469
+ updateAvatarConfig: {
37470
+ backgroundRequestModel: {
37471
+ id: model.background?.id || 0
37472
+ }
37473
+ },
37474
+ updateAvatarModel: model.outfit.toCleanJson()
37475
+ }
37476
+ });
37477
+ return response;
37478
+ },
37479
+ GetOutfitModel: async function(id, creatorId) {
37480
+ const response = await RBLXGet(`https://avatar.roblox.com/v4/outfits/${id}/details`);
37481
+ if (response.status !== 200) return response;
37482
+ const body = await response.json();
37483
+ const outfitModel = new OutfitModel().fromJson(body);
37484
+ outfitModel.outfit.origin = OutfitOrigin.WebOutfit;
37485
+ outfitModel.outfit.id = Number(id);
37486
+ outfitModel.outfit.creatorId = creatorId;
37487
+ return outfitModel;
37488
+ },
37489
+ CreateOutfitModel: async function(auth, model) {
37490
+ const response = await RBLXPost("https://avatar.roblox.com/v4/outfits/create", auth, {
37491
+ outfitDefinition: {
37492
+ updateOutfitConfig: {
37493
+ backgroundRequestModel: {
37494
+ id: model.background?.id || 0
37495
+ }
37496
+ },
37497
+ updateOutfitModel: model.outfit.toCleanJsonV4()
37498
+ }
37499
+ });
37500
+ return response;
37501
+ },
37502
+ UpdateOutfitModel: async function(auth, model, id, updateTypes = AllAvatarModelOutfitUpdateTypes) {
37503
+ const response = await RBLXPatch(`https://avatar.roblox.com/v4/outfits/${id}`, auth, {
37504
+ updateTypes,
37505
+ outfitDefinition: {
37506
+ updateOutfitConfig: {
37507
+ backgroundRequestModel: {
37508
+ id: model.background?.id || 0
37509
+ }
37510
+ },
37511
+ updateOutfitModel: model.outfit.toCleanJsonV4()
37512
+ }
37513
+ });
37514
+ return response;
37515
+ },
37284
37516
  GetHeadShapes: async function(pageToken) {
37285
37517
  const itemSort = new ItemSort(1, "headshape");
37286
37518
  return API.Avatar.GetAvatarInventory("1", pageToken, [itemSort]);
@@ -37318,6 +37550,9 @@ const API = {
37318
37550
  return result;
37319
37551
  }
37320
37552
  },
37553
+ /**
37554
+ * @deprecated Use GetOutfitModel instead
37555
+ */
37321
37556
  GetOutfitDetails: async function(outfitId, userId) {
37322
37557
  let requestUrl = "https://avatar.roblox.com/v1/outfits/";
37323
37558
  if (FLAGS.BODYCOLOR3) {
@@ -37335,6 +37570,9 @@ const API = {
37335
37570
  return response;
37336
37571
  }
37337
37572
  },
37573
+ /**
37574
+ * @deprecated Use CreateOutfitModel instead
37575
+ */
37338
37576
  SaveOutfit: async function(auth, outfit) {
37339
37577
  const requestUrl = `https://avatar.roblox.com/${FLAGS.BODYCOLOR3 ? "v3" : "v2"}/outfits/create`;
37340
37578
  const response = await RBLXPost(requestUrl, auth, outfit.toCleanJson());
@@ -37348,6 +37586,9 @@ const API = {
37348
37586
  return response2;
37349
37587
  }
37350
37588
  },
37589
+ /**
37590
+ * @deprecated Use UpdateOutfitModel instead
37591
+ */
37351
37592
  UpdateOutfit: async function(auth, outfitId, newOutfit) {
37352
37593
  let requestUrl = "https://avatar.roblox.com/v1/outfits/";
37353
37594
  if (FLAGS.BODYCOLOR3) {
@@ -37357,6 +37598,9 @@ const API = {
37357
37598
  const response = RBLXPatch(requestUrl, auth, JSON.stringify(newOutfit.toCleanJson()));
37358
37599
  return response;
37359
37600
  },
37601
+ /**
37602
+ * @deprecated Use UpdateOutfitModel instead
37603
+ */
37360
37604
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
37361
37605
  PatchOutfit: async function(auth, outfitId, patchData) {
37362
37606
  let requestUrl = "https://avatar.roblox.com/v1/outfits/";
@@ -37722,7 +37966,8 @@ const API = {
37722
37966
  type,
37723
37967
  id,
37724
37968
  size,
37725
- headShape
37969
+ headShape,
37970
+ includeBackground: type === "Outfit"
37726
37971
  };
37727
37972
  const cachedThumbnail = CACHE.Thumbnails.get(requestIdFromThumbnailInfo(thisThumbnailInfo));
37728
37973
  if (CACHE.Thumbnails.has(requestIdFromThumbnailInfo(thisThumbnailInfo))) {
@@ -37746,7 +37991,8 @@ const API = {
37746
37991
  resolves: [resolve],
37747
37992
  attempt: 0,
37748
37993
  lastTryTimestamp: 0,
37749
- headShape
37994
+ headShape,
37995
+ includeBackground: type === "Outfit"
37750
37996
  });
37751
37997
  });
37752
37998
  },
@@ -37755,7 +38001,8 @@ const API = {
37755
38001
  type,
37756
38002
  id,
37757
38003
  size,
37758
- headShape
38004
+ headShape,
38005
+ includeBackground: type === "Outfit"
37759
38006
  };
37760
38007
  CACHE.Thumbnails.delete(requestIdFromThumbnailInfo(thisThumbnailInfo));
37761
38008
  },
@@ -37887,6 +38134,9 @@ function requestIdFromThumbnailInfo(thumbnailInfo) {
37887
38134
  if (thumbnailInfo.headShape) {
37888
38135
  requestId += `:${thumbnailInfo.headShape}`;
37889
38136
  }
38137
+ if (thumbnailInfo.includeBackground) {
38138
+ requestId += `:${thumbnailInfo.includeBackground}`;
38139
+ }
37890
38140
  return requestId;
37891
38141
  }
37892
38142
  function PurgeFailedThumbnails() {
@@ -37917,7 +38167,8 @@ function BatchThumbnails() {
37917
38167
  "size": thumbnailInfo.size,
37918
38168
  "targetId": thumbnailInfo.id,
37919
38169
  "type": thumbnailInfo.type,
37920
- "headShape": thumbnailInfo.headShape
38170
+ "headShape": thumbnailInfo.headShape,
38171
+ "includeBackground": thumbnailInfo.includeBackground
37921
38172
  });
37922
38173
  auth = thumbnailInfo.auth;
37923
38174
  thumbnailInfo.lastTryTimestamp = Date.now() / 1e3;
@@ -37965,28 +38216,6 @@ function startBatchThumbnails() {
37965
38216
  }
37966
38217
  }, 10);
37967
38218
  }
37968
- function cloneSearch_Payload(data) {
37969
- const newData = {
37970
- taxonomy: data.taxonomy,
37971
- salesTypeFilter: data.salesTypeFilter,
37972
- categoryFilter: data.categoryFilter,
37973
- sortType: data.sortType,
37974
- keyword: data.keyword,
37975
- topics: void 0,
37976
- creatorName: data.creatorName,
37977
- minPrice: data.minPrice,
37978
- maxPrice: data.maxPrice,
37979
- includeNotForSale: data.includeNotForSale,
37980
- limit: data.limit
37981
- };
37982
- if (data.topics) {
37983
- newData.topics = [];
37984
- for (const topic of data.topics) {
37985
- newData.topics.push(topic);
37986
- }
37987
- }
37988
- return newData;
37989
- }
37990
38219
  function browserSendMessage(data) {
37991
38220
  return (chrome || browser).runtime.sendMessage(data);
37992
38221
  }
@@ -45581,6 +45810,8 @@ class MaterialDesc {
45581
45810
  dirty = false;
45582
45811
  //result
45583
45812
  createdTextures = [];
45813
+ noTextureTransparency = false;
45814
+ result;
45584
45815
  isSame(other) {
45585
45816
  if (this.dirty || other.dirty) return false;
45586
45817
  const propertiesSame = this.isDecal === other.isDecal && this.transparent === other.transparent && Math.round(this.transparency * 100) === Math.round(other.transparency * 100) && this.doubleSided === other.doubleSided && this.visible === other.visible && this.canHaveMipmaps === other.canHaveMipmaps;
@@ -45596,6 +45827,21 @@ class MaterialDesc {
45596
45827
  }
45597
45828
  return propertiesSame && layersSame;
45598
45829
  }
45830
+ needsRegeneration(other) {
45831
+ if (this.dirty || other.dirty) return true;
45832
+ const propertiesSame = this.isDecal === other.isDecal && this.doubleSided === other.doubleSided && this.visible === other.visible && this.canHaveMipmaps === other.canHaveMipmaps;
45833
+ let layersSame = true;
45834
+ if (this.layers.length !== other.layers.length) {
45835
+ layersSame = false;
45836
+ } else {
45837
+ for (let i = 0; i < this.layers.length; i++) {
45838
+ const thisLayer = this.layers[i];
45839
+ const otherLayer = other.layers[i];
45840
+ layersSame = layersSame && thisLayer.isSame(otherLayer);
45841
+ }
45842
+ }
45843
+ return !propertiesSame || !layersSame;
45844
+ }
45599
45845
  getTexturesOfType(textureType) {
45600
45846
  const urls = [];
45601
45847
  for (const layer of this.layers) {
@@ -46037,6 +46283,16 @@ class MaterialDesc {
46037
46283
  return this.compileTexture_DirectCompose(textureType);
46038
46284
  }
46039
46285
  }
46286
+ hasTransparency() {
46287
+ let hasTransparency = this.transparent;
46288
+ if (this.noTextureTransparency) {
46289
+ hasTransparency = false;
46290
+ }
46291
+ if (this.transparency > 0.01) {
46292
+ hasTransparency = true;
46293
+ }
46294
+ return hasTransparency;
46295
+ }
46040
46296
  async compileMaterial(meshDesc) {
46041
46297
  const colorTexturePromise = this.compileTexture("color", meshDesc);
46042
46298
  const normalTexturePromise = this.compileTexture("normal", meshDesc);
@@ -46050,11 +46306,10 @@ class MaterialDesc {
46050
46306
  let metalnessTexture = void 0;
46051
46307
  let emissiveTexture = void 0;
46052
46308
  let hasEmissive = false;
46053
- let hasTransparency = this.transparent;
46054
46309
  if (colorTextureInfo) {
46055
46310
  colorTexture = colorTextureInfo[0];
46056
46311
  if (!colorTextureInfo[1]) {
46057
- hasTransparency = false;
46312
+ this.noTextureTransparency = true;
46058
46313
  }
46059
46314
  }
46060
46315
  if (normalTextureInfo) {
@@ -46072,9 +46327,7 @@ class MaterialDesc {
46072
46327
  hasEmissive = true;
46073
46328
  }
46074
46329
  }
46075
- if (this.transparency > 0.01) {
46076
- hasTransparency = true;
46077
- }
46330
+ const hasTransparency = this.hasTransparency();
46078
46331
  let material = void 0;
46079
46332
  const textureTemplate = {};
46080
46333
  if (colorTexture) textureTemplate.map = colorTexture;
@@ -46115,8 +46368,27 @@ class MaterialDesc {
46115
46368
  depthWrite: this.transparency > 0 ? false : true
46116
46369
  });
46117
46370
  }
46371
+ this.result = material;
46118
46372
  return material;
46119
46373
  }
46374
+ fromMaterialDesc(other) {
46375
+ this.transparency = other.transparency;
46376
+ this.transparent = other.transparent;
46377
+ }
46378
+ updateTransparency() {
46379
+ if (this.result) {
46380
+ const ogHasTransparency = this.result.transparent;
46381
+ this.result.transparent = this.hasTransparency();
46382
+ this.result.opacity = 1 - this.transparency;
46383
+ this.result.depthWrite = this.transparency > 0 ? false : true;
46384
+ if (ogHasTransparency !== this.result.transparent) {
46385
+ this.result.needsUpdate = true;
46386
+ }
46387
+ }
46388
+ }
46389
+ updateResult() {
46390
+ this.updateTransparency();
46391
+ }
46120
46392
  addClothingLayers(parent) {
46121
46393
  const pants = parent.FindFirstChildOfClass("Pants");
46122
46394
  if (pants) {
@@ -46823,12 +47095,13 @@ class ObjectDesc extends RenderDesc {
46823
47095
  if (this.meshDesc.layerDesc && Date.now() / 1e3 - this.meshDesc.compilationTimestamp < FLAGS.LAYERED_CLOTHING_COOLDOWN) {
46824
47096
  return false;
46825
47097
  }
46826
- return !this.meshDesc.isSame(other.meshDesc) || !this.materialDesc.isSame(other.materialDesc);
47098
+ return !this.meshDesc.isSame(other.meshDesc) || this.materialDesc.needsRegeneration(other.materialDesc);
46827
47099
  }
46828
47100
  virtualFromRenderDesc(other) {
46829
47101
  this.cframe = other.cframe;
46830
47102
  this.size = other.size;
46831
47103
  this.isBodyPart = other.isBodyPart;
47104
+ this.materialDesc.fromMaterialDesc(other.materialDesc);
46832
47105
  }
46833
47106
  fromInstance(child) {
46834
47107
  this.instance = child;
@@ -47008,6 +47281,9 @@ class ObjectDesc extends RenderDesc {
47008
47281
  }
47009
47282
  }
47010
47283
  }
47284
+ if (this.materialDesc.result) {
47285
+ this.materialDesc.updateResult();
47286
+ }
47011
47287
  }
47012
47288
  static shouldRenderInstance(instance) {
47013
47289
  const isDecal = instance.className === "Decal";
@@ -51253,6 +51529,9 @@ class SoundWrapper extends InstanceWrapper {
51253
51529
  this.data.gainNode = void 0;
51254
51530
  this.data.buffer = void 0;
51255
51531
  });
51532
+ this.instance.Changed.Connect(() => {
51533
+ this._updateVolume();
51534
+ });
51256
51535
  }
51257
51536
  _updateVolume() {
51258
51537
  if (this.data.gainNode) {
@@ -52892,7 +53171,7 @@ function zoomExtents(cameraCFrame, modelCFrame, modelSize, targetFOV, distanceSc
52892
53171
  if (sizeType === "calculate") {
52893
53172
  largestSize = modelSize.magnitude() / 2 / Math.sin(rad(targetFOV / 2));
52894
53173
  }
52895
- const fovMultiplier = 70 / targetFOV;
53174
+ const fovMultiplier = sizeType === "largestAxis" ? 70 / targetFOV : 1;
52896
53175
  const lookDir = multiply(normalize(minus(cameraCFrame.Position, modelCFrame.Position)), [distanceScale, distanceScale, distanceScale]);
52897
53176
  cameraCFrame.Position = add(modelCFrame.Position, multiply(multiply(lookDir, [largestSize, largestSize, largestSize]), [fovMultiplier, fovMultiplier, fovMultiplier]));
52898
53177
  }
@@ -52991,7 +53270,7 @@ function getCameraCFrameForAvatarNonCustomized(rig) {
52991
53270
  zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
52992
53271
  return cameraCF;
52993
53272
  }
52994
- function getThumbnailCameraCFrame(model) {
53273
+ function getThumbnailCameraCFrame(model, fov2, forceAngle) {
52995
53274
  const thumbnailCamera = model.FindFirstChildOfClass("Camera");
52996
53275
  if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
52997
53276
  let rootPart = model.PropOrDefault("PrimaryPart", void 0);
@@ -53011,14 +53290,18 @@ function getThumbnailCameraCFrame(model) {
53011
53290
  lookVector = normalize(lookVector);
53012
53291
  }
53013
53292
  let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
53014
- lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, rad(45)));
53015
- lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(35), 0, 0));
53016
- lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, 0));
53293
+ if (!forceAngle) {
53294
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, rad(45)));
53295
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(35), 0, 0));
53296
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, 0));
53297
+ } else {
53298
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(forceAngle[0]), rad(forceAngle[1]), rad(forceAngle[2])));
53299
+ }
53017
53300
  lookVector = lookCF.lookVector();
53018
53301
  lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
53019
53302
  lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
53020
53303
  const cameraCF = lookCF.clone();
53021
- zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
53304
+ zoomExtents(cameraCF, rootPartCF, extentsSize, fov2, 1);
53022
53305
  return cameraCF;
53023
53306
  }
53024
53307
  class OutfitRenderer {
@@ -53281,7 +53564,7 @@ async function renderTargetToCanvas(renderTarget) {
53281
53564
  }
53282
53565
  async function generateModelThumbnail(auth, renderScene, model, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false, includeAnimations = false) {
53283
53566
  return new Promise((resolve) => {
53284
- const cameraCFrame = getThumbnailCameraCFrame(model);
53567
+ const cameraCFrame = getThumbnailCameraCFrame(model, renderScene.camera.fov);
53285
53568
  if (cameraCFrame) {
53286
53569
  RBXRenderer.setCameraCFrame(cameraCFrame, renderScene);
53287
53570
  }
@@ -53319,11 +53602,54 @@ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150
53319
53602
  }
53320
53603
  });
53321
53604
  }
53322
- async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false, includeAnimations = false) {
53605
+ async function generateOutfitModelThumbnail(auth, outfitModel, options) {
53606
+ const defaultOptions = {
53607
+ size: [150, 150],
53608
+ type: "png",
53609
+ quality: 1,
53610
+ gltfAutoDownload: false,
53611
+ includeAnimations: false
53612
+ };
53613
+ Object.assign(defaultOptions, options);
53614
+ const renderScene = RBXRenderer.addScene();
53615
+ setupThumbnailScene(renderScene);
53616
+ if (outfitModel.background?.id) {
53617
+ const avatarCycloramaRBX = await API.Asset.GetRBX("roavatar://AvatarCyclorama.rbxm");
53618
+ if (avatarCycloramaRBX instanceof Response) return void 0;
53619
+ const avatarCycloramaRoot = avatarCycloramaRBX.generateTree();
53620
+ const avatarCyclorama = avatarCycloramaRoot.GetChildren()[0];
53621
+ if (avatarCyclorama) {
53622
+ const backgroundDataRBX = await API.Asset.GetRBX("rbxassetid://" + outfitModel.background.id);
53623
+ if (backgroundDataRBX instanceof Response) return void 0;
53624
+ const backgroundDataRoot = backgroundDataRBX.generateTree();
53625
+ const backgroundData = backgroundDataRoot.GetChildren()[0];
53626
+ if (backgroundData) {
53627
+ if (backgroundData) {
53628
+ const colorValue = backgroundData.Child("Color");
53629
+ const imageIdValue = backgroundData.Child("ImageId");
53630
+ if (colorValue && imageIdValue) {
53631
+ const color = colorValue.Prop("Value");
53632
+ const imageId = imageIdValue.Prop("Value");
53633
+ avatarCyclorama.Child("color_mesh").setProperty("Color", color.toColor3uint8());
53634
+ avatarCyclorama.Child("texture_mesh").setProperty("TextureID", `rbxassetid://${imageId}`);
53635
+ avatarCyclorama.preRender();
53636
+ RBXRenderer.addInstance(avatarCyclorama, auth, renderScene);
53637
+ renderScene.camera.fov = 30;
53638
+ renderScene.camera.updateProjectionMatrix();
53639
+ }
53640
+ }
53641
+ }
53642
+ }
53643
+ }
53644
+ return generateOutfitThumbnail(auth, outfitModel.outfit, defaultOptions.size, defaultOptions.type, defaultOptions.quality, defaultOptions.gltfAutoDownload, defaultOptions.includeAnimations, renderScene);
53645
+ }
53646
+ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false, includeAnimations = false, renderSceneParam) {
53323
53647
  return new Promise((resolve) => {
53324
53648
  const startTime = performance.now();
53325
- const renderScene = RBXRenderer.addScene();
53326
- setupThumbnailScene(renderScene);
53649
+ const renderScene = renderSceneParam || RBXRenderer.addScene();
53650
+ if (renderScene !== renderSceneParam) {
53651
+ setupThumbnailScene(renderScene);
53652
+ }
53327
53653
  const outfitRenderer = new OutfitRenderer(auth, outfit, renderScene);
53328
53654
  outfitRenderer.doAddInstance = false;
53329
53655
  if (outfit.playerAvatarType === AvatarType.R6) outfitRenderer.deltaTimeMultiplier = 0;
@@ -53406,6 +53732,7 @@ export {
53406
53732
  AllAccessorySorts,
53407
53733
  AllAnimationSorts,
53408
53734
  AllAnimations,
53735
+ AllAvatarModelOutfitUpdateTypes,
53409
53736
  AllBodyParts,
53410
53737
  AllBodyPartsSorts,
53411
53738
  AllCharacterSorts,
@@ -53502,6 +53829,7 @@ export {
53502
53829
  NumberSequence,
53503
53830
  NumberSequenceKeypoint,
53504
53831
  Outfit,
53832
+ OutfitModel,
53505
53833
  OutfitOrigin,
53506
53834
  OutfitRenderer,
53507
53835
  PartType,
@@ -53536,6 +53864,7 @@ export {
53536
53864
  SpecialInfo,
53537
53865
  SpecialLayeredAssetTypes,
53538
53866
  StringBufferProperties,
53867
+ ThumbnailCustomization,
53539
53868
  ToRemoveBeforeBundleType,
53540
53869
  ToolWrapper,
53541
53870
  UDim,
@@ -53593,6 +53922,7 @@ export {
53593
53922
  floor,
53594
53923
  gaussian_rbf,
53595
53924
  generateModelThumbnail,
53925
+ generateOutfitModelThumbnail,
53596
53926
  generateOutfitThumbnail,
53597
53927
  generateUUIDv4,
53598
53928
  getCameraCFrameForAvatarNonCustomized,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.5.17",
3
+ "version": "1.5.18",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",