Skip to content

Commit

Permalink
feature: Loading Progress 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
JongMany committed Jun 26, 2024
1 parent 8f95cef commit 15d1122
Show file tree
Hide file tree
Showing 18 changed files with 368 additions and 916 deletions.
769 changes: 61 additions & 708 deletions fe/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions fe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
"@react-three/drei": "^9.107.0",
"@react-three/fiber": "^8.16.8",
"@types/three": "^0.165.0",
"axios": "^1.7.2",
"framer-motion": "^11.2.10",
"framer-motion-3d": "^11.2.10",
"gsap": "^3.12.5",
"leva": "^0.9.35",
"nprogress": "^0.2.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet-async": "^2.0.5",
Expand All @@ -26,6 +25,7 @@
"devDependencies": {
"@prerenderer/renderer-puppeteer": "^1.2.4",
"@prerenderer/rollup-plugin": "^0.3.12",
"@types/nprogress": "^0.2.3",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
Expand Down
File renamed without changes.
File renamed without changes.
Binary file added fe/src/assets/star.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions fe/src/components/progress/LazyLoad.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import nProgress from "nprogress";
import { useEffect } from "react";

export const LazyLoad = () => {
useEffect(() => {
nProgress.start();
return () => {
nProgress.done();
};
}, []);

return (
<div>
<h1>LazyLoad</h1>
</div>
);
};
1 change: 1 addition & 0 deletions fe/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "./index.css";
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "nprogress/nprogress.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
Expand Down
48 changes: 1 addition & 47 deletions fe/src/pages/main/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
import { useEffect, useState } from "react";
import { DetailHelmet } from "../../components/meta/DetailHelmet";
import { Canvas } from "@react-three/fiber";
import { Scroll, ScrollControls } from "@react-three/drei";
import Interface from "./components/Interface";
import ScrollManager from "./components/ScrollManager";
import { Menu } from "./components/Menu";
import Model from "./components/Model";
import { MotionConfig } from "framer-motion";
import { ErrorBoundary } from "../../components/errorboundary/ErrorBoundary";
import { Cursor } from "./components/Cursor";

export default function MainPage() {
const [currentSectionIndex, setCurrentSectionIndex] = useState(0);
Expand All @@ -28,44 +19,7 @@ export default function MainPage() {
url={import.meta.env.VITE_BASE_URL + "/main"}
shortDesc="방구석 코딩쟁이의 포트폴리오를 소개합니다."
/>
<>
<MotionConfig
transition={{
type: "spring",
mass: 5,
stiffness: 50,
damping: 50,
restDelta: 0.0001,
}}
>
<Canvas shadows camera={{ position: [0, 3, 10], fov: 42 }}>
<color attach="background" args={["#e6e7ff"]} />
<ScrollControls pages={4} damping={0.1}>
<ScrollManager
currentSectionIndex={currentSectionIndex}
onCurrentSectionIndexChange={setCurrentSectionIndex}
/>
<Scroll>
<ErrorBoundary hasError={false}>
<Model
currentSectionIndex={currentSectionIndex}
menuOpened={menuOpened}
/>
</ErrorBoundary>
</Scroll>
<Scroll html>
<Interface />
</Scroll>
</ScrollControls>
</Canvas>
<Menu
onCurrentSectionIndexChange={setCurrentSectionIndex}
menuOpened={menuOpened}
setMenuOpened={setMenuOpened}
/>
<Cursor />
</MotionConfig>
</>
<></>
</>
);
}
6 changes: 3 additions & 3 deletions fe/src/pages/main/components/Model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from "@react-three/drei";
import { Office } from "./modeling/Office";
import { motion } from "framer-motion-3d";
import { Avatar } from "./modeling/Avatar";
import { AvatarWrapper } from "./modeling/AvatarWrapper";
import { useEffect } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { animate, useMotionValue } from "framer-motion";
Expand All @@ -28,7 +28,7 @@ export default function Model({ currentSectionIndex, menuOpened }: Props) {
animate(cameraLookAtX, menuOpened ? 5 : 0, {
...framerMotionConfig,
});
}, [menuOpened]);
}, [menuOpened, cameraLookAtX, cameraPositionX]);

useFrame((state) => {
state.camera.position.x = cameraPositionX.get();
Expand Down Expand Up @@ -96,7 +96,7 @@ export default function Model({ currentSectionIndex, menuOpened }: Props) {
</mesh>
</Float>
<group scale={[2, 2, 2]} position-y={-1.5}>
<Avatar
<AvatarWrapper
animation={currentSectionIndex === 0 ? "Falling" : "Standing"}
/>
</group>
Expand Down
2 changes: 1 addition & 1 deletion fe/src/pages/main/components/ScrollManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function ScrollManager({
isAnimating.current = false;
},
});
}, [currentSectionIndex]);
}, [currentSectionIndex, data.el]);
// data.

