roavatar-renderer 1.3.6 → 1.4.0

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/dist/index.d.ts CHANGED
@@ -97,7 +97,7 @@ export declare class AnimationConstraintWrapper extends InstanceWrapper {
97
97
  setup(): void;
98
98
  }
99
99
 
100
- export declare type AnimationProp = "ClimbAnimation" | "FallAnimation" | "IdleAnimation" | "JumpAnimation" | "MoodAnimation" | "RunAnimation" | "SwimAnimation" | "WalkAnimation" | "dance1" | "dance2" | "dance3" | "toolnone";
100
+ export declare type AnimationProp = "ClimbAnimation" | "FallAnimation" | "IdleAnimation" | "JumpAnimation" | "MoodAnimation" | "RunAnimation" | "SwimAnimation" | "WalkAnimation" | "dance1" | "dance2" | "dance3" | "toolnone" | "pose";
101
101
 
102
102
  export declare const AnimationPropToName: {
103
103
  [K in AnimationProp]: string;
@@ -309,6 +309,9 @@ export declare const API: {
309
309
  PremiumFeatures: {
310
310
  GetSubscription: (userId: number) => Promise<Response | GetSubscription_Result>;
311
311
  };
312
+ Subscriptions: {
313
+ HasPlus: () => Promise<Response | boolean>;
314
+ };
312
315
  RBLXGet: typeof RBLXGet;
313
316
  RBLXPost: typeof RBLXPost;
314
317
  RBLXDelete: typeof RBLXDelete;
@@ -418,6 +421,13 @@ export declare const AssetTypeToMakeupType: {
418
421
  EyeMakeup: number;
419
422
  };
420
423
 
424
+ export declare class AttachmentWrapper extends InstanceWrapper {
425
+ static className: string;
426
+ static requiredProperties: string[];
427
+ setup(): void;
428
+ getWorldCFrame(): CFrame;
429
+ }
430
+
421
431
  export declare class Authentication {
422
432
  TOKEN?: string;
423
433
  SessionUUID?: string;
@@ -810,6 +820,9 @@ declare class COREMESH {
810
820
  getColors(): Uint8Array;
811
821
  getIndices(): Uint16Array;
812
822
  getTouchingVerts(index: number): number[];
823
+ getEdgeId(v0: number, v1: number): bigint;
824
+ getFaceEdges(i: number): [bigint, bigint, bigint];
825
+ getEdgeCounts(): Map<bigint, number>;
813
826
  }
814
827
 
815
828
  export declare function createContentMap(): void;
@@ -893,6 +906,8 @@ declare class DisposableDesc {
893
906
  dispose(_renderer: THREE.WebGLRenderer, _scene: THREE.Scene): void;
894
907
  }
895
908
 
909
+ export declare function disposeMesh(scene: THREE.Scene, mesh: THREE.Mesh): void;
910
+
896
911
  export declare function distance(v0: Vec3, v1: Vec3): number;
897
912
 
898
913
  export declare function divide(v0: Vec3, v1: Vec3): Vec3;
@@ -914,8 +929,12 @@ export { Event_2 as Event }
914
929
 
915
930
  export declare function exposeAPI(): void;
916
931
 
932
+ export declare function exposeFLAGS(): void;
933
+
917
934
  export declare function exposeMesh(): void;
918
935
 
936
+ export declare function exposeThumbnailGenerator(): void;
937
+
919
938
  export declare const FaceControlNames: string[];
920
939
 
921
940
  export declare class FaceControlsWrapper extends InstanceWrapper {
@@ -1012,6 +1031,8 @@ export declare class FileMeshSubset {
1012
1031
 
1013
1032
  export declare function fileMeshToTHREEGeometry(mesh: FileMesh, canIncludeSkinning?: boolean, forceVertexColor?: Vector3): THREE.BufferGeometry<THREE.NormalBufferAttributes, THREE.BufferGeometryEventMap>;
1014
1033
 
1034
+ export declare function FindFirstMatchingAttachment(attachmentName: string, rig: Instance): Instance | null;
1035
+
1015
1036
  export declare const FLAGS: {
1016
1037
  HAIR_IS_BODYPART: boolean;
1017
1038
  AVATAR_JOINT_UPGRADE: boolean;
@@ -1045,6 +1066,8 @@ export declare const FLAGS: {
1045
1066
  LEGACY_WELD_BEHAVIOR: boolean;
1046
1067
  USE_RENDERTARGET: boolean;
1047
1068
  AUTO_RESTORE_CONTEXT: boolean;
1069
+ RENDERTARGET_TO_CANVASTEXTURE: boolean;
1070
+ THUMBNAIL_TIMEOUT: number;
1048
1071
  SHOW_SKELETON_HELPER: boolean;
1049
1072
  UPDATE_SKELETON: boolean;
1050
1073
  ANIMATE_SKELETON: boolean;
@@ -1085,16 +1108,26 @@ export declare const FullBodyColors: string[];
1085
1108
 
1086
1109
  export declare function gaussian_rbf(v0: Vec3, v1: Vec3, sigma?: number): number;
1087
1110
 
1111
+ export declare function generateModelThumbnail(auth: Authentication, renderScene: RBXRendererScene, model: Instance, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean): Promise<ThumbnailResult>;
1112
+
1113
+ export declare function generateOutfitThumbnail(auth: Authentication, outfit: Outfit, size?: Vec2, type?: ThumbnailType, quality?: number, gltfAutoDownload?: boolean): Promise<ThumbnailResult>;
1114
+
1088
1115
  export declare function generateUUIDv4(): string;
1089
1116
 
1090
1117
  export declare function GetAttachedPart(accessory: Instance, rig: Instance): Instance | undefined;
1091
1118
 
1119
+ export declare function getCameraCFrameForAvatarNonCustomized(rig: Instance): CFrame | undefined;
1120
+
1092
1121
  export declare function getCameraCFrameForHeadshotCustomized(rig: Instance, fov: number, yRot: number, distance: number): CFrame | undefined;
1093
1122
 
1123
+ export declare function getCameraOffset(fov: number, extentsSize: Vector3): number;
1124
+
1094
1125
  export declare function getDistIndexArray(ref: FileMesh, dist: FileMesh): (number | undefined)[];
1095
1126
 
1096
1127
  export declare function getExtents(cframe: CFrame, parts: Instance[]): [Vector3, Vector3];
1097
1128
 
1129
+ export declare function getExtentsCenter(extents: [Vector3, Vector3]): Vector3;
1130
+
1098
1131
  /**@deprecated this is SO broken */
1099
1132
  export declare function getExtentsForParts(parts: Instance[], includeTransform?: boolean): [Vector3, Vector3];
1100
1133
 
@@ -1113,10 +1146,16 @@ export declare interface GetInfoForId_Result {
1113
1146
 
1114
1147
  export declare function getOffsetArray(inner: FileMesh, outer: FileMesh): ([Vec3, THREE.Quaternion, number] | undefined)[];
1115
1148
 
1149
+ export declare function getOriginalAttachmentOrientation(attachment: Instance): Vector3;
1150
+
1151
+ export declare function getOriginalAttachmentPosition(attachment: Instance): Vector3;
1152
+
1116
1153
  export declare function getOriginalSize(part: Instance): Vector3;
1117
1154
 
1118
1155
  export declare function getRandomBetweenInclusive(min: number, max: number): number;
1119
1156
 
1157
+ export declare function getRigExtentsWorld(rig: Instance): [Vector3, Vector3];
1158
+
1120
1159
  export declare interface GetSubscription_Result {
1121
1160
  "subscriptionProductModel": {
1122
1161
  "premiumFeatureId": number;
@@ -2254,6 +2293,8 @@ export declare class RBXRendererScene {
2254
2293
  scene: THREE.Scene;
2255
2294
  camera: THREE.PerspectiveCamera;
2256
2295
  controls: OrbitControls | undefined;
2296
+ shouldAnimate: boolean;
2297
+ destroyed: boolean;
2257
2298
  effectComposer: EffectComposer | undefined;
2258
2299
  scissor?: [number, number, number, number];
2259
2300
  viewport?: [number, number, number, number];
@@ -2274,6 +2315,10 @@ export declare class RBXRendererScene {
2274
2315
  directionalLight2?: THREE.DirectionalLight;
2275
2316
  setRect(bounds: DOMRect): void;
2276
2317
  noRect(): void;
2318
+ destroy(): void;
2319
+ exportGLTF(name?: string, autoDownload?: boolean): Promise<ArrayBuffer | {
2320
+ [key: string]: unknown;
2321
+ }>;
2277
2322
  }
2278
2323
 
2279
2324
  declare class RBXSimpleView {
@@ -2503,6 +2548,8 @@ export declare interface Search_Result {
2503
2548
  }[];
2504
2549
  }
2505
2550
 
2551
+ export declare function setupThumbnailScene(renderScene: RBXRendererScene): void;
2552
+
2506
2553
  declare class SimpleView {
2507
2554
  view: DataView;
2508
2555
  viewOffset: number;
@@ -2606,6 +2653,10 @@ export declare interface ThumbnailCustomizations_Result {
2606
2653
  }[];
2607
2654
  }
2608
2655
 
2656
+ export declare type ThumbnailResult = ArrayBuffer | {
2657
+ [key: string]: unknown;
2658
+ } | string | undefined;
2659
+
2609
2660
  export declare interface ThumbnailsCustomization_Payload {
2610
2661
  thumbnailType: number;
2611
2662
  emoteAssetId: number;
@@ -2616,6 +2667,8 @@ export declare interface ThumbnailsCustomization_Payload {
2616
2667
  };
2617
2668
  }
2618
2669
 
2670
+ export declare type ThumbnailType = "png" | "webp" | "gltf";
2671
+
2619
2672
  export declare class ToolWrapper extends InstanceWrapper {
2620
2673
  static className: string;
2621
2674
  static requiredProperties: string[];
@@ -2803,4 +2856,6 @@ export declare const xmlMagic = "<roblox ";
2803
2856
 
2804
2857
  export declare function zoomExtents(cameraCFrame: CFrame, modelCFrame: CFrame, modelSize: Vector3, targetFOV: number, distanceScale: number): void;
2805
2858
 
2859
+ export declare function zoomToExtents(cameraCFrame: CFrame, modelCFrame: CFrame, modelSize: Vector3, fov?: number): void;
2860
+
2806
2861
  export { }
package/dist/index.js CHANGED
@@ -27277,7 +27277,8 @@ const AnimationPropToName = {
27277
27277
  "dance1": "dance1",
27278
27278
  "dance2": "dance2",
27279
27279
  "dance3": "dance3",
27280
- "toolnone": "toolnone"
27280
+ "toolnone": "toolnone",
27281
+ "pose": "pose"
27281
27282
  };
27282
27283
  const DefaultAnimations = {
27283
27284
  "ClimbAnimation": ["climb", [["ClimbAnim", 507765644n]]],
@@ -27292,7 +27293,8 @@ const DefaultAnimations = {
27292
27293
  "dance1": ["dance1", [["2", 507772104n]]],
27293
27294
  "dance2": ["dance2", [["2", 507776879n]]],
27294
27295
  "dance3": ["dance3", [["2", 507777623n]]],
27295
- "toolnone": ["toolnone", [["ToolNoneAnim", 507768375n]]]
27296
+ "toolnone": ["toolnone", [["ToolNoneAnim", 507768375n]]],
27297
+ "pose": ["pose", [["pose", 11600209531n]]]
27296
27298
  };
27297
27299
  const DefaultAnimationsR6 = {
27298
27300
  "ClimbAnimation": ["climb", [["ClimbAnim", 180436334n]]],
@@ -27307,7 +27309,8 @@ const DefaultAnimationsR6 = {
27307
27309
  "dance1": ["dance1", [["2", 182491065n]]],
27308
27310
  "dance2": ["dance2", [["2", 182491277n]]],
27309
27311
  "dance3": ["dance3", [["2", 182491423n]]],
27310
- "toolnone": ["toolnone", [["ToolNoneAnim", 182393478n]]]
27312
+ "toolnone": ["toolnone", [["ToolNoneAnim", 182393478n]]],
27313
+ "pose": ["pose", []]
27311
27314
  };
27312
27315
  const animNamesR6 = {
27313
27316
  idle: [
@@ -27410,6 +27413,9 @@ const animNamesR15 = {
27410
27413
  ],
27411
27414
  mood: [
27412
27415
  { id: "http://www.roblox.com/asset/?id=14366558676", weight: 10 }
27416
+ ],
27417
+ pose: [
27418
+ { id: "http://www.roblox.com/asset/?id=11600209531", weight: 10 }
27413
27419
  ]
27414
27420
  /*wave: [
27415
27421
  { id: "http://www.roblox.com/asset/?id=507770239", weight: 10 }
@@ -28490,7 +28496,7 @@ function hashVec3Safe(a, b, c) {
28490
28496
  a = BigInt(a);
28491
28497
  b = BigInt(b);
28492
28498
  c = BigInt(c);
28493
- return a * 100n + b * 10n + c * 1n;
28499
+ return a * 10000000n + b * 1000n + c * 1n;
28494
28500
  }
28495
28501
  function calculateMagnitude3D(x, y, z) {
28496
28502
  return Math.sqrt(x * x + y * y + z * z);
@@ -28663,6 +28669,7 @@ function buildVertKD(mesh) {
28663
28669
  function inheritUV(to, from) {
28664
28670
  const meshCollider = new MeshCollider(to);
28665
28671
  const faceKD = buildFaceKD(from);
28672
+ const edgeCountMap = from.coreMesh.getEdgeCounts();
28666
28673
  for (let i = 0; i < to.coreMesh.numverts; i++) {
28667
28674
  const pos = to.coreMesh.getPos(i);
28668
28675
  const closest = nearestSearch(faceKD, pos);
@@ -28671,6 +28678,7 @@ function inheritUV(to, from) {
28671
28678
  const va = from.coreMesh.getUV(face[0]);
28672
28679
  const vb = from.coreMesh.getUV(face[1]);
28673
28680
  const vc = from.coreMesh.getUV(face[2]);
28681
+ let newAlpha = 255;
28674
28682
  const triangle = from.coreMesh.getTriangle(closestI);
28675
28683
  const closestPointPos = closestPointTriangle(pos, triangle);
28676
28684
  const barycentricPos = barycentric(closestPointPos, triangle);
@@ -28678,15 +28686,27 @@ function inheritUV(to, from) {
28678
28686
  barycentricPos[0] * va[0] + barycentricPos[1] * vb[0] + barycentricPos[2] * vc[0],
28679
28687
  barycentricPos[0] * va[1] + barycentricPos[1] * vb[1] + barycentricPos[2] * vc[1]
28680
28688
  ];
28689
+ if (barycentricPos[0] <= 0.1) {
28690
+ const edgeId = from.coreMesh.getEdgeId(face[1], face[2]);
28691
+ const edgeCount = edgeCountMap.get(edgeId) || 999;
28692
+ if (edgeCount <= 1) newAlpha = 0;
28693
+ } else if (barycentricPos[1] <= 0.1) {
28694
+ const edgeId = from.coreMesh.getEdgeId(face[0], face[2]);
28695
+ const edgeCount = edgeCountMap.get(edgeId) || 999;
28696
+ if (edgeCount <= 1) newAlpha = 0;
28697
+ } else if (barycentricPos[2] <= 0.1) {
28698
+ const edgeId = from.coreMesh.getEdgeId(face[0], face[1]);
28699
+ const edgeCount = edgeCountMap.get(edgeId) || 999;
28700
+ if (edgeCount <= 1) newAlpha = 0;
28701
+ }
28681
28702
  const ray = new Ray$1(pos, closestPointPos);
28682
28703
  if (meshCollider.raycast(ray)) {
28683
- newUV[0] = -Infinity;
28684
- newUV[1] = -Infinity;
28704
+ newAlpha = 0;
28685
28705
  }
28686
28706
  if (magnitude(minus(closestPointPos, pos)) > 0.1) {
28687
- newUV[0] = -Infinity;
28688
- newUV[1] = -Infinity;
28707
+ newAlpha = 0;
28689
28708
  }
28709
+ to.coreMesh.setColor(i, [255, 255, 255, newAlpha]);
28690
28710
  to.coreMesh.setUV(i, newUV);
28691
28711
  }
28692
28712
  }
@@ -29505,7 +29525,7 @@ const FLAGS = {
29505
29525
  //only used by linear algorithms
29506
29526
  LAYERED_CLOTHING_ALGORITHM: "rbf",
29507
29527
  SHOW_CAGE: false,
29508
- LAYERED_CLOTHING_COOLDOWN: 0.6,
29528
+ LAYERED_CLOTHING_COOLDOWN: 0.25,
29509
29529
  GET_WORKER_FUNC: DefaultGetWorkerFunc,
29510
29530
  RBF_PATCH_COUNT: 300,
29511
29531
  //amount of "patches" that are used for layered clothing, multiple verts share the same patch
@@ -29524,6 +29544,8 @@ const FLAGS = {
29524
29544
  LEGACY_WELD_BEHAVIOR: false,
29525
29545
  USE_RENDERTARGET: true,
29526
29546
  AUTO_RESTORE_CONTEXT: true,
29547
+ RENDERTARGET_TO_CANVASTEXTURE: false,
29548
+ THUMBNAIL_TIMEOUT: 750,
29527
29549
  //skeleton
29528
29550
  SHOW_SKELETON_HELPER: false,
29529
29551
  UPDATE_SKELETON: true,
@@ -33962,6 +33984,36 @@ class COREMESH {
33962
33984
  }
33963
33985
  return touchingVerts;
33964
33986
  }
33987
+ getEdgeId(v0, v1) {
33988
+ const [x0, y0, z0] = this.getPos(v0);
33989
+ const [x1, y1, z1] = this.getPos(v1);
33990
+ const v0h = hashVec3Safe(Math.round(x0 * 1e3), Math.round(y0 * 1e3), Math.round(z0 * 1e3));
33991
+ const v1h = hashVec3Safe(Math.round(x1 * 1e3), Math.round(y1 * 1e3), Math.round(z1 * 1e3));
33992
+ const tv0 = v0h < v1h ? v0h : v1h;
33993
+ const tv1 = v0h > v1h ? v0h : v1h;
33994
+ return tv1 * 10000000n + tv0;
33995
+ }
33996
+ getFaceEdges(i) {
33997
+ const face = this.getFace(i);
33998
+ const edge0 = this.getEdgeId(face[0], face[1]);
33999
+ const edge1 = this.getEdgeId(face[1], face[2]);
34000
+ const edge2 = this.getEdgeId(face[2], face[0]);
34001
+ return [edge0, edge1, edge2];
34002
+ }
34003
+ getEdgeCounts() {
34004
+ const edgeCountMap = /* @__PURE__ */ new Map();
34005
+ for (let i = 0; i < this.numfaces; i++) {
34006
+ const edges = this.getFaceEdges(i);
34007
+ for (const edge of edges) {
34008
+ if (!edgeCountMap.has(edge)) {
34009
+ edgeCountMap.set(edge, 1);
34010
+ } else {
34011
+ edgeCountMap.set(edge, edgeCountMap.get(edge) + 1);
34012
+ }
34013
+ }
34014
+ }
34015
+ return edgeCountMap;
34016
+ }
33965
34017
  }
33966
34018
  class LODS {
33967
34019
  lodType = LodType.Unknown;
@@ -36096,6 +36148,15 @@ const API = {
36096
36148
  return await response.json();
36097
36149
  }
36098
36150
  },
36151
+ "Subscriptions": {
36152
+ HasPlus: async function() {
36153
+ const response = await RBLXGet("https://apis.roblox.com/subscriptions/v2/user/subscriptions?ProductType=Blackbird&ResultsPerPage=1");
36154
+ if (response.status !== 200) {
36155
+ return response;
36156
+ }
36157
+ return (await response.json()).subscriptions.length > 0;
36158
+ }
36159
+ },
36099
36160
  "RBLXGet": RBLXGet,
36100
36161
  "RBLXPost": RBLXPost,
36101
36162
  "RBLXDelete": RBLXDelete,
@@ -42317,27 +42378,7 @@ class MeshDesc {
42317
42378
  }
42318
42379
  return true;
42319
42380
  }
42320
- async compileMesh() {
42321
- if (!this.mesh) {
42322
- return void 0;
42323
- }
42324
- const meshToLoad = this.mesh;
42325
- const mesh = await API.Asset.GetMesh(meshToLoad, void 0);
42326
- if (mesh instanceof Response) {
42327
- warn(true, "Failed to get mesh for compileMesh", mesh);
42328
- return mesh;
42329
- }
42330
- if (!mesh.facs && this.headMesh && mesh.skinning.skinnings.length > 0) {
42331
- const headMesh = await API.Asset.GetMesh(this.headMesh, void 0, true);
42332
- if (headMesh instanceof Response) {
42333
- warn(true, "Failed to get headMesh for compileMesh", headMesh);
42334
- return headMesh;
42335
- }
42336
- if (headMesh.facs) {
42337
- mesh.facs = headMesh.facs.clone();
42338
- }
42339
- }
42340
- let the_ref_mesh = void 0;
42381
+ async wrapDeformer(mesh) {
42341
42382
  if (this.deformerDesc) {
42342
42383
  const meshMap = /* @__PURE__ */ new Map();
42343
42384
  const meshPromises = [];
@@ -42366,6 +42407,9 @@ class MeshDesc {
42366
42407
  await targetDeformer.solveAsync();
42367
42408
  targetDeformer.deformMesh();
42368
42409
  }
42410
+ }
42411
+ async wrapLayer(mesh) {
42412
+ let the_ref_mesh = void 0;
42369
42413
  if (this.layerDesc && this.modelLayersDesc && this.modelLayersDesc.targetCages && this.modelLayersDesc.targetCages.length > 0 && this.modelLayersDesc.targetCFrames && this.modelLayersDesc.targetSizes && this.modelLayersDesc.layers) {
42370
42414
  const meshMap = /* @__PURE__ */ new Map();
42371
42415
  const meshPromises = [];
@@ -42503,8 +42547,11 @@ class MeshDesc {
42503
42547
  offsetMesh(mesh, totalOffset);
42504
42548
  }
42505
42549
  if (!FLAGS.SHOW_CAGE) the_ref_mesh = void 0;
42506
- if (FLAGS.HIDE_LAYERED_CLOTHING) return;
42550
+ if (FLAGS.HIDE_LAYERED_CLOTHING) return the_ref_mesh;
42507
42551
  }
42552
+ return the_ref_mesh;
42553
+ }
42554
+ async wrapTarget(mesh) {
42508
42555
  if (this.target && this.targetOrigin && this.hsrDesc) {
42509
42556
  const meshMap = /* @__PURE__ */ new Map();
42510
42557
  const meshPromises = [];
@@ -42537,6 +42584,8 @@ class MeshDesc {
42537
42584
  doHSR(totalUvToHits, targetCage, mesh, true, `${this.target}-${this.mesh}`);
42538
42585
  }
42539
42586
  }
42587
+ }
42588
+ async wrapTextureTransfer(mesh) {
42540
42589
  if (this.wrapTextureTarget && this.wrapTextureTargetOrigin && this.wrapTextureMinBound && this.wrapTextureMaxBound) {
42541
42590
  const meshMap = /* @__PURE__ */ new Map();
42542
42591
  const meshPromises = [];
@@ -42566,11 +42615,38 @@ class MeshDesc {
42566
42615
  }
42567
42616
  for (let i = mesh.coreMesh.numverts - 1; i >= 0; i--) {
42568
42617
  const vertUV = mesh.coreMesh.getUV(i);
42569
- if (vertUV[0] < -0.05 || vertUV[0] > 1.05 || vertUV[1] < -0.05 || vertUV[1] > 1.05) {
42570
- mesh.coreMesh.setUV(i, [-Infinity, -Infinity]);
42618
+ if (vertUV[0] < 0.05 || vertUV[0] > 0.95 || vertUV[1] < 0.05 || vertUV[1] > 0.95) {
42619
+ mesh.coreMesh.setColor(i, [255, 255, 255, 0]);
42571
42620
  }
42572
42621
  }
42573
42622
  }
42623
+ }
42624
+ async compileMesh() {
42625
+ if (!this.mesh) return;
42626
+ const meshToLoad = this.mesh;
42627
+ const mesh = await API.Asset.GetMesh(meshToLoad, void 0);
42628
+ if (mesh instanceof Response) {
42629
+ warn(true, "Failed to get mesh for compileMesh", mesh);
42630
+ return mesh;
42631
+ }
42632
+ if (!mesh.facs && this.headMesh && mesh.skinning.skinnings.length > 0) {
42633
+ const headMesh = await API.Asset.GetMesh(this.headMesh, void 0, true);
42634
+ if (headMesh instanceof Response) {
42635
+ warn(true, "Failed to get headMesh for compileMesh", headMesh);
42636
+ return headMesh;
42637
+ }
42638
+ if (headMesh.facs) {
42639
+ mesh.facs = headMesh.facs.clone();
42640
+ }
42641
+ }
42642
+ const wrapDeformerResult = await this.wrapDeformer(mesh);
42643
+ if (wrapDeformerResult instanceof Response) return wrapDeformerResult;
42644
+ const the_ref_mesh = await this.wrapLayer(mesh);
42645
+ if (the_ref_mesh instanceof Response) return the_ref_mesh;
42646
+ const wrapTargetResult = await this.wrapTarget(mesh);
42647
+ if (wrapTargetResult instanceof Response) return wrapTargetResult;
42648
+ const wrapTextureTransferResult = await this.wrapTextureTransfer(mesh);
42649
+ if (wrapTextureTransferResult instanceof Response) return wrapTextureTransferResult;
42574
42650
  this.fileMesh = mesh;
42575
42651
  const geometry = fileMeshToTHREEGeometry(the_ref_mesh || mesh, this.canHaveSkinning, this.forceVertexColor);
42576
42652
  let threeMesh = void 0;
@@ -42610,6 +42686,9 @@ class MeshDesc {
42610
42686
  break;
42611
42687
  }
42612
42688
  }
42689
+ if (child.className === "Decal") {
42690
+ this.forceVertexColor = void 0;
42691
+ }
42613
42692
  }
42614
42693
  fromPart(child) {
42615
42694
  this.canHaveSkinning = false;
@@ -43126,6 +43205,26 @@ function fastMask(mask, image) {
43126
43205
  ctx.drawImage(image, 0, 0, mask.width, mask.height);
43127
43206
  return canvas;
43128
43207
  }
43208
+ function imageDataToCanvas(data, width, height) {
43209
+ const offscreenCanvas = new OffscreenCanvas(width, height);
43210
+ const offscreenCtx = offscreenCanvas.getContext("2d");
43211
+ const canvas = document.createElement("canvas");
43212
+ const ctx = canvas.getContext("2d");
43213
+ canvas.width = width;
43214
+ canvas.height = height;
43215
+ if (!ctx || !offscreenCtx) {
43216
+ throw new Error("Failed to get CanvasContext");
43217
+ }
43218
+ const imgData = new ImageData(new Uint8ClampedArray(data.buffer), width, height);
43219
+ offscreenCtx.putImageData(imgData, 0, 0);
43220
+ ctx.translate(0, height);
43221
+ ctx.scale(1, -1);
43222
+ ctx.drawImage(offscreenCanvas, 0, 0);
43223
+ return canvas;
43224
+ }
43225
+ function imageDataToCanvasTexture(data, width, height) {
43226
+ return new CanvasTexture(imageDataToCanvas(data, width, height));
43227
+ }
43129
43228
  class ColorLayer {
43130
43229
  color;
43131
43230
  bodyPart;
@@ -43476,7 +43575,7 @@ class MaterialDesc {
43476
43575
  }
43477
43576
  let hasTransparency = false;
43478
43577
  const rbxRenderer = RBXRenderer.getRenderer();
43479
- if (!hasColorLayer && rbxRenderer) {
43578
+ if (!hasColorLayer && rbxRenderer || FLAGS.RENDERTARGET_TO_CANVASTEXTURE && rbxRenderer) {
43480
43579
  const data = new Uint8Array(width * height * 4);
43481
43580
  await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
43482
43581
  for (let i = 3; i < data.length; i += 4) {
@@ -43485,6 +43584,15 @@ class MaterialDesc {
43485
43584
  break;
43486
43585
  }
43487
43586
  }
43587
+ if (FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
43588
+ const ogTexture = texture;
43589
+ texture = imageDataToCanvasTexture(data, width, height);
43590
+ texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
43591
+ texture.wrapS = ogTexture.wrapS;
43592
+ texture.wrapT = ogTexture.wrapT;
43593
+ texture.minFilter = ogTexture.minFilter;
43594
+ texture.magFilter = ogTexture.magFilter;
43595
+ }
43488
43596
  }
43489
43597
  if (!this.transparent) {
43490
43598
  hasTransparency = false;
@@ -43537,7 +43645,7 @@ class MaterialDesc {
43537
43645
  }
43538
43646
  }
43539
43647
  let hasTransparency = false;
43540
- if (this.transparent) {
43648
+ if (this.transparent || FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
43541
43649
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
43542
43650
  const data = imageData.data;
43543
43651
  for (let i = 3; i < data.length; i += 4) {
@@ -43600,7 +43708,7 @@ class MaterialDesc {
43600
43708
  if (!hasLayerOfType) return;
43601
43709
  if ((hasSpecialUVType || this.bodyPart !== void 0) && FLAGS.USE_RENDERTARGET) {
43602
43710
  return "full";
43603
- } else if (this.layers.length > 1 || hasColorLayer && FLAGS.USE_RENDERTARGET) {
43711
+ } else if ((this.layers.length > 1 || hasColorLayer) && FLAGS.USE_RENDERTARGET) {
43604
43712
  return "simple";
43605
43713
  } else {
43606
43714
  return "direct";
@@ -43657,13 +43765,15 @@ class MaterialDesc {
43657
43765
  hasTransparency = true;
43658
43766
  }
43659
43767
  let material = void 0;
43768
+ const textureTemplate = {};
43769
+ if (colorTexture) textureTemplate.map = colorTexture;
43770
+ if (normalTexture) textureTemplate.normalMap = normalTexture;
43771
+ if (roughnessTexture) textureTemplate.roughnessMap = roughnessTexture;
43772
+ if (metalnessTexture) textureTemplate.metalnessMap = metalnessTexture;
43773
+ if (emissiveTexture) textureTemplate.emissiveMap = emissiveTexture;
43660
43774
  if (normalTexture || roughnessTexture || metalnessTexture || emissiveTexture) {
43661
43775
  material = new MeshStandardMaterial({
43662
- map: colorTexture,
43663
- normalMap: normalTexture,
43664
- roughnessMap: roughnessTexture,
43665
- metalnessMap: metalnessTexture,
43666
- emissiveMap: emissiveTexture,
43776
+ ...textureTemplate,
43667
43777
  emissiveIntensity: hasEmissive ? this.emissiveStrength : 0,
43668
43778
  emissive: hasEmissive ? new Color(this.emissiveTint.R, this.emissiveTint.G, this.emissiveTint.B) : new Color(0, 0, 0),
43669
43779
  transparent: hasTransparency,
@@ -43679,7 +43789,7 @@ class MaterialDesc {
43679
43789
  });
43680
43790
  } else {
43681
43791
  material = new MeshPhongMaterial({
43682
- map: colorTexture,
43792
+ ...textureTemplate,
43683
43793
  specular: new Color(1 / 102, 1 / 102, 1 / 102),
43684
43794
  shininess: 9,
43685
43795
  transparent: hasTransparency,
@@ -44779,31 +44889,7 @@ class SkeletonDesc2 {
44779
44889
  }
44780
44890
  class DisposableDesc {
44781
44891
  disposeMesh(scene, mesh) {
44782
- if (mesh.material) {
44783
- const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
44784
- for (const material of materials) {
44785
- for (const key of Object.keys(material)) {
44786
- const value = material[key];
44787
- if (value instanceof Texture) {
44788
- value.dispose();
44789
- }
44790
- }
44791
- if (material instanceof ShaderMaterial) {
44792
- const uniforms = material.uniforms;
44793
- for (const key of Object.keys(uniforms)) {
44794
- const value = uniforms[key].value;
44795
- if (value instanceof Texture) {
44796
- value.dispose();
44797
- }
44798
- }
44799
- }
44800
- material.dispose();
44801
- }
44802
- }
44803
- if (mesh.geometry) {
44804
- mesh.geometry.dispose();
44805
- }
44806
- scene.remove(mesh);
44892
+ disposeMesh(scene, mesh);
44807
44893
  }
44808
44894
  disposeMeshes(scene, meshes) {
44809
44895
  for (const mesh of meshes) {
@@ -47061,6 +47147,26 @@ class AnimatorWrapper extends InstanceWrapper {
47061
47147
  return false;
47062
47148
  }
47063
47149
  }
47150
+ class AttachmentWrapper extends InstanceWrapper {
47151
+ static className = "Attachment";
47152
+ static requiredProperties = [
47153
+ "Name",
47154
+ "CFrame"
47155
+ ];
47156
+ setup() {
47157
+ if (!this.instance.HasProperty("Name")) this.instance.addProperty(new Property("Name", DataType.String), this.instance.className);
47158
+ if (!this.instance.HasProperty("CFrame")) this.instance.addProperty(new Property("CFrame", DataType.CFrame), new CFrame());
47159
+ }
47160
+ getWorldCFrame() {
47161
+ if (this.instance.parent) {
47162
+ if (this.instance.parent.className.includes("Part")) {
47163
+ const parentCF = this.instance.parent.PropOrDefault("CFrame", new CFrame());
47164
+ return parentCF.multiply(this.instance.Prop("CFrame"));
47165
+ }
47166
+ }
47167
+ return this.instance.Prop("CFrame");
47168
+ }
47169
+ }
47064
47170
  class BodyColorsWrapper extends InstanceWrapper {
47065
47171
  static className = "BodyColors";
47066
47172
  static requiredProperties = [
@@ -48610,6 +48716,7 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
48610
48716
  toChange.push("dance2");
48611
48717
  toChange.push("dance3");
48612
48718
  toChange.push("toolnone");
48719
+ if (this.instance.Prop("IdleAnimation") <= 0) toChange.push("pose");
48613
48720
  }
48614
48721
  miniPromises.push(this._applyAnimations(humanoid, toChange));
48615
48722
  }
@@ -48979,6 +49086,7 @@ function RegisterWrappers() {
48979
49086
  WeldWrapper.register();
48980
49087
  Motor6DWrapper.register();
48981
49088
  ManualWeldWrapper.register();
49089
+ AttachmentWrapper.register();
48982
49090
  AnimationConstraintWrapper.register();
48983
49091
  AnimatorWrapper.register();
48984
49092
  FaceControlsWrapper.register();
@@ -48989,11 +49097,40 @@ function RegisterWrappers() {
48989
49097
  BodyColorsWrapper.register();
48990
49098
  AccessoryWrapper.register();
48991
49099
  }
49100
+ function disposeMesh(scene, mesh) {
49101
+ if (mesh.material) {
49102
+ const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
49103
+ for (const material of materials) {
49104
+ for (const key of Object.keys(material)) {
49105
+ const value = material[key];
49106
+ if (value instanceof Texture) {
49107
+ value.dispose();
49108
+ }
49109
+ }
49110
+ if (material instanceof ShaderMaterial) {
49111
+ const uniforms = material.uniforms;
49112
+ for (const key of Object.keys(uniforms)) {
49113
+ const value = uniforms[key].value;
49114
+ if (value instanceof Texture) {
49115
+ value.dispose();
49116
+ }
49117
+ }
49118
+ }
49119
+ material.dispose();
49120
+ }
49121
+ }
49122
+ if (mesh.geometry) {
49123
+ mesh.geometry.dispose();
49124
+ }
49125
+ scene.remove(mesh);
49126
+ }
48992
49127
  class RBXRendererScene {
48993
49128
  //important scene components
48994
49129
  scene = new Scene();
48995
49130
  camera = new PerspectiveCamera(70, 1 / 1, 0.1, 100);
48996
49131
  controls;
49132
+ shouldAnimate = true;
49133
+ destroyed = false;
48997
49134
  //renderer
48998
49135
  effectComposer;
48999
49136
  //viewport
@@ -49032,6 +49169,39 @@ class RBXRendererScene {
49032
49169
  this.viewport = [0, 0, 0, 0];
49033
49170
  this.scissor = [0, 0, 0, 0];
49034
49171
  }
49172
+ destroy() {
49173
+ if (this.destroyed) return;
49174
+ this.destroyed = true;
49175
+ for (const instance of this.renderDescs.keys()) {
49176
+ RBXRenderer.removeInstance(instance, this);
49177
+ }
49178
+ RBXRenderer.scenes.splice(RBXRenderer.scenes.indexOf(this), 1);
49179
+ if (this.plane) {
49180
+ disposeMesh(this.scene, this.plane);
49181
+ this.plane = void 0;
49182
+ }
49183
+ if (this.shadowPlane) {
49184
+ disposeMesh(this.scene, this.shadowPlane);
49185
+ this.shadowPlane = void 0;
49186
+ }
49187
+ }
49188
+ async exportGLTF(name = "scene", autoDownload = true) {
49189
+ return new Promise((resolve, reject) => {
49190
+ const exporter = new GLTFExporter();
49191
+ exporter.parse(this.scene, (gltf) => {
49192
+ if (autoDownload) {
49193
+ if (gltf instanceof ArrayBuffer) {
49194
+ saveByteArray([gltf], `${name}.glb`);
49195
+ } else {
49196
+ download(`${name}.gltf`, JSON.stringify(gltf));
49197
+ }
49198
+ }
49199
+ resolve(gltf);
49200
+ }, (error2) => {
49201
+ reject(error2);
49202
+ });
49203
+ });
49204
+ }
49035
49205
  }
49036
49206
  class RBXRenderer {
49037
49207
  static orbitControlsTarget = [0, 3, 0];
@@ -49425,6 +49595,7 @@ class RBXRenderer {
49425
49595
  }
49426
49596
  static renderScene(renderScene, autoClear = true) {
49427
49597
  if (!RBXRenderer.renderer) return;
49598
+ if (!renderScene.shouldAnimate) return;
49428
49599
  RBXRenderer.renderer.autoClear = autoClear;
49429
49600
  if (!autoClear) {
49430
49601
  RBXRenderer.renderer.clearDepth();
@@ -49545,6 +49716,7 @@ class RBXRenderer {
49545
49716
  }
49546
49717
  /**Adds an instance to the renderer or updates it */
49547
49718
  static addInstance(instance, auth, renderScene = RBXRenderer.firstScene) {
49719
+ if (renderScene.destroyed) return;
49548
49720
  const isDecal = instance.className === "Decal";
49549
49721
  const isBakedDecal = isDecal && !instance.FindFirstChildOfClass("WrapTextureTransfer");
49550
49722
  let isFirstDecal = true;
@@ -49745,14 +49917,6 @@ class HSR {
49745
49917
  }
49746
49918
  }
49747
49919
  }
49748
- function exposeAPI() {
49749
- globalThis.API = API;
49750
- globalThis.APICACHE = CACHE;
49751
- globalThis.Authentication = Authentication;
49752
- }
49753
- function exposeMesh() {
49754
- globalThis.fileMeshToTHREEGeometry = fileMeshToTHREEGeometry;
49755
- }
49756
49920
  function getCorners(cframe, size) {
49757
49921
  const halfX = size.X / 2;
49758
49922
  const halfY = size.Y / 2;
@@ -49815,12 +49979,27 @@ function getExtents(cframe, parts) {
49815
49979
  }
49816
49980
  return [lowerExtents, higherExtents];
49817
49981
  }
49982
+ function getExtentsCenter(extents) {
49983
+ return extents[1].minus(extents[0]).divide(new Vector32(2, 2, 2)).add(extents[0]);
49984
+ }
49818
49985
  function zoomExtents(cameraCFrame, modelCFrame, modelSize, targetFOV, distanceScale) {
49819
49986
  const largestSize = Math.max(modelSize.X, modelSize.Y, modelSize.Z);
49820
49987
  const fovMultiplier = 70 / targetFOV;
49821
49988
  const lookDir = multiply(normalize(minus(cameraCFrame.Position, modelCFrame.Position)), [distanceScale, distanceScale, distanceScale]);
49822
49989
  cameraCFrame.Position = add(modelCFrame.Position, multiply(multiply(lookDir, [largestSize, largestSize, largestSize]), [fovMultiplier, fovMultiplier, fovMultiplier]));
49823
49990
  }
49991
+ function getCameraOffset(fov2, extentsSize) {
49992
+ const halfSize = extentsSize.magnitude() / 2;
49993
+ const fovDivisor = Math.tan(rad(fov2 / 2));
49994
+ return halfSize / fovDivisor;
49995
+ }
49996
+ function zoomToExtents(cameraCFrame, modelCFrame, modelSize, fov2 = 70) {
49997
+ const cameraOffset = getCameraOffset(fov2, modelSize);
49998
+ const cameraRotation = new CFrame();
49999
+ cameraRotation.Orientation = cameraCFrame.Orientation;
50000
+ const instancePosition = modelCFrame.Position;
50001
+ cameraCFrame.Position = add(instancePosition, multiply(minus([0, 0, 0], cameraRotation.lookVector()), [cameraOffset, cameraOffset, cameraOffset]));
50002
+ }
49824
50003
  function getHeadExtents(rig) {
49825
50004
  const head = rig.FindFirstChild("Head");
49826
50005
  if (!head) return;
@@ -49840,6 +50019,16 @@ function getHeadExtents(rig) {
49840
50019
  const extents = getExtents(head.Prop("CFrame"), headParts);
49841
50020
  return extents;
49842
50021
  }
50022
+ function getRigExtentsWorld(rig) {
50023
+ const rigParts = [];
50024
+ for (const child of rig.GetDescendants()) {
50025
+ if (child.className === "Part" || child.className === "MeshPart") {
50026
+ rigParts.push(child);
50027
+ }
50028
+ }
50029
+ const extents = getExtents(new CFrame(), rigParts);
50030
+ return extents;
50031
+ }
49843
50032
  function getCameraCFrameForHeadshotCustomized(rig, fov2, yRot, distance2) {
49844
50033
  const head = rig.FindFirstChild("Head");
49845
50034
  if (!head) return;
@@ -49866,6 +50055,34 @@ function getCameraCFrameForHeadshotCustomized(rig, fov2, yRot, distance2) {
49866
50055
  zoomExtents(cameraCF, headCenterCF, headLocalExtents[1].minus(headLocalExtents[0]), fov2, distance2);
49867
50056
  return cameraCF;
49868
50057
  }
50058
+ function getCameraCFrameForAvatarNonCustomized(rig) {
50059
+ const thumbnailCamera = rig.FindFirstChildOfClass("Camera");
50060
+ if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
50061
+ let rootPart = rig.PropOrDefault("PrimaryPart", void 0);
50062
+ if (!rootPart) rootPart = rig.FindFirstChildOfClass("Part");
50063
+ if (!rootPart) rootPart = rig.FindFirstChildOfClass("MeshPart");
50064
+ if (!rootPart) return;
50065
+ const rootPartCF = rootPart.PropOrDefault("CFrame", new CFrame()).clone();
50066
+ const worldExtents = getRigExtentsWorld(rig);
50067
+ if (!worldExtents) return;
50068
+ const extentsSize = worldExtents[1].minus(worldExtents[0]);
50069
+ rootPartCF.Position = getExtentsCenter(worldExtents).toVec3();
50070
+ let lookVector = rootPartCF.lookVector();
50071
+ if (Math.abs(lookVector[1]) > 0.95) {
50072
+ lookVector = [0, 0, -1];
50073
+ } else {
50074
+ lookVector[1] = 0;
50075
+ lookVector = normalize(lookVector);
50076
+ }
50077
+ let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
50078
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(25 * Math.PI / 180, 27.5 * Math.PI / 180, 0, "ZXY"));
50079
+ lookVector = lookCF.lookVector();
50080
+ lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
50081
+ lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
50082
+ const cameraCF = lookCF.clone();
50083
+ zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
50084
+ return cameraCF;
50085
+ }
49869
50086
  class OutfitRenderer {
49870
50087
  auth;
49871
50088
  outfit;
@@ -50054,6 +50271,128 @@ class OutfitRenderer {
50054
50271
  }
50055
50272
  }
50056
50273
  }
50274
+ function renderToRenderTarget(width, height, renderScene) {
50275
+ const renderTarget = new WebGLRenderTarget(width, height, {
50276
+ colorSpace: SRGBColorSpace,
50277
+ generateMipmaps: false,
50278
+ minFilter: LinearFilter,
50279
+ magFilter: LinearFilter,
50280
+ type: UnsignedByteType
50281
+ });
50282
+ const rbxRenderer = RBXRenderer.getRenderer();
50283
+ if (!rbxRenderer) return renderTarget;
50284
+ rbxRenderer.setRenderTarget(renderTarget);
50285
+ rbxRenderer.render(renderScene.scene, renderScene.camera);
50286
+ return renderTarget;
50287
+ }
50288
+ async function renderTargetToCanvas(renderTarget) {
50289
+ const rbxRenderer = RBXRenderer.getRenderer();
50290
+ if (!rbxRenderer) return;
50291
+ const width = renderTarget.width;
50292
+ const height = renderTarget.height;
50293
+ const data = new Uint8Array(width * height * 4);
50294
+ await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
50295
+ return imageDataToCanvas(data, width, height);
50296
+ }
50297
+ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
50298
+ return new Promise((resolve) => {
50299
+ const cameraCFrame = getCameraCFrameForAvatarNonCustomized(model);
50300
+ if (cameraCFrame) {
50301
+ RBXRenderer.setCameraCFrame(cameraCFrame, renderScene);
50302
+ }
50303
+ RBXRenderer.addInstance(model, auth, renderScene);
50304
+ let exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50305
+ const onLoadingConnection = API.Events.OnLoadingAssets.Connect((currentlyLoading) => {
50306
+ if (exportTimeout) {
50307
+ clearTimeout(exportTimeout);
50308
+ exportTimeout = void 0;
50309
+ }
50310
+ if (!currentlyLoading) {
50311
+ exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50312
+ }
50313
+ });
50314
+ async function doExport() {
50315
+ onLoadingConnection.Disconnect();
50316
+ if (type === "gltf") {
50317
+ if (!FLAGS.RENDERTARGET_TO_CANVASTEXTURE && FLAGS.USE_RENDERTARGET) {
50318
+ warn(true, "FLAGS.RENDERTARGET_TO_CANVASTEXTURE is false, GLTF export cannot export render target textures, consider setting this flag to true");
50319
+ }
50320
+ resolve(await renderScene.exportGLTF(`result`, gltfAutoDownload));
50321
+ } else {
50322
+ const renderTarget = renderToRenderTarget(...size, renderScene);
50323
+ const canvasTarget = await renderTargetToCanvas(renderTarget);
50324
+ if (canvasTarget) {
50325
+ resolve(canvasTarget.toDataURL(`image/${type}`, quality));
50326
+ } else {
50327
+ resolve(void 0);
50328
+ }
50329
+ }
50330
+ renderScene.destroy();
50331
+ }
50332
+ });
50333
+ }
50334
+ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
50335
+ return new Promise((resolve) => {
50336
+ const renderScene = RBXRenderer.addScene();
50337
+ setupThumbnailScene(renderScene);
50338
+ const outfitRenderer = new OutfitRenderer(auth, outfit, renderScene);
50339
+ if (outfit.playerAvatarType === AvatarType.R6) outfitRenderer.deltaTimeMultiplier = 0;
50340
+ outfitRenderer.startAnimating();
50341
+ let exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50342
+ const onLoadingConnection = API.Events.OnLoadingAssets.Connect((currentlyLoading) => {
50343
+ if (exportTimeout) {
50344
+ clearTimeout(exportTimeout);
50345
+ exportTimeout = void 0;
50346
+ }
50347
+ if (!currentlyLoading) {
50348
+ exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50349
+ }
50350
+ });
50351
+ async function doExport() {
50352
+ onLoadingConnection.Disconnect();
50353
+ if (!outfit.containsAssetType("Gear")) {
50354
+ if (outfit.playerAvatarType === AvatarType.R15) {
50355
+ outfitRenderer.setMainAnimation("pose");
50356
+ }
50357
+ } else {
50358
+ outfitRenderer.setMainAnimation("toolnone");
50359
+ }
50360
+ if (outfitRenderer.currentRig) {
50361
+ const thumbnailResult = await generateModelThumbnail(auth, renderScene, outfitRenderer.currentRig, size, type, quality, gltfAutoDownload);
50362
+ resolve(thumbnailResult);
50363
+ outfitRenderer.stopAnimating();
50364
+ if (outfitRenderer.currentRig) outfitRenderer.currentRig.Destroy();
50365
+ } else {
50366
+ resolve(void 0);
50367
+ }
50368
+ }
50369
+ });
50370
+ }
50371
+ function setupThumbnailScene(renderScene) {
50372
+ renderScene.shouldAnimate = false;
50373
+ renderScene.wellLitDirectionalLightIntensity *= 2;
50374
+ renderScene.shadowEnabled = false;
50375
+ RBXRenderer.setupScene("WellLit", 16777215, renderScene);
50376
+ if (renderScene.plane) renderScene.scene.remove(renderScene.plane);
50377
+ if (renderScene.shadowPlane) renderScene.scene.remove(renderScene.shadowPlane);
50378
+ renderScene.scene.background = null;
50379
+ }
50380
+ function exposeAPI() {
50381
+ globalThis.API = API;
50382
+ globalThis.APICACHE = CACHE;
50383
+ globalThis.Authentication = Authentication;
50384
+ }
50385
+ function exposeMesh() {
50386
+ globalThis.fileMeshToTHREEGeometry = fileMeshToTHREEGeometry;
50387
+ }
50388
+ function exposeFLAGS() {
50389
+ globalThis.FLAGS = FLAGS;
50390
+ }
50391
+ function exposeThumbnailGenerator() {
50392
+ globalThis.generateOutfitThumbnail = generateOutfitThumbnail;
50393
+ globalThis.generateModelThumbnail = generateModelThumbnail;
50394
+ globalThis.setupThumbnailScene = setupThumbnailScene;
50395
+ }
50057
50396
  export {
50058
50397
  API,
50059
50398
  AbbreviationToFaceControlProperty,
@@ -50083,6 +50422,7 @@ export {
50083
50422
  AssetTypeToAccessoryType,
50084
50423
  AssetTypeToMakeupType,
50085
50424
  AssetTypes,
50425
+ AttachmentWrapper,
50086
50426
  Authentication,
50087
50427
  AvatarType,
50088
50428
  BodyColor3s,
@@ -50120,6 +50460,7 @@ export {
50120
50460
  FileMesh,
50121
50461
  FileMeshSkinning,
50122
50462
  FileMeshSubset,
50463
+ FindFirstMatchingAttachment,
50123
50464
  FullBodyColors,
50124
50465
  GetAttachedPart,
50125
50466
  HSR,
@@ -50217,24 +50558,35 @@ export {
50217
50558
  defaultShirtTemplateAssetIds,
50218
50559
  deformReferenceToBaseBodyParts,
50219
50560
  deg,
50561
+ disposeMesh,
50220
50562
  distance,
50221
50563
  divide,
50222
50564
  dot,
50223
50565
  download,
50224
50566
  exposeAPI,
50567
+ exposeFLAGS,
50225
50568
  exposeMesh,
50569
+ exposeThumbnailGenerator,
50226
50570
  fileMeshToTHREEGeometry,
50227
50571
  floor,
50228
50572
  gaussian_rbf,
50573
+ generateModelThumbnail,
50574
+ generateOutfitThumbnail,
50229
50575
  generateUUIDv4,
50576
+ getCameraCFrameForAvatarNonCustomized,
50230
50577
  getCameraCFrameForHeadshotCustomized,
50578
+ getCameraOffset,
50231
50579
  getDistIndexArray,
50232
50580
  getExtents,
50581
+ getExtentsCenter,
50233
50582
  getExtentsForParts,
50234
50583
  getHeadExtents,
50235
50584
  getOffsetArray,
50585
+ getOriginalAttachmentOrientation,
50586
+ getOriginalAttachmentPosition,
50236
50587
  getOriginalSize,
50237
50588
  getRandomBetweenInclusive,
50589
+ getRigExtentsWorld,
50238
50590
  getUVtoIndexMap,
50239
50591
  getUVtoIndicesMap,
50240
50592
  getWorkerOnMessage,
@@ -50278,6 +50630,7 @@ export {
50278
50630
  rotationMatrixToEulerAngles,
50279
50631
  saveByteArray,
50280
50632
  scaleMesh,
50633
+ setupThumbnailScene,
50281
50634
  snapToNumber,
50282
50635
  specialClamp,
50283
50636
  transferSkeleton,
@@ -50287,5 +50640,6 @@ export {
50287
50640
  versionToNumber,
50288
50641
  vertPosToChunkPos,
50289
50642
  xmlMagic,
50290
- zoomExtents
50643
+ zoomExtents,
50644
+ zoomToExtents
50291
50645
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",