기존 프로젝트는 기획부터 내가 다 구상해서 A-Z 셀프로 수작업을 했다면,
이번 웹 포폴은 기존에 다른 분이 구현하신 커뮤니티에 있는 포트폴리오를 참고하여 코드를 분석하고 나만의 방식으로 조금 변형을 시도해보려 한다.
회사 입사 후에 처음부터 다 만드는게 아닌 기존 코드가 있는 프로젝트에 참여하여 유지보수를 해야할 경우가 더 많기에 이러한 경험도 충분히 도움이 될 것이라 생각한다.
총 제작 과정은
이정도로 생각하고 접근해 보려 한다
이렇게 나와야 하나
현재 렌더링 시점 차이가 있는지 액박이 나오는 모습
여기서도 이유 모를 액박이 나옴
여기선 EmailJS를 이용하여 이메일 보내지도록 설정 완료
일단 에러나는 부분 제외 내용 수정은 완료하였고,
코드 전체적으로 분석 준비 완료!
일단 문제 해결 전에 전체 코드 분석부터
하나의 페이지에 아래로 스크롤해서 보여주는 페이지이기 때문에
라우팅보다는 컴포넌트를 불러와서 배치함
배열로 고정된 값을 담아서 가져오기 위한 파일
const services = [
{
title: "React 개발자",
icon: web,
},
{
title: "Next.js 개발자",
icon: mobile,
},
{
title: "TypeScript 개발자",
icon: backend,
},
{
title: "성능 최적화",
icon: creator,
},
];
framer-motion으로 둥근 원형을 위아래로 계속 움직이는 애니메이션 효과를 주었다.
ComputersCanvas 컴포넌트에서 3D 컴퓨터 모델 가지고 오고 있음
이런식으로 선언해서 export 시켰다
그런데 이 컴포넌트 때문에 흰 화면이 뜨고 있다(렌더링 문제)
import React from "react";
import { motion } from "framer-motion";
import { styles } from "../styles";
import { ComputersCanvas } from "./canvas";
const Hero = () => {
return (
<section className="relative w-full h-screen mx-auto">
<div
className={`${styles.paddingX} absolute inset-0 top-[120px] max-w-7xl mx-auto flex flex-row items-start gap-5`}
>
<div className="flex flex-col justify-center items-center mt-5">
<div className="w-5 h-5 rounded-full bg-[#915EFF]" />
<div className="w-1 sm:h-80 h-40 violet-gradient" />
</div>
<div>
<h1 className={`${styles.heroHeadText} text-white`}>
안녕하세요, 프론트엔드 개발자
<br />
<span className="text-[#915eff]">천민규 입니다!</span>
</h1>
<p className={`${styles.heroSubText} mt-2 text-white-100`}>
React와 Next.js 위주로 웹 개발을 하고 있습니다.
<br className="sm:block hidden" />{" "}
</p>
</div>
</div>
<ComputersCanvas />
<div className="absolute xs:bottom-10 bottom-32 w-full flex justify-center items-center">
<a href="#about">
<div className="w-[35px] h-[64px] rounded-3xl border-4 border-secondary flex justify-center items-start p-2">
<motion.div
animate={{
y: [0, 24, 0],
}}
transition={{
duration: 1.5,
repeat: Infinity,
repeatType: "loop",
}}
className="w-3 h-3 rounded-full bg-secondary mb-1"
/>
</div>
</a>
</div>
</section>
);
};
export default Hero;
해당 흰색 화면이 뜨는 부분은 Hero 컴포넌트이자 저 컴퓨터는 ComputersCanvas컴포넌트인데 이 부분을 주석처리하면 정상적으로 화면이 나오고, 이후 다시 활성화하면 컴퓨터도 제대로 나오고 있는 현상을 발견하였다.
console을 확인해보면
"Too many active WebGL contexts. Oldest context will be lost."
WebGL 컨텍스트가 너무 많다는 문제가 있는데,
WebGL 컨텍스트
웹 브라우저에서 3D 그래픽을 렌더링할 수 있도록 해주는 환경(Context)
HTML5의 canvas 요소를 사용하여 GPU를 활용한 고성능 2D 및 3D 그래픽 렌더링을 가능하게 함
이 컨텍스트가 WebGL의 모든 API 호출 처리하고, 그래픽 렌더링을 담당하는 핵심 객체 역할을 함
즉, 브라우저는 제한된 수의 WebGL 컨텍스트만 동시에 유지될 수 있는데 너무 과하게 사용하였던 문제여서 더 가벼운 3D 객체를 사용하려 한다.
추후에 어떤 모델을 넣을지는 고민
좀 여러번 알아보니까 지금 현재 내가 3D모델링을 쓰는 건 로봇,3d공, 지구본인데 너무 많은 모델링을 쓰니까 브라우저가 소화를 못해서 일어나는 현상이였다.
왜냐면 다른 모델링을 잠시 비활성화하니까 잘 나왔기 때문
그래서 일단 간단하게 로봇만 나오게 하고, 스택은 2d로 표현하였다.
당장 코드분석하는 것보다 이력서 지원을 위해서 배포 먼저 진행해보려한다.
사실 지금 스터디카페에서 노트북으로 작업중인데 집에서 큰 화면으로 보다가 노트북으로하려니 너무 벅차서 일단 배포 먼저하고 추가적인 코드분석은 집에서 하는걸로!
직관적인 UI와 간편 배포 프로세스로 많은 프론트개발자들이 선호한다고 함
기존엔 vercel만 써봤으니 한번 체험해보자
일단 github으로 회원가입해주고~
그냥 바로 레포지토리 선택하면 바로 되는게 vercel과 비슷하다 그런데 한글버전으로 안해서 그런지 없는지 체크는 안해봤지만 뭔가 버셀이 더 익숙해서 그런지 편한 느낌??
성공적으로 잘 뜬 모습
이제 코드 분석과 에러를 잡으면 된다
but 할게 많으므로 오늘은 여기까지
THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN
3D 모델인 지구본의 위치 속성에 값자기 NaN값이 포함되어 있다고 떴다
그리고 Preload문제도 발생했고, 기존 지구본은 earthVisible 상태에 따라 EarthCanvas를 조건부로 마운트/언마운트 시켰는데 그 방식에서도 문제가 발생되었다.
프리로드 자체는 넣엇다 뺴봤을때 원인이 아니였고,
3D 라이브러리는 WebGL 컨텍스트와 GPU리소스를 직접 관리하다보니, 컴포넌트를 자주 마운트.언마운트하면 이러한 리소스 정리가 잘 안될 수 있어서 항상 렌더링하게 해서 조치를 하였다.
import { BrowserRouter } from "react-router-dom";
import {
About,
Contact,
Experience,
// Feedbacks,
Hero,
Navbar,
Tech,
Works,
StarsCanvas,
} from "./components";
const App = () => {
return (
<BrowserRouter>
<div className="relative z-0 bg-primary">
<div className="bg-hero-pattern bg-cover bg-no-repeat bg-center ">
<Navbar />
<Hero />
</div>
<About />
<Experience />
<Tech />
<Works />
{/* <Feedbacks /> */}
<div className="relative z-0">
<Contact />
<StarsCanvas />
</div>
</div>
</BrowserRouter>
);
};
export default App;
react router로 라우팅 처리
import React from "react";
import { styles } from "../styles";
import RobotCanvas from "./canvas/Robot";
const Hero = () => {
return (
<section className="relative w-full h-screen mx-auto overflow-hidden">
<div
className={`${styles.paddingX} absolute inset-0 top-[120px] max-w-7xl mx-auto flex flex-row items-start gap-5`}
>
<div className="flex flex-col justify-center items-center mt-5">
<div className="w-5 h-5 rounded-full bg-[#915EFF]" />
<div className="w-1 sm:h-80 h-40 violet-gradient" />
</div>
<div>
<h1 className={`${styles.heroHeadText} text-white`}>
안녕하세요, 프론트엔드 개발자
<br />
<span className="text-[#915eff]">천민규 입니다!</span>
</h1>
<p className={`${styles.heroSubText} mt-2 text-white-100`}>
React와 Next.js 위주로 웹 개발을 하고 있습니다.
<br className="sm:block hidden" />{" "}
</p>
</div>
</div>
{/* <div className="absolute inset-0 top-[30%] sm:top-[40%] pointer-events-none"> */}
<RobotCanvas />
{/* </div> */}
</section>
);
};
export default Hero;
가장 먼저 나에 대해 소개하는 섹션
3d로 로봇을 구현해서 걸어가는 모습까지 보여주고 있음
import React, { Suspense, useRef, useEffect } from "react";
import { Canvas, useFrame, useThree } from "@react-three/fiber";
import {
OrbitControls,
Preload,
useGLTF,
useAnimations,
} from "@react-three/drei";
import CanvasLoader from "../Loader";
import * as THREE from "three";
const Robot = () => {
const group = useRef();
const { scene, animations } = useGLTF("/robot/scene.gltf");
const { actions } = useAnimations(animations, group);
const { viewport } = useThree();
useEffect(() => {
if (actions["Prowler_Rig Bipe"]) {
actions["Prowler_Rig Bipe"].play();
actions["Prowler_Rig Bipe"].setLoop(THREE.LoopRepeat, Infinity);
}
}, [actions]);
useFrame((state) => {
if (group.current) {
group.current.position.x += 0.04;
if (group.current.position.x > 40) {
group.current.position.x = -40;
}
// viewport 높이에 따라 y 위치 조정
group.current.position.y = -viewport.height / 3;
}
});
// scale을 viewport 너비에 따라 조정 (선택적)
const scale = Math.min(3, viewport.width / 10);
return (
<primitive
ref={group}
object={scene}
scale={scale}
rotation-y={Math.PI / 2}
/>
);
};
const RobotCanvas = () => {
return (
<Canvas
frameloop="always"
gl={{ preserveDrawingBuffer: true }}
camera={{ position: [0, 0, 35], fov: 55 }}
className="w-full h-full absolute bottom-0 left-0"
>
<Suspense fallback={<CanvasLoader />}>
<OrbitControls
enableZoom={false}
enablePan={false}
enableRotate={false}
/>
<Robot />
<ambientLight intensity={0.7} />
<pointLight position={[10, 10, 10]} intensity={1} />
</Suspense>
<Preload all />
</Canvas>
);
};
export default RobotCanvas;
react three fiber 라이브러리를 사용해서 리액트에서 three.js 선언적으로 사용할 수 있게 조치
GLTF 모델 - 3D 로봇 모델
로봇이 x축 이동시켜서 화면에서 벗어나면 반대편에서 다시 등장하도록 조치
Framer Motion - 애니메이션 효과 위한 라이브러리
React Parallax Tilt - 마우스 호버 시 틸트(기울임) 효과 주는 라이브러리
HOC(Higher Order Component)패턴 - SectionWrapper로 컴포넌트 감싸고 있음
제목 / 소개 / 서비스 카드 섹션으로 구분
아냐 근데... 여기까지 하겠다......