roavatar-renderer 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,9 +13,17 @@ Basic (not really) example on how to load an avatar, that is also untested:
13
13
  <script src="/draco_decoder.js"></script>
14
14
  ```
15
15
  ```ts
16
+
17
+ //setup flags that are compatible with you environment
18
+ FLAGS.ASSETS_PATH = chrome.runtime.getURL("assets/rbxasset/")
19
+ FLAGS.USE_WORKERS = true //if layered assets dont work set this to false
20
+
16
21
  //setup instance wrappers and renderer
17
22
  RegisterWrappers()
18
23
  RBXRenderer.fullSetup() //you can alternatively choose to only setup specific parts and do some yourself
24
+ RBXRenderer.setBackgroundColor( 0xffffff )
25
+ RBXRenderer.setRendererSize(1000,500)
26
+ document.body.appendChild(RBXRenderer.getRendererDom())
19
27
 
20
28
  //get avatar data for the user with id 1
21
29
  const outfit = API.Avatar.GetAvatarDetails(1)
package/dist/index.d.ts CHANGED
@@ -187,7 +187,9 @@ export declare const API: {
187
187
  startCurrentlyLoadingAssets: () => void;
188
188
  stopCurrentlyLoadingAssets: () => void;
189
189
  idFromStr: (str: string) => number;
190
- parseAssetString: (str: string) => string | undefined;
190
+ parseAssetString: (str: string) => string;
191
+ getCDNURLFromAssetDelivery: (url: string, headers?: any) => Promise<string | Response>;
192
+ assetURLToCDNURL: (url: string | number | bigint, headers?: any) => Promise<string | Response>;
191
193
  };