useFrame(() => {
Expand Down
222 changes: 86 additions & 136 deletions fe/src/pages/main/components/modeling/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,145 +1,95 @@
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
*/
import { useAnimations, useFBX, useGLTF } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useControls } from "leva";
import { useEffect, useRef } from "react";
import { useEffect } from "react";
import * as THREE from "three";

type Props = { animation: string };
export function Avatar({ animation, ...props }: Props) {
const { headFollow, cursorFollow, wireframe } = useControls({
headFollow: false,
cursorFollow: false,
wireframe: false,
});

const group = useRef<THREE.Group | null>(null);
const { nodes, materials } = useGLTF(
`${import.meta.env.VITE_BASE_URL}/models/646d9dcdc8a5f5bddbfac913.glb`
);

const { animations: typingAnimation } = useFBX(
`${import.meta.env.VITE_BASE_URL}/animations/Typing.fbx`
);
const { animations: standingAnimation } = useFBX(
`${import.meta.env.VITE_BASE_URL}/animations/Standing Idle.fbx`
);
const { animations: fallingAnimation } = useFBX(
`${import.meta.env.VITE_BASE_URL}/animations/Falling Idle.fbx`
);

typingAnimation[0].name = "Typing";
standingAnimation[0].name = "Standing";
fallingAnimation[0].name = "Falling";

const { actions } = useAnimations(
[typingAnimation[0], standingAnimation[0], fallingAnimation[0]],
group
);

useFrame((state) => {
// console.log(headFollow);
console.log(group.current);
if (headFollow) {
// TODO: 이부분 수정
if (group.current) {
group.current.getObjectByName("Head")?.lookAt(state.camera.position);
console.log(group.current.getObjectByName("Head"));
}
}
if (cursorFollow) {
// const target = new THREE.Vector3(state.mouse.x, state.mouse.y, 1);
const target = new THREE.Vector3(state.pointer.x, state.pointer.y, 1);
if (group.current) {
group.current.getObjectByName("Spine2")?.lookAt(target);
}
}
});

type Props = {
nodes: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[name: string]: any;
};
materials: {
[name: string]: THREE.Material;
};
actions: {
[x: string]: THREE.AnimationAction;
};
actionName: string;
};
export default function Avatar({
nodes,
materials,
actions,
actionName,
}: Props) {
// console.log(animation.getClip().name);
useEffect(() => {
// if (!actions || !animation || !actions[animation]) {
// return;
// }

// console.log(animation, actions[animation]);
actions[animation]!.reset().fadeIn(0.5).play();
const animation = actions[actionName];
animation.reset().fadeIn(0.5).play();
return () => {
actions[animation]!.reset().fadeOut(0.5);
animation.reset().fadeOut(0.5);
};
}, [animation]);

useEffect(() => {
Object.values(materials).forEach((material) => {
material.wireframe = wireframe;
});
}, [wireframe]);

// console.dir(actions["Standing"]);
// actions["Standing"].reset().fadeIn(0.5).play();
}, [actionName]);
return (
<group {...props} ref={group} dispose={null}>
<group>
<primitive object={nodes.Hips} />
<skinnedMesh
geometry={nodes.Wolf3D_Body.geometry}
material={materials.Wolf3D_Body}
skeleton={nodes.Wolf3D_Body.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
material={materials.Wolf3D_Outfit_Bottom}
skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
material={materials.Wolf3D_Outfit_Footwear}
skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Top.geometry}
material={materials.Wolf3D_Outfit_Top}
skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Hair.geometry}
material={materials.Wolf3D_Hair}
skeleton={nodes.Wolf3D_Hair.skeleton}
/>
<skinnedMesh
name="EyeLeft"
geometry={nodes.EyeLeft.geometry}
material={materials.Wolf3D_Eye}
skeleton={nodes.EyeLeft.skeleton}
morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
/>
<skinnedMesh
name="EyeRight"
geometry={nodes.EyeRight.geometry}
material={materials.Wolf3D_Eye}
skeleton={nodes.EyeRight.skeleton}
morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Head"
geometry={nodes.Wolf3D_Head.geometry}
material={materials.Wolf3D_Skin}
skeleton={nodes.Wolf3D_Head.skeleton}
morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Teeth"
geometry={nodes.Wolf3D_Teeth.geometry}
material={materials.Wolf3D_Teeth}
skeleton={nodes.Wolf3D_Teeth.skeleton}
morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
/>
</group>
<group>
<primitive object={nodes.Hips} />
<skinnedMesh
geometry={nodes.Wolf3D_Body.geometry}
material={materials.Wolf3D_Body}
skeleton={nodes.Wolf3D_Body.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
material={materials.Wolf3D_Outfit_Bottom}
skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
material={materials.Wolf3D_Outfit_Footwear}
skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Top.geometry}
material={materials.Wolf3D_Outfit_Top}
skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Hair.geometry}
material={materials.Wolf3D_Hair}
skeleton={nodes.Wolf3D_Hair.skeleton}
/>
<skinnedMesh
name="EyeLeft"
geometry={nodes.EyeLeft.geometry}
material={materials.Wolf3D_Eye}
skeleton={nodes.EyeLeft.skeleton}
morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
/>
<skinnedMesh
name="EyeRight"
geometry={nodes.EyeRight.geometry}
material={materials.Wolf3D_Eye}
skeleton={nodes.EyeRight.skeleton}
morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Head"
geometry={nodes.Wolf3D_Head.geometry}
material={materials.Wolf3D_Skin}
skeleton={nodes.Wolf3D_Head.skeleton}
morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Teeth"
geometry={nodes.Wolf3D_Teeth.geometry}
material={materials.Wolf3D_Teeth}
skeleton={nodes.Wolf3D_Teeth.skeleton}
morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
/>
</group>
);
}

useGLTF.preload("models/646d9dcdc8a5f5bddbfac913.glb");
Loading

0 comments on commit 15d1122

Please sign in to comment.