@react-three/drei 9.116.2 → 9.116.3

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.
@@ -4,18 +4,14 @@ import { useThree, useLoader } from '@react-three/fiber';
4
4
  import * as React from 'react';
5
5
  import { useState } from 'react';
6
6
 
7
+ /* eslint react-hooks/exhaustive-deps: 1 */
7
8
  // utils
8
- const getFirstItem = param => {
9
- if (Array.isArray(param)) {
10
- return param[0];
11
- } else if (typeof param === 'object' && param !== null) {
12
- const keys = Object.keys(param);
13
- return param[keys[0]][0];
9
+ const getFirstFrame = (frames, frameName) => {
10
+ if (Array.isArray(frames)) {
11
+ return frames[0];
14
12
  } else {
15
- return {
16
- w: 0,
17
- h: 0
18
- };
13
+ const k = frameName !== null && frameName !== void 0 ? frameName : Object.keys(frames)[0];
14
+ return frames[k][0];
19
15
  }
20
16
  };
21
17
  const checkIfFrameIsEmpty = frameData => {
@@ -26,166 +22,42 @@ const checkIfFrameIsEmpty = frameData => {
26
22
  }
27
23
  return true;
28
24
  };
29
- const calculateAspectRatio = (width, height, factor, v) => {
30
- const adaptedHeight = height * (v.aspect > width / height ? v.width / width : v.height / height);
31
- const adaptedWidth = width * (v.aspect > width / height ? v.width / width : v.height / height);
32
- const scaleX = adaptedWidth * factor;
33
- const scaleY = adaptedHeight * factor;
34
- const currentMaxScale = 1;
35
- // Calculate the maximum scale based on the aspect ratio and max scale limit
36
- let finalMaxScaleW = Math.min(currentMaxScale, scaleX);
37
- let finalMaxScaleH = Math.min(currentMaxScale, scaleY);
38
-
39
- // Ensure that scaleX and scaleY do not exceed the max scale while maintaining aspect ratio
40
- if (scaleX > currentMaxScale) {
41
- finalMaxScaleW = currentMaxScale;
42
- finalMaxScaleH = scaleY / scaleX * currentMaxScale;
43
- }
44
- return new THREE.Vector3(finalMaxScaleW, finalMaxScaleH, 1);
45
- };
46
- function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, canvasRenderingContext2DSettings) {
47
- const v = useThree(state => state.viewport);
25
+ function useSpriteLoader(/** The URL of the sprite sheet. */
26
+ input, /** The JSON data of the sprite sheet. */
27
+ json, /** The names of the animations in the sprite sheet. */
28
+ animationNames, /** The number of frames in the sprite sheet. */
29
+ numberOfFrames, /** A callback that is called when the sprite sheet is loaded. */
30
+ onLoad, /** The settings to use when creating the 2D context. */
31
+ canvasRenderingContext2DSettings) {
32
+ const viewportRef = React.useRef(useThree(state => state.viewport));
48
33
  const spriteDataRef = React.useRef(null);
49
34
  const totalFrames = React.useRef(0);
50
35
  const aspectFactor = 0.1;
36
+ const inputRef = React.useRef(input);
37
+ const jsonRef = React.useRef(json);
38
+ const animationFramesRef = React.useRef(animationNames);
51
39
  const [spriteData, setSpriteData] = useState(null);
52
40
  const [spriteTexture, setSpriteTexture] = React.useState(new THREE.Texture());
53
- const textureLoader = new THREE.TextureLoader();
41
+ const textureLoader = React.useMemo(() => new THREE.TextureLoader(), []);
54
42
  const [spriteObj, setSpriteObj] = useState(null);
55
- React.useLayoutEffect(() => {
56
- if (json && input) {
57
- loadJsonAndTextureAndExecuteCallback(json, input, parseSpriteData);
58
- } else if (input) {
59
- // only load the texture, this is an image sprite only
60
- loadStandaloneSprite();
61
- }
62
- return () => {
63
- if (input) {
64
- useLoader.clear(TextureLoader, input);
65
- }
66
- };
67
- }, []);
68
- function loadJsonAndTexture(textureUrl, jsonUrl) {
69
- if (jsonUrl && textureUrl) {
70
- loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, parseSpriteData);
71
- } else {
72
- loadStandaloneSprite(textureUrl);
73
- }
74
- }
75
- function loadStandaloneSprite(textureUrl) {
76
- if (!textureUrl && !input) {
77
- throw new Error('Either textureUrl or input must be provided');
78
- }
79
- const validUrl = textureUrl !== null && textureUrl !== void 0 ? textureUrl : input;
80
- if (!validUrl) {
81
- throw new Error('A valid texture URL must be provided');
82
- }
83
- new Promise(resolve => {
84
- textureLoader.load(validUrl, resolve);
85
- }).then(texture => {
86
- parseSpriteData(null, texture);
87
- });
88
- }
89
-
90
- /**
91
- *
92
- */
93
- function loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, callback) {
94
- const jsonPromise = fetch(jsonUrl).then(response => response.json());
95
- const texturePromise = new Promise(resolve => {
96
- textureLoader.load(textureUrl, resolve);
97
- });
98
- Promise.all([jsonPromise, texturePromise]).then(response => {
99
- callback(response[0], response[1]);
100
- });
101
- }
102
- const parseSpriteData = (json, _spriteTexture) => {
103
- let aspect = new THREE.Vector3(1, 1, 1);
104
- // sprite only case
105
- if (json === null) {
106
- if (_spriteTexture && numberOfFrames) {
107
- //get size from texture
108
- const width = _spriteTexture.image.width;
109
- const height = _spriteTexture.image.height;
110
- totalFrames.current = numberOfFrames;
111
- const {
112
- rows,
113
- columns,
114
- frameWidth,
115
- frameHeight,
116
- emptyFrames
117
- } = getRowsAndColumns(_spriteTexture, numberOfFrames);
118
- spriteDataRef.current = {
119
- frames: [],
120
- meta: {
121
- version: '1.0',
122
- size: {
123
- w: width,
124
- h: height
125
- },
126
- rows,
127
- columns,
128
- frameWidth,
129
- frameHeight,
130
- scale: '1'
131
- }
132
- };
133
- for (let row = 0; row < rows; row++) {
134
- for (let col = 0; col < columns; col++) {
135
- const isExcluded = (emptyFrames !== null && emptyFrames !== void 0 ? emptyFrames : []).some(coord => coord.row === row && coord.col === col);
136
- if (isExcluded) {
137
- continue;
138
- }
139
- spriteDataRef.current.frames.push({
140
- frame: {
141
- x: col * frameWidth,
142
- y: row * frameHeight,
143
- w: frameWidth,
144
- h: frameHeight
145
- },
146
- rotated: false,
147
- trimmed: false,
148
- spriteSourceSize: {
149
- x: 0,
150
- y: 0,
151
- w: frameWidth,
152
- h: frameHeight
153
- },
154
- sourceSize: {
155
- w: frameWidth,
156
- h: frameHeight
157
- }
158
- });
159
- }
160
- }
161
- aspect = calculateAspectRatio(frameWidth, frameHeight, aspectFactor, v);
162
- }
43
+ const calculateAspectRatio = React.useCallback((width, height, factor) => {
44
+ const adaptedHeight = height * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height);
45
+ const adaptedWidth = width * (viewportRef.current.aspect > width / height ? viewportRef.current.width / width : viewportRef.current.height / height);
46
+ const scaleX = adaptedWidth * factor;
47
+ const scaleY = adaptedHeight * factor;
48
+ const currentMaxScale = 1;
49
+ // Calculate the maximum scale based on the aspect ratio and max scale limit
50
+ let finalMaxScaleW = Math.min(currentMaxScale, scaleX);
51
+ let finalMaxScaleH = Math.min(currentMaxScale, scaleY);
163
52
 
164
- //scale ratio for stadalone sprite
165
- spriteDataRef.current.frames = calculateScaleRatio(spriteDataRef.current.frames);
166
- } else if (_spriteTexture) {
167
- spriteDataRef.current = json;
168
- spriteDataRef.current.frames = parseFrames();
169
- totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
170
- const {
171
- w,
172
- h
173
- } = getFirstItem(json.frames).sourceSize;
174
- aspect = calculateAspectRatio(w, h, aspectFactor, v);
53
+ // Ensure that scaleX and scaleY do not exceed the max scale while maintaining aspect ratio
54
+ if (scaleX > currentMaxScale) {
55
+ finalMaxScaleW = currentMaxScale;
56
+ finalMaxScaleH = scaleY / scaleX * currentMaxScale;
175
57
  }
176
- setSpriteData(spriteDataRef.current);
177
- // @ts-ignore
178
- if ('encoding' in _spriteTexture) _spriteTexture.encoding = 3001; // sRGBEncoding
179
- // @ts-ignore
180
- else _spriteTexture.colorSpace = THREE.SRGBColorSpace;
181
- setSpriteTexture(_spriteTexture);
182
- setSpriteObj({
183
- spriteTexture: _spriteTexture,
184
- spriteData: spriteDataRef.current,
185
- aspect: aspect
186
- });
187
- };
188
- const getRowsAndColumns = (texture, totalFrames) => {
58
+ return new THREE.Vector3(finalMaxScaleW, finalMaxScaleH, 1);
59
+ }, []);
60
+ const getRowsAndColumns = React.useCallback((texture, totalFrames) => {
189
61
  if (texture.image) {
190
62
  const canvas = document.createElement('canvas');
191
63
  const ctx = canvas.getContext('2d', canvasRenderingContext2DSettings);
@@ -240,125 +112,285 @@ function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, ca
240
112
  emptyFrames: []
241
113
  };
242
114
  }
243
- };
115
+ }, [canvasRenderingContext2DSettings]);
116
+
117
+ // calculate scale ratio for the frames
118
+ const calculateScaleRatio = React.useCallback(frames => {
119
+ // Helper function to calculate scale ratio for an array of frames
120
+ const processFrameArray = frameArray => {
121
+ // Find the largest frame
122
+ let largestFrame = null;
123
+ for (const frame of frameArray) {
124
+ const {
125
+ w,
126
+ h
127
+ } = frame.frame;
128
+ const area = w * h;
129
+ if (!largestFrame || area > largestFrame.area) {
130
+ largestFrame = {
131
+ w,
132
+ h,
133
+ area
134
+ };
135
+ }
136
+ }
137
+
138
+ // Set scaleRatio property on each frame
139
+ const frameArr = frameArray.map(frame => {
140
+ const {
141
+ w,
142
+ h
143
+ } = frame.frame;
144
+ const area = w * h;
145
+ const scaleRatio = largestFrame ? area === largestFrame.area ? 1 : Math.sqrt(area / largestFrame.area) : 1;
146
+ return {
147
+ ...frame,
148
+ scaleRatio
149
+ };
150
+ });
151
+ return frameArr;
152
+ };
153
+
154
+ // Handle both array and record cases
155
+ if (Array.isArray(frames)) {
156
+ return processFrameArray(frames);
157
+ } else {
158
+ const result = {};
159
+ for (const key in frames) {
160
+ result[key] = processFrameArray(frames[key]);
161
+ }
162
+ return result;
163
+ }
164
+ }, []);
244
165
 
