Justin Haaheim commited on
Commit
3459a79
1 Parent(s): 6535945

Copy over my latest oss cleanup changes

Browse files
streaming-react-app/.gitignore CHANGED
@@ -10,6 +10,7 @@ lerna-debug.log*
10
  node_modules
11
  dist
12
  dist-ssr
 
13
  *.local
14
 
15
  # Editor directories and files
 
10
  node_modules
11
  dist
12
  dist-ssr
13
+ build
14
  *.local
15
 
16
  # Editor directories and files
streaming-react-app/package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
streaming-react-app/src/SocketWrapper.tsx CHANGED
@@ -11,9 +11,8 @@ import {getURLParams} from './URLParams';
11
 
12
  // The time to wait before showing a "disconnected" screen upon initial app load
13
  const INITIAL_DISCONNECT_SCREEN_DELAY = 2000;
14
- const SERVER_URL_DEFAULT = `${window.location.protocol === "https:" ? "wss" : "ws"
15
- }://${window.location.host}`;
16
-
17
  export default function SocketWrapper({children}) {
18
  const [socket, setSocket] = useState<Socket | null>(null);
19
  const [connected, setConnected] = useState<boolean | null>(null);
@@ -63,7 +62,6 @@ export default function SocketWrapper({children}) {
63
  // want that because that'd mean awful performance. It'd be better for the app
64
  // to simply break in that case and not connect.
65
  transports: ['websocket'],
66
- path: '/ws/socket.io'
67
  });
68
 
69
  const onServerID = (serverID: string) => {
 
11
 
12
  // The time to wait before showing a "disconnected" screen upon initial app load
13
  const INITIAL_DISCONNECT_SCREEN_DELAY = 2000;
14
+ const SERVER_URL_DEFAULT = 'localhost:8000';
15
+
 
16
  export default function SocketWrapper({children}) {
17
  const [socket, setSocket] = useState<Socket | null>(null);
18
  const [connected, setConnected] = useState<boolean | null>(null);
 
62
  // want that because that'd mean awful performance. It'd be better for the app
63
  // to simply break in that case and not connect.
64
  transports: ['websocket'],
 
65
  });
66
 