192
194
  Events: {
193
195
  OnLoadingAssets: Event_2;
@@ -225,8 +227,8 @@ export declare const API: {
225
227
  SetThumbnailCustomization: (auth: Authentication, body: ThumbnailsCustomization_Payload) => Promise<Response>;
226
228
  };
227
229
  Asset: {
228
- GetAssetBuffer: (url: string, headers?: HeadersInit) => Promise<ArrayBuffer | Response>;
229
- GetRBX: (url: string, headers?: HeadersInit) => Promise<RBX | Response>;
230
+ GetAssetBuffer: (url: string, headers?: HeadersInit) => Promise<Response | ArrayBuffer>;
231
+ GetRBX: (url: string, headers?: HeadersInit) => Promise<Response | RBX>;
230
232
  GetMesh: (url: string, headers?: HeadersInit, readOnly?: boolean) => Promise<FileMesh | Response>;
231
233
  IsLayered: (id: number) => Promise<boolean | Response>;
232
234
  };
@@ -910,6 +912,9 @@ export declare const FLAGS: {
910
912
  ENABLE_API_CACHE: boolean;
911
913
  ROAVATAR_DATA_URL: string;
912
914
  ROAVATAR_TRYON_PLACE: number;
915
+ ASSETS_PATH: string;
916
+ ASSETDELIVERY_V2: boolean;
917
+ USE_WORKERS: boolean;
913
918
  ENABLE_LC_WEIGHT_CACHE: boolean;
914
919
  INFLATE_LAYERED_CLOTHING: number;
915
920
  LAYERED_CLOTHING_ALGORITHM: "linear" | "linearnormal" | "linearnormal2" | "rbf";
@@ -1873,16 +1878,22 @@ export declare class RBXRenderer {
1873
1878
  static renderer: THREE.WebGLRenderer;
1874
1879
  static effectComposer: EffectComposer | undefined;
1875
1880
  static resolution: [number, number];
1881
+ static plane?: THREE.Mesh;
1876
1882
  /**Fully sets up renderer with scene, camera and frame rendering*/
1877
- static fullSetup(): void;
1883
+ static fullSetup(includeScene?: boolean, includeControls?: boolean): void;
1878
1884
  /**Sets up the THREE.js renderer */
1879
1885
  static create(): void;
1880
1886
  /**Sets up a basic scene with lighting
1881
1887
  * @param lightingType "WellLit" is the default lighting for RoAvatar, "Thumbnail" tries to match the Roblox thumbnail lighting
1888
+ * @param backgroundColorHex is the hex code for the background color, for example 0x2b2d33
1882
1889
  */
1883
- static setupScene(lightingType?: "WellLit" | "Thumbnail"): void;
1890
+ static setupScene(lightingType?: "WellLit" | "Thumbnail", backgroundColorHex?: number): void;
1884
1891
  /**Sets up orbit controls */
1885
1892
  static setupControls(): void;
1893
+ /**
1894
+ * @param colorHex example: 0x2b2d33 which is the default
1895
+ */
1896
+ static setBackgroundColor(colorHex: number): void;
1886
1897
  /**Makes the renderer render a new frame on every animationFrame */
1887
1898
  static animate(): void;
1888
1899
  static _createEffectComposer(): void;
package/dist/index.js CHANGED
@@ -28252,7 +28252,10 @@ const FLAGS = {
28252
28252
  ROAVATAR_DATA_URL: "rbxassetid://102463700065175",
28253
28253
  //url of model to load that lists issues with specific versions
28254
28254
  ROAVATAR_TRYON_PLACE: 135979364355750,
28255
+ ASSETS_PATH: "../assets/rbxasset/",
28256
+ ASSETDELIVERY_V2: true,
28255
28257
  //layered clothing
28258
+ USE_WORKERS: true,
28256
28259
  ENABLE_LC_WEIGHT_CACHE: true,
28257
28260
  INFLATE_LAYERED_CLOTHING: 0.05,
28258
28261
  //only used by linear algorithms
@@ -34263,7 +34266,7 @@ async function RBLXPost(url, auth, body, attempt = 0, method = "POST") {
34263
34266
  }
34264
34267
  });
34265
34268
  }
34266
- async function RBLXGet(url, headers) {
34269
+ async function RBLXGet(url, headers, includeCredentials = true) {
34267
34270
  return new Promise((resolve) => {
34268
34271
  let newHeaders = {
34269
34272
  "Content-Type": "application/json"
@@ -34271,10 +34274,13 @@ async function RBLXGet(url, headers) {
34271
34274
  if (headers) {
34272
34275
  newHeaders = { ...newHeaders, ...headers };
34273
34276
  }
34277
+ if (url.includes("rbxcdn.com")) {
34278
+ includeCredentials = false;
34279
+ }
34274
34280
  const fetchHeaders = new Headers(newHeaders);
34275
34281
  try {
34276
34282
  fetch(url, {
34277
- credentials: "include",
34283
+ credentials: includeCredentials ? "include" : void 0,
34278
34284
  headers: fetchHeaders
34279
34285
  }).then((response) => {
34280
34286
  resolve(response);
@@ -34332,24 +34338,52 @@ const API = {
34332
34338
  return numStrs.length > 0 ? Number(numStrs[numStrs.length - 1]) : NaN;
34333
34339
  },
34334
34340
  "parseAssetString": function(str) {
34341
+ let url = str;
34335
34342
  if (!isNaN(Number(str))) {
34336
- return `https://assetdelivery.roblox.com/v1/asset?id=${str}`;
34343
+ url = `https://assetdelivery.roblox.com/v1/asset?id=${str}`;
34337
34344
  } else if (str.startsWith("rbxassetid://")) {
34338
- return `https://assetdelivery.roblox.com/v1/asset?id=${str.slice(13)}`;
34345
+ url = `https://assetdelivery.roblox.com/v1/asset?id=${str.slice(13)}`;
34339
34346
  } else if (str.startsWith("rbxasset://")) {
34340
34347
  str = str.replaceAll("\\", "/");
34341
- return new URL("../assets/rbxasset/" + str.slice(11), import.meta.url).toString();
34348
+ url = FLAGS.ASSETS_PATH + str.slice(11);
34342
34349
  } else if (str.includes("roblox.com/asset")) {
34343
- return `https://assetdelivery.roblox.com/v1/asset?id=${API.Misc.idFromStr(str)}`;
34350
+ url = `https://assetdelivery.roblox.com/v1/asset?id=${API.Misc.idFromStr(str)}`;
34344
34351
  } else if (str.startsWith("https://assetdelivery.roblox.com/v1/asset/?id=")) {
34345
- return `https://assetdelivery.roblox.com/v1/asset?id=${str.slice(46)}`;
34352
+ url = `https://assetdelivery.roblox.com/v1/asset?id=${str.slice(46)}`;
34346
34353
  } else if (str.includes("assetdelivery.roblox.com")) {
34347
- return `https://assetdelivery.roblox.com/v1/asset?id=${API.Misc.idFromStr(str)}`;
34354
+ url = `https://assetdelivery.roblox.com/v1/asset?id=${API.Misc.idFromStr(str)}`;
34348
34355
  } else if (str.startsWith(".")) {
34349
- return new URL(str, import.meta.url).toString();
34356
+ url = str;
34350
34357
  } else {
34351
34358
  console.warn(`Failed to parse path of ${str}`);
34352
34359
  }
34360
+ if (FLAGS.ASSETDELIVERY_V2) {
34361
+ if (url.includes("/v1/")) {
34362
+ url = url.replace("/v1/", "/v2/");
34363
+ }
34364
+ }
34365
+ return url;
34366
+ },
34367
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34368
+ "getCDNURLFromAssetDelivery": async function(url, headers) {
34369
+ if (!FLAGS.ASSETDELIVERY_V2 || !url.includes("assetdelivery.roblox.com/v2/")) {
34370
+ return url;
34371
+ } else {
34372
+ const response = await RBLXGet(url, headers);
34373
+ if (response.status !== 200) {
34374
+ return response;
34375
+ }
34376
+ const data = await response.json();
34377
+ return data.locations[0].location;
34378
+ }
34379
+ },
34380
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34381
+ "assetURLToCDNURL": async function(url, headers) {
34382
+ url = String(url);
34383
+ if (url.includes("rbxcdn.com")) return url;
34384
+ const fetchStr = API.Misc.parseAssetString(url) || url;
34385
+ const cdnURL = await API.Misc.getCDNURLFromAssetDelivery(fetchStr, headers);
34386
+ return cdnURL;
34353
34387
  }
34354
34388
  },
34355
34389
  "Events": {
@@ -34358,26 +34392,32 @@ const API = {
34358
34392
  "Generic": {
34359
34393
  LoadImage: async function(url) {
34360
34394
  return new Promise((resolve) => {
34361
- const fetchStr = API.Misc.parseAssetString(url) || url;
34362
- const cachedImage = CACHE.Image.get(fetchStr);
34395
+ const cacheURL = API.Misc.parseAssetString(url) || url;
34396
+ const cachedImage = CACHE.Image.get(cacheURL);
34363
34397
  if (cachedImage) {
34364
34398
  resolve(cachedImage);
34365
34399
  } else {
34366
- const image = new Image();
34367
- image.onload = () => {
34368
- if (FLAGS.ENABLE_API_CACHE) {
34369
- CACHE.Image.set(fetchStr, image);
34370
- }
34371
- resolve(image);
34372
- };
34373
- image.onerror = () => {
34374
- if (FLAGS.ENABLE_API_CACHE) {
34375
- CACHE.Image.set(fetchStr, void 0);
34376
- }
34377
- resolve(void 0);
34378
- };
34379
- image.crossOrigin = "anonymous";
34380
- image.src = fetchStr;
34400
+ CACHE.Image.set(cacheURL, new Promise((cacheResolve) => {
34401
+ API.Misc.assetURLToCDNURL(url).then((fetchStr) => {
34402
+ if (fetchStr instanceof Response) {
34403
+ resolve(void 0);
34404
+ return;
34405
+ }
34406
+ const image = new Image();
34407
+ image.onload = () => {
34408
+ cacheResolve(image);
34409
+ resolve(image);
34410
+ CACHE.Image.set(cacheURL, image);
34411
+ };
34412
+ image.onerror = () => {
34413
+ cacheResolve(image);
34414
+ resolve(void 0);
34415
+ CACHE.Image.set(cacheURL, void 0);
34416
+ };
34417
+ image.crossOrigin = "anonymous";
34418
+ image.src = fetchStr;
34419
+ });
34420
+ }));
34381
34421
  }
34382
34422
  });
34383
34423
  },
@@ -34625,8 +34665,7 @@ const API = {
34625
34665
  },
34626
34666
  "Asset": {
34627
34667
  GetAssetBuffer: async function(url, headers) {
34628
- const fetchStr = API.Misc.parseAssetString(url) || url;
34629
- let cacheStr = fetchStr;
34668
+ let cacheStr = API.Misc.parseAssetString(url) || url;
34630
34669
  if (headers) {
34631
34670
  cacheStr += JSON.stringify(headers);
34632
34671
  }
@@ -34635,7 +34674,9 @@ const API = {
34635
34674
  return cachedBuffer;
34636
34675
  } else {
34637
34676
  API.Misc.startCurrentlyLoadingAssets();
34638
- const response = await RBLXGet(fetchStr, headers);
34677
+ const fetchStr = await API.Misc.assetURLToCDNURL(url, headers);
34678
+ if (fetchStr instanceof Response) return fetchStr;
34679
+ const response = await RBLXGet(fetchStr, void 0, false);
34639
34680
  API.Misc.stopCurrentlyLoadingAssets();
34640
34681
  if (response.status === 200) {
34641
34682
  const data = await response.arrayBuffer();
@@ -34649,7 +34690,7 @@ const API = {
34649
34690
  }
34650
34691
  },
34651
34692
  GetRBX: async function(url, headers) {
34652
- const fetchStr = API.Misc.parseAssetString(url) || url;
34693
+ const fetchStr = url;
34653
34694
  let cacheStr = fetchStr;
34654
34695
  if (headers) {
34655
34696
  cacheStr += JSON.stringify(headers);
@@ -34673,7 +34714,7 @@ const API = {
34673
34714
  }
34674
34715
  },
34675
34716
  GetMesh: async function(url, headers, readOnly = false) {
34676
- const fetchStr = API.Misc.parseAssetString(url) || url;
34717
+ const fetchStr = url;
34677
34718
  let cacheStr = fetchStr;
34678
34719
  if (headers) {
34679
34720
  cacheStr += JSON.stringify(headers);
@@ -48679,6 +48720,7 @@ function WorkerWrapper(options) {
48679
48720
  );
48680
48721
  }
48681
48722
  }
48723
+ console.log(WorkerWrapper);
48682
48724
  let idCounter = 0;
48683
48725
  class WorkerPool {
48684
48726
  static instance;
@@ -48686,7 +48728,7 @@ class WorkerPool {
48686
48728
  workersActiveTasks = [];
48687
48729
  workersResolves = [];
48688
48730
  constructor() {
48689
- if (window.Worker) {
48731
+ if (window.Worker && FLAGS.USE_WORKERS) {
48690
48732
  const workerCount = navigator.hardwareConcurrency || 4;
48691
48733
  for (let i = 0; i < workerCount; i++) {
48692
48734
  const worker = new WorkerWrapper();
@@ -48697,6 +48739,10 @@ class WorkerPool {
48697
48739
  const [id, data] = e.data;
48698
48740
  this._onMessage(i, id, data);
48699
48741
  };
48742
+ worker.onerror = (e) => {
48743
+ console.warn(e);
48744
+ throw new Error("Failed to create worker, try disabling workers by setting FLAGS.USE_WORKERS = false but do note doing so will degrade performance");
48745
+ };
48700
48746
  }
48701
48747
  }
48702
48748
  }
@@ -48740,7 +48786,9 @@ class WorkerPool {
48740
48786
  }
48741
48787
  }
48742
48788
  }
48743
- WorkerPool.instance = new WorkerPool();
48789
+ function setupWorkerPool() {
48790
+ WorkerPool.instance = new WorkerPool();
48791
+ }
48744
48792
  class RBFDeformer {
48745
48793
  refVerts = [];
48746
48794
  distVerts = [];
@@ -52553,7 +52601,11 @@ class SoundWrapper extends InstanceWrapper {
52553
52601
  audioUrl = this.instance.Prop("AudioContent").uri;
52554
52602
  }
52555
52603
  if (audioUrl && audioUrl.length > 0) {
52556
- this.data.audio = new Audio(API.Misc.parseAssetString(audioUrl));
52604
+ this.data.audio = new Audio();
52605
+ API.Misc.assetURLToCDNURL(audioUrl).then((url) => {
52606
+ if (url instanceof Response || !this.data.audio) return;
52607
+ this.data.audio.src = url;
52608
+ });
52557
52609
  }
52558
52610
  }
52559
52611
  if (this.data.audio) {
@@ -57518,7 +57570,7 @@ class MeshDesc {
57518
57570
  for (const child2 of children2) {
57519
57571
  if (child2.className === "CharacterMesh") {
57520
57572
  if (BodyPartNameToEnum[child.Property("Name")] === child2.Property("BodyPart")) {
57521
- characterMeshStr = child2.Property("MeshId");
57573
+ characterMeshStr = "rbxassetid://" + child2.Property("MeshId");
57522
57574
  }
57523
57575
  }
57524
57576
  }
@@ -60091,12 +60143,14 @@ class RBXRenderer {
60091
60143
  static renderer = new WebGLRenderer({ antialias: true });
60092
60144
  static effectComposer;
60093
60145
  static resolution = [420, 420];
60146
+ static plane;
60094
60147
  /**Fully sets up renderer with scene, camera and frame rendering*/
60095
- static fullSetup() {
60148
+ static fullSetup(includeScene = true, includeControls = true) {
60149
+ setupWorkerPool();
60096
60150
  loadCompositMeshes();
60097
60151
  RBXRenderer.create();
60098
- RBXRenderer.setupScene();
60099
- RBXRenderer.setupControls();
60152
+ if (includeScene) RBXRenderer.setupScene();
60153
+ if (includeControls) RBXRenderer.setupControls();
60100
60154
  RBXRenderer.animate();
60101
60155
  }
60102
60156
  /**Sets up the THREE.js renderer */
@@ -60118,9 +60172,10 @@ class RBXRenderer {
60118
60172
  }
60119
60173
  /**Sets up a basic scene with lighting
60120
60174
  * @param lightingType "WellLit" is the default lighting for RoAvatar, "Thumbnail" tries to match the Roblox thumbnail lighting
60175
+ * @param backgroundColorHex is the hex code for the background color, for example 0x2b2d33
60121
60176
  */
60122
- static setupScene(lightingType = "WellLit") {
60123
- const backgroundColor = new Color(2829619);
60177
+ static setupScene(lightingType = "WellLit", backgroundColorHex = 2829619) {
60178
+ const backgroundColor = new Color(backgroundColorHex);
60124
60179
  RBXRenderer.scene.background = backgroundColor;
60125
60180
  let thumbnailAmbientVal = 138;
60126
60181
  thumbnailAmbientVal = 128;
@@ -60188,6 +60243,7 @@ class RBXRenderer {
60188
60243
  plane.rotation.set(rad(-90), 0, 0);
60189
60244
  plane.position.set(0, 0, 0);
60190
60245
  plane.receiveShadow = false;
60246
+ RBXRenderer.plane = plane;
60191
60247
  RBXRenderer.scene.add(plane);
60192
60248
  }
60193
60249
  /**Sets up orbit controls */
@@ -60202,6 +60258,15 @@ class RBXRenderer {
60202
60258
  RBXRenderer.camera.lookAt(new Vector3$1(...RBXRenderer.orbitControlsTarget));
60203
60259
  controls.update();
60204
60260
  }
60261
+ /**
60262
+ * @param colorHex example: 0x2b2d33 which is the default
60263
+ */
60264
+ static setBackgroundColor(colorHex) {
60265
+ RBXRenderer.scene.background = new Color(colorHex);
60266
+ if (RBXRenderer.plane) {
60267
+ RBXRenderer.plane.material = new MeshBasicMaterial({ color: colorHex });
60268
+ }
60269
+ }
60205
60270
  /**Makes the renderer render a new frame on every animationFrame */
60206
60271
  static animate() {
60207
60272
  RBXRenderer.renderer.setRenderTarget(null);
@@ -60319,6 +60384,8 @@ class RBXRenderer {
60319
60384
  }
60320
60385
  static setRendererSize(width, height) {
60321
60386
  RBXRenderer.renderer.setSize(width, height);
60387
+ RBXRenderer.camera.aspect = width / height;
60388
+ RBXRenderer.camera.updateProjectionMatrix();
60322
60389
  }
60323
60390
  static getRendererDom() {
60324
60391
  return RBXRenderer.renderer.domElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",