245
166
  // for frame based JSON Hash sprite data
246
- const parseFrames = () => {
167
+ const parseFrames = React.useCallback(() => {
247
168
  const sprites = {};
248
169
  const data = spriteDataRef.current;
249
- const delimiters = animationNames;
250
- if (delimiters && Array.isArray(data['frames'])) {
251
- for (let i = 0; i < delimiters.length; i++) {
252
- // we convert each named animation group into an array
253
- sprites[delimiters[i]] = [];
254
- for (const value of data['frames']) {
255
- const frameData = value['frame'];
256
- const x = frameData['x'];
257
- const y = frameData['y'];
258
- const width = frameData['w'];
259
- const height = frameData['h'];
260
- const sourceWidth = value['sourceSize']['w'];
261
- const sourceHeight = value['sourceSize']['h'];
262
- if (typeof value['filename'] === 'string' && value['filename'].toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
263
- sprites[delimiters[i]].push({
264
- x: x,
265
- y: y,
266
- w: width,
267
- h: height,
268
- frame: frameData,
269
- sourceSize: {
270
- w: sourceWidth,
271
- h: sourceHeight
272
- }
273
- });
170
+ const delimiters = animationFramesRef.current;
171
+ if (data) {
172
+ if (delimiters && Array.isArray(data['frames'])) {
173
+ for (let i = 0; i < delimiters.length; i++) {
174
+ // we convert each named animation group into an array
175
+ sprites[delimiters[i]] = [];
176
+ for (const value of data['frames']) {
177
+ const frameData = value['frame'];
178
+ const sourceWidth = value['sourceSize']['w'];
179
+ const sourceHeight = value['sourceSize']['h'];
180
+ if (typeof value['filename'] === 'string' && value['filename'].toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
181
+ sprites[delimiters[i]].push({
182
+ ...value,
183
+ frame: frameData,
184
+ sourceSize: {
185
+ w: sourceWidth,
186
+ h: sourceHeight
187
+ }
188
+ });
189
+ }
274
190
  }
275
191
  }
192
+ for (const frame in sprites) {
193
+ const scaleRatioData = calculateScaleRatio(sprites[frame]);
194
+ if (Array.isArray(scaleRatioData)) {
195
+ sprites[frame] = scaleRatioData;
196
+ }
197
+ }
198
+ return sprites;
199
+ } else if (delimiters && typeof data['frames'] === 'object') {
200
+ for (let i = 0; i < delimiters.length; i++) {
201
+ // we convert each named animation group into an array
202
+ sprites[delimiters[i]] = [];
203
+ for (const innerKey in data['frames']) {
204
+ const value = data['frames'][innerKey];
205
+ const frameData = value['frame'];
206
+ const sourceWidth = value['sourceSize']['w'];
207
+ const sourceHeight = value['sourceSize']['h'];
208
+ if (typeof innerKey === 'string' && innerKey.toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
209
+ sprites[delimiters[i]].push({
210
+ ...value,
211
+ frame: frameData,
212
+ sourceSize: {
213
+ w: sourceWidth,
214
+ h: sourceHeight
215
+ }
216
+ });
217
+ }
218
+ }
219
+ }
220
+ for (const frame in sprites) {
221
+ const scaleRatioData = calculateScaleRatio(sprites[frame]);
222
+ if (Array.isArray(scaleRatioData)) {
223
+ sprites[frame] = scaleRatioData;
224
+ }
225
+ }
226
+ return sprites;
227
+ } else {
228
+ let spritesArr = [];
229
+ if (data != null && data.frames) {
230
+ if (Array.isArray(data.frames)) {
231
+ spritesArr = data.frames.map(frame => ({
232
+ ...frame,
233
+ x: frame.frame.x,
234
+ y: frame.frame.y,
235
+ w: frame.frame.w,
236
+ h: frame.frame.h
237
+ }));
238
+ } else {
239
+ spritesArr = Object.values(data.frames).flat().map(frame => ({
240
+ ...frame,
241
+ x: frame.frame.x,
242
+ y: frame.frame.y,
243
+ w: frame.frame.w,
244
+ h: frame.frame.h
245
+ }));
246
+ }
247
+ }
248
+ return calculateScaleRatio(spritesArr);
276
249
  }
277
- for (const frame in sprites) {
278
- sprites[frame].frame = calculateScaleRatio(sprites[frame]);
279
- }
280
- return sprites;
281
- } else if (delimiters && typeof data['frames'] === 'object') {
282
- for (let i = 0; i < delimiters.length; i++) {
283
- // we convert each named animation group into an array
284
- sprites[delimiters[i]] = [];
285
- for (const innerKey in data['frames']) {
286
- const value = data['frames'][innerKey];
287
- const frameData = value['frame'];
288
- const x = frameData['x'];
289
- const y = frameData['y'];
290
- const width = frameData['w'];
291
- const height = frameData['h'];
292
- const sourceWidth = value['sourceSize']['w'];
293
- const sourceHeight = value['sourceSize']['h'];
294
- if (typeof innerKey === 'string' && innerKey.toLowerCase().indexOf(delimiters[i].toLowerCase()) !== -1) {
295
- sprites[delimiters[i]].push({
296
- x: x,
297
- y: y,
250
+ }
251
+ return [];
252
+ }, [calculateScaleRatio, spriteDataRef]);
253
+ const parseSpriteData = React.useCallback((json, _spriteTexture) => {
254
+ let aspect = new THREE.Vector3(1, 1, 1);
255
+ // sprite only case
256
+ if (json === null) {
257
+ if (_spriteTexture && numberOfFrames) {
258
+ //get size from texture
259
+ const width = _spriteTexture.image.width;
260
+ const height = _spriteTexture.image.height;
261
+ totalFrames.current = numberOfFrames;
262
+ const {
263
+ rows,
264
+ columns,
265
+ frameWidth,
266
+ frameHeight,
267
+ emptyFrames
268
+ } = getRowsAndColumns(_spriteTexture, numberOfFrames);
269
+ const nonJsonFrames = {
270
+ frames: [],
271
+ meta: {
272
+ version: '1.0',
273
+ size: {
298
274
  w: width,
299
- h: height,
300
- frame: frameData,
301
- sourceSize: {
302
- w: sourceWidth,
303
- h: sourceHeight
304
- }
305
- });
275
+ h: height
276
+ },
277
+ rows,
278
+ columns,
279
+ frameWidth,
280
+ frameHeight,
281
+ scale: '1'
282
+ }
283
+ };
284
+ for (let row = 0; row < rows; row++) {
285
+ for (let col = 0; col < columns; col++) {
286
+ const isExcluded = (emptyFrames !== null && emptyFrames !== void 0 ? emptyFrames : []).some(coord => coord.row === row && coord.col === col);
287
+ if (isExcluded) {
288
+ continue;
289
+ }
290
+ if (Array.isArray(nonJsonFrames.frames)) {
291
+ nonJsonFrames.frames.push({
292
+ frame: {
293
+ x: col * frameWidth,
294
+ y: row * frameHeight,
295
+ w: frameWidth,
296
+ h: frameHeight
297
+ },
298
+ scaleRatio: 1,
299
+ rotated: false,
300
+ trimmed: false,
301
+ spriteSourceSize: {
302
+ x: 0,
303
+ y: 0,
304
+ w: frameWidth,
305
+ h: frameHeight
306
+ },
307
+ sourceSize: {
308
+ w: frameWidth,
309
+ h: frameHeight
310
+ }
311
+ });
312
+ }
306
313
  }
307
314
  }
315
+ aspect = calculateAspectRatio(frameWidth, frameHeight, aspectFactor);
316
+ spriteDataRef.current = nonJsonFrames;
308
317
  }
309
- for (const frame in sprites) {
310
- sprites[frame].frame = calculateScaleRatio(sprites[frame]);
311
- }
312
- return sprites;
313
- } else {
314
- // we need to convert it into an array
315
- let spritesArr = [];
316
- for (const key in data.frames) {
317
- spritesArr.push(data.frames[key]);
318
- }
319
- spritesArr = calculateScaleRatio(spritesArr);
320
- return spritesArr;
321
- }
322
- };
323
318
 
324
- // calculate scale ratio for the frames
325
- const calculateScaleRatio = frames => {
326
- // Find the largest frame
327
- let largestFrame = null;
328
- for (const frame of frames) {
319
+ //scale ratio for standalone sprite
320
+ if (spriteDataRef.current && spriteDataRef.current.frames) {
321
+ spriteDataRef.current.frames = calculateScaleRatio(spriteDataRef.current.frames);
322
+ }
323
+ } else if (_spriteTexture) {
324
+ spriteDataRef.current = json;
325
+ spriteDataRef.current.frames = parseFrames();
326
+ totalFrames.current = Array.isArray(json.frames) ? json.frames.length : Object.keys(json.frames).length;
329
327
  const {
330
328
  w,
331
329
  h
332
- } = frame.frame;
333
- const area = w * h;
334
- if (!largestFrame || area > largestFrame.area) {
335
- largestFrame = {
336
- ...frame.frame,
337
- area
338
- };
339
- }
330
+ } = getFirstFrame(json.frames).sourceSize;
331
+ aspect = calculateAspectRatio(w, h, aspectFactor);
332
+ }
333
+ setSpriteData(spriteDataRef.current);
334
+ if ('encoding' in _spriteTexture) {
335
+ _spriteTexture.encoding = 3001; // sRGBEncoding
336
+ } else if ('colorSpace' in _spriteTexture) {
337
+ //@ts-ignore
338
+ _spriteTexture.colorSpace = THREE.SRGBColorSpace;
340
339
  }
340
+ setSpriteTexture(_spriteTexture);
341
+ setSpriteObj({
342
+ spriteTexture: _spriteTexture,
343
+ spriteData: spriteDataRef.current,
344
+ aspect: aspect
345
+ });
346
+ }, [getRowsAndColumns, numberOfFrames, parseFrames, calculateAspectRatio, calculateScaleRatio]);
341
347
 
342
- // Set scaleRatio property on each frame
343
- for (const frame of frames) {
344
- var _largestFrame;
345
- const {
346
- w,
347
- h
348
- } = frame.frame;
349
- const area = w * h;
350
- if (area === ((_largestFrame = largestFrame) == null ? void 0 : _largestFrame.area)) {
351
- frame.scaleRatio = 1;
352
- } else {
353
- var _largestFrame2;
354
- frame.scaleRatio = Math.sqrt(area / ((_largestFrame2 = largestFrame) == null ? void 0 : _largestFrame2.area));
355
- }
348
+ /**
349
+ *
350
+ */
351
+ const loadJsonAndTextureAndExecuteCallback = React.useCallback((jsonUrl, textureUrl, callback) => {
352
+ const jsonPromise = fetch(jsonUrl).then(response => response.json());
353
+ const texturePromise = new Promise(resolve => {
354
+ textureLoader.load(textureUrl, resolve);
355
+ });
356
+ Promise.all([jsonPromise, texturePromise]).then(response => {
357
+ callback(response[0], response[1]);
358
+ });
359
+ }, [textureLoader]);
360
+ const loadStandaloneSprite = React.useCallback(textureUrl => {
361
+ if (!textureUrl && !inputRef.current) {
362
+ throw new Error('Either textureUrl or input must be provided');
356
363
  }
357
- return frames;
358
- };
364
+ const validUrl = textureUrl !== null && textureUrl !== void 0 ? textureUrl : inputRef.current;
365
+ if (!validUrl) {
366
+ throw new Error('A valid texture URL must be provided');
367
+ }
368
+ textureLoader.load(validUrl, texture => parseSpriteData(null, texture));
369
+ }, [textureLoader, parseSpriteData]);
370
+ const loadJsonAndTexture = React.useCallback((textureUrl, jsonUrl) => {
371
+ if (jsonUrl && textureUrl) {
372
+ loadJsonAndTextureAndExecuteCallback(jsonUrl, textureUrl, parseSpriteData);
373
+ } else {
374
+ loadStandaloneSprite(textureUrl);
375
+ }
376
+ }, [loadJsonAndTextureAndExecuteCallback, loadStandaloneSprite, parseSpriteData]);
377
+ React.useLayoutEffect(() => {
378
+ if (jsonRef.current && inputRef.current) {
379
+ loadJsonAndTextureAndExecuteCallback(jsonRef.current, inputRef.current, parseSpriteData);
380
+ } else if (inputRef.current) {
381
+ // only load the texture, this is an image sprite only
382
+ loadStandaloneSprite();
383
+ }
384
+ const _inputRef = inputRef.current;
385
+ return () => {
386
+ if (_inputRef) {
387
+ useLoader.clear(TextureLoader, _inputRef);
388
+ }
389
+ };
390
+ }, [loadJsonAndTextureAndExecuteCallback, loadStandaloneSprite, parseSpriteData]);
359
391
  React.useLayoutEffect(() => {
360
- onLoad == null || onLoad(spriteTexture, spriteData);
361
- }, [spriteTexture, spriteData]);
392
+ onLoad == null || onLoad(spriteTexture, spriteData !== null && spriteData !== void 0 ? spriteData : null);
393
+ }, [spriteTexture, spriteData, onLoad]);
362
394
  return {
363
395
  spriteObj,
364
396
  loadJsonAndTexture
@@ -367,4 +399,4 @@ function useSpriteLoader(input, json, animationNames, numberOfFrames, onLoad, ca
367
399
  useSpriteLoader.preload = url => useLoader.preload(TextureLoader, url);
368
400
  useSpriteLoader.clear = input => useLoader.clear(TextureLoader, input);
369
401
 
370
- export { calculateAspectRatio, checkIfFrameIsEmpty, getFirstItem, useSpriteLoader };
402
+ export { checkIfFrameIsEmpty, getFirstFrame, useSpriteLoader };