67
  const onServerID = (serverID: string) => {
streaming-react-app/src/StreamingInterface.tsx CHANGED
@@ -58,6 +58,7 @@ import {CURSOR_BLINK_INTERVAL_MS} from './cursorBlinkInterval';
58
  import {getURLParams} from './URLParams';
59
  import debug from './debug';
60
  import DebugSection from './DebugSection';
 
61
  import {Grid} from '@mui/material';
62
 
63
  const AUDIO_STREAM_DEFAULTS: {
@@ -171,6 +172,9 @@ export default function StreamingInterface() {
171
 
172
  // Dynamic Params:
173
  const [targetLang, setTargetLang] = useState<string | null>(null);
 
 
 
174
 
175
  const [serverDebugFlag, setServerDebugFlag] = useState<boolean>(
176
  debugParam ?? false,
@@ -252,6 +256,7 @@ export default function StreamingInterface() {
252
  setAgent((prevAgent) => {
253
  if (prevAgent?.name !== newAgent?.name) {
254
  setTargetLang(newAgent?.targetLangs[0] ?? null);
 
255
  }
256
  return newAgent;
257
  });
@@ -427,6 +432,7 @@ export default function StreamingInterface() {
427
  // available before actually configuring and starting the stream
428
  const fullDynamicConfig: DynamicConfig = {
429
  targetLanguage: targetLang,
 
430
  };
431
 
432
  await onSetDynamicConfig(fullDynamicConfig);
@@ -752,11 +758,6 @@ export default function StreamingInterface() {
752
  Seamless Translation
753
  </Typography>
754
  </div>
755
- <div>
756
- <Typography variant="body2" sx={{color: '#65676B'}}>
757
- Welcome! Join a room as speaker or listener (or both), and share the room code to invite listeners.
758
- </Typography>
759
- </div>
760
  </div>
761
 
762
  <Stack spacing="22px" direction="column">
@@ -830,6 +831,11 @@ export default function StreamingInterface() {
830
  </Select>
831
  </FormControl>
832
 
 
 
 
 
 
833
  </Stack>
834
 
835
  <Stack spacing={0.5}>
@@ -895,6 +901,28 @@ export default function StreamingInterface() {
895
  spacing={1}
896
  alignItems="flex-start"
897
  sx={{flexGrow: 1}}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
  {isListener && (
899
  <Box
900
  sx={{
@@ -911,13 +939,6 @@ export default function StreamingInterface() {
911
  </Grid>
912
  </Stack>
913
 
914
- <Typography variant="body2">
915
- Note: we don't recommend echo cancellation, as it may distort
916
- the input audio (dropping words/sentences) if there is output
917
- audio playing. Instead, you should use headphones if you'd like
918
- to listen to the output audio while speaking.
919
- </Typography>
920
-
921
  <Stack
922
  direction="row"
923
  spacing={2}
@@ -967,7 +988,7 @@ export default function StreamingInterface() {
967
  }
968
  label="Noise Suppression (Browser)"
969
  />
970
- <FormControlLabel
971
  control={
972
  <Checkbox
973
  checked={
 
58
  import {getURLParams} from './URLParams';
59
  import debug from './debug';
60
  import DebugSection from './DebugSection';
61
+ import Switch from '@mui/material/Switch';
62
  import {Grid} from '@mui/material';
63
 
64
  const AUDIO_STREAM_DEFAULTS: {
 
172
 
173
  // Dynamic Params:
174
  const [targetLang, setTargetLang] = useState<string | null>(null);
175
+ const [enableExpressive, setEnableExpressive] = useState<boolean | null>(
176
+ null,
177
+ );
178
 
179
  const [serverDebugFlag, setServerDebugFlag] = useState<boolean>(
180
  debugParam ?? false,
 
256
  setAgent((prevAgent) => {
257
  if (prevAgent?.name !== newAgent?.name) {
258
  setTargetLang(newAgent?.targetLangs[0] ?? null);
259
+ setEnableExpressive(null);
260
  }
261
  return newAgent;
262
  });
 
432
  // available before actually configuring and starting the stream
433
  const fullDynamicConfig: DynamicConfig = {
434
  targetLanguage: targetLang,
435
+ expressive: enableExpressive,
436
  };
437
 
438
  await onSetDynamicConfig(fullDynamicConfig);
 
758
  Seamless Translation
759
  </Typography>
760
  </div>
 
 
 
 
 
761
  </div>
762
 
763
  <Stack spacing="22px" direction="column">
 
831
  </Select>
832
  </FormControl>
833
 
834
+ <Typography variant="body2">
835
+ {`Supported Source Languages: ${
836
+ currentAgent?.sourceLangs.join(', ') ?? 'None'
837
+ }`}
838
+ </Typography>
839
  </Stack>
840
 
841
  <Stack spacing={0.5}>
 
901
  spacing={1}
902
  alignItems="flex-start"
903
  sx={{flexGrow: 1}}>
904
+ {currentAgent?.dynamicParams?.includes(
905
+ 'expressive',
906
+ ) && (
907
+ <FormControlLabel
908
+ control={
909
+ <Switch
910
+ checked={enableExpressive ?? false}
911
+ onChange={(
912
+ event: React.ChangeEvent<HTMLInputElement>,
913
+ ) => {
914
+ const newValue = event.target.checked;
915
+ setEnableExpressive(newValue);
916
+ onSetDynamicConfig({
917
+ expressive: newValue,
918
+ });
919
+ }}
920
+ />
921
+ }
922
+ label="Expressive"
923
+ />
924
+ )}
925
+
926
  {isListener && (
927
  <Box
928
  sx={{
 
939
  </Grid>
940
  </Stack>
941
 
 
 
 
 
 
 
 
942
  <Stack
943
  direction="row"
944
  spacing={2}
 
988
  }
989
  label="Noise Suppression (Browser)"
990
  />
991
+ <FormControlLabel
992
  control={
993
  <Checkbox
994
  checked={
streaming-react-app/src/URLParams.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { getBooleanParamFlag, getStringParamFlag } from './getParamFlag';
2
- import { URLParamsObject } from './types/URLParamsTypes';
3
 
4
  /**
5
  * These are the URL parameters you can provide to the app to change its behavior.
 
1
+ import {getBooleanParamFlag, getStringParamFlag} from './getParamFlag';
2
+ import {URLParamsObject} from './types/URLParamsTypes';
3
 
4
  /**
5
  * These are the URL parameters you can provide to the app to change its behavior.
streaming-react-app/src/react-xr/TextBlocks.tsx CHANGED
@@ -1,9 +1,8 @@
1
- import {JSX, useEffect, useRef, useState} from 'react';
2
  import robotoFontFamilyJson from '../assets/RobotoMono-Regular-msdf.json?url';
3
  import robotoFontTexture from '../assets/RobotoMono-Regular.png';
4
  import ThreeMeshUIText, {ThreeMeshUITextType} from './ThreeMeshUIText';
5
- import {getURLParams} from '../URLParams';
6
- import {CURSOR_BLINK_INTERVAL_MS} from '../cursorBlinkInterval';
7
 
8
  const NUM_LINES = 3;
9
 
@@ -22,44 +21,80 @@ const SCROLL_Y_DELTA = 0.001;
22
  const OFFSET = 0.01;
23
  const OFFSET_WIDTH = OFFSET * 3;
24
 
25
- type Props = {
 
 
 
 
 
 
 
26
  content: string;
27
  // The actual position or end position when animating
28
  y: number;
29
  // The start position when animating
30
  startY: number;
31
- width: number;
32
- height: number;
33
  textOpacity: number;
34
  backgroundOpacity: number;
35
- // Use this to keep track of sentence + line position for animation
36
- index: string;
37
- enableAnimation: boolean;
 
 
 
 
 
 
 
 
38
  };
39
 
40
  function TextBlock({
41
  content,
42
  y,
43
  startY,
44
- width,
45
- height,
46
  textOpacity,
47
  backgroundOpacity,
48
  index,
49
- enableAnimation,
50
- }: Props) {
51
  const [scrollY, setScrollY] = useState<number>(y);
52
-
53
  // We are reusing text blocks so this keeps track of when we changed rows so we can restart animation
54
- const lastIndex = useRef<string>(index);
55
  useEffect(() => {
56
  if (index != lastIndex.current) {
57
  lastIndex.current = index;
58
- enableAnimation && setScrollY(startY);
59
  } else if (scrollY < y) {
60
  setScrollY((prev) => prev + SCROLL_Y_DELTA);
61
  }
62
- }, [enableAnimation, index, scrollY, setScrollY, startY, y]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  // This is needed to update text content (doesn't work if we just update the content prop)
65
  const textRef = useRef<ThreeMeshUITextType>();
@@ -111,125 +146,162 @@ function TextBlock({
111
  );
112
  }
113
 
114
- // Background behind the text so it covers any missing spaces
115
- function TranscriptionPanel() {
116
- const panelHeight = LINE_HEIGHT * NUM_LINES + 2 * BLOCK_SPACING + 2 * OFFSET;
117
- const xPosition = OFFSET_WIDTH;
118
- return (
119
- <block
120
- args={[
121
- {
122
- backgroundOpacity: 1,
123
- width:
124
- MAX_WIDTH * ((CHARS_PER_LINE + 2) / CHARS_PER_LINE) +
125
- 2 * OFFSET_WIDTH,
126
- height: panelHeight,
127
- borderRadius: 0,
128
- },
129
- ]}
130
- position={[
131
- -OFFSET + xPosition,
132
- Y_COORD_START + panelHeight / 2 - 2 * OFFSET,
133
- Z_COORD,
134
- ]}></block>
135
- );
136
  }
137
 
138
  export default function TextBlocks({
139
- sentences,
140
- blinkCursor,
141
  }: {
142
- sentences: string[][];
143
- blinkCursor: boolean;
144
  }) {
145
- const showTranscriptionPanel =
146
- getURLParams().ARTranscriptionType === 'lines_with_background';
147
- const textBlocks: JSX.Element[] = [];
 
 
 
 
 
 
 
 
 
 
148
 
149
- const [cursorBlinkOn, setCursorBlinkOn] = useState(false);
150
  useEffect(() => {
151
- if (blinkCursor) {
152
- const interval = setInterval(() => {
153
- setCursorBlinkOn((prev) => !prev);
154
- }, CURSOR_BLINK_INTERVAL_MS);
 
 
 
155
 
156
- return () => clearInterval(interval);
157
- } else {
158
- setCursorBlinkOn(false);
159
- }
160
- }, [blinkCursor]);
161
 
162
- // Start from bottom and populate most recent sentences by line until we fill max lines.
163
- let currentY = Y_COORD_START;
164
- for (let i = sentences.length - 1; i >= 0; i--) {
165
- const sentenceLines = sentences[i];
166
- for (let j = sentenceLines.length - 1; j >= 0; j--) {
167
- if (textBlocks.length == NUM_LINES) {
168
- if (showTranscriptionPanel) {
169
- textBlocks.push(<TranscriptionPanel key={textBlocks.length} />);
170
- }
171
- return textBlocks;
172
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- const isBottomSentence = i === sentences.length - 1;
175
- const isBottomLine = isBottomSentence && textBlocks.length === 0;
176
- const y = currentY + LINE_HEIGHT / 2;
177
- let textBlockLine = sentenceLines[j];
178
- const numChars = textBlockLine.length;
179
 
180
- if (cursorBlinkOn && isBottomLine) {
181
- textBlockLine = textBlockLine + '|';
 
 
182
  }
 
183
 
184
- // Accounting for potential cursor for block width (the +1)
185
- const blockWidth =
186
- (numChars + (isBottomLine ? 1.1 : 0) + (numChars < 10 ? 1 : 0)) *
187
- CHAR_WIDTH;
188
- const textOpacity = 1 - 0.1 * textBlocks.length;
189
- textBlocks.push(
190
- <TextBlock
191
- key={textBlocks.length}
192
- y={y}
193
- startY={currentY}
194
- index={`${sentences.length - i},${j}`}
195
- textOpacity={textOpacity}
196
- backgroundOpacity={0.98}
197
- height={LINE_HEIGHT}
198
- width={blockWidth}
199
- // content={"BLOCK " + textBlocks.length + ": " + content}
200
- content={textBlockLine}
201
- enableAnimation={!isBottomLine}
202
- />,
203
- );
204
 
205
- currentY = y + LINE_HEIGHT / 2;
 
 
 
 
 
206
  }
207
- currentY += showTranscriptionPanel ? BLOCK_SPACING / 3 : BLOCK_SPACING;
208
- }
209
 
210
- const numRemainingBlocks = textBlocks.length - NUM_LINES;
211
- if (numRemainingBlocks > 0) {
212
- Array.from({length: numRemainingBlocks}).forEach(() => {
213
- // Push in non display blocks because mesh UI crashes if elements are add / removed from screen.
214
- textBlocks.push(
215
- <TextBlock
216
- key={textBlocks.length}
217
- y={Y_COORD_START}
218
- startY={0}
219
- index="0,0"
220
- textOpacity={0}
221
- backgroundOpacity={0}
222
- enableAnimation={false}
223
- width={MAX_WIDTH}
224
- height={LINE_HEIGHT}
225
- content=""
226
- />,
227
- );
228
  });
229
- }
230
 
231
- if (showTranscriptionPanel) {
232
- textBlocks.push(<TranscriptionPanel key={textBlocks.length} />);
 
 
 
 
233
  }
234
- return textBlocks;
 
 
 
 
 
235
  }
 
1
+ import {useEffect, useRef, useState} from 'react';
2
  import robotoFontFamilyJson from '../assets/RobotoMono-Regular-msdf.json?url';
3
  import robotoFontTexture from '../assets/RobotoMono-Regular.png';
4
  import ThreeMeshUIText, {ThreeMeshUITextType} from './ThreeMeshUIText';
5
+ import supportedCharSet from './supportedCharSet';
 
6
 
7
  const NUM_LINES = 3;
8
 
 
21
  const OFFSET = 0.01;
22
  const OFFSET_WIDTH = OFFSET * 3;
23
 
24
+ const CHARS_PER_SECOND = 10;
25
+
26
+ // The tick interval
27
+ const RENDER_INTERVAL = 300;
28
+
29
+ const CURSOR_BLINK_INTERVAL_MS = 1000;
30
+
31
+ type TextBlockProps = {
32
  content: string;
33
  // The actual position or end position when animating
34
  y: number;
35
  // The start position when animating
36
  startY: number;
 
 
37
  textOpacity: number;
38
  backgroundOpacity: number;
39
+ index: number;
40
+ isBottomLine: boolean;
41
+ // key: number;
42
+ };
43
+
44
+ type TranscriptState = {
45
+ textBlocksProps: TextBlockProps[];
46
+ lastTranslationStringIndex: number;
47
+ lastTranslationLineStartIndex: number;
48
+ transcriptLines: string[];
49
+ lastRenderTime: number;
50
  };
51
 
52
  function TextBlock({
53
  content,
54
  y,
55
  startY,
 
 
56
  textOpacity,
57
  backgroundOpacity,
58
  index,
59
+ isBottomLine,
60
+ }: TextBlockProps) {
61
  const [scrollY, setScrollY] = useState<number>(y);
 
62
  // We are reusing text blocks so this keeps track of when we changed rows so we can restart animation
63
+ const lastIndex = useRef<number>(index);
64
  useEffect(() => {
65
  if (index != lastIndex.current) {
66
  lastIndex.current = index;
67
+ !isBottomLine && setScrollY(startY);
68
  } else if (scrollY < y) {
69
  setScrollY((prev) => prev + SCROLL_Y_DELTA);
70
  }
71
+ }, [isBottomLine, index, scrollY, setScrollY, startY, y]);
72
+
73
+ const [cursorBlinkOn, setCursorBlinkOn] = useState(false);
74
+ useEffect(() => {
75
+ if (isBottomLine) {
76
+ const interval = setInterval(() => {
77
+ setCursorBlinkOn((prev) => !prev);
78
+ }, CURSOR_BLINK_INTERVAL_MS);
79
+
80
+ return () => clearInterval(interval);
81
+ } else {
82
+ setCursorBlinkOn(false);
83
+ }
84
+ }, [isBottomLine]);
85
+
86
+ const numChars = content.length;
87
+
88
+ if (cursorBlinkOn) {
89
+ content = content + '|';
90
+ }
91
+
92
+ // Accounting for potential cursor for block width (the +1)
93
+ const width =
94
+ (numChars + (isBottomLine ? 1.1 : 0) + (numChars < 10 ? 1 : 0)) *
95
+ CHAR_WIDTH;
96
+
97
+ const height = LINE_HEIGHT;
98
 
99
  // This is needed to update text content (doesn't work if we just update the content prop)
100
  const textRef = useRef<ThreeMeshUITextType>();
 
146
  );
147
  }
148
 
149
+ function initialTextBlockProps(count: number): TextBlockProps[] {
150
+ return Array.from({length: count}).map(() => {
151
+ // Push in non display blocks because mesh UI crashes if elements are add / removed from screen.
152
+ return {
153
+ y: Y_COORD_START,
154
+ startY: 0,
155
+ index: 0,
156
+ textOpacity: 0,
157
+ backgroundOpacity: 0,
158
+ width: MAX_WIDTH,
159
+ height: LINE_HEIGHT,
160
+ content: '',
161
+ isBottomLine: true,
162
+ };
163
+ });
 
 
 
 
 
 
 
164
  }
165
 
166
  export default function TextBlocks({
167
+ translationText,
 
168
  }: {
169
+ translationText: string;
 
170
  }) {
171
+ const transcriptStateRef = useRef<TranscriptState>({
172
+ textBlocksProps: initialTextBlockProps(NUM_LINES),
173
+ lastTranslationStringIndex: 0,
174
+ lastTranslationLineStartIndex: 0,
175
+ transcriptLines: [],
176
+ lastRenderTime: new Date().getTime(),
177
+ });
178
+
179
+ const transcriptState = transcriptStateRef.current;
180
+ const {textBlocksProps, lastTranslationStringIndex, lastRenderTime} =
181
+ transcriptState;
182
+
183
+ const [charsToRender, setCharsToRender] = useState<number>(0);
184
 
 
185
  useEffect(() => {
186
+ const interval = setInterval(() => {
187
+ const currentTime = new Date().getTime();
188
+ const charsToRender = Math.round(
189
+ ((currentTime - lastRenderTime) * CHARS_PER_SECOND) / 1000,
190
+ );
191
+ setCharsToRender(charsToRender);
192
+ }, RENDER_INTERVAL);
193
 
194
+ return () => clearInterval(interval);
195
+ }, [lastRenderTime]);
 
 
 
196
 
197
+ const currentTime = new Date().getTime();
198
+ if (charsToRender < 1) {
199
+ return textBlocksProps.map((props, idx) => (
200
+ <TextBlock {...props} key={idx} />
201
+ ));
202
+ }
203
+
204
+ const nextTranslationStringIndex = Math.min(
205
+ lastTranslationStringIndex + charsToRender,
206
+ translationText.length,
207
+ );
208
+ const newString = translationText.substring(
209
+ lastTranslationStringIndex,
210
+ nextTranslationStringIndex,
211
+ );
212
+ if (nextTranslationStringIndex === lastTranslationStringIndex) {
213
+ transcriptState.lastRenderTime = currentTime;
214
+ return textBlocksProps.map((props, idx) => (
215
+ <TextBlock {...props} key={idx} />
216
+ ));
217
+ }
218
+
219
+ // Wait until more characters are accumulated if its just blankspace
220
+ if (/^\s*$/.test(newString)) {
221
+ transcriptState.lastRenderTime = currentTime;
222
+ return textBlocksProps.map((props, idx) => (
223
+ <TextBlock {...props} key={idx} />
224
+ ));
225
+ }
226
+
227
+ // Ideally we continue where we left off but this is complicated when we have mid-words. Recalculating for now
228
+ const runAll = true;
229
+ const newSentences = runAll
230
+ ? translationText.substring(0, nextTranslationStringIndex).split('\n')
231
+ : newString.split('\n');
232
+ const transcriptLines = runAll ? [''] : transcriptState.transcriptLines;
233
+ newSentences.forEach((newSentence, sentenceIdx) => {
234
+ const words = newSentence.split(/\s+/);
235
+ words.forEach((word) => {
236
+ const filteredWord = [...word]
237
+ .filter((c) => {
238
+ if (supportedCharSet().has(c)) {
239
+ return true;
240
+ }
241
+ console.error(
242
+ `Unsupported char ${c} - make sure this is supported in the font family msdf file`,
243
+ );
244
+ return false;
245
+ })
246
+ .join('');
247
 
248
+ const lastLineSoFar = transcriptLines[0];
249
+ const charCount = lastLineSoFar.length + filteredWord.length + 1;
 
 
 
250
 
251
+ if (charCount <= CHARS_PER_LINE) {
252
+ transcriptLines[0] = lastLineSoFar + ' ' + filteredWord;
253
+ } else {
254
+ transcriptLines.unshift(filteredWord);
255
  }
256
+ });
257
 
258
+ if (sentenceIdx < newSentences.length - 1) {
259
+ transcriptLines.unshift('\n');
260
+ transcriptLines.unshift('');
261
+ }
262
+ });
263
+
264
+ transcriptState.transcriptLines = transcriptLines;
265
+ transcriptState.lastTranslationStringIndex = nextTranslationStringIndex;
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
+ const newTextBlocksProps: TextBlockProps[] = [];
268
+ let currentY = Y_COORD_START;
269
+
270
+ transcriptLines.forEach((line, i) => {
271
+ if (newTextBlocksProps.length == NUM_LINES) {
272
+ return;
273
  }
 
 
274
 
275
+ // const line = transcriptLines[i];
276
+ if (line === '\n') {
277
+ currentY += BLOCK_SPACING;
278
+ return;
279
+ }
280
+ const y = currentY + LINE_HEIGHT / 2;
281
+ const isBottomLine = newTextBlocksProps.length === 0;
282
+
283
+ const textOpacity = 1 - 0.1 * newTextBlocksProps.length;
284
+ newTextBlocksProps.push({
285
+ y,
286
+ startY: currentY,
287
+ index: i,
288
+ textOpacity,
289
+ backgroundOpacity: 0.98,
290
+ content: line,
291
+ isBottomLine,
 
292
  });
 
293
 
294
+ currentY = y + LINE_HEIGHT / 2;
295
+ });
296
+
297
+ const numRemainingBlocks = NUM_LINES - newTextBlocksProps.length;
298
+ if (numRemainingBlocks > 0) {
299
+ newTextBlocksProps.push(...initialTextBlockProps(numRemainingBlocks));
300
  }
301
+
302
+ transcriptState.textBlocksProps = newTextBlocksProps;
303
+ transcriptState.lastRenderTime = currentTime;
304
+ return newTextBlocksProps.map((props, idx) => (
305
+ <TextBlock {...props} key={idx} />
306
+ ));
307
  }
streaming-react-app/src/react-xr/XRConfig.tsx CHANGED
@@ -25,29 +25,15 @@ import {BLACK, WHITE} from './Colors';
25
  import robotoFontFamilyJson from '../assets/RobotoMono-Regular-msdf.json?url';
26
  import robotoFontTexture from '../assets/RobotoMono-Regular.png';
27
  import {getURLParams} from '../URLParams';
28
- import TextBlocks, {CHARS_PER_LINE} from './TextBlocks';
29
  import {BufferedSpeechPlayer} from '../createBufferedSpeechPlayer';
30
  import {CURSOR_BLINK_INTERVAL_MS} from '../cursorBlinkInterval';
 
31
 
32
  // Adds on react JSX for add-on libraries to react-three-fiber
33
  extend(ThreeMeshUI);
34
  extend({TextGeometry});
35
 
36
- async function fetchSupportedCharSet(): Promise<Set<string>> {
37
- try {
38
- const response = await fetch(robotoFontFamilyJson);
39
- const fontFamily = await response.json();
40
-
41
- return new Set(fontFamily.info.charset);
42
- } catch (e) {
43
- console.error('Failed to fetch supported XR charset', e);
44
- return new Set();
45
- }
46
- }
47
-
48
- let supportedCharSet = new Set();
49
- fetchSupportedCharSet().then((result) => (supportedCharSet = result));
50
-
51
  // This component wraps any children so it is positioned relative to the camera, rather than from the origin
52
  function CameraLinkedObject({children}) {
53
  const camera = useThree((state) => state.camera);
@@ -76,10 +62,7 @@ function ThreeMeshUIComponents({
76
  translationSentences={translationSentences}
77
  />
78
  ) : (
79
- <TranscriptPanelBlocks
80
- animateTextDisplay={animateTextDisplay}
81
- translationSentences={translationSentences}
82
- />
83
  )}
84
  {skipARIntro ? null : (
85
  <IntroPanel started={started} setStarted={setStarted} />
@@ -153,7 +136,7 @@ function TranscriptPanelSingleBlock({
153
  (wordChunks, currentWord) => {
154
  const filteredWord = [...currentWord]
155
  .filter((c) => {
156
- if (supportedCharSet.has(c)) {
157
  return true;
158
  }
159
  console.error(
@@ -223,59 +206,14 @@ function TranscriptPanelSingleBlock({
223
  // Splits up the lines into separate blocks to treat each one separately.
224
  // This allows changing of opacity, animating per line, changing height / width per line etc
225
  function TranscriptPanelBlocks({
226
- animateTextDisplay,
227
  translationSentences,
228
  }: {
229
- animateTextDisplay: boolean;
230
  translationSentences: TranslationSentences;
231
  }) {
232
- const [didReceiveTranslationSentences, setDidReceiveTranslationSentences] =
233
- // Currently causing issues with displaying dummy text, skip over
234
- useState(false);
235
-
236
- // Normally we don't setState in render, but here we need to for computed state, and this if statement assures it won't loop infinitely
237
- if (!didReceiveTranslationSentences && translationSentences.length > 0) {
238
- setDidReceiveTranslationSentences(true);
239
- }
240
-
241
- const initialPrompt = 'Listening...';
242
- const transcriptSentences: string[] = didReceiveTranslationSentences
243
- ? translationSentences
244
- : [initialPrompt];
245
-
246
- // The transcript is an array of sentences. For each sentence we break this down into an array of words per line.
247
- // This is needed so we can "scroll" through without changing the order of words in the transcript
248
- const sentenceLines = transcriptSentences.map((sentence) => {
249
- const words = sentence.split(/\s+/);
250
- // Here we break each sentence up with newlines so all words per line fit within the panel
251
- return words.reduce(
252
- (wordChunks, currentWord) => {
253
- const filteredWord = [...currentWord]
254
- .filter((c) => {
255
- if (supportedCharSet.has(c)) {
256
- return true;
257
- }
258
- console.error(
259
- `Unsupported char ${c} - make sure this is supported in the font family msdf file`,
260
- );
261
- return false;
262
- })
263
- .join('');
264
- const lastLineSoFar = wordChunks[wordChunks.length - 1];
265
- const charCount = lastLineSoFar.length + filteredWord.length + 1;
266
- if (charCount <= CHARS_PER_LINE) {
267
- wordChunks[wordChunks.length - 1] =
268
- lastLineSoFar + ' ' + filteredWord;
269
- } else {
270
- wordChunks.push(filteredWord);
271
- }
272
- return wordChunks;
273
- },
274
- [''],
275
- );
276
- });
277
  return (
278
- <TextBlocks sentences={sentenceLines} blinkCursor={animateTextDisplay} />
 
 
279
  );
280
  }
281
 
@@ -361,6 +299,8 @@ export type XRConfigProps = {
361
  startStreaming: () => Promise<void>;
362
  stopStreaming: () => Promise<void>;
363
  debugParam: boolean | null;
 
 
364
  };
365
 
366
  export default function XRConfig(props: XRConfigProps) {
 
25
  import robotoFontFamilyJson from '../assets/RobotoMono-Regular-msdf.json?url';
26
  import robotoFontTexture from '../assets/RobotoMono-Regular.png';
27
  import {getURLParams} from '../URLParams';
28
+ import TextBlocks from './TextBlocks';
29
  import {BufferedSpeechPlayer} from '../createBufferedSpeechPlayer';
30
  import {CURSOR_BLINK_INTERVAL_MS} from '../cursorBlinkInterval';
31
+ import supportedCharSet from './supportedCharSet';
32
 
33
  // Adds on react JSX for add-on libraries to react-three-fiber
34
  extend(ThreeMeshUI);
35
  extend({TextGeometry});
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  // This component wraps any children so it is positioned relative to the camera, rather than from the origin
38
  function CameraLinkedObject({children}) {
39
  const camera = useThree((state) => state.camera);
 
62
  translationSentences={translationSentences}
63
  />
64
  ) : (
65
+ <TranscriptPanelBlocks translationSentences={translationSentences} />
 
 
 
66
  )}
67
  {skipARIntro ? null : (
68
  <IntroPanel started={started} setStarted={setStarted} />
 
136
  (wordChunks, currentWord) => {
137
  const filteredWord = [...currentWord]
138
  .filter((c) => {
139
+ if (supportedCharSet().has(c)) {
140
  return true;
141
  }
142
  console.error(
 
206
  // Splits up the lines into separate blocks to treat each one separately.
207
  // This allows changing of opacity, animating per line, changing height / width per line etc
208
  function TranscriptPanelBlocks({
 
209
  translationSentences,
210
  }: {
 
211
  translationSentences: TranslationSentences;
212
  }) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  return (
214
+ <TextBlocks
215
+ translationText={'Listening...\n' + translationSentences.join('\n')}
216
+ />
217
  );
218
  }
219
 
 
299
  startStreaming: () => Promise<void>;
300
  stopStreaming: () => Promise<void>;
301
  debugParam: boolean | null;
302
+ onARVisible?: () => void;
303
+ onARHidden?: () => void;
304
  };
305
 
306
  export default function XRConfig(props: XRConfigProps) {
streaming-react-app/src/react-xr/XRDialog.tsx CHANGED
@@ -8,27 +8,12 @@ import {
8
  Typography,
9
  } from '@mui/material';
10
  import CloseIcon from '@mui/icons-material/Close';
 
11
  import {useEffect, useRef, useState} from 'react';
12
  import './XRDialog.css';
13
  import {getRenderer, init, updatetranslationText} from './XRRendering';
14
  import ARButton from './ARButton';
15
  import {getURLParams} from '../URLParams';
16
- import { BufferedSpeechPlayer } from '../createBufferedSpeechPlayer';
17
- import { TranslationSentences } from '../types/StreamingTypes';
18
- import { RoomState } from '../types/RoomState';
19
-
20
- type XRConfigProps = {
21
- animateTextDisplay: boolean;
22
- bufferedSpeechPlayer: BufferedSpeechPlayer;
23
- translationSentences: TranslationSentences;
24
- roomState: RoomState | null;
25
- roomID: string | null;
26
- startStreaming: () => Promise<void>;
27
- stopStreaming: () => Promise<void>;
28
- debugParam: boolean | null;
29
- onARVisible?: () => void;
30
- onARHidden?: () => void;
31
- };
32
 
33
  function XRContent(props: XRConfigProps) {
34
  const debugParam = getURLParams().debug;
 
8
  Typography,
9
  } from '@mui/material';
10
  import CloseIcon from '@mui/icons-material/Close';
11
+ import {XRConfigProps} from './XRConfig';
12
  import {useEffect, useRef, useState} from 'react';
13
  import './XRDialog.css';
14
  import {getRenderer, init, updatetranslationText} from './XRRendering';
15
  import ARButton from './ARButton';
16
  import {getURLParams} from '../URLParams';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  function XRContent(props: XRConfigProps) {
19
  const debugParam = getURLParams().debug;
streaming-react-app/src/types/StreamingTypes.ts CHANGED
@@ -1,3 +1,13 @@
 
 
 
 
 
 
 
 
 
 
1
  interface ServerTranslationDataBase {
2
  eos: boolean;
3
  event: string;
@@ -26,6 +36,7 @@ export type AgentCapabilities = {
26
  name: string;
27
  description: string;
28
  modalities: Array<OutputModalitiesBase>;
 
29
  targetLangs: Array<string>;
30
  dynamicParams: Array<DynamicParams>;
31
  };
@@ -38,10 +49,10 @@ export const SUPPORTED_OUTPUT_MODES: Array<{
38
  value: (typeof SUPPORTED_OUTPUT_MODE_VALUES)[number];
39
  label: string;
40
  }> = [
41
- { value: 's2s&t', label: 'Text & Speech' },
42
- { value: 's2t', label: 'Text' },
43
- { value: 's2s', label: 'Speech' },
44
- ];
45
 
46
  export const SUPPORTED_INPUT_SOURCE_VALUES = [
47
  'userMedia',
@@ -55,14 +66,15 @@ export const SUPPORTED_INPUT_SOURCES: Array<{
55
  value: SupportedInputSource;
56
  label: string;
57
  }> = [
58
- { value: 'userMedia', label: 'Microphone' },
59
- { value: 'displayMedia', label: 'Browser Tab' },
60
- ];
61
 
62
  export type StartStreamEventConfig = {
63
  event: 'config';
64
  rate: number;
65
  model_name: string;
 
66
  debug: boolean;
67
  async_processing: boolean;
68
  model_type: SupportedOutputMode;
@@ -70,8 +82,8 @@ export type StartStreamEventConfig = {
70
  };
71
 
72
  export interface BrowserAudioStreamConfig {
73
- noiseSuppression: boolean;
74
  echoCancellation: boolean;
 
75
  }
76
 
77
  export interface ServerStateItem {
@@ -88,7 +100,7 @@ export type ServerLockObject = {
88
  export type ServerState = ServerStateItem & {
89
  agentsCapabilities: Array<AgentCapabilities>;
90
  statusByRoom: {
91
- [key: string]: { activeConnections: number; activeTranscoders: number };
92
  };
93
  totalActiveConnections: number;
94
  totalActiveTranscoders: number;
@@ -111,7 +123,10 @@ export type TranslationSentences = Array<string>;
111
 
112
  export type DynamicConfig = {
113
  // targetLanguage: a 3-letter string representing the desired output language.
 
114
  targetLanguage: string;
 
 
115
  };
116
 
117
  export type PartialDynamicConfig = Partial<DynamicConfig>;
 
1
+ export const SUPPORTED_LANGUAGE_CODES = ['en-US', 'es-ES'] as const;
2
+
3
+ export type SupportedLanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
4
+
5
+ export type StartStreamingData = {
6
+ inputLang: SupportedLanguageCode;
7
+ outputLang: SupportedLanguageCode;
8
+ outputMode: SupportedOutputMode;
9
+ };
10
+
11
  interface ServerTranslationDataBase {
12
  eos: boolean;
13
  event: string;
 
36
  name: string;
37
  description: string;
38
  modalities: Array<OutputModalitiesBase>;
39
+ sourceLangs: Array<string>;
40
  targetLangs: Array<string>;
41
  dynamicParams: Array<DynamicParams>;
42
  };
 
49
  value: (typeof SUPPORTED_OUTPUT_MODE_VALUES)[number];
50
  label: string;
51
  }> = [
52
+ {value: 's2s&t', label: 'Text & Speech'},
53
+ {value: 's2t', label: 'Text'},
54
+ {value: 's2s', label: 'Speech'},
55
+ ];
56
 
57
  export const SUPPORTED_INPUT_SOURCE_VALUES = [
58
  'userMedia',
 
66
  value: SupportedInputSource;
67
  label: string;
68
  }> = [
69
+ {value: 'userMedia', label: 'Microphone'},
70
+ {value: 'displayMedia', label: 'Browser Tab'},
71
+ ];
72
 
73
  export type StartStreamEventConfig = {
74
  event: 'config';
75
  rate: number;
76
  model_name: string;
77
+ // source_language: SupportedLanguageCode;
78
  debug: boolean;
79
  async_processing: boolean;
80
  model_type: SupportedOutputMode;
 
82
  };
83
 
84
  export interface BrowserAudioStreamConfig {
 
85
  echoCancellation: boolean;
86
+ noiseSuppression: boolean;
87
  }
88
 
89
  export interface ServerStateItem {
 
100
  export type ServerState = ServerStateItem & {
101
  agentsCapabilities: Array<AgentCapabilities>;
102
  statusByRoom: {
103
+ [key: string]: {activeConnections: number; activeTranscoders: number};
104
  };
105
  totalActiveConnections: number;
106
  totalActiveTranscoders: number;
 
123
 
124
  export type DynamicConfig = {
125
  // targetLanguage: a 3-letter string representing the desired output language.
126
+ // Supported languages are provided by the agent capabilities config
127
  targetLanguage: string;
128
+
129
+ expressive: boolean | null;
130
  };
131
 
132
  export type PartialDynamicConfig = Partial<DynamicConfig>;
streaming-react-app/src/types/URLParamsTypes.ts CHANGED
@@ -7,10 +7,10 @@ export type URLParamsObject = {
7
  serverURL: string | null;
8
  skipARIntro: boolean;
9
  ARTranscriptionType:
10
- | 'single_block'
11
- | 'lines'
12
- | 'lines_with_background'
13
- | string;
14
  };
15
 
16
  export type URLParamNames = keyof URLParamsObject;
 
7
  serverURL: string | null;
8
  skipARIntro: boolean;
9
  ARTranscriptionType:
10
+ | 'single_block'
11
+ | 'lines'
12
+ | 'lines_with_background'
13
+ | string;
14
  };
15
 
16
  export type URLParamNames = keyof URLParamsObject;
streaming-react-app/vite.config.ts CHANGED
@@ -1,13 +1,8 @@
1
- import { defineConfig } from 'vite';
2
  import react from '@vitejs/plugin-react';
3
- // import {resolve} from 'path';
4
-
5
- // const rootDir = resolve(__dirname, 'src');
6
- // const assetsDir = resolve(rootDir, 'assets');
7
- // const typesDir = resolve(__dirname, 'types');
8
 
9
  // https://vitejs.dev/config/
10
- export default defineConfig(({ command }) => {
11
  let define = {};
12
  if (command === 'serve') {
13
  define = {
@@ -17,13 +12,5 @@ export default defineConfig(({ command }) => {
17
  return {
18
  plugins: [react()],
19
  define: define,
20
- server: {
21
- proxy: {
22
- '/ws': {
23
- target: 'ws://localhost:7860',
24
- ws: true
25
- }
26
- },
27
- },
28
- }
29
  });
 
1
+ import {defineConfig} from 'vite';
2
  import react from '@vitejs/plugin-react';
 
 
 
 
 
3
 
4
  // https://vitejs.dev/config/
5
+ export default defineConfig(({command}) => {
6
  let define = {};
7
  if (command === 'serve') {
8
  define = {
 
12
  return {
13
  plugins: [react()],
14
  define: define,
15
+ };
 
 
 
 
 
 
 
 
16
  });
streaming-react-app/yarn.lock CHANGED
@@ -61,7 +61,7 @@
61
  resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz"
62
  integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==
63
 
64
- "@babel/core@^7.22.9":
65
  version "7.22.10"
66
  resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz"
67
  integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==
@@ -298,7 +298,7 @@
298
  resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz"
299
  integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
300
 
301
- "@emotion/react@11.11.1":
302
  version "11.11.1"
303
  resolved "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz"
304
  integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==
@@ -328,7 +328,7 @@
328
  resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz"
329
  integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
330
 
331
- "@emotion/styled@11.11.0":
332
  version "11.11.0"
333
  resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz"
334
  integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==
@@ -360,116 +360,11 @@
360
  resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz"
361
  integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
362
 
363
- "@esbuild/android-arm64@0.18.20":
364
- version "0.18.20"
365
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622"
366
- integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
367
-
368
- "@esbuild/android-arm@0.18.20":
369
- version "0.18.20"
370
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682"
371
- integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
372
-
373
- "@esbuild/android-x64@0.18.20":
374
- version "0.18.20"
375
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2"
376
- integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
377
-
378
- "@esbuild/darwin-arm64@0.18.20":
379
- version "0.18.20"
380
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1"
381
- integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
382
-
383
- "@esbuild/darwin-x64@0.18.20":
384
- version "0.18.20"
385
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d"
386
- integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
387
-
388
- "@esbuild/freebsd-arm64@0.18.20":
389
- version "0.18.20"
390
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54"
391
- integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
392
-
393
- "@esbuild/freebsd-x64@0.18.20":
394
- version "0.18.20"
395
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e"
396
- integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
397
-
398
- "@esbuild/linux-arm64@0.18.20":
399
- version "0.18.20"
400
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0"
401
- integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
402
-
403
- "@esbuild/linux-arm@0.18.20":
404
- version "0.18.20"
405
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0"
406
- integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
407
-
408
- "@esbuild/linux-ia32@0.18.20":
409
- version "0.18.20"
410
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7"
411
- integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
412
-
413
- "@esbuild/linux-loong64@0.18.20":
414
- version "0.18.20"
415
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d"
416
- integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
417
-
418
- "@esbuild/linux-mips64el@0.18.20":
419
- version "0.18.20"
420
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231"
421
- integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
422
-
423
- "@esbuild/linux-ppc64@0.18.20":
424
- version "0.18.20"
425
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb"
426
- integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
427
-
428
- "@esbuild/linux-riscv64@0.18.20":
429
- version "0.18.20"
430
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6"
431
- integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
432
-
433
- "@esbuild/linux-s390x@0.18.20":
434
- version "0.18.20"
435
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071"
436
- integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
437
-
438
  "@esbuild/linux-x64@0.18.20":
439
  version "0.18.20"
440
  resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
441
  integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
442
 
443
- "@esbuild/netbsd-x64@0.18.20":
444
- version "0.18.20"
445
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1"
446
- integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
447
-
448
- "@esbuild/openbsd-x64@0.18.20":
449
- version "0.18.20"
450
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae"
451
- integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
452
-
453
- "@esbuild/sunos-x64@0.18.20":
454
- version "0.18.20"
455
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d"
456
- integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
457
-
458
- "@esbuild/win32-arm64@0.18.20":
459
- version "0.18.20"
460
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9"
461
- integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
462
-
463
- "@esbuild/win32-ia32@0.18.20":
464
- version "0.18.20"
465
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102"
466
- integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
467
-
468
- "@esbuild/win32-x64@0.18.20":
469
- version "0.18.20"
470
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d"
471
- integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
472
-
473
  "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
474
  version "4.4.0"
475
  resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
@@ -584,7 +479,7 @@
584
  dependencies:
585
  "@babel/runtime" "^7.22.6"
586
 
587
- "@mui/material@5.14.5":
588
  version "5.14.5"
589
  resolved "https://registry.npmjs.org/@mui/material/-/material-5.14.5.tgz"
590
  integrity sha512-4qa4GMfuZH0Ai3mttk5ccXP8a3sf7aPlAJwyMrUSz6h9hPri6BPou94zeu3rENhhmKLby9S/W1y+pmficy8JKA==
@@ -659,7 +554,7 @@
659
  "@nodelib/fs.stat" "2.0.5"
660
  run-parallel "^1.1.9"
661
 
662
- "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
663
  version "2.0.5"
664
  resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
665
  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -752,7 +647,7 @@
752
  utility-types "^3.10.0"
753
  zustand "^3.5.13"
754
 
755
- "@react-three/fiber@^8.14.1":
756
  version "8.14.1"
757
  resolved "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.14.1.tgz"
758
  integrity sha512-Ky/FiCyJiyaI8bd+vckzgkHgKDSQDOcSSUVFOHCuCO9XOLb7Ebs6lof2hPpFa1HkaeE5ZIbTWIprvN0QqdPF0w==
@@ -798,7 +693,7 @@
798
  resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz"
799
  integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
800
 
801
- "@types/node@^20.5.3":
802
  version "20.5.3"
803
  resolved "https://registry.npmjs.org/@types/node/-/node-20.5.3.tgz"
804
  integrity sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==
@@ -853,7 +748,7 @@
853
  dependencies:
854
  "@types/react" "*"
855
 
856
- "@types/react@*", "@types/react@^18.2.15":
857
  version "18.2.20"
858
  resolved "https://registry.npmjs.org/@types/react/-/react-18.2.20.tgz"
859
  integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==
@@ -872,6 +767,21 @@
872
  resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz"
873
  integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
874
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
  "@types/uuid@^9.0.2":
876
  version "9.0.2"
877
  resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz"
@@ -899,7 +809,7 @@
899
  semver "^7.5.4"
900
  ts-api-utils "^1.0.1"
901
 
902
- "@typescript-eslint/parser@^6.0.0":
903
  version "6.4.0"
904
  resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz"
905
  integrity sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==
@@ -994,7 +904,7 @@ acorn-jsx@^5.3.2:
994
  resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
995
  integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
996
 
997
- acorn@^8.9.0:
998
  version "8.10.0"
999
  resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
1000
  integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
@@ -1032,7 +942,14 @@ ansi-styles@^3.2.1:
1032
  dependencies:
1033
  color-convert "^1.9.0"
1034
 
1035
- ansi-styles@^4.0.0, ansi-styles@^4.1.0:
 
 
 
 
 
 
 
1036
  version "4.3.0"
1037
  resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
1038
  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
@@ -1116,7 +1033,7 @@ braces@^3.0.2:
1116
  dependencies:
1117
  fill-range "^7.0.1"
1118
 
1119
- browserslist@^4.21.9:
1120
  version "4.21.10"
1121
  resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz"
1122
  integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==
@@ -1167,7 +1084,15 @@ chalk@^2.4.2:
1167
  escape-string-regexp "^1.0.5"
1168
  supports-color "^5.3.0"
1169
 
1170
- chalk@^4.0.0, chalk@^4.1.2:
 
 
 
 
 
 
 
 
1171
  version "4.1.2"
1172
  resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
1173
  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -1203,16 +1128,16 @@ color-convert@^2.0.1:
1203
  dependencies:
1204
  color-name "~1.1.4"
1205
 
1206
- color-name@1.1.3:
1207
- version "1.1.3"
1208
- resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
1209
- integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
1210
-
1211
  color-name@~1.1.4:
1212
  version "1.1.4"
1213
  resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
1214
  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
1215
 
 
 
 
 
 
1216
  concat-map@0.0.1:
1217
  version "0.0.1"
1218
  resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
@@ -1427,7 +1352,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
1427
  resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
1428
  integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
1429
 
1430
- eslint@^8.45.0:
1431
  version "8.47.0"
1432
  resolved "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz"
1433
  integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==
@@ -1546,7 +1471,7 @@ fastq@^1.6.0:
1546
  dependencies:
1547
  reusify "^1.0.4"
1548
 
1549
- fflate@^0.6.9:
1550
  version "0.6.10"
1551
  resolved "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz"
1552
  integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==
@@ -1603,11 +1528,6 @@ fs.realpath@^1.0.0:
1603
  resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
1604
  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
1605
 
1606
- fsevents@~2.3.2:
1607
- version "2.3.3"
1608
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
1609
- integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
1610
-
1611
  function-bind@^1.1.1:
1612
  version "1.1.1"
1613
  resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
@@ -1741,7 +1661,7 @@ hoist-non-react-statics@^3.3.1:
1741
  dependencies:
1742
  react-is "^16.7.0"
1743
 
1744
- ieee754@1.1.13, ieee754@^1.1.4:
1745
  version "1.1.13"
1746
  resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz"
1747
  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
@@ -1772,7 +1692,7 @@ inflight@^1.0.4:
1772
  once "^1.3.0"
1773
  wrappy "1"
1774
 
1775
- inherits@2, inherits@^2.0.3:
1776
  version "2.0.4"
1777
  resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
1778
  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1970,7 +1890,7 @@ lodash.pick@^4.4.0:
1970
  resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz"
1971
  integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==
1972
 
1973
- lodash@4.17.21, lodash@^4.17.21:
1974
  version "4.17.21"
1975
  resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
1976
  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -2011,6 +1931,11 @@ meshline@^3.1.6:
2011
  resolved "https://registry.npmjs.org/meshline/-/meshline-3.1.6.tgz"
2012
  integrity sha512-8JZJOdaL5oz3PI/upG8JvP/5FfzYUOhrkJ8np/WKvXzl0/PZ2V9pqTvCIjSKv+w9ccg2xb+yyBhXAwt6ier3ug==
2013
 
 
 
 
 
 
2014
  micromatch@^4.0.4:
2015
  version "4.0.5"
2016
  resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
@@ -2184,16 +2109,16 @@ prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
2184
  object-assign "^4.1.1"
2185
  react-is "^16.13.1"
2186
 
2187
- punycode@1.3.2:
2188
- version "1.3.2"
2189
- resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
2190
- integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
2191
-
2192
  punycode@^2.1.0:
2193
  version "2.3.0"
2194
  resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
2195
  integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
2196
 
 
 
 
 
 
2197
  querystring@0.2.0:
2198
  version "0.2.0"
2199
  resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
@@ -2211,7 +2136,7 @@ react-composer@^5.0.3:
2211
  dependencies:
2212
  prop-types "^15.6.0"
2213
 
2214
- react-dom@^18.2.0:
2215
  version "18.2.0"
2216
  resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
2217
  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
@@ -2224,7 +2149,12 @@ react-google-charts@^4.0.1:
2224
  resolved "https://registry.npmjs.org/react-google-charts/-/react-google-charts-4.0.1.tgz"
2225
  integrity sha512-V/hcMcNuBgD5w49BYTUDye+bUKaPmsU5vy/9W/Nj2xEeGn+6/AuH9IvBkbDcNBsY00cV9OeexdmgfI5RFHgsXQ==
2226
 
2227
- react-is@^16.13.1, react-is@^16.7.0:
 
 
 
 
 
2228
  version "16.13.1"
2229
  resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
2230
  integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -2269,7 +2199,7 @@ react-use-measure@^2.1.1:
2269
  dependencies:
2270
  debounce "^1.2.1"
2271
 
2272
- react@^18.2.0:
2273
  version "18.2.0"
2274
  resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
2275
  integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@@ -2338,7 +2268,7 @@ rxjs@^7.8.1:
2338
  dependencies:
2339
  tslib "^2.1.0"
2340
 
2341
- sax@1.2.1, sax@>=0.6.0:
2342
  version "1.2.1"
2343
  resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz"
2344
  integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==
@@ -2527,7 +2457,7 @@ three-stdlib@^2.21.1, three-stdlib@^2.25.1:
2527
  potpack "^1.0.1"
2528
  zstddec "^0.0.2"
2529
 
2530
- three@^0.156.1:
2531
  version "0.156.1"
2532
  resolved "https://registry.npmjs.org/three/-/three-0.156.1.tgz"
2533
  integrity sha512-kP7H0FK9d/k6t/XvQ9FO6i+QrePoDcNhwl0I02+wmUJRNSLCUIDMcfObnzQvxb37/0Uc9TDT0T1HgsRRrO6SYQ==
@@ -2589,7 +2519,17 @@ tslib@^1.11.1:
2589
  resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
2590
  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
2591
 
2592
- tslib@^2.1.0, tslib@^2.3.1, tslib@^2.5.0:
 
 
 
 
 
 
 
 
 
 
2593
  version "2.6.2"
2594
  resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
2595
  integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
@@ -2606,7 +2546,7 @@ type-fest@^0.20.2:
2606
  resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
2607
  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
2608
 
2609
- typescript@5.1.6:
2610
  version "5.1.6"
2611
  resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz"
2612
  integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
@@ -2660,17 +2600,17 @@ utility-types@^3.10.0:
2660
  resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz"
2661
  integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
2662
 
2663
- uuid@8.0.0:
2664
- version "8.0.0"
2665
- resolved "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz"
2666
- integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==
2667
-
2668
  uuid@^9.0.0:
2669
  version "9.0.0"
2670
  resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz"
2671
  integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
2672
 
2673
- vite@^4.4.5:
 
 
 
 
 
2674
  version "4.4.9"
2675
  resolved "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz"
2676
  integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
@@ -2807,7 +2747,12 @@ zstddec@^0.0.2:
2807
  resolved "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz"
2808
  integrity sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==
2809
 
2810
- zustand@^3.5.13, zustand@^3.7.1:
 
 
 
 
 
2811
  version "3.7.2"
2812
  resolved "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz"
2813
  integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
 
61
  resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz"
62
  integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==
63
 
64
+ "@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.22.9":
65
  version "7.22.10"
66
  resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz"
67
  integrity sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==
 
298
  resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz"
299
  integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
300
 
301
+ "@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0", "@emotion/react@11.11.1":
302
  version "11.11.1"
303
  resolved "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz"
304
  integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==
 
328
  resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz"
329
  integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
330
 
331
+ "@emotion/styled@^11.3.0", "@emotion/styled@11.11.0":
332
  version "11.11.0"
333
  resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz"
334
  integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==
 
360
  resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz"
361
  integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  "@esbuild/linux-x64@0.18.20":
364
  version "0.18.20"
365
  resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
366
  integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
367
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
369
  version "4.4.0"
370
  resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
 
479
  dependencies:
480
  "@babel/runtime" "^7.22.6"
481
 
482
+ "@mui/material@^5.0.0", "@mui/material@5.14.5":
483
  version "5.14.5"
484
  resolved "https://registry.npmjs.org/@mui/material/-/material-5.14.5.tgz"
485
  integrity sha512-4qa4GMfuZH0Ai3mttk5ccXP8a3sf7aPlAJwyMrUSz6h9hPri6BPou94zeu3rENhhmKLby9S/W1y+pmficy8JKA==
 
554
  "@nodelib/fs.stat" "2.0.5"
555
  run-parallel "^1.1.9"
556
 
557
+ "@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
558
  version "2.0.5"
559
  resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
560
  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
 
647
  utility-types "^3.10.0"
648
  zustand "^3.5.13"
649
 
650
+ "@react-three/fiber@^8.14.1", "@react-three/fiber@>=6.0", "@react-three/fiber@>=8.0", "@react-three/fiber@>=8.0.0":
651
  version "8.14.1"
652
  resolved "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.14.1.tgz"
653
  integrity sha512-Ky/FiCyJiyaI8bd+vckzgkHgKDSQDOcSSUVFOHCuCO9XOLb7Ebs6lof2hPpFa1HkaeE5ZIbTWIprvN0QqdPF0w==
 
693
  resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz"
694
  integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==
695
 
696
+ "@types/node@^20.5.3", "@types/node@>= 14":
697
  version "20.5.3"
698
  resolved "https://registry.npmjs.org/@types/node/-/node-20.5.3.tgz"
699
  integrity sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA==
 
748
  dependencies:
749
  "@types/react" "*"
750
 
751
+ "@types/react@*", "@types/react@^17.0.0 || ^18.0.0", "@types/react@^18.2.15", "@types/react@>=16.8":
752
  version "18.2.20"
753
  resolved "https://registry.npmjs.org/@types/react/-/react-18.2.20.tgz"
754
  integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw==
 
767
  resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz"
768
  integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==
769
 
770
+ "@types/stats.js@*":
771
+ version "0.17.3"
772
+ resolved "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz"
773
+ integrity sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==
774
+
775
+ "@types/three@>=0.144.0":
776
+ version "0.158.3"
777
+ resolved "https://registry.npmjs.org/@types/three/-/three-0.158.3.tgz"
778
+ integrity sha512-6Qs1rUvLSbkJ4hlIe6/rdwIf61j1x2UKvGJg7s8KjswYsz1C1qDTs6voVXXB8kYaI0hgklgZgbZUupfL1l9xdA==
779
+ dependencies:
780
+ "@types/stats.js" "*"
781
+ "@types/webxr" "*"
782
+ fflate "~0.6.10"
783
+ meshoptimizer "~0.18.1"
784
+
785
  "@types/uuid@^9.0.2":
786
  version "9.0.2"
787
  resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.2.tgz"
 
809
  semver "^7.5.4"
810
  ts-api-utils "^1.0.1"
811
 
812
+ "@typescript-eslint/parser@^6.0.0", "@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha":
813
  version "6.4.0"
814
  resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz"
815
  integrity sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==
 
904
  resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
905
  integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
906
 
907
+ "acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
908
  version "8.10.0"
909
  resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz"
910
  integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
 
942
  dependencies:
943
  color-convert "^1.9.0"
944
 
945
+ ansi-styles@^4.0.0:
946
+ version "4.3.0"
947
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
948
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
949
+ dependencies:
950
+ color-convert "^2.0.1"
951
+
952
+ ansi-styles@^4.1.0:
953
  version "4.3.0"
954
  resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
955
  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
 
1033
  dependencies:
1034
  fill-range "^7.0.1"
1035
 
1036
+ browserslist@^4.21.9, "browserslist@>= 4.21.0":
1037
  version "4.21.10"
1038
  resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz"
1039
  integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==
 
1084
  escape-string-regexp "^1.0.5"
1085
  supports-color "^5.3.0"
1086
 
1087
+ chalk@^4.0.0:
1088
+ version "4.1.2"
1089
+ resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
1090
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
1091
+ dependencies:
1092
+ ansi-styles "^4.1.0"
1093
+ supports-color "^7.1.0"
1094
+
1095
+ chalk@^4.1.2:
1096
  version "4.1.2"
1097
  resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
1098
  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
 
1128
  dependencies:
1129
  color-name "~1.1.4"
1130
 
 
 
 
 
 
1131
  color-name@~1.1.4:
1132
  version "1.1.4"
1133
  resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
1134
  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
1135
 
1136
+ color-name@1.1.3:
1137
+ version "1.1.3"
1138
+ resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
1139
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
1140
+
1141
  concat-map@0.0.1:
1142
  version "0.0.1"
1143
  resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
 
1352
  resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
1353
  integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
1354
 
1355
+ "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.45.0, eslint@>=7:
1356
  version "8.47.0"
1357
  resolved "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz"
1358
  integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==
 
1471
  dependencies:
1472
  reusify "^1.0.4"
1473
 
1474
+ fflate@^0.6.9, fflate@~0.6.10:
1475
  version "0.6.10"
1476
  resolved "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz"
1477
  integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==
 
1528
  resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
1529
  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
1530
 
 
 
 
 
 
1531
  function-bind@^1.1.1:
1532
  version "1.1.1"
1533
  resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
 
1661
  dependencies:
1662
  react-is "^16.7.0"
1663
 
1664
+ ieee754@^1.1.4, ieee754@1.1.13:
1665
  version "1.1.13"
1666
  resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz"
1667
  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
 
1692
  once "^1.3.0"
1693
  wrappy "1"
1694
 
1695
+ inherits@^2.0.3, inherits@2:
1696
  version "2.0.4"
1697
  resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
1698
  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
1890
  resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz"
1891
  integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==
1892
 
1893
+ lodash@^4.17.21, lodash@4.17.21:
1894
  version "4.17.21"
1895
  resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
1896
  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
1931
  resolved "https://registry.npmjs.org/meshline/-/meshline-3.1.6.tgz"
1932
  integrity sha512-8JZJOdaL5oz3PI/upG8JvP/5FfzYUOhrkJ8np/WKvXzl0/PZ2V9pqTvCIjSKv+w9ccg2xb+yyBhXAwt6ier3ug==
1933
 
1934
+ meshoptimizer@~0.18.1:
1935
+ version "0.18.1"
1936
+ resolved "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz"
1937
+ integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==
1938
+
1939
  micromatch@^4.0.4:
1940
  version "4.0.5"
1941
  resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"
 
2109
  object-assign "^4.1.1"
2110
  react-is "^16.13.1"
2111
 
 
 
 
 
 
2112
  punycode@^2.1.0:
2113
  version "2.3.0"
2114
  resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz"
2115
  integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
2116
 
2117
+ punycode@1.3.2:
2118
+ version "1.3.2"
2119
+ resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
2120
+ integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
2121
+
2122
  querystring@0.2.0:
2123
  version "0.2.0"
2124
  resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
 
2136
  dependencies:
2137
  prop-types "^15.6.0"
2138
 
2139
+ "react-dom@^17.0.0 || ^18.0.0", react-dom@^18.2.0, react-dom@>=16.13, react-dom@>=16.3.0, react-dom@>=16.6.0, react-dom@>=18.0:
2140
  version "18.2.0"
2141
  resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
2142
  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
 
2149
  resolved "https://registry.npmjs.org/react-google-charts/-/react-google-charts-4.0.1.tgz"
2150
  integrity sha512-V/hcMcNuBgD5w49BYTUDye+bUKaPmsU5vy/9W/Nj2xEeGn+6/AuH9IvBkbDcNBsY00cV9OeexdmgfI5RFHgsXQ==
2151
 
2152
+ react-is@^16.13.1:
2153
+ version "16.13.1"
2154
+ resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
2155
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
2156
+
2157
+ react-is@^16.7.0:
2158
  version "16.13.1"
2159
  resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
2160
  integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
2199
  dependencies:
2200
  debounce "^1.2.1"
2201
 
2202
+ "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^17.0.0 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16.8.0", react@>=16.13, react@>=16.3.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=17.0, react@>=18.0:
2203
  version "18.2.0"
2204
  resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
2205
  integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
 
2268
  dependencies:
2269
  tslib "^2.1.0"
2270
 
2271
+ sax@>=0.6.0, sax@1.2.1:
2272
  version "1.2.1"
2273
  resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz"
2274
  integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==
 
2457
  potpack "^1.0.1"
2458
  zstddec "^0.0.2"
2459
 
2460
+ three@^0.156.1, "three@>= 0.151.0", three@>=0.125.0, three@>=0.126, three@>=0.126.1, three@>=0.128.0, three@>=0.133, three@>=0.137, three@>=0.141, three@>=0.144.0:
2461
  version "0.156.1"
2462
  resolved "https://registry.npmjs.org/three/-/three-0.156.1.tgz"
2463
  integrity sha512-kP7H0FK9d/k6t/XvQ9FO6i+QrePoDcNhwl0I02+wmUJRNSLCUIDMcfObnzQvxb37/0Uc9TDT0T1HgsRRrO6SYQ==
 
2519
  resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
2520
  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
2521
 
2522
+ tslib@^2.1.0:
2523
+ version "2.6.2"
2524
+ resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
2525
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
2526
+
2527
+ tslib@^2.3.1:
2528
+ version "2.6.2"
2529
+ resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
2530
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
2531
+
2532
+ tslib@^2.5.0:
2533
  version "2.6.2"
2534
  resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
2535
  integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
 
2546
  resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
2547
  integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
2548
 
2549
+ typescript@>=4.2.0, typescript@5.1.6:
2550
  version "5.1.6"
2551
  resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz"
2552
  integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==
 
2600
  resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz"
2601
  integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
2602
 
 
 
 
 
 
2603
  uuid@^9.0.0:
2604
  version "9.0.0"
2605
  resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz"
2606
  integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
2607
 
2608
+ uuid@8.0.0:
2609
+ version "8.0.0"
2610
+ resolved "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz"
2611
+ integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==
2612
+
2613
+ vite@^4.2.0, vite@^4.4.5:
2614
  version "4.4.9"
2615
  resolved "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz"
2616
  integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
 
2747
  resolved "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz"
2748
  integrity sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==
2749
 
2750
+ zustand@^3.5.13:
2751
+ version "3.7.2"
2752
+ resolved "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz"
2753
+ integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
2754
+
2755
+ zustand@^3.7.1:
2756
  version "3.7.2"
2757
  resolved "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz"
2758
  integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==