fix: pr issues

This commit is contained in:
math-pixel
2026-04-29 11:23:40 +02:00
parent 7c5d7f3834
commit 2b6b045f4a
7 changed files with 67 additions and 40 deletions
+29 -40
View File
@@ -1,15 +1,9 @@
import { /* eslint-disable react-hooks/immutability */
createContext, import { createContext, useRef, useState, useEffect, useCallback } from "react";
useContext,
useRef,
useState,
useEffect,
useCallback,
} from "react";
import { useGLTF, useAnimations } from "@react-three/drei"; import { useGLTF, useAnimations } from "@react-three/drei";
import type { AnimationAction } from "three"; import type { AnimationAction } from "three";
import * as THREE from "three"; import * as THREE from "three";
import type { Vector3Tuple } from "@/types/3d"; import type { Vector3Tuple } from "@/types/three";
export interface AnimatedModelConfig { export interface AnimatedModelConfig {
modelPath: string; modelPath: string;
@@ -25,7 +19,7 @@ export interface AnimatedModelConfig {
onAnimationEnd?: (animationName: string) => void; onAnimationEnd?: (animationName: string) => void;
} }
interface AnimatedModelContextValue { export interface AnimatedModelContextValue {
play: (name: string, fade?: number) => void; play: (name: string, fade?: number) => void;
stop: (fade?: number) => void; stop: (fade?: number) => void;
fadeTo: (name: string, fade?: number) => void; fadeTo: (name: string, fade?: number) => void;
@@ -39,13 +33,7 @@ const AnimatedModelContext = createContext<AnimatedModelContextValue | null>(
null, null,
); );
export function useAnimatedModel(): AnimatedModelContextValue { export { AnimatedModelContext };
const context = useContext(AnimatedModelContext);
if (!context) {
throw new Error("useAnimatedModel must be used within AnimatedModel");
}
return context;
}
interface AnimatedModelProps extends AnimatedModelConfig { interface AnimatedModelProps extends AnimatedModelConfig {
children?: React.ReactNode; children?: React.ReactNode;
@@ -53,7 +41,6 @@ interface AnimatedModelProps extends AnimatedModelConfig {
export function AnimatedModel({ export function AnimatedModel({
modelPath, modelPath,
animations: _animations = [],
defaultAnimation = "Idle", defaultAnimation = "Idle",
position = [0, 0, 0], position = [0, 0, 0],
rotation = [0, 0, 0], rotation = [0, 0, 0],
@@ -144,28 +131,31 @@ export function AnimatedModel({
); );
useEffect(() => { useEffect(() => {
if (autoPlay && names.length > 0) { if (!autoPlay || names.length === 0) {
console.log(`[AnimatedModel] Available animations: ${names.join(", ")}`);
let defaultAction = actions[defaultAnimation as string];
if (!defaultAction && names.length > 0) {
console.log(
`[AnimatedModel] "${defaultAnimation}" not found, using: ${names[0]}`,
);
defaultAction = actions[names[0] as string];
}
if (defaultAction) {
defaultAction.play();
setIsReady(true);
setCurrentAnim(defaultAction.getClip().name);
onLoaded?.();
} else {
console.log("[AnimatedModel] No available animation in actions");
}
} else if (names.length === 0) {
console.log("[AnimatedModel] No animation found in model"); console.log("[AnimatedModel] No animation found in model");
return;
}
console.log(`[AnimatedModel] Available animations: ${names.join(", ")}`);
let defaultAction = actions[defaultAnimation as string];
if (!defaultAction && names.length > 0) {
console.log(
`[AnimatedModel] "${defaultAnimation}" not found, using: ${names[0]}`,
);
defaultAction = actions[names[0] as string];
}
if (defaultAction) {
defaultAction.play();
// eslint-disable-next-line react-hooks/set-state-in-effect
setIsReady(true);
// eslint-disable-next-line react-hooks/set-state-in-effect
setCurrentAnim(defaultAction.getClip().name);
onLoaded?.();
} else {
console.log("[AnimatedModel] No available animation in actions");
} }
}, [actions, defaultAnimation, names, autoPlay, onLoaded]); }, [actions, defaultAnimation, names, autoPlay, onLoaded]);
@@ -179,7 +169,6 @@ export function AnimatedModel({
names, names,
}; };
// Apply transforms to scene directly
useEffect(() => { useEffect(() => {
scene.position.set(...position); scene.position.set(...position);
scene.rotation.set( scene.rotation.set(
+6
View File
@@ -55,6 +55,12 @@ export const docGroups: DocGroup[] = [
subtitle: "Editing workflow", subtitle: "Editing workflow",
meta: "06", meta: "06",
}, },
{
path: "/docs/animation",
title: "Animation & 3D Model System",
subtitle: "Components and usage",
meta: "07",
},
], ],
}, },
]; ];
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/immutability */
import { useRef, useEffect, useState, useCallback } from "react"; import { useRef, useEffect, useState, useCallback } from "react";
import { useGLTF, useAnimations } from "@react-three/drei"; import { useGLTF, useAnimations } from "@react-three/drei";
import type { AnimationAction, AnimationMixer } from "three"; import type { AnimationAction, AnimationMixer } from "three";
+13
View File
@@ -0,0 +1,13 @@
import animation from "../../../../docs/technical/animation.md?raw";
import { DocsDocument } from "@/components/docs/DocsDocument";
export function DocsAnimationPage(): React.JSX.Element {
return (
<DocsDocument
content={animation}
frContent={animation}
meta="07"
title="Animation & 3D Model System"
/>
);
}
+2
View File
@@ -7,6 +7,7 @@ import {
import { HomePage } from "@/pages/page"; import { HomePage } from "@/pages/page";
import { EditorPage } from "@/pages/editor/page"; import { EditorPage } from "@/pages/editor/page";
import { import {
DocsAnimationRoute,
DocsArchitectureRoute, DocsArchitectureRoute,
DocsEditorRoute, DocsEditorRoute,
DocsFeaturesRoute, DocsFeaturesRoute,
@@ -45,6 +46,7 @@ const docsChildRoutes = [
{ path: "technical-editor", component: DocsTechnicalEditorRoute }, { path: "technical-editor", component: DocsTechnicalEditorRoute },
{ path: "features", component: DocsFeaturesRoute }, { path: "features", component: DocsFeaturesRoute },
{ path: "editor", component: DocsEditorRoute }, { path: "editor", component: DocsEditorRoute },
{ path: "animation", component: DocsAnimationRoute },
].map(({ path, component }) => ].map(({ path, component }) =>
createRoute({ createRoute({
getParentRoute: () => docsRoute, getParentRoute: () => docsRoute,
+14
View File
@@ -42,6 +42,12 @@ const LazyDocsEditorPage = lazy(() =>
})), })),
); );
const LazyDocsAnimationPage = lazy(() =>
import("@/pages/docs/animation/page").then((module) => ({
default: module.DocsAnimationPage,
})),
);
export function DocsLayoutRoute(): React.JSX.Element { export function DocsLayoutRoute(): React.JSX.Element {
return ( return (
<Suspense fallback={null}> <Suspense fallback={null}>
@@ -97,3 +103,11 @@ export function DocsEditorRoute(): React.JSX.Element {
</Suspense> </Suspense>
); );
} }
export function DocsAnimationRoute(): React.JSX.Element {
return (
<Suspense fallback={null}>
<LazyDocsAnimationPage />
</Suspense>
);
}
+2
View File
@@ -26,10 +26,12 @@ class ModelErrorBoundary extends Component<
this.state = { hasError: false }; this.state = { hasError: false };
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static getDerivedStateFromError(_error: Error): ErrorBoundaryState { static getDerivedStateFromError(_error: Error): ErrorBoundaryState {
return { hasError: true }; return { hasError: true };
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
componentDidCatch(_error: Error): void { componentDidCatch(_error: Error): void {
console.warn(`Failed to load model`); console.warn(`Failed to load model`);
} }