diff --git a/gui/package.json b/gui/package.json
index cc46ae840..ab9074005 100644
--- a/gui/package.json
+++ b/gui/package.json
@@ -32,6 +32,7 @@
"react": "^18.0.0",
"react-dev-utils": "^12.0.0",
"react-dom": "^18.0.0",
+ "react-error-boundary": "^4.0.12",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.29.0",
"react-modal": "^3.15.1",
diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl
index 3f641df01..0c3d0904b 100644
--- a/gui/public/i18n/en/translation.ftl
+++ b/gui/public/i18n/en/translation.ftl
@@ -20,6 +20,7 @@ tips-do_not_move_heels = Ensure your heels do not move during recording!
tips-file_select = Drag & drop files to use, or browse.
tips-tap_setup = You can slowly tap 2 times your tracker to choose it instead of selecting it from the menu.
tips-turn_on_tracker = Using official SlimeVR trackers? Remember to turn on your tracker after connecting it to the PC!
+tips-failed_webgl = Failed to initialize WebGL.
## Body parts
body_part-NONE = Unassigned
diff --git a/gui/src/components/widgets/IMUVisualizerWidget.tsx b/gui/src/components/widgets/IMUVisualizerWidget.tsx
index a88df3ba0..a03f50101 100644
--- a/gui/src/components/widgets/IMUVisualizerWidget.tsx
+++ b/gui/src/components/widgets/IMUVisualizerWidget.tsx
@@ -11,6 +11,7 @@ import { QuatObject } from '@/maths/quaternion';
import { useLocalization } from '@fluent/react';
import { Vector3Object } from '@/maths/vector3';
import { Gltf } from '@react-three/drei';
+import { ErrorBoundary } from 'react-error-boundary';
const groundColor = '#4444aa';
@@ -158,13 +159,21 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
>
{l10n.getString('widget-imu_visualizer-rotation_hide')}
-
+ {l10n.getString('tips-failed_webgl')}
+
}
- >
+ >
+
+
>
)}
diff --git a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx
index cd2143347..6f7c4bfa0 100644
--- a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx
+++ b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx
@@ -18,6 +18,8 @@ import { QuaternionFromQuatT, isIdentity } from '@/maths/quaternion';
import classNames from 'classnames';
import { Button } from '@/components/commons/Button';
import { useLocalization } from '@fluent/react';
+import { ErrorBoundary } from 'react-error-boundary';
+import { Typography } from '@/components/commons/Typography';
extend({ BasedSkeletonHelper });
@@ -119,6 +121,7 @@ export function ToggleableSkeletonVisualizerWidget(
>
{l10n.getString('widget-skeleton_visualizer-hide')}
+
>
)}
@@ -132,6 +135,7 @@ export function SkeletonVisualizerWidget({
}: SkeletonVisualizerWidgetProps) {
const { bones: _bones } = useAppContext();
+ const { l10n } = useLocalization();
const bones = useMemo(
() => new Map(_bones.map((b) => [b.bodyPart, b])),
[JSON.stringify(_bones)]
@@ -194,27 +198,35 @@ export function SkeletonVisualizerWidget({
if (!skeleton.current) return <>>;
return (
-
+
+
);
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e11691ba5..79b39d304 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -104,6 +104,9 @@ importers:
react-dom:
specifier: ^18.0.0
version: 18.2.0(react@18.2.0)
+ react-error-boundary:
+ specifier: ^4.0.12
+ version: 4.0.12(react@18.2.0)
react-helmet:
specifier: ^6.1.0
version: 6.1.0(react@18.2.0)
@@ -6144,6 +6147,15 @@ packages:
scheduler: 0.23.0
dev: false
+ /react-error-boundary@4.0.12(react@18.2.0):
+ resolution: {integrity: sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==}
+ peerDependencies:
+ react: '>=16.13.1'
+ dependencies:
+ '@babel/runtime': 7.23.1
+ react: 18.2.0
+ dev: false
+
/react-error-overlay@6.0.11:
resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==}
dev: false