roavatar-renderer 1.9.8 → 1.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +123 -7
  2. package/dist/index.js +581 -235
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -33687,7 +33687,13 @@ class Instance {
33687
33687
  }
33688
33688
  return lastChild;
33689
33689
  }
33690
+ /**
33691
+ * IMPORTANT: Only works properly for instances with an InstanceWrapper
33692
+ * @param className
33693
+ * @returns
33694
+ */
33690
33695
  IsA(className) {
33696
+ if (this.className === className) return true;
33691
33697
  const wrapper = this.w;
33692
33698
  if (wrapper) {
33693
33699
  return wrapper.IsA(className);
@@ -36722,7 +36728,7 @@ class LocalOutfit {
36722
36728
  this.name = outfit.name;
36723
36729
  this.id = outfit.id;
36724
36730
  this.creator = outfit.creatorId;
36725
- this.date = Date.now();
36731
+ this.date = outfit.creationDate || Date.now();
36726
36732
  this.buffer = arrayBufferToBase64(outfit.toBuffer());
36727
36733
  }
36728
36734
  toJson() {
@@ -36740,6 +36746,7 @@ class LocalOutfit {
36740
36746
  this.name = data.name;
36741
36747
  this.id = data.id;
36742
36748
  this.creator = data.creator;
36749
+ this.date = data.date;
36743
36750
  this.image = data.image;
36744
36751
  this.buffer = data.buffer;
36745
36752
  this.bg = data.bg || 0;
@@ -36759,6 +36766,7 @@ class LocalOutfit {
36759
36766
  outfit.name = this.name;
36760
36767
  outfit.id = this.id;
36761
36768
  outfit.creatorId = this.creator;
36769
+ outfit.creationDate = this.date;
36762
36770
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36763
36771
  return outfit;
36764
36772
  }
@@ -36768,6 +36776,7 @@ class LocalOutfit {
36768
36776
  outfit.name = this.name;
36769
36777
  outfit.id = this.id;
36770
36778
  outfit.creatorId = this.creator;
36779
+ outfit.creationDate = this.date;
36771
36780
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36772
36781
  if (this.bg) {
36773
36782
  await outfit.addAssetId(this.bg, auth);
@@ -36817,9 +36826,7 @@ const AllAccessorySorts = [
36817
36826
  new ItemSort(46),
36818
36827
  new ItemSort(47)
36819
36828
  ];
36820
- if (!FLAGS.HAIR_IS_BODYPART) {
36821
- AllAccessorySorts.push(new ItemSort(41));
36822
- }
36829
+ AllAccessorySorts.push(new ItemSort(41));
36823
36830
  const AllClothingSorts = [
36824
36831
  new ItemSort(12),
36825
36832
  new ItemSort(11),
@@ -36843,9 +36850,7 @@ const AllBodyPartsSorts = [
36843
36850
  new ItemSort(31),
36844
36851
  new ItemSort(27)
36845
36852
  ];
36846
- if (FLAGS.HAIR_IS_BODYPART) {
36847
- AllBodyPartsSorts.push(new ItemSort(41));
36848
- }
36853
+ AllBodyPartsSorts.push(new ItemSort(41));
36849
36854
  const AllAnimationSorts = [
36850
36855
  new ItemSort(48),
36851
36856
  new ItemSort(50),
@@ -36906,6 +36911,7 @@ const CategoryDictionary = {
36906
36911
  "Dynamic Heads": new SortInfo([new ItemSort(2, "Outfit")]),
36907
36912
  "Adjustment": new SpecialInfo("HeadAdjustment"),
36908
36913
  "|": new SortDivision(),
36914
+ "Hair": new SortInfo([new ItemSort(41)]),
36909
36915
  "Heads": new SortInfo([new ItemSort(17)], "inventory"),
36910
36916
  "Faces": new SortInfo([new ItemSort(18)], "inventory")
36911
36917
  },
@@ -39386,6 +39392,7 @@ class Cache {
39386
39392
  map = /* @__PURE__ */ new Map();
39387
39393
  lastAccess = /* @__PURE__ */ new Map();
39388
39394
  maxEntries;
39395
+ minDeleteLifetime = 5;
39389
39396
  onDelete;
39390
39397
  constructor(maxEntries = 250) {
39391
39398
  this.maxEntries = maxEntries;
@@ -39399,12 +39406,7 @@ class Cache {
39399
39406
  set(key, value) {
39400
39407
  this.map.set(key, value);
39401
39408
  this.lastAccess.set(key, Date.now());
39402
- if (this.map.size > this.maxEntries) {
39403
- const toDelete = [...this.lastAccess.entries()].reduce((min, current) => {
39404
- return current[1] < min[1] ? current : min;
39405
- });
39406
- this.delete(toDelete[0]);
39407
- }
39409
+ this.deleteUntil();
39408
39410
  return this;
39409
39411
  }
39410
39412
  has(key) {
@@ -39416,11 +39418,28 @@ class Cache {
39416
39418
  this.lastAccess.delete(key);
39417
39419
  return toReturn;
39418
39420
  }
39421
+ deleteUntil() {
39422
+ while (this.map.size > this.maxEntries) {
39423
+ if (!this.deleteOne()) break;
39424
+ }
39425
+ }
39426
+ deleteOne() {
39427
+ if (this.map.size > this.maxEntries) {
39428
+ const toDelete = [...this.lastAccess.entries()].reduce((min, current) => {
39429
+ return current[1] < min[1] ? current : min;
39430
+ });
39431
+ if (Date.now() - toDelete[1] >= this.minDeleteLifetime * 1e3) {
39432
+ this.delete(toDelete[0]);
39433
+ return true;
39434
+ }
39435
+ }
39436
+ return false;
39437
+ }
39419
39438
  }
39420
39439
  const CACHE = {
39421
- "AssetBuffer": new Cache(250),
39440
+ "AssetBuffer": new Cache(100),
39422
39441
  "RBX": new Cache(100),
39423
- "Mesh": new Cache(250),
39442
+ "Mesh": new Cache(100),
39424
39443
  "Image": new Cache(100),
39425
39444
  "Thumbnails": new Cache(1e3),
39426
39445
  "ItemOwned": new Cache(1e3),
@@ -39429,6 +39448,54 @@ const CACHE = {
39429
39448
  "ItemDetails": new Cache(1e4),
39430
39449
  "UserInfo": void 0
39431
39450
  };
39451
+ function setCacheFootprintPreset(preset) {
39452
+ switch (preset) {
39453
+ case "none":
39454
+ CACHE.AssetBuffer.maxEntries = 0;
39455
+ CACHE.RBX.maxEntries = 0;
39456
+ CACHE.Mesh.maxEntries = 0;
39457
+ CACHE.Image.maxEntries = 0;
39458
+ CACHE.Thumbnails.maxEntries = 0;
39459
+ CACHE.ItemOwned.maxEntries = 0;
39460
+ CACHE.IsLayered.maxEntries = 0;
39461
+ CACHE.AvatarInventoryItem.maxEntries = 0;
39462
+ CACHE.ItemDetails.maxEntries = 0;
39463
+ break;
39464
+ case "low":
39465
+ CACHE.AssetBuffer.maxEntries = 10;
39466
+ CACHE.RBX.maxEntries = 10;
39467
+ CACHE.Mesh.maxEntries = 10;
39468
+ CACHE.Image.maxEntries = 10;
39469
+ CACHE.Thumbnails.maxEntries = 500;
39470
+ CACHE.ItemOwned.maxEntries = 500;
39471
+ CACHE.IsLayered.maxEntries = 100;
39472
+ CACHE.AvatarInventoryItem.maxEntries = 500;
39473
+ CACHE.ItemDetails.maxEntries = 5e3;
39474
+ break;
39475
+ case "normal":
39476
+ CACHE.AssetBuffer.maxEntries = 100;
39477
+ CACHE.RBX.maxEntries = 100;
39478
+ CACHE.Mesh.maxEntries = 100;
39479
+ CACHE.Image.maxEntries = 100;
39480
+ CACHE.Thumbnails.maxEntries = 1e3;
39481
+ CACHE.ItemOwned.maxEntries = 1e3;
39482
+ CACHE.IsLayered.maxEntries = 1e3;
39483
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39484
+ CACHE.ItemDetails.maxEntries = 1e4;
39485
+ break;
39486
+ case "high":
39487
+ CACHE.AssetBuffer.maxEntries = 250;
39488
+ CACHE.RBX.maxEntries = 250;
39489
+ CACHE.Mesh.maxEntries = 250;
39490
+ CACHE.Image.maxEntries = 250;
39491
+ CACHE.Thumbnails.maxEntries = 1e3;
39492
+ CACHE.ItemOwned.maxEntries = 1e3;
39493
+ CACHE.IsLayered.maxEntries = 1e3;
39494
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39495
+ CACHE.ItemDetails.maxEntries = 1e4;
39496
+ break;
39497
+ }
39498
+ }
39432
39499
  const ContentMap = /* @__PURE__ */ new Map();
39433
39500
  function createContentMap() {
39434
39501
  ContentMap.set("rbxasset://fonts/BaseballCap.mesh", "12220916");
@@ -43854,6 +43921,89 @@ GLTFExporter.Utils = {
43854
43921
  return dstAttribute;
43855
43922
  }
43856
43923
  };
43924
+ const managedTextures = /* @__PURE__ */ new Map();
43925
+ async function createTexturePromise(url, params) {
43926
+ const image = await API.Generic.LoadImage(url.replace(".dds", ".png"));
43927
+ if (!image) return void 0;
43928
+ const texture = new Texture(
43929
+ image,
43930
+ void 0,
43931
+ params?.wrapS || ClampToEdgeWrapping,
43932
+ params?.wrapT || ClampToEdgeWrapping,
43933
+ params?.magFilter,
43934
+ params?.minFilter,
43935
+ void 0,
43936
+ void 0,
43937
+ void 0,
43938
+ params?.colorSpace || SRGBColorSpace
43939
+ );
43940
+ if (params?.generateMipmaps !== void 0) texture.generateMipmaps = params?.generateMipmaps;
43941
+ texture.needsUpdate = true;
43942
+ return texture;
43943
+ }
43944
+ function createManagedTexture(url, params) {
43945
+ const textureInfo = {
43946
+ texture: void 0,
43947
+ uses: 1
43948
+ //used by texture promise (internal), so we dont try to dispose when it doesnt even exist yet
43949
+ };
43950
+ textureInfo.texture = new Promise((resolve) => {
43951
+ createTexturePromise(url, params).then((result) => {
43952
+ textureInfo.texture = result;
43953
+ finishManagedTexture(url, params);
43954
+ resolve(result);
43955
+ });
43956
+ });
43957
+ return textureInfo;
43958
+ }
43959
+ function getTextureInfoKey(url, params) {
43960
+ url = url.replace(".dds", ".png");
43961
+ if (params?.colorSpace === "srgb") delete params.colorSpace;
43962
+ if (params?.wrapS === ClampToEdgeWrapping) delete params.wrapS;
43963
+ if (params?.wrapT === ClampToEdgeWrapping) delete params.wrapT;
43964
+ if (params?.magFilter === LinearFilter) delete params.magFilter;
43965
+ if (params?.minFilter === LinearMipmapLinearFilter) delete params.minFilter;
43966
+ if (params && Object.keys(params).length > 0) {
43967
+ return url + JSON.stringify(params);
43968
+ } else {
43969
+ return url;
43970
+ }
43971
+ }
43972
+ async function getManagedTexture(url, params) {
43973
+ const key = getTextureInfoKey(url, params);
43974
+ let managedTextureInfo = managedTextures.get(key);
43975
+ if (!managedTextureInfo) {
43976
+ managedTextureInfo = createManagedTexture(url, params);
43977
+ managedTextures.set(key, managedTextureInfo);
43978
+ }
43979
+ managedTextureInfo.uses += 1;
43980
+ const disposeTimeout = managedTextureInfo.disposeTimeout;
43981
+ if (disposeTimeout) {
43982
+ clearTimeout(disposeTimeout);
43983
+ managedTextureInfo.disposeTimeout = void 0;
43984
+ }
43985
+ return managedTextureInfo.texture;
43986
+ }
43987
+ async function finishManagedTexture(url, params) {
43988
+ const key = getTextureInfoKey(url, params);
43989
+ const managedTextureInfo = managedTextures.get(key);
43990
+ if (managedTextureInfo) {
43991
+ managedTextureInfo.uses -= 1;
43992
+ if (managedTextureInfo.uses <= 0) {
43993
+ if (!managedTextureInfo.disposeTimeout) {
43994
+ const disposeTimeout = setTimeout(() => {
43995
+ if (managedTextureInfo.disposeTimeout !== disposeTimeout || managedTextureInfo.uses > 0) return;
43996
+ const texture = managedTextureInfo.texture;
43997
+ if (texture && texture instanceof Texture || texture === void 0) {
43998
+ managedTextures.delete(key);
43999
+ if (texture) texture.dispose();
44000
+ }
44001
+ }, 5e3);
44002
+ managedTextureInfo.disposeTimeout = disposeTimeout;
44003
+ }
44004
+ }
44005
+ }
44006
+ }
43857
44007
  const RenderDescClassTypes = /* @__PURE__ */ new Map();
43858
44008
  function getRenderDescForClass(className) {
43859
44009
  return RenderDescClassTypes.get(className);
@@ -43870,22 +44020,9 @@ function setTHREEObjectCF(threeObject, cframe) {
43870
44020
  threeObject.rotation.y = rad(cframe.Orientation[1]);
43871
44021
  threeObject.rotation.z = rad(cframe.Orientation[2]);
43872
44022
  }
43873
- async function getTexture(texture, colorSpace = SRGBColorSpace) {
43874
- if (texture) {
43875
- const source = texture.replace(".dds", ".png");
43876
- const image = await API.Generic.LoadImage(source);
43877
- if (image) {
43878
- const texture2 = new Texture(image);
43879
- texture2.wrapS = ClampToEdgeWrapping;
43880
- texture2.wrapT = ClampToEdgeWrapping;
43881
- texture2.colorSpace = colorSpace;
43882
- texture2.needsUpdate = true;
43883
- return texture2;
43884
- }
43885
- }
43886
- return void 0;
43887
- }
43888
44023
  class DisposableDesc {
44024
+ toDispose = [];
44025
+ managedTextures = [];
43889
44026
  disposeMesh(scene, mesh) {
43890
44027
  disposeMesh(scene, mesh);
43891
44028
  }
@@ -43901,6 +44038,22 @@ class DisposableDesc {
43901
44038
  dispose(_renderer, _scene) {
43902
44039
  throw new Error("Virtual method dispose called");
43903
44040
  }
44041
+ clearToDispose() {
44042
+ for (const disposeable of this.toDispose) {
44043
+ disposeable.dispose();
44044
+ }
44045
+ this.toDispose = [];
44046
+ for (const managedTexture of this.managedTextures) {
44047
+ finishManagedTexture(managedTexture.url, managedTexture.params);
44048
+ }
44049
+ this.managedTextures = [];
44050
+ }
44051
+ removeFromToDispose(disposable) {
44052
+ const index = this.toDispose.indexOf(disposable);
44053
+ if (index > -1) {
44054
+ this.toDispose.splice(index, 1);
44055
+ }
44056
+ }
43904
44057
  }
43905
44058
  class RenderDesc extends DisposableDesc {
43906
44059
  static classTypes = [];
@@ -46158,7 +46311,7 @@ async function promiseForMesh(url, readOnly = false) {
46158
46311
  });
46159
46312
  });
46160
46313
  }
46161
- class MeshDesc {
46314
+ class MeshDesc extends DisposableDesc {
46162
46315
  //size: Vector3 = new Vector3(1,1,1)
46163
46316
  scaleIsRelative = false;
46164
46317
  mesh;
@@ -46186,9 +46339,6 @@ class MeshDesc {
46186
46339
  fileMesh;
46187
46340
  wasAutoSkinned = false;
46188
46341
  wasDeformed = false;
46189
- dispose() {
46190
- this.instance = void 0;
46191
- }
46192
46342
  isSame(other) {
46193
46343
  const singularTrue = (
46194
46344
  //this.size.isSame(other.size) &&
@@ -46535,6 +46685,7 @@ class MeshDesc {
46535
46685
  if (wrapTextureTransferResult instanceof Response) return wrapTextureTransferResult;
46536
46686
  this.fileMesh = mesh;
46537
46687
  const geometry = fileMeshToTHREEGeometry(the_ref_mesh || mesh, this.canHaveSkinning, this.forceVertexColor);
46688
+ this.toDispose.push(geometry);
46538
46689
  let threeMesh = void 0;
46539
46690
  if (geometry.attributes.skinWeight) {
46540
46691
  threeMesh = new SkinnedMesh(geometry);
@@ -46699,6 +46850,11 @@ class MeshDesc {
46699
46850
  this.wrapTextureTargetOrigin = wrapTarget.Prop("CageOrigin").removeNaN();
46700
46851
  }
46701
46852
  }
46853
+ dispose(renderer) {
46854
+ this.instance = void 0;
46855
+ this.clearToDispose();
46856
+ this.disposeRenderLists(renderer);
46857
+ }
46702
46858
  }
46703
46859
  const compositMeshPaths = [
46704
46860
  "rbxasset://avatar/compositing/CompositFullAtlasBaseTexture.mesh",
@@ -47050,67 +47206,6 @@ const Shader_TextureComposer_Gamma = new ShaderMaterial({
47050
47206
  depthWrite: false,
47051
47207
  transparent: true
47052
47208
  });
47053
- const managedTextures = /* @__PURE__ */ new Map();
47054
- async function createTexturePromise(url, params) {
47055
- const image = await API.Generic.LoadImage(url);
47056
- if (!image) return void 0;
47057
- const texture = new Texture(image, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, params?.colorSpace || "srgb");
47058
- texture.needsUpdate = true;
47059
- return texture;
47060
- }
47061
- function createManagedTexture(url, params) {
47062
- const textureInfo = {
47063
- texture: void 0,
47064
- uses: 1
47065
- //used by texture promise (internal), so we dont try to dispose when it doesnt even exist yet
47066
- };
47067
- textureInfo.texture = new Promise((resolve) => {
47068
- createTexturePromise(url, params).then((result) => {
47069
- textureInfo.texture = result;
47070
- finishManagedTexture(url, params);
47071
- resolve(result);
47072
- });
47073
- });
47074
- return textureInfo;
47075
- }
47076
- function getTextureInfoKey(url, params) {
47077
- return url + JSON.stringify(params);
47078
- }
47079
- async function getManagedTexture(url, params) {
47080
- const key = getTextureInfoKey(url, params);
47081
- let managedTextureInfo = managedTextures.get(key);
47082
- if (!managedTextureInfo) {
47083
- managedTextureInfo = createManagedTexture(url, params);
47084
- managedTextures.set(key, managedTextureInfo);
47085
- }
47086
- managedTextureInfo.uses += 1;
47087
- const disposeTimeout = managedTextureInfo.disposeTimeout;
47088
- if (disposeTimeout) {
47089
- clearTimeout(disposeTimeout);
47090
- managedTextureInfo.disposeTimeout = void 0;
47091
- }
47092
- return managedTextureInfo.texture;
47093
- }
47094
- async function finishManagedTexture(url, params) {
47095
- const key = getTextureInfoKey(url, params);
47096
- const managedTextureInfo = managedTextures.get(key);
47097
- if (managedTextureInfo) {
47098
- managedTextureInfo.uses -= 1;
47099
- if (managedTextureInfo.uses <= 0) {
47100
- if (!managedTextureInfo.disposeTimeout) {
47101
- const disposeTimeout = setTimeout(() => {
47102
- if (managedTextureInfo.disposeTimeout !== disposeTimeout || managedTextureInfo.uses > 0) return;
47103
- managedTextures.delete(key);
47104
- const texture = managedTextureInfo.texture;
47105
- if (texture && texture instanceof Texture) {
47106
- texture.dispose();
47107
- }
47108
- }, 5e3);
47109
- managedTextureInfo.disposeTimeout = disposeTimeout;
47110
- }
47111
- }
47112
- }
47113
- }
47114
47209
  async function renderBodyPartClothingR15(limbId, texture) {
47115
47210
  let instruction;
47116
47211
  if (limbId !== BodyPart.Torso) {
@@ -47249,7 +47344,7 @@ class TextureLayer {
47249
47344
  return this.uvType === other.uvType && this.face === other.face && this.color === other.color && this.normal === other.normal && this.roughness === other.roughness && this.metalness === other.metalness && this.emissive === other.emissive;
47250
47345
  }
47251
47346
  }
47252
- class MaterialDesc {
47347
+ class MaterialDesc extends DisposableDesc {
47253
47348
  layers = [];
47254
47349
  isDecal = false;
47255
47350
  canHaveMipmaps = true;
@@ -47268,6 +47363,7 @@ class MaterialDesc {
47268
47363
  createdTextures = [];
47269
47364
  noTextureTransparency = false;
47270
47365
  result;
47366
+ resultRenderTarget;
47271
47367
  isSame(other) {
47272
47368
  if (this.dirty || other.dirty) return false;
47273
47369
  const propertiesSame = this.isDecal === other.isDecal && this.transparent === other.transparent && Math.round(this.transparency * 100) === Math.round(other.transparency * 100) && this.doubleSided === other.doubleSided && this.visible === other.visible && this.canHaveMipmaps === other.canHaveMipmaps && this.resampleMode === other.resampleMode;
@@ -47578,6 +47674,7 @@ class MaterialDesc {
47578
47674
  }
47579
47675
  }
47580
47676
  if (composeInsts.length === 0) {
47677
+ this.finishManagedTextures(textureType);
47581
47678
  return void 0;
47582
47679
  }
47583
47680
  TextureComposer.new(width, height, textureType === "color" ? LinearSRGBColorSpace : NoColorSpace, RepeatWrapping, noMipmaps);
@@ -47586,12 +47683,15 @@ class MaterialDesc {
47586
47683
  TextureComposer.add(inst);
47587
47684
  }
47588
47685
  const renderTarget = TextureComposer.render();
47686
+ this.toDispose.push(renderTarget);
47589
47687
  this.finishManagedTextures(textureType);
47688
+ const linearRenderTarget = renderTarget;
47590
47689
  const lineartexture = renderTarget.texture;
47591
47690
  lineartexture.wrapS = RepeatWrapping;
47592
47691
  lineartexture.wrapT = RepeatWrapping;
47593
47692
  lineartexture.needsUpdate = true;
47594
47693
  let texture = lineartexture;
47694
+ let renderTargetFinal = linearRenderTarget;
47595
47695
  if (textureType === "color") {
47596
47696
  const gammaInst = await TextureComposer.simpleMesh(
47597
47697
  "CompositQuad",
@@ -47605,11 +47705,15 @@ class MaterialDesc {
47605
47705
  TextureComposer.new(width, height, SRGBColorSpace, RepeatWrapping, noMipmaps);
47606
47706
  TextureComposer.cameraSize(camWidth, camHeight);
47607
47707
  TextureComposer.add(gammaInst);
47608
- texture = TextureComposer.render().texture;
47708
+ renderTargetFinal = TextureComposer.render();
47709
+ this.toDispose.push(renderTargetFinal);
47710
+ texture = renderTargetFinal.texture;
47609
47711
  }
47610
- if (texture !== lineartexture) {
47611
- lineartexture.dispose();
47712
+ if (linearRenderTarget !== renderTargetFinal) {
47713
+ linearRenderTarget.dispose();
47714
+ this.removeFromToDispose(linearRenderTarget);
47612
47715
  }
47716
+ this.resultRenderTarget = renderTargetFinal;
47613
47717
  texture.magFilter = this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter;
47614
47718
  let hasTransparency = false;
47615
47719
  const rbxRenderer = RBXRenderer.getRenderer();
@@ -47625,6 +47729,7 @@ class MaterialDesc {
47625
47729
  if (FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
47626
47730
  const ogTexture = texture;
47627
47731
  texture = imageDataToCanvasTexture(data, width, height);
47732
+ this.toDispose.push(texture);
47628
47733
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47629
47734
  texture.wrapS = ogTexture.wrapS;
47630
47735
  texture.wrapT = ogTexture.wrapT;
@@ -47632,6 +47737,7 @@ class MaterialDesc {
47632
47737
  texture.magFilter = ogTexture.magFilter;
47633
47738
  texture.generateMipmaps = ogTexture.generateMipmaps;
47634
47739
  ogTexture.dispose();
47740
+ this.removeFromToDispose(ogTexture);
47635
47741
  }
47636
47742
  }
47637
47743
  if (!this.transparent) {
@@ -47660,6 +47766,7 @@ class MaterialDesc {
47660
47766
  throw new Error("Failed to get CanvasContext");
47661
47767
  }
47662
47768
  const texture = new CanvasTexture(canvas);
47769
+ this.toDispose.push(texture);
47663
47770
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47664
47771
  texture.wrapS = RepeatWrapping;
47665
47772
  texture.wrapT = RepeatWrapping;
@@ -47711,21 +47818,21 @@ class MaterialDesc {
47711
47818
  }
47712
47819
  }
47713
47820
  if (textureUrl) {
47714
- const image = await API.Generic.LoadImage(textureUrl);
47715
- if (image) {
47716
- let hasTransparency = true;
47717
- if (!this.transparent) {
47718
- hasTransparency = false;
47719
- }
47720
- const texture = new Texture(image);
47721
- texture.wrapS = RepeatWrapping;
47722
- texture.wrapT = RepeatWrapping;
47723
- texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47724
- texture.generateMipmaps = this.canHaveMipmaps;
47725
- texture.magFilter = this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter;
47726
- texture.needsUpdate = true;
47727
- return [texture, hasTransparency];
47728
- }
47821
+ let hasTransparency = true;
47822
+ if (!this.transparent) {
47823
+ hasTransparency = false;
47824
+ }
47825
+ const textureParams = {
47826
+ colorSpace: textureType === "color" ? SRGBColorSpace : NoColorSpace,
47827
+ wrapS: RepeatWrapping,
47828
+ wrapT: RepeatWrapping,
47829
+ generateMipmaps: this.canHaveMipmaps,
47830
+ //resampling mode
47831
+ magFilter: this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter
47832
+ };
47833
+ const texture = await getManagedTexture(textureUrl, textureParams);
47834
+ this.managedTextures.push({ url: textureUrl, params: textureParams });
47835
+ return texture ? [texture, hasTransparency] : void 0;
47729
47836
  }
47730
47837
  }
47731
47838
  getComposeType(textureType) {
@@ -47742,8 +47849,8 @@ class MaterialDesc {
47742
47849
  }
47743
47850
  }
47744
47851
  if (layer instanceof ColorLayer) {
47745
- hasColorLayer = true;
47746
47852
  if (layer.textureType === textureType) {
47853
+ hasColorLayer = true;
47747
47854
  hasLayerOfType = true;
47748
47855
  }
47749
47856
  }
@@ -48178,6 +48285,10 @@ class MaterialDesc {
48178
48285
  this.addDecals(child.parent, "Normal", true);
48179
48286
  }
48180
48287
  }
48288
+ dispose() {
48289
+ this.resultRenderTarget = void 0;
48290
+ this.clearToDispose();
48291
+ }
48181
48292
  }
48182
48293
  class BasePartWrapperData {
48183
48294
  assemblyNode;
@@ -48289,7 +48400,7 @@ function boneIsChildOf(bone, parentName) {
48289
48400
  }
48290
48401
  return false;
48291
48402
  }
48292
- class SkeletonDesc {
48403
+ class SkeletonDesc extends DisposableDesc {
48293
48404
  renderableDesc;
48294
48405
  meshDesc;
48295
48406
  skeleton;
@@ -48300,6 +48411,7 @@ class SkeletonDesc {
48300
48411
  skeletonHelper;
48301
48412
  frameCount = 0;
48302
48413
  constructor(renderableDesc, meshDesc, scene) {
48414
+ super();
48303
48415
  this.renderableDesc = renderableDesc;
48304
48416
  this.meshDesc = meshDesc;
48305
48417
  const mesh = this.meshDesc.fileMesh;
@@ -48576,14 +48688,14 @@ class SkeletonDesc {
48576
48688
  this.updateMatrixWorld();
48577
48689
  this.frameCount += 1;
48578
48690
  }
48579
- dispose(scene) {
48691
+ dispose() {
48580
48692
  if (this.skeletonHelper) {
48581
- scene.remove(this.skeletonHelper);
48693
+ this.skeletonHelper.removeFromParent();
48582
48694
  this.skeletonHelper.dispose();
48583
48695
  this.skeletonHelper = void 0;
48584
48696
  }
48585
48697
  if (this.rootBone.parent) {
48586
- this.rootBone.parent.remove(this.rootBone);
48698
+ this.rootBone.removeFromParent();
48587
48699
  }
48588
48700
  for (let i = 0; i < this.skeleton.bones.length; i++) {
48589
48701
  const bone = this.skeleton.bones[i];
@@ -48591,6 +48703,7 @@ class SkeletonDesc {
48591
48703
  bone.removeFromParent();
48592
48704
  }
48593
48705
  }
48706
+ this.skeleton.dispose();
48594
48707
  }
48595
48708
  static descNeedsSkeleton(meshDesc) {
48596
48709
  return meshDesc.canHaveSkinning && meshDesc.fileMesh && meshDesc.fileMesh.skinning && meshDesc.fileMesh.skinning.numskinnings > 0;
@@ -48694,32 +48807,10 @@ class ObjectDesc extends RenderDesc {
48694
48807
  this.meshDesc.fromInstance(child);
48695
48808
  this.materialDesc.fromInstance(child);
48696
48809
  }
48697
- disposeSkeleton(scene, skeletonDesc) {
48698
- skeletonDesc.dispose(scene);
48699
- }
48700
- //Used to dispose OLD stuff
48701
- dispose(renderer, scene) {
48702
- if (this.meshDesc) {
48703
- this.meshDesc.dispose();
48704
- }
48705
- if (this.results) {
48706
- for (const mesh of this.results) {
48707
- this.disposeMesh(scene, mesh);
48708
- }
48709
- }
48710
- if (this.skeletonDesc) {
48711
- this.disposeSkeleton(scene, this.skeletonDesc);
48712
- }
48713
- if (this.results) {
48714
- this.disposeRenderLists(renderer);
48715
- }
48716
- }
48717
- async compileResults(renderer, scene) {
48810
+ async compileResults(_renderer, scene) {
48718
48811
  const loadingLabel = this.instance ? this.instance.GetFullName() : "unknown";
48719
48812
  API.Misc.startCurrentlyLoadingAssets(loadingLabel);
48720
48813
  try {
48721
- const originalResult = this.results;
48722
- const originalSkeletonDesc = this.skeletonDesc;
48723
48814
  this.results = void 0;
48724
48815
  this.skeletonDesc = void 0;
48725
48816
  const promises = [
@@ -48756,15 +48847,6 @@ class ObjectDesc extends RenderDesc {
48756
48847
  } else {
48757
48848
  this.meshDesc.fileMesh = void 0;
48758
48849
  }
48759
- if (originalResult) {
48760
- this.disposeMeshes(scene, originalResult);
48761
- }
48762
- if (originalSkeletonDesc) {
48763
- this.disposeSkeleton(scene, originalSkeletonDesc);
48764
- }
48765
- if (originalResult) {
48766
- this.disposeRenderLists(renderer);
48767
- }
48768
48850
  } finally {
48769
48851
  API.Misc.stopCurrentlyLoadingAssets(loadingLabel);
48770
48852
  }
@@ -48840,6 +48922,17 @@ class ObjectDesc extends RenderDesc {
48840
48922
  }
48841
48923
  return !isBakedDecal && (!isDecal || isFirstDecal);
48842
48924
  }
48925
+ //Used to dispose OLD stuff
48926
+ dispose(renderer) {
48927
+ if (this.results) {
48928
+ for (const result of this.results) {
48929
+ result.removeFromParent();
48930
+ }
48931
+ }
48932
+ if (this.meshDesc) this.meshDesc.dispose(renderer);
48933
+ if (this.materialDesc) this.materialDesc.dispose();
48934
+ if (this.skeletonDesc) this.skeletonDesc.dispose();
48935
+ }
48843
48936
  }
48844
48937
  const __vite_glob_0_4$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
48845
48938
  __proto__: null,
@@ -59819,7 +59912,7 @@ const $05f6997e4b65da14$export$ed4ee5d1e55474a5 = {
59819
59912
  class RBXRendererScene {
59820
59913
  //important scene components
59821
59914
  scene = new Scene();
59822
- camera = new PerspectiveCamera(70, 1 / 1, 0.1, 100);
59915
+ camera = new PerspectiveCamera(70, 1 / 1, 0.1, 1e3);
59823
59916
  controls;
59824
59917
  shouldAnimate = true;
59825
59918
  destroyed = false;
@@ -59967,6 +60060,41 @@ class RBXRendererScene {
59967
60060
  isFullyCompiled() {
59968
60061
  return this.areInstancesCompiled(this.addedInstances);
59969
60062
  }
60063
+ /**
60064
+ * @param instances Array of instances you want to wait to be finished compiling
60065
+ * @param timeoutSeconds Default is 30 seconds
60066
+ * @returns true if successful, false if a RenderDesc failed to compile or timed out
60067
+ */
60068
+ async waitUntilFullyCompiled(instances, timeoutSeconds = 30) {
60069
+ if (this.areInstancesCompiled(instances)) return true;
60070
+ const connections = [];
60071
+ const compiledSuccessfully = await Promise.race([
60072
+ //on fail compilation
60073
+ new Promise((resolve) => {
60074
+ connections.push(this.failedRenderDesc.Connect(() => {
60075
+ resolve(false);
60076
+ }));
60077
+ }),
60078
+ //on success compilation, check if everything is successfull
60079
+ new Promise((resolve) => {
60080
+ connections.push(this.compiledRenderDesc.Connect(() => {
60081
+ if (this.areInstancesCompiled(instances)) {
60082
+ resolve(true);
60083
+ }
60084
+ }));
60085
+ }),
60086
+ //on fail due to timeout
60087
+ new Promise((resolve) => {
60088
+ setTimeout(() => {
60089
+ resolve(false);
60090
+ }, timeoutSeconds * 1e3);
60091
+ })
60092
+ ]);
60093
+ for (const connection of connections) {
60094
+ connection.Disconnect();
60095
+ }
60096
+ return compiledSuccessfully;
60097
+ }
59970
60098
  /**
59971
60099
  * Exports scene as a GLTF or GLB
59972
60100
  * @param name Name of the resulting file if autoDownload is true
@@ -60741,7 +60869,8 @@ const EmitterShaderType = {
60741
60869
  const EmitterBlendType = {
60742
60870
  "PremultipliedAdditive": 0,
60743
60871
  "Additive": 1,
60744
- "Normal": 2
60872
+ "Normal": 2,
60873
+ "Add": 3
60745
60874
  };
60746
60875
  class EmitterDesc extends DisposableDesc {
60747
60876
  renderScene;
@@ -60841,13 +60970,6 @@ class EmitterDesc extends DisposableDesc {
60841
60970
  this.flipbookSizeY = other.flipbookSizeY;
60842
60971
  this.flipbookStartRandom = other.flipbookStartRandom;
60843
60972
  }
60844
- dispose(renderer, scene) {
60845
- const mesh = this.result;
60846
- if (mesh) {
60847
- this.disposeMesh(scene, mesh);
60848
- this.disposeRenderLists(renderer);
60849
- }
60850
- }
60851
60973
  getFlipbookSize() {
60852
60974
  let flipbookSizeX = this.flipbookSizeX;
60853
60975
  let flipbookSizeY = this.flipbookSizeY;
@@ -60873,27 +60995,33 @@ class EmitterDesc extends DisposableDesc {
60873
60995
  }
60874
60996
  return [flipbookSizeX, flipbookSizeY];
60875
60997
  }
60876
- async compileResult(renderer, scene) {
60877
- const originalResult = this.result;
60998
+ async compileResult() {
60878
60999
  const texturePromises = [
60879
- getTexture(this.texture),
60880
- getTexture(this.alphaTexture, NoColorSpace),
60881
- getTexture(this.colorTexture)
61000
+ this.texture ? getManagedTexture(this.texture, { colorSpace: SRGBColorSpace }) : void 0,
61001
+ this.alphaTexture ? getManagedTexture(this.alphaTexture, { colorSpace: NoColorSpace }) : void 0,
61002
+ this.colorTexture ? getManagedTexture(this.colorTexture, { colorSpace: SRGBColorSpace }) : void 0
60882
61003
  ];
61004
+ if (this.texture) this.managedTextures.push({ url: this.texture, params: { colorSpace: SRGBColorSpace } });
61005
+ if (this.alphaTexture) this.managedTextures.push({ url: this.alphaTexture, params: { colorSpace: NoColorSpace } });
61006
+ if (this.colorTexture) this.managedTextures.push({ url: this.colorTexture, params: { colorSpace: SRGBColorSpace } });
60883
61007
  let [mapToUse, alphaMapToUse, colorMapToUse] = await Promise.all(texturePromises);
60884
61008
  if (!mapToUse) {
60885
61009
  mapToUse = new DataTexture(new Uint8Array([0, 0, 0, 0]), 1, 1, RGBAFormat);
60886
61010
  mapToUse.needsUpdate = true;
61011
+ this.toDispose.push(mapToUse);
60887
61012
  }
60888
61013
  if (!alphaMapToUse) {
60889
61014
  alphaMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60890
61015
  alphaMapToUse.needsUpdate = true;
61016
+ this.toDispose.push(alphaMapToUse);
60891
61017
  }
60892
61018
  if (!colorMapToUse) {
60893
61019
  colorMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60894
61020
  colorMapToUse.needsUpdate = true;
61021
+ this.toDispose.push(colorMapToUse);
60895
61022
  }
60896
61023
  const geometry = new PlaneGeometry(2, 2);
61024
+ this.toDispose.push(geometry);
60897
61025
  this.instanceColorBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount * 3), 3);
60898
61026
  geometry.setAttribute("instanceColor", this.instanceColorBuffer);
60899
61027
  this.instanceOpacityBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount), 1);
@@ -60935,9 +61063,9 @@ class EmitterDesc extends DisposableDesc {
60935
61063
  lights: true,
60936
61064
  premultipliedAlpha: true,
60937
61065
  toneMapped: true,
60938
- blending: this.blending === EmitterBlendType.PremultipliedAdditive ? CustomBlending : this.blending === EmitterBlendType.Additive ? AdditiveBlending : NormalBlending,
61066
+ blending: this.blending === EmitterBlendType.PremultipliedAdditive || this.blending === EmitterBlendType.Add ? CustomBlending : this.blending === EmitterBlendType.Additive ? AdditiveBlending : NormalBlending,
60939
61067
  blendSrc: OneFactor,
60940
- blendDst: OneMinusSrcAlphaFactor,
61068
+ blendDst: this.blending === EmitterBlendType.Add ? OneFactor : OneMinusSrcAlphaFactor,
60941
61069
  blendEquation: AddEquation,
60942
61070
  blendSrcAlpha: OneMinusDstAlphaFactor,
60943
61071
  blendDstAlpha: OneFactor,
@@ -60959,14 +61087,12 @@ class EmitterDesc extends DisposableDesc {
60959
61087
  }
60960
61088
  ])
60961
61089
  });
61090
+ this.toDispose.push(material);
60962
61091
  this.resultMaterial = material;
60963
61092
  this.result = new InstancedMesh(geometry, material, this.maxCount);
61093
+ this.toDispose.push(this.result);
60964
61094
  this.result.name = "Particles";
60965
61095
  this.result.frustumCulled = false;
60966
- if (originalResult) {
60967
- this.disposeMesh(scene, originalResult);
60968
- this.disposeRenderLists(renderer);
60969
- }
60970
61096
  return this.result;
60971
61097
  }
60972
61098
  emit(groupDesc, force = false) {
@@ -61088,6 +61214,14 @@ class EmitterDesc extends DisposableDesc {
61088
61214
  this.instanceSeedTimeBuffer.needsUpdate = true;
61089
61215
  this.instanceFlipbookBuffer.needsUpdate = true;
61090
61216
  }
61217
+ dispose(renderer) {
61218
+ const mesh = this.result;
61219
+ if (mesh) {
61220
+ mesh.removeFromParent();
61221
+ }
61222
+ this.clearToDispose();
61223
+ this.disposeRenderLists(renderer);
61224
+ }
61091
61225
  }
61092
61226
  class EmitterGroupDesc extends RenderDesc {
61093
61227
  static classTypes = ["ParticleEmitter", "Sparkles", "Fire", "Smoke"];
@@ -61227,7 +61361,7 @@ class EmitterGroupDesc extends RenderDesc {
61227
61361
  }
61228
61362
  }
61229
61363
  fromParticleEmitter(child) {
61230
- this.emitterDir = child.Prop("EmissionDirection");
61364
+ this.emitterDir = child.PropOrDefault("EmissionDirection", this.emitterDir);
61231
61365
  const emitterDesc = new EmitterDesc(this.renderScene);
61232
61366
  if (child.HasProperty("Lifetime")) emitterDesc.lifetime = child.Prop("Lifetime");
61233
61367
  if (child.HasProperty("Rate")) emitterDesc.rate = child.Prop("Rate");
@@ -61244,7 +61378,7 @@ class EmitterGroupDesc extends RenderDesc {
61244
61378
  if (child.HasProperty("Color")) emitterDesc.color = child.Prop("Color");
61245
61379
  if (child.HasProperty("Texture")) emitterDesc.texture = child.Prop("Texture");
61246
61380
  if (child.HasProperty("Transparency")) emitterDesc.transparency = child.Prop("Transparency");
61247
- if (child.HasProperty("LightEmission")) emitterDesc.lightEmission = child.Prop("LightEmission");
61381
+ emitterDesc.lightEmission = specialClamp(child.PropOrDefault("LightEmission", emitterDesc.lightEmission), 0, 1);
61248
61382
  emitterDesc.blending = emitterDesc.lightEmission === 0 ? EmitterBlendType.Normal : EmitterBlendType.PremultipliedAdditive;
61249
61383
  if (child.HasProperty("LightInfluence")) emitterDesc.lightInfluence = child.Prop("LightInfluence");
61250
61384
  if (child.HasProperty("ZOffset")) emitterDesc.zOffset = child.Prop("ZOffset");
@@ -61340,7 +61474,7 @@ class EmitterGroupDesc extends RenderDesc {
61340
61474
  localAcceleration: new Vector3(0, 0.5 * (1 * size * size / 4 + 0.7 * heat), 0),
61341
61475
  rotation: new NumberRange(-90, 90),
61342
61476
  size: new NumberSequence([new NumberSequenceKeypoint(0, sparkSize, 0), new NumberSequenceKeypoint(2, sparkSize - sparkSize / 2 * 2, 0)]),
61343
- speed: new NumberRange(0.4 * (0.1 * size * size + 0.2 * heat), 0.4 * (0.2 * size * size + 0.2 * heat)),
61477
+ speed: new NumberRange(0.4 * (0.1 * size * size + 0.2 * heat), 0.4 * (0.1 * size * size + 0.2 * heat)),
61344
61478
  rotationSpeed: new NumberRange(100, 100),
61345
61479
  spreadAngle: new Vector2(10, 10),
61346
61480
  rate: 65,
@@ -61349,7 +61483,7 @@ class EmitterGroupDesc extends RenderDesc {
61349
61483
  timeScale,
61350
61484
  color: ColorSequence.fromColor(secondaryColor),
61351
61485
  shader: EmitterShaderType.BasicParticle,
61352
- blending: EmitterBlendType.Additive
61486
+ blending: EmitterBlendType.Add
61353
61487
  }));
61354
61488
  }
61355
61489
  fromSmoke(child) {
@@ -61380,18 +61514,10 @@ class EmitterGroupDesc extends RenderDesc {
61380
61514
  shader: EmitterShaderType.Smoke
61381
61515
  }));
61382
61516
  }
61383
- dispose(renderer, scene) {
61384
- const meshes = this.results;
61385
- if (meshes) {
61386
- this.disposeMeshes(scene, meshes);
61387
- this.disposeRenderLists(renderer);
61388
- }
61389
- }
61390
61517
  async compileResults(renderer, scene) {
61391
- const originalResults = this.results;
61392
61518
  const resultPromises = [];
61393
61519
  for (const emitterDesc of this.emitterDescs) {
61394
- resultPromises.push(emitterDesc.compileResult(renderer, scene));
61520
+ resultPromises.push(emitterDesc.compileResult());
61395
61521
  }
61396
61522
  this.results = [];
61397
61523
  const compiledResults = await Promise.all(resultPromises);
@@ -61404,10 +61530,6 @@ class EmitterGroupDesc extends RenderDesc {
61404
61530
  return compiledResult;
61405
61531
  }
61406
61532
  }
61407
- if (originalResults) {
61408
- this.disposeMeshes(scene, originalResults);
61409
- this.disposeRenderLists(renderer);
61410
- }
61411
61533
  const startFull = this.renderScene.particlesStartFull || FLAGS.PARTICLES_START_FULL;
61412
61534
  const startFullFramerate = this.renderScene.particlesStartFullFramerate;
61413
61535
  if (startFull) {
@@ -61437,6 +61559,11 @@ class EmitterGroupDesc extends RenderDesc {
61437
61559
  }
61438
61560
  }
61439
61561
  }
61562
+ dispose(renderer) {
61563
+ for (const emitterDesc of this.emitterDescs) {
61564
+ emitterDesc.dispose(renderer);
61565
+ }
61566
+ }
61440
61567
  }
61441
61568
  const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
61442
61569
  __proto__: null,
@@ -62171,21 +62298,20 @@ class BeamDesc extends RenderDesc {
62171
62298
  this.segments = child.PropOrDefault("Segments", this.segments);
62172
62299
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62173
62300
  }
62174
- async compileResults(renderer, scene) {
62175
- const originalResults = this.results;
62301
+ async compileResults() {
62176
62302
  this.results = [];
62177
62303
  if (this.enabled) {
62178
62304
  let textureResult = void 0;
62179
62305
  if (this.texture) {
62180
- textureResult = await getTexture(this.texture);
62181
- if (textureResult) {
62182
- textureResult.wrapT = RepeatWrapping;
62183
- }
62306
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62307
+ textureResult = await getManagedTexture(this.texture, params);
62308
+ this.managedTextures.push({ url: this.texture, params });
62184
62309
  }
62185
62310
  if (!textureResult) {
62186
62311
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62187
62312
  textureResult.colorSpace = SRGBColorSpace;
62188
62313
  textureResult.needsUpdate = true;
62314
+ this.toDispose.push(textureResult);
62189
62315
  }
62190
62316
  const material = new ShaderMaterial({
62191
62317
  side: DoubleSide,
@@ -62214,17 +62340,15 @@ class BeamDesc extends RenderDesc {
62214
62340
  }
62215
62341
  ])
62216
62342
  });
62343
+ this.toDispose.push(material);
62217
62344
  const geometry = new PlaneGeometry(1, 1, this.segments, 1);
62345
+ this.toDispose.push(geometry);
62218
62346
  const colorValues = new Float32Array((this.segments + 1) * 2 * 4).fill(0);
62219
62347
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62220
62348
  const mesh = new Mesh(geometry, material);
62221
62349
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Beam" : "Unknown_Beam";
62222
62350
  this.results.push(mesh);
62223
62351
  }
62224
- if (originalResults) {
62225
- this.disposeMeshes(scene, originalResults);
62226
- this.disposeRenderLists(renderer);
62227
- }
62228
62352
  this.updateResults();
62229
62353
  return this.results;
62230
62354
  }
@@ -62348,11 +62472,13 @@ class BeamDesc extends RenderDesc {
62348
62472
  }
62349
62473
  this.lastTime = this.time;
62350
62474
  }
62351
- dispose(_renderer, scene) {
62475
+ dispose(renderer) {
62352
62476
  if (!this.results) return;
62353
62477
  for (const result of this.results) {
62354
- scene.remove(result);
62478
+ result.removeFromParent();
62355
62479
  }
62480
+ this.clearToDispose();
62481
+ this.disposeRenderLists(renderer);
62356
62482
  }
62357
62483
  }
62358
62484
  const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -62600,21 +62726,20 @@ class TrailDesc extends RenderDesc {
62600
62726
  this.faceCamera = child.PropOrDefault("FaceCamera", this.faceCamera);
62601
62727
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62602
62728
  }
62603
- async compileResults(renderer, scene) {
62604
- const originalResults = this.results;
62729
+ async compileResults() {
62605
62730
  this.results = [];
62606
62731
  if (this.enabled) {
62607
62732
  let textureResult = void 0;
62608
62733
  if (this.texture) {
62609
- textureResult = await getTexture(this.texture);
62610
- if (textureResult) {
62611
- textureResult.wrapT = RepeatWrapping;
62612
- }
62734
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62735
+ textureResult = await getManagedTexture(this.texture, params);
62736
+ this.managedTextures.push({ url: this.texture, params });
62613
62737
  }
62614
62738
  if (!textureResult) {
62615
62739
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62616
62740
  textureResult.colorSpace = SRGBColorSpace;
62617
62741
  textureResult.needsUpdate = true;
62742
+ this.toDispose.push(textureResult);
62618
62743
  }
62619
62744
  const material = new ShaderMaterial({
62620
62745
  side: DoubleSide,
@@ -62643,7 +62768,9 @@ class TrailDesc extends RenderDesc {
62643
62768
  }
62644
62769
  ])
62645
62770
  });
62771
+ this.toDispose.push(material);
62646
62772
  const geometry = new PlaneGeometry(1, 1, this.maxSegments, 1);
62773
+ this.toDispose.push(geometry);
62647
62774
  const colorValues = new Float32Array((this.maxSegments + 1) * 2 * 4).fill(1);
62648
62775
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62649
62776
  const mesh = new Mesh(geometry, material);
@@ -62651,10 +62778,6 @@ class TrailDesc extends RenderDesc {
62651
62778
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Trail" : "Unknown_Trail";
62652
62779
  this.results.push(mesh);
62653
62780
  }
62654
- if (originalResults) {
62655
- this.disposeMeshes(scene, originalResults);
62656
- this.disposeRenderLists(renderer);
62657
- }
62658
62781
  this.updateResults();
62659
62782
  return this.results;
62660
62783
  }
@@ -62791,11 +62914,13 @@ class TrailDesc extends RenderDesc {
62791
62914
  segment.cframe.Position = add(segment.cframe.Position, vec);
62792
62915
  }
62793
62916
  }
62794
- dispose(_renderer, scene) {
62917
+ dispose(renderer, scene) {
62795
62918
  if (!this.results) return;
62796
62919
  for (const result of this.results) {
62797
62920
  scene.remove(result);
62798
62921
  }
62922
+ this.clearToDispose();
62923
+ this.disposeRenderLists(renderer);
62799
62924
  }
62800
62925
  }
62801
62926
  const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -63417,31 +63542,35 @@ class RBXRenderer {
63417
63542
  renderScene.scene.add(result);
63418
63543
  }
63419
63544
  }
63545
+ static _updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance) {
63546
+ if (!oldDesc.compiled && !oldDesc.failed) {
63547
+ oldDesc.compiled = true;
63548
+ renderScene.compiledRenderDesc.Fire(instance);
63549
+ }
63550
+ if (!oldDesc.isSame(newDesc)) {
63551
+ oldDesc.fromRenderDesc(newDesc);
63552
+ oldDesc.updateResults();
63553
+ }
63554
+ }
63420
63555
  static _addRenderDesc(instance, auth, DescClass, renderScene) {
63421
63556
  if (!RBXRenderer.renderer) return;
63422
63557
  const oldDesc = renderScene.renderDescs.get(instance);
63423
63558
  const newDesc = new DescClass(renderScene);
63424
63559
  newDesc.fromInstance(instance);
63425
63560
  if (oldDesc && !oldDesc.needsRegeneration(newDesc) && !renderScene.isRenderingMesh.get(instance)) {
63426
- if (!oldDesc.compiled && !oldDesc.failed) {
63427
- oldDesc.compiled = true;
63428
- renderScene.compiledRenderDesc.Fire(instance);
63429
- }
63430
- if (!oldDesc.isSame(newDesc)) {
63431
- oldDesc.fromRenderDesc(newDesc);
63432
- oldDesc.updateResults();
63433
- }
63561
+ RBXRenderer._updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance);
63434
63562
  } else {
63435
63563
  if (!renderScene.isRenderingMesh.get(instance)) {
63436
- if (oldDesc) newDesc.transferFrom(oldDesc);
63437
- newDesc.results = oldDesc?.results;
63564
+ if (oldDesc && Object.getPrototypeOf(oldDesc).constructor === Object.getPrototypeOf(newDesc).constructor) {
63565
+ newDesc.transferFrom(oldDesc);
63566
+ }
63438
63567
  renderScene.renderDescs.set(instance, newDesc);
63439
63568
  renderScene.isRenderingMesh.set(instance, true);
63440
63569
  newDesc.compileResults(RBXRenderer.renderer, renderScene.scene).then((results) => {
63570
+ if (RBXRenderer.renderer) oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63441
63571
  if (results && !(results instanceof Response)) {
63442
63572
  newDesc.updateResults();
63443
- if (renderScene.renderDescs.get(instance) && RBXRenderer.renderer) {
63444
- oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63573
+ if (renderScene.renderDescs.get(instance) === newDesc && RBXRenderer.renderer) {
63445
63574
  for (const result of results) {
63446
63575
  RBXRenderer._addSkeletonToResult(result, newDesc, renderScene);
63447
63576
  }
@@ -63451,9 +63580,12 @@ class RBXRenderer {
63451
63580
  newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63452
63581
  }
63453
63582
  } else {
63583
+ if (RBXRenderer.renderer) newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63454
63584
  newDesc.failed = true;
63455
- renderScene.isRenderingMesh.set(instance, false);
63456
- renderScene.failedRenderDesc.Fire(instance);
63585
+ if (renderScene.renderDescs.get(instance) === newDesc) {
63586
+ renderScene.isRenderingMesh.set(instance, false);
63587
+ renderScene.failedRenderDesc.Fire(instance);
63588
+ }
63457
63589
  warn(false, "Failed to compile mesh", this, results);
63458
63590
  }
63459
63591
  });
@@ -63468,16 +63600,26 @@ class RBXRenderer {
63468
63600
  }));
63469
63601
  }
63470
63602
  }
63471
- /**Adds an instance to the renderer or updates it */
63472
- static addInstance(instance, auth, renderScene = RBXRenderer.firstScene) {
63603
+ /** */
63604
+ /**
63605
+ * Adds an instance to the renderer or updates it, add it again to update it after changes have been made
63606
+ * @param instance The instance that will be updated (the descendants will also update)
63607
+ * @param auth This is here just in case something requires it in the future
63608
+ * @param renderScene The scene the instances will be rendered in. Default RBXRenderer.firstScene
63609
+ * @param includeDescendants If descendants should also have addInstance called on them. Default true
63610
+ * @returns
63611
+ */
63612
+ static addInstance(instance, auth, renderScene = RBXRenderer.firstScene, includeDescendants = true) {
63473
63613
  if (renderScene.destroyed) return;
63474
63614
  const RenderDescType = getRenderDescForInstance(instance);
63475
63615
  if (RenderDescType) {
63476
63616
  if (renderScene.addedInstances.indexOf(instance) < 0) renderScene.addedInstances.push(instance);
63477
63617
  RBXRenderer._addRenderDesc(instance, auth, RenderDescType, renderScene);
63478
63618
  }
63479
- for (const child of instance.GetChildren()) {
63480
- RBXRenderer.addInstance(child, auth, renderScene);
63619
+ if (includeDescendants) {
63620
+ for (const child of instance.GetDescendants()) {
63621
+ RBXRenderer.addInstance(child, auth, renderScene, false);
63622
+ }
63481
63623
  }
63482
63624
  }
63483
63625
  static setRendererSize(width, height) {
@@ -64187,8 +64329,8 @@ function getExtentsForParts(parts, includeTransform) {
64187
64329
  }
64188
64330
  function getExtents(cframe, parts) {
64189
64331
  const inverseCF = cframe.inverse();
64190
- let lowerExtents = new Vector3(0, 0, 0);
64191
- let higherExtents = new Vector3(0, 0, 0);
64332
+ let lowerExtents = new Vector3(1e6, 1e6, 1e6);
64333
+ let higherExtents = new Vector3(-1e6, -1e6, -1e5);
64192
64334
  for (const child of parts) {
64193
64335
  if (child.createWrapper()?.IsA("BasePart")) {
64194
64336
  const partCF = child.Prop("CFrame");
@@ -65069,10 +65211,11 @@ async function renderTargetToCanvas$1(renderTarget) {
65069
65211
  }
65070
65212
  async function imageThumbnailClick(renderScene, width, height, format, options) {
65071
65213
  const resultOptions = {
65072
- quality: 1
65214
+ quality: 1,
65215
+ size: [width, height]
65073
65216
  };
65074
65217
  if (options) Object.assign(resultOptions, options);
65075
- const renderTarget = renderToRenderTarget$1(width, height, renderScene);
65218
+ const renderTarget = renderToRenderTarget$1(resultOptions.size[0], resultOptions.size[1], renderScene);
65076
65219
  const canvas = await renderTargetToCanvas$1(renderTarget);
65077
65220
  renderTarget.dispose();
65078
65221
  if (canvas) {
@@ -65092,8 +65235,24 @@ async function modelThumbnailClick(renderScene, format, options) {
65092
65235
  });
65093
65236
  }
65094
65237
  function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65095
- const thumbnailCamera = model.FindFirstChildOfClass("Camera");
65096
- if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65238
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65239
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65240
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65241
+ if (thumbnailConfiguration) {
65242
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65243
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65244
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65245
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65246
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65247
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65248
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65249
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65250
+ const resultCF = targetCF.multiply(cf);
65251
+ return resultCF;
65252
+ }
65253
+ }
65254
+ }
65255
+ }
65097
65256
  let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65098
65257
  if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65099
65258
  if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
@@ -65125,6 +65284,56 @@ function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65125
65284
  zoomExtents(cameraCF, rootPartCF, extentsSize, fov2, 1);
65126
65285
  return cameraCF;
65127
65286
  }
65287
+ function getThumbnailCamera(model) {
65288
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65289
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera;
65290
+ const camera = new Instance("Camera");
65291
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65292
+ if (thumbnailConfiguration) {
65293
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65294
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65295
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65296
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65297
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65298
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65299
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65300
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65301
+ const resultCF = targetCF.multiply(cf);
65302
+ camera.setProperty("FieldOfView", 70);
65303
+ camera.setProperty("CFrame", resultCF);
65304
+ return camera;
65305
+ }
65306
+ }
65307
+ }
65308
+ }
65309
+ let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65310
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65311
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
65312
+ if (!rootPart) return camera;
65313
+ const rootPartCF = rootPart.PropOrDefault("CFrame", new CFrame()).clone();
65314
+ const worldExtents = getExtentsWorld(model);
65315
+ if (!worldExtents) return camera;
65316
+ const extentsSize = worldExtents[1].minus(worldExtents[0]);
65317
+ rootPartCF.Position = getExtentsCenter(worldExtents).toVec3();
65318
+ let lookVector = rootPartCF.lookVector();
65319
+ if (Math.abs(lookVector[1]) > 0.95) {
65320
+ lookVector = [0, 0, -1];
65321
+ } else {
65322
+ lookVector[1] = 0;
65323
+ lookVector = normalize(lookVector);
65324
+ }
65325
+ let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
65326
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, rad(45)));
65327
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(35), 0, 0));
65328
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, 0));
65329
+ lookVector = lookCF.lookVector();
65330
+ lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
65331
+ lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
65332
+ const cameraCF = lookCF.clone();
65333
+ zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
65334
+ camera.setProperty("CFrame", cameraCF);
65335
+ return camera;
65336
+ }
65128
65337
  function setupThumbnailScene(renderScene) {
65129
65338
  renderScene.particlesStartFull = 4;
65130
65339
  renderScene.particlesStartFullFramerate = 20;
@@ -65213,6 +65422,135 @@ async function generateOutfitModelThumbnail(auth, outfitModel, options) {
65213
65422
  Object.assign(defaultOptions, options);
65214
65423
  return generateOutfitThumbnail(auth, outfitModel, defaultOptions.size, defaultOptions.type, defaultOptions.quality, defaultOptions.gltfAutoDownload, defaultOptions.includeAnimations);
65215
65424
  }
65425
+ function getViewExtents(camera, positions, width, height) {
65426
+ const minExtents = new Vector2(1e6, 1e6);
65427
+ const maxExtents = new Vector2(-1e6, -1e6);
65428
+ for (const pos of positions) {
65429
+ const projPos = new Vector3$1(...pos.toVec3()).project(camera);
65430
+ const x = (projPos.x / 2 + 0.5) * width;
65431
+ const y = (-projPos.y / 2 + 0.5) * height;
65432
+ if (x < minExtents.X) minExtents.X = x;
65433
+ if (x > maxExtents.X) maxExtents.X = x;
65434
+ if (y < minExtents.Y) minExtents.Y = y;
65435
+ if (y > maxExtents.Y) maxExtents.Y = y;
65436
+ }
65437
+ minExtents.X = Math.max(0, minExtents.X);
65438
+ minExtents.Y = Math.max(0, minExtents.Y);
65439
+ maxExtents.X = Math.min(width, maxExtents.X);
65440
+ maxExtents.Y = Math.min(height, maxExtents.Y);
65441
+ return [minExtents, maxExtents];
65442
+ }
65443
+ function getModelViewExtents(model, camera, width, height) {
65444
+ const worldExtents = getExtentsWorld(model);
65445
+ const corners = [
65446
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[0].Z),
65447
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[1].Z),
65448
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[0].Z),
65449
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[1].Z),
65450
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[0].Z),
65451
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[1].Z),
65452
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[0].Z),
65453
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[1].Z)
65454
+ ];
65455
+ return getViewExtents(camera, corners, width, height);
65456
+ }
65457
+ function cropCameraToViewExtents(camera, viewExtents, width, height, keepAspectRatio = true) {
65458
+ const blx = viewExtents[0].X;
65459
+ const bly = viewExtents[0].Y;
65460
+ const bhx = viewExtents[1].X;
65461
+ const bhy = viewExtents[1].Y;
65462
+ const xDiff = bhx - blx;
65463
+ const yDiff = bhy - bly;
65464
+ const cx = blx + xDiff / 2;
65465
+ const cy = bly + yDiff / 2;
65466
+ const scaleW = xDiff / width;
65467
+ const scaleH = yDiff / height;
65468
+ const maxScale = Math.max(scaleW, scaleH);
65469
+ const cropWidth = keepAspectRatio ? width * maxScale : xDiff;
65470
+ const cropHeight = keepAspectRatio ? height * maxScale : yDiff;
65471
+ const flx = cx - cropWidth / 2;
65472
+ const fly = cy - cropHeight / 2;
65473
+ const x = flx;
65474
+ const y = fly;
65475
+ camera.setViewOffset(
65476
+ width,
65477
+ height,
65478
+ x,
65479
+ y,
65480
+ cropWidth,
65481
+ cropHeight
65482
+ );
65483
+ return cropWidth / cropHeight;
65484
+ }
65485
+ function cropForModel(model, renderScene, width, height, resizeToRemoveUnusedSpace = false) {
65486
+ const viewExtents = getModelViewExtents(model, renderScene.camera, width, height);
65487
+ const targetAspectRatio = cropCameraToViewExtents(renderScene.camera, viewExtents, width, height, !resizeToRemoveUnusedSpace);
65488
+ renderScene.camera.updateProjectionMatrix();
65489
+ let newHeight = height;
65490
+ let newWidth = width;
65491
+ if (resizeToRemoveUnusedSpace) {
65492
+ newWidth = width * targetAspectRatio;
65493
+ if (newWidth > width) {
65494
+ newWidth = width;
65495
+ newHeight = height / targetAspectRatio;
65496
+ }
65497
+ }
65498
+ return [Math.ceil(newWidth), Math.ceil(newHeight)];
65499
+ }
65500
+ function createThumbnailScene() {
65501
+ const renderScene = RBXRenderer.addScene(false);
65502
+ renderScene.isForRenderTarget = true;
65503
+ setupThumbnailScene(renderScene);
65504
+ return renderScene;
65505
+ }
65506
+ async function generateAccessoryThumbnail(auth, id, type, imageOptions, isAccessoryCamera = false) {
65507
+ let renderSceneToDestroy = void 0;
65508
+ const instancesToDestroy = [];
65509
+ const cleanup = () => {
65510
+ if (renderSceneToDestroy) renderSceneToDestroy.destroy();
65511
+ for (const instance of instancesToDestroy) {
65512
+ instance.Destroy();
65513
+ }
65514
+ return void 0;
65515
+ };
65516
+ const resultOptions = {
65517
+ quality: 1,
65518
+ size: [420, 420]
65519
+ };
65520
+ if (imageOptions) Object.assign(resultOptions, imageOptions);
65521
+ const renderScene = createThumbnailScene();
65522
+ renderSceneToDestroy = renderScene;
65523
+ const rbx = await API.Asset.GetRBX(`rbxassetid://${id}`, { "Roblox-AssetFormat": "avatar_meshpart_accessory" });
65524
+ if (rbx instanceof Response) return cleanup();
65525
+ const root = rbx.generateTree();
65526
+ instancesToDestroy.push(root);
65527
+ const accessory = root.FindFirstChildOfClass("Accessory");
65528
+ if (!accessory) return cleanup();
65529
+ let camera = void 0;
65530
+ if (isAccessoryCamera) {
65531
+ camera = new Instance("Camera");
65532
+ setupAccessoryCamera(root, camera);
65533
+ } else {
65534
+ camera = getThumbnailCamera(accessory);
65535
+ }
65536
+ instancesToDestroy.push(camera);
65537
+ RBXRenderer.setCameraCFrame(camera.PropOrDefault("CFrame", new CFrame()), renderScene);
65538
+ RBXRenderer.setCameraFov(camera.PropOrDefault("FieldOfView", 70), renderScene);
65539
+ renderScene.camera.aspect = resultOptions.size[0] / resultOptions.size[1];
65540
+ renderScene.camera.updateProjectionMatrix();
65541
+ let [newWidth, newHeight] = [resultOptions.size[0], resultOptions.size[1]];
65542
+ if (!isAccessoryCamera) {
65543
+ [newWidth, newHeight] = cropForModel(accessory, renderScene, resultOptions.size[0], resultOptions.size[1]);
65544
+ }
65545
+ RBXRenderer.addInstance(accessory, auth, renderScene);
65546
+ const compiledSuccessfully = await renderScene.waitUntilFullyCompiled([accessory, ...accessory.GetChildrenDangerous()]);
65547
+ if (!compiledSuccessfully) return cleanup();
65548
+ const result = type === "gltf" || type === "glb" ? await modelThumbnailClick(renderScene, type) : await imageThumbnailClick(renderScene, newWidth, newHeight, type, {
65549
+ quality: resultOptions.quality
65550
+ });
65551
+ cleanup();
65552
+ return result;
65553
+ }
65216
65554
  async function runTests() {
65217
65555
  const auth = new Authentication();
65218
65556
  const testModel = await API.Asset.GetRBX(FLAGS.AUTOTEST_MODEL);
@@ -65393,6 +65731,7 @@ function exposeThumbnailGenerator() {
65393
65731
  globalThis.generateModelThumbnail = generateModelThumbnail;
65394
65732
  globalThis.setupThumbnailScene = setupThumbnailScene;
65395
65733
  globalThis.getThumbnailCameraCFrame = getThumbnailCameraCFrame;
65734
+ globalThis.generateAccessoryThumbnail = generateAccessoryThumbnail;
65396
65735
  }
65397
65736
  function exposeTests() {
65398
65737
  globalThis.runTests = runTests;
@@ -65592,7 +65931,10 @@ export {
65592
65931
  closestPointTriangle,
65593
65932
  createContentMap,
65594
65933
  createThumbnailCamera,
65934
+ createThumbnailScene,
65595
65935
  createWeightsForMeshChunked,
65936
+ cropCameraToViewExtents,
65937
+ cropForModel,
65596
65938
  cross,
65597
65939
  defaultPantAssetIds,
65598
65940
  defaultPantTemplateAssetIds,
@@ -65634,6 +65976,7 @@ export {
65634
65976
  getFullBodyCameraCFrame,
65635
65977
  getHeadExtents,
65636
65978
  getHeadshotCameraCFrame,
65979
+ getModelViewExtents,
65637
65980
  getOffsetArray,
65638
65981
  getOriginalAttachmentOrientation,
65639
65982
  getOriginalAttachmentPosition,
@@ -65642,9 +65985,11 @@ export {
65642
65985
  getPartsInAssembly_Generate,
65643
65986
  getRandomBetweenInclusive,
65644
65987
  getRootAssemblyPart_Generate,
65988
+ getThumbnailCamera,
65645
65989
  getThumbnailCameraCFrame,
65646
65990
  getUVtoIndexMap,
65647
65991
  getUVtoIndicesMap,
65992
+ getViewExtents,
65648
65993
  getWorkerOnMessage,
65649
65994
  hasSameVal,
65650
65995
  hasSameValFloat,
@@ -65688,6 +66033,7 @@ export {
65688
66033
  rotationMatrixToEulerAngles,
65689
66034
  saveByteArray,
65690
66035
  scaleMesh,
66036
+ setCacheFootprintPreset,
65691
66037
  setupAccessoryCamera,
65692
66038
  setupBodyPartCamera,
65693
66039
  setupCamera,