roavatar-renderer 1.3.6 → 1.4.1

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.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,
@@ -29608,10 +29630,19 @@ class InstanceWrapper {
29608
29630
  log(false, "Registered InstanceWrapper:", ClassNameToWrapper);
29609
29631
  }
29610
29632
  //virtual functions
29633
+ /**
29634
+ * @virtual
29635
+ */
29611
29636
  created() {
29612
29637
  }
29638
+ /**
29639
+ * @virtual
29640
+ */
29613
29641
  destroy() {
29614
29642
  }
29643
+ /**
29644
+ * @virtual
29645
+ */
29615
29646
  preRender() {
29616
29647
  }
29617
29648
  }
@@ -29742,6 +29773,9 @@ class Color3 {
29742
29773
  clone() {
29743
29774
  return new Color3(this.R, this.G, this.B);
29744
29775
  }
29776
+ isSame(other) {
29777
+ return this.R === other.R && this.G === other.G && this.B === other.B;
29778
+ }
29745
29779
  toColor3uint8() {
29746
29780
  return new Color3uint8(Math.round(this.R * 255), Math.round(this.G * 255), Math.round(this.B * 255));
29747
29781
  }
@@ -29786,6 +29820,9 @@ class NumberSequenceKeypoint {
29786
29820
  clone() {
29787
29821
  return new NumberSequenceKeypoint(this.time, this.value, this.envelope);
29788
29822
  }
29823
+ isSame(other) {
29824
+ return this.time === other.time && this.value === other.value && this.envelope === other.envelope;
29825
+ }
29789
29826
  }
29790
29827
  class NumberSequence {
29791
29828
  keypoints = [];
@@ -29799,6 +29836,13 @@ class NumberSequence {
29799
29836
  }
29800
29837
  return copy;
29801
29838
  }
29839
+ isSame(other) {
29840
+ if (this.keypoints.length !== other.keypoints.length) return false;
29841
+ for (let i = 0; i < this.keypoints.length; i++) {
29842
+ if (!this.keypoints[i].isSame(other.keypoints[i])) return false;
29843
+ }
29844
+ return true;
29845
+ }
29802
29846
  getLowerKey(time2) {
29803
29847
  let resultKey = null;
29804
29848
  for (const key of this.keypoints) {
@@ -29854,6 +29898,9 @@ class ColorSequenceKeypoint {
29854
29898
  clone() {
29855
29899
  return new ColorSequenceKeypoint(this.time, this.value.R, this.value.G, this.value.B);
29856
29900
  }
29901
+ isSame(other) {
29902
+ return this.time === other.time && this.value.isSame(other.value);
29903
+ }
29857
29904
  }
29858
29905
  class ColorSequence {
29859
29906
  keypoints = [];
@@ -29869,6 +29916,13 @@ class ColorSequence {
29869
29916
  }
29870
29917
  return copy;
29871
29918
  }
29919
+ isSame(other) {
29920
+ if (this.keypoints.length !== other.keypoints.length) return false;
29921
+ for (let i = 0; i < this.keypoints.length; i++) {
29922
+ if (!this.keypoints[i].isSame(other.keypoints[i])) return false;
29923
+ }
29924
+ return true;
29925
+ }
29872
29926
  getLowerKey(time2) {
29873
29927
  let resultKey = null;
29874
29928
  for (const key of this.keypoints) {
@@ -30056,17 +30110,23 @@ let lastInstanceId = 0;
30056
30110
  const AllInstances = [];
30057
30111
  class Instance {
30058
30112
  _id;
30113
+ /**
30114
+ * @deprecated Use .Prop("Name") instead
30115
+ */
30059
30116
  _name;
30060
30117
  //USED TO MAKE VIEWING EASIER
30061
30118
  className;
30119
+ /**
30120
+ * @deprecated Do not use this directly
30121
+ */
30062
30122
  _properties = /* @__PURE__ */ new Map();
30063
30123
  _referencedBy = [];
30064
30124
  _connectionReferences = [];
30065
- children = [];
30125
+ _children = [];
30066
30126
  parent = void 0;
30067
30127
  destroyed = false;
30068
- hasWrappered = false;
30069
- canGC = true;
30128
+ _hasWrappered = false;
30129
+ //private _canGC: boolean = true
30070
30130
  classID;
30071
30131
  //dont use this to identify instance class, it is only used during file loading
30072
30132
  objectFormat;
@@ -30101,8 +30161,8 @@ class Instance {
30101
30161
  }
30102
30162
  createWrapper() {
30103
30163
  const wrapper = GetWrapperForInstance(this);
30104
- if (wrapper && !this.hasWrappered) {
30105
- this.hasWrappered = true;
30164
+ if (wrapper && !this._hasWrappered) {
30165
+ this._hasWrappered = true;
30106
30166
  wrapper.created();
30107
30167
  }
30108
30168
  }
@@ -30220,6 +30280,13 @@ class Instance {
30220
30280
  name = this.fixPropertyName(name);
30221
30281
  return !!this._properties.get(name);
30222
30282
  }
30283
+ /**
30284
+ * Returns the value of a property
30285
+ * @param name Name of property
30286
+ * @returns Property's value
30287
+ *
30288
+ * @throws When property doesn't exist, PropOrDefault is a safer alternative
30289
+ */
30223
30290
  Property(name) {
30224
30291
  let property = this._properties.get(name);
30225
30292
  if (property) return property.value;
@@ -30263,6 +30330,13 @@ class Instance {
30263
30330
  throw new Error(`Property: ${name} does not exist`);
30264
30331
  }
30265
30332
  }
30333
+ /**
30334
+ * Returns the value of a property
30335
+ * @param name Name of property
30336
+ * @returns Property's value
30337
+ *
30338
+ * @throws When property doesn't exist, PropOrDefault is a safer alternative
30339
+ */
30266
30340
  Prop(name) {
30267
30341
  return this.Property(name);
30268
30342
  }
@@ -30283,9 +30357,9 @@ class Instance {
30283
30357
  throw new Error("Cannot set parent of instance to a destroyed instance");
30284
30358
  }
30285
30359
  if (this.parent) {
30286
- const index = this.parent.children.indexOf(this);
30360
+ const index = this.parent._children.indexOf(this);
30287
30361
  if (index !== -1) {
30288
- this.parent.children.splice(index, 1);
30362
+ this.parent._children.splice(index, 1);
30289
30363
  }
30290
30364
  }
30291
30365
  const originalParent = this.parent;
@@ -30294,7 +30368,7 @@ class Instance {
30294
30368
  originalParent.ChildRemoved.Fire(this);
30295
30369
  }
30296
30370
  if (instance) {
30297
- instance.children.push(this);
30371
+ instance._children.push(this);
30298
30372
  }
30299
30373
  if (fireEvents) {
30300
30374
  if (instance) {
@@ -30351,7 +30425,7 @@ class Instance {
30351
30425
  }
30352
30426
  GetChildren() {
30353
30427
  const childrenList = [];
30354
- for (const child of this.children) {
30428
+ for (const child of this._children) {
30355
30429
  childrenList.push(child);
30356
30430
  }
30357
30431
  return childrenList;
@@ -30381,7 +30455,7 @@ class Instance {
30381
30455
  return this.FindFirstChild(name);
30382
30456
  }
30383
30457
  FindFirstChildOfClass(className) {
30384
- for (const child of this.children) {
30458
+ for (const child of this._children) {
30385
30459
  if (child.className === className) {
30386
30460
  return child;
30387
30461
  }
@@ -30389,7 +30463,7 @@ class Instance {
30389
30463
  }
30390
30464
  FindLastChildOfClass(className) {
30391
30465
  let lastChild = void 0;
30392
- for (const child of this.children) {
30466
+ for (const child of this._children) {
30393
30467
  if (child.className === className) {
30394
30468
  lastChild = child;
30395
30469
  }
@@ -30505,7 +30579,7 @@ class RBX {
30505
30579
  treeGenerated = false;
30506
30580
  xmlString;
30507
30581
  get instances() {
30508
- return this.dataModel.children;
30582
+ return this.dataModel.GetChildren();
30509
30583
  }
30510
30584
  constructor() {
30511
30585
  this.reset();
@@ -31399,6 +31473,10 @@ class RBX {
31399
31473
  }
31400
31474
  return buffer2;
31401
31475
  }
31476
+ /**
31477
+ * Generates if needed hierarchy and returns root instance
31478
+ * @returns Root instance
31479
+ */
31402
31480
  generateTree() {
31403
31481
  if (this.treeGenerated) {
31404
31482
  warn(false, "Tree already generated");
@@ -32854,10 +32932,12 @@ class Outfit {
32854
32932
  return HumanoidDescription;
32855
32933
  }
32856
32934
  //TODO: Implement
32935
+ /** @deprecated */
32857
32936
  async fromHumanoidDescription(rootDocument) {
32858
32937
  const humanoidDescription = rootDocument.querySelector(".HumanoidDescription");
32859
32938
  log(false, humanoidDescription);
32860
32939
  }
32940
+ /** @deprecated */
32861
32941
  async downloadHumanoidDescription() {
32862
32942
  const humanoidDescription = await this.toHumanoidDescription();
32863
32943
  if (humanoidDescription) {
@@ -33962,6 +34042,36 @@ class COREMESH {
33962
34042
  }
33963
34043
  return touchingVerts;
33964
34044
  }
34045
+ getEdgeId(v0, v1) {
34046
+ const [x0, y0, z0] = this.getPos(v0);
34047
+ const [x1, y1, z1] = this.getPos(v1);
34048
+ const v0h = hashVec3Safe(Math.round(x0 * 1e3), Math.round(y0 * 1e3), Math.round(z0 * 1e3));
34049
+ const v1h = hashVec3Safe(Math.round(x1 * 1e3), Math.round(y1 * 1e3), Math.round(z1 * 1e3));
34050
+ const tv0 = v0h < v1h ? v0h : v1h;
34051
+ const tv1 = v0h > v1h ? v0h : v1h;
34052
+ return tv1 * 10000000n + tv0;
34053
+ }
34054
+ getFaceEdges(i) {
34055
+ const face = this.getFace(i);
34056
+ const edge0 = this.getEdgeId(face[0], face[1]);
34057
+ const edge1 = this.getEdgeId(face[1], face[2]);
34058
+ const edge2 = this.getEdgeId(face[2], face[0]);
34059
+ return [edge0, edge1, edge2];
34060
+ }
34061
+ getEdgeCounts() {
34062
+ const edgeCountMap = /* @__PURE__ */ new Map();
34063
+ for (let i = 0; i < this.numfaces; i++) {
34064
+ const edges = this.getFaceEdges(i);
34065
+ for (const edge of edges) {
34066
+ if (!edgeCountMap.has(edge)) {
34067
+ edgeCountMap.set(edge, 1);
34068
+ } else {
34069
+ edgeCountMap.set(edge, edgeCountMap.get(edge) + 1);
34070
+ }
34071
+ }
34072
+ }
34073
+ return edgeCountMap;
34074
+ }
33965
34075
  }
33966
34076
  class LODS {
33967
34077
  lodType = LodType.Unknown;
@@ -36096,6 +36206,15 @@ const API = {
36096
36206
  return await response.json();
36097
36207
  }
36098
36208
  },
36209
+ "Subscriptions": {
36210
+ HasPlus: async function() {
36211
+ const response = await RBLXGet("https://apis.roblox.com/subscriptions/v2/user/subscriptions?ProductType=Blackbird&ResultsPerPage=1");
36212
+ if (response.status !== 200) {
36213
+ return response;
36214
+ }
36215
+ return (await response.json()).subscriptions.length > 0;
36216
+ }
36217
+ },
36099
36218
  "RBLXGet": RBLXGet,
36100
36219
  "RBLXPost": RBLXPost,
36101
36220
  "RBLXDelete": RBLXDelete,
@@ -42317,27 +42436,7 @@ class MeshDesc {
42317
42436
  }
42318
42437
  return true;
42319
42438
  }
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;
42439
+ async wrapDeformer(mesh) {
42341
42440
  if (this.deformerDesc) {
42342
42441
  const meshMap = /* @__PURE__ */ new Map();
42343
42442
  const meshPromises = [];
@@ -42366,6 +42465,9 @@ class MeshDesc {
42366
42465
  await targetDeformer.solveAsync();
42367
42466
  targetDeformer.deformMesh();
42368
42467
  }
42468
+ }
42469
+ async wrapLayer(mesh) {
42470
+ let the_ref_mesh = void 0;
42369
42471
  if (this.layerDesc && this.modelLayersDesc && this.modelLayersDesc.targetCages && this.modelLayersDesc.targetCages.length > 0 && this.modelLayersDesc.targetCFrames && this.modelLayersDesc.targetSizes && this.modelLayersDesc.layers) {
42370
42472
  const meshMap = /* @__PURE__ */ new Map();
42371
42473
  const meshPromises = [];
@@ -42503,8 +42605,11 @@ class MeshDesc {
42503
42605
  offsetMesh(mesh, totalOffset);
42504
42606
  }
42505
42607
  if (!FLAGS.SHOW_CAGE) the_ref_mesh = void 0;
42506
- if (FLAGS.HIDE_LAYERED_CLOTHING) return;
42608
+ if (FLAGS.HIDE_LAYERED_CLOTHING) return the_ref_mesh;
42507
42609
  }
42610
+ return the_ref_mesh;
42611
+ }
42612
+ async wrapTarget(mesh) {
42508
42613
  if (this.target && this.targetOrigin && this.hsrDesc) {
42509
42614
  const meshMap = /* @__PURE__ */ new Map();
42510
42615
  const meshPromises = [];
@@ -42537,6 +42642,8 @@ class MeshDesc {
42537
42642
  doHSR(totalUvToHits, targetCage, mesh, true, `${this.target}-${this.mesh}`);
42538
42643
  }
42539
42644
  }
42645
+ }
42646
+ async wrapTextureTransfer(mesh) {
42540
42647
  if (this.wrapTextureTarget && this.wrapTextureTargetOrigin && this.wrapTextureMinBound && this.wrapTextureMaxBound) {
42541
42648
  const meshMap = /* @__PURE__ */ new Map();
42542
42649
  const meshPromises = [];
@@ -42566,11 +42673,38 @@ class MeshDesc {
42566
42673
  }
42567
42674
  for (let i = mesh.coreMesh.numverts - 1; i >= 0; i--) {
42568
42675
  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]);
42676
+ if (vertUV[0] < 0.05 || vertUV[0] > 0.95 || vertUV[1] < 0.05 || vertUV[1] > 0.95) {
42677
+ mesh.coreMesh.setColor(i, [255, 255, 255, 0]);
42571
42678
  }
42572
42679
  }
42573
42680
  }
42681
+ }
42682
+ async compileMesh() {
42683
+ if (!this.mesh) return;
42684
+ const meshToLoad = this.mesh;
42685
+ const mesh = await API.Asset.GetMesh(meshToLoad, void 0);
42686
+ if (mesh instanceof Response) {
42687
+ warn(true, "Failed to get mesh for compileMesh", mesh);
42688
+ return mesh;
42689
+ }
42690
+ if (!mesh.facs && this.headMesh && mesh.skinning.skinnings.length > 0) {
42691
+ const headMesh = await API.Asset.GetMesh(this.headMesh, void 0, true);
42692
+ if (headMesh instanceof Response) {
42693
+ warn(true, "Failed to get headMesh for compileMesh", headMesh);
42694
+ return headMesh;
42695
+ }
42696
+ if (headMesh.facs) {
42697
+ mesh.facs = headMesh.facs.clone();
42698
+ }
42699
+ }
42700
+ const wrapDeformerResult = await this.wrapDeformer(mesh);
42701
+ if (wrapDeformerResult instanceof Response) return wrapDeformerResult;
42702
+ const the_ref_mesh = await this.wrapLayer(mesh);
42703
+ if (the_ref_mesh instanceof Response) return the_ref_mesh;
42704
+ const wrapTargetResult = await this.wrapTarget(mesh);
42705
+ if (wrapTargetResult instanceof Response) return wrapTargetResult;
42706
+ const wrapTextureTransferResult = await this.wrapTextureTransfer(mesh);
42707
+ if (wrapTextureTransferResult instanceof Response) return wrapTextureTransferResult;
42574
42708
  this.fileMesh = mesh;
42575
42709
  const geometry = fileMeshToTHREEGeometry(the_ref_mesh || mesh, this.canHaveSkinning, this.forceVertexColor);
42576
42710
  let threeMesh = void 0;
@@ -42610,6 +42744,9 @@ class MeshDesc {
42610
42744
  break;
42611
42745
  }
42612
42746
  }
42747
+ if (child.className === "Decal") {
42748
+ this.forceVertexColor = void 0;
42749
+ }
42613
42750
  }
42614
42751
  fromPart(child) {
42615
42752
  this.canHaveSkinning = false;
@@ -43126,6 +43263,26 @@ function fastMask(mask, image) {
43126
43263
  ctx.drawImage(image, 0, 0, mask.width, mask.height);
43127
43264
  return canvas;
43128
43265
  }
43266
+ function imageDataToCanvas(data, width, height) {
43267
+ const offscreenCanvas = new OffscreenCanvas(width, height);
43268
+ const offscreenCtx = offscreenCanvas.getContext("2d");
43269
+ const canvas = document.createElement("canvas");
43270
+ const ctx = canvas.getContext("2d");
43271
+ canvas.width = width;
43272
+ canvas.height = height;
43273
+ if (!ctx || !offscreenCtx) {
43274
+ throw new Error("Failed to get CanvasContext");
43275
+ }
43276
+ const imgData = new ImageData(new Uint8ClampedArray(data.buffer), width, height);
43277
+ offscreenCtx.putImageData(imgData, 0, 0);
43278
+ ctx.translate(0, height);
43279
+ ctx.scale(1, -1);
43280
+ ctx.drawImage(offscreenCanvas, 0, 0);
43281
+ return canvas;
43282
+ }
43283
+ function imageDataToCanvasTexture(data, width, height) {
43284
+ return new CanvasTexture(imageDataToCanvas(data, width, height));
43285
+ }
43129
43286
  class ColorLayer {
43130
43287
  color;
43131
43288
  bodyPart;
@@ -43476,7 +43633,7 @@ class MaterialDesc {
43476
43633
  }
43477
43634
  let hasTransparency = false;
43478
43635
  const rbxRenderer = RBXRenderer.getRenderer();
43479
- if (!hasColorLayer && rbxRenderer) {
43636
+ if (!hasColorLayer && rbxRenderer || FLAGS.RENDERTARGET_TO_CANVASTEXTURE && rbxRenderer) {
43480
43637
  const data = new Uint8Array(width * height * 4);
43481
43638
  await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
43482
43639
  for (let i = 3; i < data.length; i += 4) {
@@ -43485,6 +43642,15 @@ class MaterialDesc {
43485
43642
  break;
43486
43643
  }
43487
43644
  }
43645
+ if (FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
43646
+ const ogTexture = texture;
43647
+ texture = imageDataToCanvasTexture(data, width, height);
43648
+ texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
43649
+ texture.wrapS = ogTexture.wrapS;
43650
+ texture.wrapT = ogTexture.wrapT;
43651
+ texture.minFilter = ogTexture.minFilter;
43652
+ texture.magFilter = ogTexture.magFilter;
43653
+ }
43488
43654
  }
43489
43655
  if (!this.transparent) {
43490
43656
  hasTransparency = false;
@@ -43537,7 +43703,7 @@ class MaterialDesc {
43537
43703
  }
43538
43704
  }
43539
43705
  let hasTransparency = false;
43540
- if (this.transparent) {
43706
+ if (this.transparent || FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
43541
43707
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
43542
43708
  const data = imageData.data;
43543
43709
  for (let i = 3; i < data.length; i += 4) {
@@ -43600,7 +43766,7 @@ class MaterialDesc {
43600
43766
  if (!hasLayerOfType) return;
43601
43767
  if ((hasSpecialUVType || this.bodyPart !== void 0) && FLAGS.USE_RENDERTARGET) {
43602
43768
  return "full";
43603
- } else if (this.layers.length > 1 || hasColorLayer && FLAGS.USE_RENDERTARGET) {
43769
+ } else if ((this.layers.length > 1 || hasColorLayer) && FLAGS.USE_RENDERTARGET) {
43604
43770
  return "simple";
43605
43771
  } else {
43606
43772
  return "direct";
@@ -43657,13 +43823,15 @@ class MaterialDesc {
43657
43823
  hasTransparency = true;
43658
43824
  }
43659
43825
  let material = void 0;
43826
+ const textureTemplate = {};
43827
+ if (colorTexture) textureTemplate.map = colorTexture;
43828
+ if (normalTexture) textureTemplate.normalMap = normalTexture;
43829
+ if (roughnessTexture) textureTemplate.roughnessMap = roughnessTexture;
43830
+ if (metalnessTexture) textureTemplate.metalnessMap = metalnessTexture;
43831
+ if (emissiveTexture) textureTemplate.emissiveMap = emissiveTexture;
43660
43832
  if (normalTexture || roughnessTexture || metalnessTexture || emissiveTexture) {
43661
43833
  material = new MeshStandardMaterial({
43662
- map: colorTexture,
43663
- normalMap: normalTexture,
43664
- roughnessMap: roughnessTexture,
43665
- metalnessMap: metalnessTexture,
43666
- emissiveMap: emissiveTexture,
43834
+ ...textureTemplate,
43667
43835
  emissiveIntensity: hasEmissive ? this.emissiveStrength : 0,
43668
43836
  emissive: hasEmissive ? new Color(this.emissiveTint.R, this.emissiveTint.G, this.emissiveTint.B) : new Color(0, 0, 0),
43669
43837
  transparent: hasTransparency,
@@ -43679,7 +43847,7 @@ class MaterialDesc {
43679
43847
  });
43680
43848
  } else {
43681
43849
  material = new MeshPhongMaterial({
43682
- map: colorTexture,
43850
+ ...textureTemplate,
43683
43851
  specular: new Color(1 / 102, 1 / 102, 1 / 102),
43684
43852
  shininess: 9,
43685
43853
  transparent: hasTransparency,
@@ -44779,31 +44947,7 @@ class SkeletonDesc2 {
44779
44947
  }
44780
44948
  class DisposableDesc {
44781
44949
  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);
44950
+ disposeMesh(scene, mesh);
44807
44951
  }
44808
44952
  disposeMeshes(scene, meshes) {
44809
44953
  for (const mesh of meshes) {
@@ -44840,6 +44984,12 @@ class RenderDesc extends DisposableDesc {
44840
44984
  }
44841
44985
  this.virtualFromRenderDesc(other);
44842
44986
  }
44987
+ transferFrom(other) {
44988
+ this.virtualTransferFrom(other);
44989
+ }
44990
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
44991
+ virtualTransferFrom(_other) {
44992
+ }
44843
44993
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
44844
44994
  virtualFromRenderDesc(_other) {
44845
44995
  throw new Error("Virtual method virtualFromRenderDesc called");
@@ -45245,7 +45395,6 @@ class EmitterDesc extends DisposableDesc {
45245
45395
  passedTime = 0;
45246
45396
  lockedToPart = false;
45247
45397
  lifetime = new NumberRange(1, 1);
45248
- rate = 10;
45249
45398
  spreadAngle = new Vector22(0, 0);
45250
45399
  speed = new NumberRange(1, 1);
45251
45400
  rotation = new NumberRange(0, 0);
@@ -45258,9 +45407,6 @@ class EmitterDesc extends DisposableDesc {
45258
45407
  zOffset = 0;
45259
45408
  offset = new Vector32();
45260
45409
  shapeInOut = 0;
45261
- colorTexture;
45262
- alphaTexture;
45263
- texture;
45264
45410
  opacity = 1;
45265
45411
  lightEmission = 1;
45266
45412
  blending = AdditiveBlending;
@@ -45268,16 +45414,52 @@ class EmitterDesc extends DisposableDesc {
45268
45414
  size = new NumberSequence();
45269
45415
  transparency = new NumberSequence([new NumberSequenceKeypoint(0, 0, 0)]);
45270
45416
  normalizeSizeKeypointTime = true;
45417
+ //requires recompilation
45418
+ rate = 10;
45419
+ colorTexture;
45420
+ alphaTexture;
45421
+ texture;
45422
+ //results
45271
45423
  instanceOpacityBuffer;
45272
45424
  instanceColorBuffer;
45273
45425
  instanceSeedTimeBuffer;
45274
45426
  result;
45275
45427
  particles = [];
45428
+ initialParticleCount = 0;
45276
45429
  get maxCount() {
45277
- return Math.max(Math.ceil(this.lifetime.Max * this.rate) * 2, 1);
45430
+ const calculatedMax = Math.max(Math.ceil(this.lifetime.Max * this.rate) * 2, 1);
45431
+ const particleMax = this.initialParticleCount + calculatedMax;
45432
+ return particleMax;
45433
+ }
45434
+ needsRegeneration(other) {
45435
+ return this.texture === other.texture && this.alphaTexture === other.alphaTexture && this.colorTexture === other.colorTexture && this.rate === other.rate;
45278
45436
  }
45279
45437
  isSame(other) {
45280
- return this.lifetime.isSame(other.lifetime) && this.rate === other.rate && this.texture === other.texture;
45438
+ return !this.needsRegeneration(other) && this.lockedToPart === other.lockedToPart && this.lifetime.isSame(other.lifetime) && this.spreadAngle.isSame(other.spreadAngle) && this.speed.isSame(other.speed) && this.rotation.isSame(other.rotation) && this.rotationSpeed.isSame(other.rotationSpeed) && this.localAcceleration.isSame(other.localAcceleration) && this.acceleration.isSame(other.acceleration) && this.drag === other.drag && this.timeScale === other.timeScale && this.orientation === other.orientation && this.zOffset === other.zOffset && this.offset.isSame(other.offset) && this.shapeInOut === other.shapeInOut && this.opacity === other.opacity && this.lightEmission === other.lightEmission && this.blending === other.blending && this.color.isSame(other.color) && this.size.isSame(other.size) && this.transparency.isSame(other.transparency) && this.normalizeSizeKeypointTime === other.normalizeSizeKeypointTime;
45439
+ }
45440
+ fromEmitterDesc(other) {
45441
+ this.lockedToPart = other.lockedToPart;
45442
+ this.lifetime = other.lifetime.clone();
45443
+ this.rate = other.rate;
45444
+ this.spreadAngle = other.spreadAngle.clone();
45445
+ this.speed = other.speed.clone();
45446
+ this.rotation = other.rotation.clone();
45447
+ this.rotationSpeed = other.rotationSpeed.clone();
45448
+ this.localAcceleration = other.localAcceleration.clone();
45449
+ this.acceleration = other.acceleration.clone();
45450
+ this.drag = other.drag;
45451
+ this.timeScale = other.timeScale;
45452
+ this.orientation = other.orientation;
45453
+ this.zOffset = other.zOffset;
45454
+ this.offset = other.offset.clone();
45455
+ this.shapeInOut = other.shapeInOut;
45456
+ this.opacity = other.opacity;
45457
+ this.lightEmission = other.lightEmission;
45458
+ this.blending = other.blending;
45459
+ this.color = other.color.clone();
45460
+ this.size = other.size.clone();
45461
+ this.transparency = other.transparency.clone();
45462
+ this.normalizeSizeKeypointTime = other.normalizeSizeKeypointTime;
45281
45463
  }
45282
45464
  dispose(renderer, scene) {
45283
45465
  const mesh = this.result;
@@ -45503,17 +45685,14 @@ class EmitterGroupDesc extends RenderDesc {
45503
45685
  if (this.needsRegeneration(other)) {
45504
45686
  return false;
45505
45687
  }
45506
- if (this.time !== other.time) {
45507
- return false;
45508
- }
45509
- return true;
45688
+ return this.time === other.time;
45510
45689
  }
45511
45690
  needsRegeneration(other) {
45512
45691
  if (this.emitterDescs.length !== other.emitterDescs.length) {
45513
45692
  return true;
45514
45693
  }
45515
45694
  for (let i = 0; i < this.emitterDescs.length; i++) {
45516
- if (!this.emitterDescs[i].isSame(other.emitterDescs[i])) {
45695
+ if (!this.emitterDescs[i].needsRegeneration(other.emitterDescs[i])) {
45517
45696
  return true;
45518
45697
  }
45519
45698
  }
@@ -45525,6 +45704,17 @@ class EmitterGroupDesc extends RenderDesc {
45525
45704
  this.lowerBound = other.lowerBound;
45526
45705
  this.higherBound = other.higherBound;
45527
45706
  this.emitterDir = other.emitterDir;
45707
+ for (let i = 0; i < this.emitterDescs.length; i++) {
45708
+ this.emitterDescs[i].fromEmitterDesc(other.emitterDescs[i]);
45709
+ }
45710
+ }
45711
+ virtualTransferFrom(other) {
45712
+ if (this.emitterDescs.length === other.emitterDescs.length) {
45713
+ for (let i = 0; i < this.emitterDescs.length; i++) {
45714
+ this.emitterDescs[i].particles = other.emitterDescs[i].particles;
45715
+ this.emitterDescs[i].initialParticleCount = this.emitterDescs[i].particles.length;
45716
+ }
45717
+ }
45528
45718
  }
45529
45719
  fromInstance(child) {
45530
45720
  this.instance = child;
@@ -47061,6 +47251,26 @@ class AnimatorWrapper extends InstanceWrapper {
47061
47251
  return false;
47062
47252
  }
47063
47253
  }
47254
+ class AttachmentWrapper extends InstanceWrapper {
47255
+ static className = "Attachment";
47256
+ static requiredProperties = [
47257
+ "Name",
47258
+ "CFrame"
47259
+ ];
47260
+ setup() {
47261
+ if (!this.instance.HasProperty("Name")) this.instance.addProperty(new Property("Name", DataType.String), this.instance.className);
47262
+ if (!this.instance.HasProperty("CFrame")) this.instance.addProperty(new Property("CFrame", DataType.CFrame), new CFrame());
47263
+ }
47264
+ getWorldCFrame() {
47265
+ if (this.instance.parent) {
47266
+ if (this.instance.parent.className.includes("Part")) {
47267
+ const parentCF = this.instance.parent.PropOrDefault("CFrame", new CFrame());
47268
+ return parentCF.multiply(this.instance.Prop("CFrame"));
47269
+ }
47270
+ }
47271
+ return this.instance.Prop("CFrame");
47272
+ }
47273
+ }
47064
47274
  class BodyColorsWrapper extends InstanceWrapper {
47065
47275
  static className = "BodyColors";
47066
47276
  static requiredProperties = [
@@ -47647,6 +47857,11 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
47647
47857
  return void 0;
47648
47858
  }
47649
47859
  }
47860
+ /**
47861
+ * Update the data of the HumanoidDescription to match that inside an Outfit
47862
+ * @param outfit
47863
+ * @returns HumanoidDescription or Response if it fails
47864
+ */
47650
47865
  async fromOutfit(outfit) {
47651
47866
  this.instance.setProperty("BodyTypeScale", outfit.scale.bodyType);
47652
47867
  this.instance.setProperty("ProportionScale", outfit.scale.proportion);
@@ -48610,6 +48825,7 @@ class HumanoidDescriptionWrapper extends InstanceWrapper {
48610
48825
  toChange.push("dance2");
48611
48826
  toChange.push("dance3");
48612
48827
  toChange.push("toolnone");
48828
+ if (this.instance.Prop("IdleAnimation") <= 0) toChange.push("pose");
48613
48829
  }
48614
48830
  miniPromises.push(this._applyAnimations(humanoid, toChange));
48615
48831
  }
@@ -48979,6 +49195,7 @@ function RegisterWrappers() {
48979
49195
  WeldWrapper.register();
48980
49196
  Motor6DWrapper.register();
48981
49197
  ManualWeldWrapper.register();
49198
+ AttachmentWrapper.register();
48982
49199
  AnimationConstraintWrapper.register();
48983
49200
  AnimatorWrapper.register();
48984
49201
  FaceControlsWrapper.register();
@@ -48989,11 +49206,40 @@ function RegisterWrappers() {
48989
49206
  BodyColorsWrapper.register();
48990
49207
  AccessoryWrapper.register();
48991
49208
  }
49209
+ function disposeMesh(scene, mesh) {
49210
+ if (mesh.material) {
49211
+ const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
49212
+ for (const material of materials) {
49213
+ for (const key of Object.keys(material)) {
49214
+ const value = material[key];
49215
+ if (value instanceof Texture) {
49216
+ value.dispose();
49217
+ }
49218
+ }
49219
+ if (material instanceof ShaderMaterial) {
49220
+ const uniforms = material.uniforms;
49221
+ for (const key of Object.keys(uniforms)) {
49222
+ const value = uniforms[key].value;
49223
+ if (value instanceof Texture) {
49224
+ value.dispose();
49225
+ }
49226
+ }
49227
+ }
49228
+ material.dispose();
49229
+ }
49230
+ }
49231
+ if (mesh.geometry) {
49232
+ mesh.geometry.dispose();
49233
+ }
49234
+ scene.remove(mesh);
49235
+ }
48992
49236
  class RBXRendererScene {
48993
49237
  //important scene components
48994
49238
  scene = new Scene();
48995
49239
  camera = new PerspectiveCamera(70, 1 / 1, 0.1, 100);
48996
49240
  controls;
49241
+ shouldAnimate = true;
49242
+ destroyed = false;
48997
49243
  //renderer
48998
49244
  effectComposer;
48999
49245
  //viewport
@@ -49024,14 +49270,49 @@ class RBXRendererScene {
49024
49270
  ambientLight;
49025
49271
  directionalLight;
49026
49272
  directionalLight2;
49273
+ /** Forces viewport to be within bounds */
49027
49274
  setRect(bounds) {
49028
49275
  this.viewport = [bounds.left, window.innerHeight - bounds.bottom, bounds.width, bounds.height];
49029
49276
  this.scissor = [...this.viewport];
49030
49277
  }
49278
+ /** Makes viewport size 0x0, invisible */
49031
49279
  noRect() {
49032
49280
  this.viewport = [0, 0, 0, 0];
49033
49281
  this.scissor = [0, 0, 0, 0];
49034
49282
  }
49283
+ destroy() {
49284
+ if (this.destroyed) return;
49285
+ this.destroyed = true;
49286
+ for (const instance of this.renderDescs.keys()) {
49287
+ RBXRenderer.removeInstance(instance, this);
49288
+ }
49289
+ RBXRenderer.scenes.splice(RBXRenderer.scenes.indexOf(this), 1);
49290
+ if (this.plane) {
49291
+ disposeMesh(this.scene, this.plane);
49292
+ this.plane = void 0;
49293
+ }
49294
+ if (this.shadowPlane) {
49295
+ disposeMesh(this.scene, this.shadowPlane);
49296
+ this.shadowPlane = void 0;
49297
+ }
49298
+ }
49299
+ async exportGLTF(name = "scene", autoDownload = true) {
49300
+ return new Promise((resolve, reject) => {
49301
+ const exporter = new GLTFExporter();
49302
+ exporter.parse(this.scene, (gltf) => {
49303
+ if (autoDownload) {
49304
+ if (gltf instanceof ArrayBuffer) {
49305
+ saveByteArray([gltf], `${name}.glb`);
49306
+ } else {
49307
+ download(`${name}.gltf`, JSON.stringify(gltf));
49308
+ }
49309
+ }
49310
+ resolve(gltf);
49311
+ }, (error2) => {
49312
+ reject(error2);
49313
+ });
49314
+ });
49315
+ }
49035
49316
  }
49036
49317
  class RBXRenderer {
49037
49318
  static orbitControlsTarget = [0, 3, 0];
@@ -49425,6 +49706,7 @@ class RBXRenderer {
49425
49706
  }
49426
49707
  static renderScene(renderScene, autoClear = true) {
49427
49708
  if (!RBXRenderer.renderer) return;
49709
+ if (!renderScene.shouldAnimate) return;
49428
49710
  RBXRenderer.renderer.autoClear = autoClear;
49429
49711
  if (!autoClear) {
49430
49712
  RBXRenderer.renderer.clearDepth();
@@ -49496,6 +49778,7 @@ class RBXRenderer {
49496
49778
  }
49497
49779
  } else {
49498
49780
  if (!renderScene.isRenderingMesh.get(instance)) {
49781
+ if (oldDesc) newDesc.transferFrom(oldDesc);
49499
49782
  newDesc.results = oldDesc?.results;
49500
49783
  renderScene.renderDescs.set(instance, newDesc);
49501
49784
  renderScene.isRenderingMesh.set(instance, true);
@@ -49545,6 +49828,7 @@ class RBXRenderer {
49545
49828
  }
49546
49829
  /**Adds an instance to the renderer or updates it */
49547
49830
  static addInstance(instance, auth, renderScene = RBXRenderer.firstScene) {
49831
+ if (renderScene.destroyed) return;
49548
49832
  const isDecal = instance.className === "Decal";
49549
49833
  const isBakedDecal = isDecal && !instance.FindFirstChildOfClass("WrapTextureTransfer");
49550
49834
  let isFirstDecal = true;
@@ -49745,14 +50029,6 @@ class HSR {
49745
50029
  }
49746
50030
  }
49747
50031
  }
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
50032
  function getCorners(cframe, size) {
49757
50033
  const halfX = size.X / 2;
49758
50034
  const halfY = size.Y / 2;
@@ -49815,12 +50091,27 @@ function getExtents(cframe, parts) {
49815
50091
  }
49816
50092
  return [lowerExtents, higherExtents];
49817
50093
  }
50094
+ function getExtentsCenter(extents) {
50095
+ return extents[1].minus(extents[0]).divide(new Vector32(2, 2, 2)).add(extents[0]);
50096
+ }
49818
50097
  function zoomExtents(cameraCFrame, modelCFrame, modelSize, targetFOV, distanceScale) {
49819
50098
  const largestSize = Math.max(modelSize.X, modelSize.Y, modelSize.Z);
49820
50099
  const fovMultiplier = 70 / targetFOV;
49821
50100
  const lookDir = multiply(normalize(minus(cameraCFrame.Position, modelCFrame.Position)), [distanceScale, distanceScale, distanceScale]);
49822
50101
  cameraCFrame.Position = add(modelCFrame.Position, multiply(multiply(lookDir, [largestSize, largestSize, largestSize]), [fovMultiplier, fovMultiplier, fovMultiplier]));
49823
50102
  }
50103
+ function getCameraOffset(fov2, extentsSize) {
50104
+ const halfSize = extentsSize.magnitude() / 2;
50105
+ const fovDivisor = Math.tan(rad(fov2 / 2));
50106
+ return halfSize / fovDivisor;
50107
+ }
50108
+ function zoomToExtents(cameraCFrame, modelCFrame, modelSize, fov2 = 70) {
50109
+ const cameraOffset = getCameraOffset(fov2, modelSize);
50110
+ const cameraRotation = new CFrame();
50111
+ cameraRotation.Orientation = cameraCFrame.Orientation;
50112
+ const instancePosition = modelCFrame.Position;
50113
+ cameraCFrame.Position = add(instancePosition, multiply(minus([0, 0, 0], cameraRotation.lookVector()), [cameraOffset, cameraOffset, cameraOffset]));
50114
+ }
49824
50115
  function getHeadExtents(rig) {
49825
50116
  const head = rig.FindFirstChild("Head");
49826
50117
  if (!head) return;
@@ -49840,6 +50131,16 @@ function getHeadExtents(rig) {
49840
50131
  const extents = getExtents(head.Prop("CFrame"), headParts);
49841
50132
  return extents;
49842
50133
  }
50134
+ function getRigExtentsWorld(rig) {
50135
+ const rigParts = [];
50136
+ for (const child of rig.GetDescendants()) {
50137
+ if (child.className === "Part" || child.className === "MeshPart") {
50138
+ rigParts.push(child);
50139
+ }
50140
+ }
50141
+ const extents = getExtents(new CFrame(), rigParts);
50142
+ return extents;
50143
+ }
49843
50144
  function getCameraCFrameForHeadshotCustomized(rig, fov2, yRot, distance2) {
49844
50145
  const head = rig.FindFirstChild("Head");
49845
50146
  if (!head) return;
@@ -49866,6 +50167,34 @@ function getCameraCFrameForHeadshotCustomized(rig, fov2, yRot, distance2) {
49866
50167
  zoomExtents(cameraCF, headCenterCF, headLocalExtents[1].minus(headLocalExtents[0]), fov2, distance2);
49867
50168
  return cameraCF;
49868
50169
  }
50170
+ function getCameraCFrameForAvatarNonCustomized(rig) {
50171
+ const thumbnailCamera = rig.FindFirstChildOfClass("Camera");
50172
+ if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
50173
+ let rootPart = rig.PropOrDefault("PrimaryPart", void 0);
50174
+ if (!rootPart) rootPart = rig.FindFirstChildOfClass("Part");
50175
+ if (!rootPart) rootPart = rig.FindFirstChildOfClass("MeshPart");
50176
+ if (!rootPart) return;
50177
+ const rootPartCF = rootPart.PropOrDefault("CFrame", new CFrame()).clone();
50178
+ const worldExtents = getRigExtentsWorld(rig);
50179
+ if (!worldExtents) return;
50180
+ const extentsSize = worldExtents[1].minus(worldExtents[0]);
50181
+ rootPartCF.Position = getExtentsCenter(worldExtents).toVec3();
50182
+ let lookVector = rootPartCF.lookVector();
50183
+ if (Math.abs(lookVector[1]) > 0.95) {
50184
+ lookVector = [0, 0, -1];
50185
+ } else {
50186
+ lookVector[1] = 0;
50187
+ lookVector = normalize(lookVector);
50188
+ }
50189
+ let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
50190
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(25 * Math.PI / 180, 27.5 * Math.PI / 180, 0, "ZXY"));
50191
+ lookVector = lookCF.lookVector();
50192
+ lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
50193
+ lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
50194
+ const cameraCF = lookCF.clone();
50195
+ zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
50196
+ return cameraCF;
50197
+ }
49869
50198
  class OutfitRenderer {
49870
50199
  auth;
49871
50200
  outfit;
@@ -50054,6 +50383,128 @@ class OutfitRenderer {
50054
50383
  }
50055
50384
  }
50056
50385
  }
50386
+ function renderToRenderTarget(width, height, renderScene) {
50387
+ const renderTarget = new WebGLRenderTarget(width, height, {
50388
+ colorSpace: SRGBColorSpace,
50389
+ generateMipmaps: false,
50390
+ minFilter: LinearFilter,
50391
+ magFilter: LinearFilter,
50392
+ type: UnsignedByteType
50393
+ });
50394
+ const rbxRenderer = RBXRenderer.getRenderer();
50395
+ if (!rbxRenderer) return renderTarget;
50396
+ rbxRenderer.setRenderTarget(renderTarget);
50397
+ rbxRenderer.render(renderScene.scene, renderScene.camera);
50398
+ return renderTarget;
50399
+ }
50400
+ async function renderTargetToCanvas(renderTarget) {
50401
+ const rbxRenderer = RBXRenderer.getRenderer();
50402
+ if (!rbxRenderer) return;
50403
+ const width = renderTarget.width;
50404
+ const height = renderTarget.height;
50405
+ const data = new Uint8Array(width * height * 4);
50406
+ await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
50407
+ return imageDataToCanvas(data, width, height);
50408
+ }
50409
+ async function generateModelThumbnail(auth, renderScene, model, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
50410
+ return new Promise((resolve) => {
50411
+ const cameraCFrame = getCameraCFrameForAvatarNonCustomized(model);
50412
+ if (cameraCFrame) {
50413
+ RBXRenderer.setCameraCFrame(cameraCFrame, renderScene);
50414
+ }
50415
+ RBXRenderer.addInstance(model, auth, renderScene);
50416
+ let exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50417
+ const onLoadingConnection = API.Events.OnLoadingAssets.Connect((currentlyLoading) => {
50418
+ if (exportTimeout) {
50419
+ clearTimeout(exportTimeout);
50420
+ exportTimeout = void 0;
50421
+ }
50422
+ if (!currentlyLoading) {
50423
+ exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50424
+ }
50425
+ });
50426
+ async function doExport() {
50427
+ onLoadingConnection.Disconnect();
50428
+ if (type === "gltf") {
50429
+ if (!FLAGS.RENDERTARGET_TO_CANVASTEXTURE && FLAGS.USE_RENDERTARGET) {
50430
+ warn(true, "FLAGS.RENDERTARGET_TO_CANVASTEXTURE is false, GLTF export cannot export render target textures, consider setting this flag to true");
50431
+ }
50432
+ resolve(await renderScene.exportGLTF(`result`, gltfAutoDownload));
50433
+ } else {
50434
+ const renderTarget = renderToRenderTarget(...size, renderScene);
50435
+ const canvasTarget = await renderTargetToCanvas(renderTarget);
50436
+ if (canvasTarget) {
50437
+ resolve(canvasTarget.toDataURL(`image/${type}`, quality));
50438
+ } else {
50439
+ resolve(void 0);
50440
+ }
50441
+ }
50442
+ renderScene.destroy();
50443
+ }
50444
+ });
50445
+ }
50446
+ async function generateOutfitThumbnail(auth, outfit, size = [150, 150], type = "png", quality = 1, gltfAutoDownload = false) {
50447
+ return new Promise((resolve) => {
50448
+ const renderScene = RBXRenderer.addScene();
50449
+ setupThumbnailScene(renderScene);
50450
+ const outfitRenderer = new OutfitRenderer(auth, outfit, renderScene);
50451
+ if (outfit.playerAvatarType === AvatarType.R6) outfitRenderer.deltaTimeMultiplier = 0;
50452
+ outfitRenderer.startAnimating();
50453
+ let exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50454
+ const onLoadingConnection = API.Events.OnLoadingAssets.Connect((currentlyLoading) => {
50455
+ if (exportTimeout) {
50456
+ clearTimeout(exportTimeout);
50457
+ exportTimeout = void 0;
50458
+ }
50459
+ if (!currentlyLoading) {
50460
+ exportTimeout = setTimeout(doExport, FLAGS.THUMBNAIL_TIMEOUT);
50461
+ }
50462
+ });
50463
+ async function doExport() {
50464
+ onLoadingConnection.Disconnect();
50465
+ if (!outfit.containsAssetType("Gear")) {
50466
+ if (outfit.playerAvatarType === AvatarType.R15) {
50467
+ outfitRenderer.setMainAnimation("pose");
50468
+ }
50469
+ } else {
50470
+ outfitRenderer.setMainAnimation("toolnone");
50471
+ }
50472
+ if (outfitRenderer.currentRig) {
50473
+ const thumbnailResult = await generateModelThumbnail(auth, renderScene, outfitRenderer.currentRig, size, type, quality, gltfAutoDownload);
50474
+ resolve(thumbnailResult);
50475
+ outfitRenderer.stopAnimating();
50476
+ if (outfitRenderer.currentRig) outfitRenderer.currentRig.Destroy();
50477
+ } else {
50478
+ resolve(void 0);
50479
+ }
50480
+ }
50481
+ });
50482
+ }
50483
+ function setupThumbnailScene(renderScene) {
50484
+ renderScene.shouldAnimate = false;
50485
+ renderScene.wellLitDirectionalLightIntensity *= 2;
50486
+ renderScene.shadowEnabled = false;
50487
+ RBXRenderer.setupScene("WellLit", 16777215, renderScene);
50488
+ if (renderScene.plane) renderScene.scene.remove(renderScene.plane);
50489
+ if (renderScene.shadowPlane) renderScene.scene.remove(renderScene.shadowPlane);
50490
+ renderScene.scene.background = null;
50491
+ }
50492
+ function exposeAPI() {
50493
+ globalThis.API = API;
50494
+ globalThis.APICACHE = CACHE;
50495
+ globalThis.Authentication = Authentication;
50496
+ }
50497
+ function exposeMesh() {
50498
+ globalThis.fileMeshToTHREEGeometry = fileMeshToTHREEGeometry;
50499
+ }
50500
+ function exposeFLAGS() {
50501
+ globalThis.FLAGS = FLAGS;
50502
+ }
50503
+ function exposeThumbnailGenerator() {
50504
+ globalThis.generateOutfitThumbnail = generateOutfitThumbnail;
50505
+ globalThis.generateModelThumbnail = generateModelThumbnail;
50506
+ globalThis.setupThumbnailScene = setupThumbnailScene;
50507
+ }
50057
50508
  export {
50058
50509
  API,
50059
50510
  AbbreviationToFaceControlProperty,
@@ -50083,6 +50534,7 @@ export {
50083
50534
  AssetTypeToAccessoryType,
50084
50535
  AssetTypeToMakeupType,
50085
50536
  AssetTypes,
50537
+ AttachmentWrapper,
50086
50538
  Authentication,
50087
50539
  AvatarType,
50088
50540
  BodyColor3s,
@@ -50120,12 +50572,15 @@ export {
50120
50572
  FileMesh,
50121
50573
  FileMeshSkinning,
50122
50574
  FileMeshSubset,
50575
+ FindFirstMatchingAttachment,
50123
50576
  FullBodyColors,
50124
50577
  GetAttachedPart,
50578
+ GetWrapperForInstance,
50125
50579
  HSR,
50126
50580
  HumanoidDescriptionWrapper,
50127
50581
  HumanoidRigType,
50128
50582
  Instance,
50583
+ InstanceWrapper,
50129
50584
  ItemInfo,
50130
50585
  ItemSort,
50131
50586
  LayeredAssetTypes,
@@ -50217,24 +50672,35 @@ export {
50217
50672
  defaultShirtTemplateAssetIds,
50218
50673
  deformReferenceToBaseBodyParts,
50219
50674
  deg,
50675
+ disposeMesh,
50220
50676
  distance,
50221
50677
  divide,
50222
50678
  dot,
50223
50679
  download,
50224
50680
  exposeAPI,
50681
+ exposeFLAGS,
50225
50682
  exposeMesh,
50683
+ exposeThumbnailGenerator,
50226
50684
  fileMeshToTHREEGeometry,
50227
50685
  floor,
50228
50686
  gaussian_rbf,
50687
+ generateModelThumbnail,
50688
+ generateOutfitThumbnail,
50229
50689
  generateUUIDv4,
50690
+ getCameraCFrameForAvatarNonCustomized,
50230
50691
  getCameraCFrameForHeadshotCustomized,
50692
+ getCameraOffset,
50231
50693
  getDistIndexArray,
50232
50694
  getExtents,
50695
+ getExtentsCenter,
50233
50696
  getExtentsForParts,
50234
50697
  getHeadExtents,
50235
50698
  getOffsetArray,
50699
+ getOriginalAttachmentOrientation,
50700
+ getOriginalAttachmentPosition,
50236
50701
  getOriginalSize,
50237
50702
  getRandomBetweenInclusive,
50703
+ getRigExtentsWorld,
50238
50704
  getUVtoIndexMap,
50239
50705
  getUVtoIndicesMap,
50240
50706
  getWorkerOnMessage,
@@ -50278,6 +50744,7 @@ export {
50278
50744
  rotationMatrixToEulerAngles,
50279
50745
  saveByteArray,
50280
50746
  scaleMesh,
50747
+ setupThumbnailScene,
50281
50748
  snapToNumber,
50282
50749
  specialClamp,
50283
50750
  transferSkeleton,
@@ -50287,5 +50754,6 @@ export {
50287
50754
  versionToNumber,
50288
50755
  vertPosToChunkPos,
50289
50756
  xmlMagic,
50290
- zoomExtents
50757
+ zoomExtents,
50758
+ zoomToExtents
50291
50759
  };