-
-
Save adrianhajdin/7bc0603ee0b1bd2872b80a62c24b5e5f to your computer and use it in GitHub Desktop.
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&family=Work+Sans:wght@100;200;300;400;500;600;700;800;900&display=swap"); | |
@tailwind base; | |
@tailwind components; | |
@tailwind utilities; | |
:root { | |
--blue-rgb: 237 245 255; | |
--green-rgb: 125 161 35; | |
} | |
body { | |
font-family: "Work Sans", sans-serif; | |
} | |
body:has(.card[data-color="blue"]:hover) { | |
background-color: rgb(var(--blue-rgb) / 25%); | |
} | |
body:has(.card[data-color="green"]:hover) { | |
background-color: rgb(var(--green-rgb) / 25%); | |
} | |
@layer utilities { | |
.max-container { | |
@apply max-w-5xl mx-auto sm:p-16 pb-12 !pt-[126px] px-8 min-h-[calc(100vh-80px)]; | |
} | |
.head-text { | |
@apply sm:text-5xl text-3xl font-semibold sm:leading-snug font-poppins; | |
} | |
.subhead-text { | |
@apply font-semibold sm:text-3xl text-xl relative font-poppins; | |
} | |
.blue-gradient_text { | |
@apply bg-gradient-to-r from-[#00c6ff] to-[#0072ff] bg-clip-text text-transparent; | |
} | |
.input { | |
@apply bg-white border border-gray-200 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 mt-2.5 font-normal shadow-card; | |
} | |
.textarea { | |
@apply block p-2.5 w-full text-sm text-gray-900 bg-white rounded-lg border border-gray-200 focus:ring-blue-500 focus:border-blue-500 mt-2.5 font-normal shadow-card; | |
} | |
.btn { | |
@apply text-white bg-gradient-to-r from-[#00c6ff] to-[#0072ff] focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center; | |
} | |
.header { | |
@apply flex justify-between items-center sm:px-16 px-8 py-4 max-w-5xl mx-auto absolute top-0 bg-transparent z-10 right-0 left-0; | |
} | |
.footer { | |
@apply max-w-5xl mx-auto sm:px-16 pb-6 px-8 flex flex-col gap-7; | |
} | |
.footer-container { | |
@apply flex flex-wrap gap-7 items-center justify-between; | |
} | |
.info-box { | |
@apply mx-5 relative flex text-white flex-col gap-3 max-w-2xl neo-brutalism-blue pt-4 pb-12 px-8; | |
} | |
.neo-btn { | |
@apply py-3 px-6 rounded-lg text-blue-500 text-center font-semibold sm:w-1/2 w-[90%] -bottom-5 absolute mx-auto right-0 left-0 flex justify-center items-center gap-3; | |
} | |
.cta { | |
@apply w-full flex items-center md:flex-row flex-col sm:mt-16 mt-8 gap-7; | |
} | |
.cta-text { | |
@apply text-black-500 font-extrabold flex-1 text-3xl max-md:text-center; | |
} | |
} | |
.glassmorphism { | |
background: rgba(8, 116, 239, 0.07); | |
backdrop-filter: blur(10px); | |
-webkit-backdrop-filter: blur(10px); | |
border-radius: 10px; | |
border: 1px solid rgba(255, 255, 255, 0.18); | |
} | |
.logo { | |
border-radius: 8.889px; | |
background: #fff; | |
box-shadow: 0px 10px 35px -4px rgba(67, 83, 255, 0.15), | |
0px 1.5px 4px -1px rgba(67, 83, 255, 0.2); | |
} | |
.block-container { | |
position: relative; | |
transition: 250ms; | |
perspective: 500px; | |
} | |
.block-container .btn-back { | |
position: absolute; | |
inset: 0; | |
z-index: -1; | |
width: inherit; | |
height: inherit; | |
transition: 250ms; | |
transform-style: preserve-3d; | |
transform-origin: bottom right; | |
transform: rotateZ(15deg); | |
will-change: transform; | |
box-shadow: 16px 0 40px #e4e4e4; | |
} | |
.block-container .btn-back-red { | |
background: linear-gradient(135deg, #ff4b1f -20%, #ff9068 120%); | |
} | |
.block-container .btn-back-green { | |
background: linear-gradient(135deg, #adfda2 -20%, #11d3f3 120%); | |
} | |
.block-container .btn-back-yellow { | |
background: linear-gradient(135deg, #f7971e -20%, #ffd200 120%); | |
} | |
.block-container .btn-back-blue { | |
background: linear-gradient(135deg, #0061ff -20%, #60efff 120%); | |
} | |
.block-container .btn-back-orange { | |
background: linear-gradient(135deg, #ff0f7b -20%, #f89b29 120%); | |
} | |
.block-container .btn-back-pink { | |
background: linear-gradient(135deg, #e81cff -20%, #40c9ff 120%); | |
} | |
.block-container .btn-back-black { | |
background: linear-gradient(135deg, #0a1647 -20%, #e4e7e4 120%); | |
} | |
.block-container .btn-front { | |
position: absolute; | |
inset: 0; | |
z-index: 1; | |
width: inherit; | |
height: inherit; | |
background-color: #ffffff33; | |
-webkit-backdrop-filter: blur(20px); | |
backdrop-filter: blur(20px); | |
transition: 250ms; | |
transform-style: preserve-3d; | |
transform-origin: top left; | |
overflow: hidden; | |
} | |
.block-container:hover > .btn-back { | |
transform: translateZ(20px) rotateZ(15deg) rotateX(-20deg) rotateY(-20deg); | |
} | |
.block-container:hover > .btn-front { | |
transform: translateZ(80px) translateY(-5px) rotateX(15deg) rotateY(15deg); | |
} | |
/* Neo Brutalism */ | |
.neo-brutalism-blue { | |
background: #2b77e7; | |
position: relative; | |
border-radius: 10px; | |
border: #2b77e7; | |
box-shadow: 0.6vmin 0.6vmin #336cc1, 1vmin 1vmin #0092db, 1vmin 1vmin #0092db, | |
0.65vmin 1vmin #0092db, 1vmin 0.65vmin #0092db; | |
} | |
.neo-brutalism-white { | |
background: #fff; | |
border: #fff; | |
box-shadow: 0.6vmin 0.6vmin #fff, 1vmin 1vmin #d2e4ff, 1vmin 1vmin #d2e4ff, | |
0.65vmin 1vmin #d2e4ff, 1vmin 0.65vmin #d2e4ff; | |
} |
import { meta, shopify, starbucks, tesla } from "../assets/images"; | |
import { | |
car, | |
contact, | |
css, | |
estate, | |
express, | |
git, | |
github, | |
html, | |
javascript, | |
linkedin, | |
mongodb, | |
motion, | |
mui, | |
nextjs, | |
nodejs, | |
pricewise, | |
react, | |
redux, | |
sass, | |
snapgram, | |
summiz, | |
tailwindcss, | |
threads, | |
typescript | |
} from "../assets/icons"; | |
export const skills = [ | |
{ | |
imageUrl: css, | |
name: "CSS", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: express, | |
name: "Express", | |
type: "Backend", | |
}, | |
{ | |
imageUrl: git, | |
name: "Git", | |
type: "Version Control", | |
}, | |
{ | |
imageUrl: github, | |
name: "GitHub", | |
type: "Version Control", | |
}, | |
{ | |
imageUrl: html, | |
name: "HTML", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: javascript, | |
name: "JavaScript", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: mongodb, | |
name: "MongoDB", | |
type: "Database", | |
}, | |
{ | |
imageUrl: motion, | |
name: "Motion", | |
type: "Animation", | |
}, | |
{ | |
imageUrl: mui, | |
name: "Material-UI", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: nextjs, | |
name: "Next.js", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: nodejs, | |
name: "Node.js", | |
type: "Backend", | |
}, | |
{ | |
imageUrl: react, | |
name: "React", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: redux, | |
name: "Redux", | |
type: "State Management", | |
}, | |
{ | |
imageUrl: sass, | |
name: "Sass", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: tailwindcss, | |
name: "Tailwind CSS", | |
type: "Frontend", | |
}, | |
{ | |
imageUrl: typescript, | |
name: "TypeScript", | |
type: "Frontend", | |
} | |
]; | |
export const experiences = [ | |
{ | |
title: "React.js Developer", | |
company_name: "Starbucks", | |
icon: starbucks, | |
iconBg: "#accbe1", | |
date: "March 2020 - April 2021", | |
points: [ | |
"Developing and maintaining web applications using React.js and other related technologies.", | |
"Collaborating with cross-functional teams including designers, product managers, and other developers to create high-quality products.", | |
"Implementing responsive design and ensuring cross-browser compatibility.", | |
"Participating in code reviews and providing constructive feedback to other developers.", | |
], | |
}, | |
{ | |
title: "React Native Developer", | |
company_name: "Tesla", | |
icon: tesla, | |
iconBg: "#fbc3bc", | |
date: "Jan 2021 - Feb 2022", | |
points: [ | |
"Developing and maintaining web applications using React.js and other related technologies.", | |
"Collaborating with cross-functional teams including designers, product managers, and other developers to create high-quality products.", | |
"Implementing responsive design and ensuring cross-browser compatibility.", | |
"Participating in code reviews and providing constructive feedback to other developers.", | |
], | |
}, | |
{ | |
title: "Web Developer", | |
company_name: "Shopify", | |
icon: shopify, | |
iconBg: "#b7e4c7", | |
date: "Jan 2022 - Jan 2023", | |
points: [ | |
"Developing and maintaining web applications using React.js and other related technologies.", | |
"Collaborating with cross-functional teams including designers, product managers, and other developers to create high-quality products.", | |
"Implementing responsive design and ensuring cross-browser compatibility.", | |
"Participating in code reviews and providing constructive feedback to other developers.", | |
], | |
}, | |
{ | |
title: "Full stack Developer", | |
company_name: "Meta", | |
icon: meta, | |
iconBg: "#a2d2ff", | |
date: "Jan 2023 - Present", | |
points: [ | |
"Developing and maintaining web applications using React.js and other related technologies.", | |
"Collaborating with cross-functional teams including designers, product managers, and other developers to create high-quality products.", | |
"Implementing responsive design and ensuring cross-browser compatibility.", | |
"Participating in code reviews and providing constructive feedback to other developers.", | |
], | |
}, | |
]; | |
export const socialLinks = [ | |
{ | |
name: 'Contact', | |
iconUrl: contact, | |
link: '/contact', | |
}, | |
{ | |
name: 'GitHub', | |
iconUrl: github, | |
link: 'https://github.com/YourGitHubUsername', | |
}, | |
{ | |
name: 'LinkedIn', | |
iconUrl: linkedin, | |
link: 'https://www.linkedin.com/in/YourLinkedInUsername', | |
} | |
]; | |
export const projects = [ | |
{ | |
iconUrl: pricewise, | |
theme: 'btn-back-red', | |
name: 'Amazon Price Tracker', | |
description: 'Developed a web application that tracks and notifies users of price changes for products on Amazon, helping users find the best deals.', | |
link: 'https://github.com/adrianhajdin/pricewise', | |
}, | |
{ | |
iconUrl: threads, | |
theme: 'btn-back-green', | |
name: 'Full Stack Threads Clone', | |
description: 'Created a full-stack replica of the popular discussion platform "Threads," enabling users to post and engage in threaded conversations.', | |
link: 'https://github.com/adrianhajdin/threads', | |
}, | |
{ | |
iconUrl: car, | |
theme: 'btn-back-blue', | |
name: 'Car Finding App', | |
description: 'Designed and built a mobile app for finding and comparing cars on the market, streamlining the car-buying process.', | |
link: 'https://github.com/adrianhajdin/project_next13_car_showcase', | |
}, | |
{ | |
iconUrl: snapgram, | |
theme: 'btn-back-pink', | |
name: 'Full Stack Instagram Clone', | |
description: 'Built a complete clone of Instagram, allowing users to share photos and connect with friends in a familiar social media environment.', | |
link: 'https://github.com/adrianhajdin/social_media_app', | |
}, | |
{ | |
iconUrl: estate, | |
theme: 'btn-back-black', | |
name: 'Real-Estate Application', | |
description: 'Developed a web application for real estate listings, facilitating property searches and connecting buyers with sellers.', | |
link: 'https://github.com/adrianhajdin/projects_realestate', | |
}, | |
{ | |
iconUrl: summiz, | |
theme: 'btn-back-yellow', | |
name: 'AI Summarizer Application', | |
description: 'App that leverages AI to automatically generate concise & informative summaries from lengthy text content, or blogs.', | |
link: 'https://github.com/adrianhajdin/project_ai_summarizer', | |
} | |
]; |
const normalizedRotation = | |
((rotation % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI); | |
// Set the current stage based on the island's orientation | |
switch (true) { | |
case normalizedRotation >= 5.45 && normalizedRotation <= 5.85: | |
setCurrentStage(4); | |
break; | |
case normalizedRotation >= 0.85 && normalizedRotation <= 1.3: | |
setCurrentStage(3); | |
break; | |
case normalizedRotation >= 2.4 && normalizedRotation <= 2.6: | |
setCurrentStage(2); | |
break; | |
case normalizedRotation >= 4.25 && normalizedRotation <= 4.75: | |
setCurrentStage(1); | |
break; | |
default: | |
setCurrentStage(null); | |
} |
/** @type {import('tailwindcss').Config} */ | |
export default { | |
content: [ | |
"./index.html", | |
"./src/**/*.{js,ts,jsx,tsx}", | |
], | |
theme: { | |
extend: { | |
colors: { | |
gray: { | |
200: "#D5DAE1" | |
}, | |
black: { | |
DEFAULT: "#000", | |
500: "#1D2235" | |
}, | |
blue: { | |
500: "#2b77e7" | |
} | |
}, | |
fontFamily: { | |
worksans: ["Work Sans", "sans-serif"], | |
poppins: ['Poppins', "sans-serif"] | |
}, | |
boxShadow: { | |
card: '0px 1px 2px 0px rgba(0, 0, 0, 0.05)' | |
} | |
}, | |
}, | |
plugins: [], | |
} |
thank you, @ng9000!
@BenjaminAdimachukwu have you added something to the original code? I don't get this error, looks like you added something in Sky.jsx model, that crashed everithing. Can you show your sky code?
(btw its not tho best place for this kind of questions)
@alexzborovskii yeah. thanks, bro. there was an error in the Sky.jsx code. it has been corrected now, and the app works fine. Thank you
hey @Arshnoor19
whenver I am using useAnimations in Project i am getting error . Please refere above screenshots
Thank you @Arshnoor19 , Now its working great
hello i want to move my dragon as he used Take 001 to fly dragon i want to Walk my dragon what should i do
Could log the actions and see what is available
If you work out the walk you can use something like this to make it walk with some minor modifications to the x, y, z
` useEffect(() => {
actions["Take 01"].play();
return () => {
actions["Take 01"].stop();
};
}, [actions]);
useFrame(({ clock }) => {
const time = clock.getElapsedTime() / 2;
// Define the flight path here, for example a circular path
const x = Math.sin(time) * 3;
const y = Math.cos(time) * 1;
const z = Math.sin(time) * Math.cos(time);
// Update position
ref.current.position.set(x, y, z);
// Update rotation to face the direction of movement
// Assuming the butterfly faces along the positive Y-axis by default
ref.current.rotation.y = Math.atan2(x, y);
// Add some scale changes for more natural movement
ref.current.scale.set(
1 + Math.sin(time) * 0.1,
1 + Math.cos(time) * 0.1,
1
);
});`
Thankyou @DLParkin but its not working what is Take 01 , Take 001 and from where its coming?
Does anyone know how to solve mobile scrolling issue where it freezes after trying to scroll? (edit) I found the solution you have to add touch event listener to make it scroll nicely
useEffect(() => { // Add event listeners for pointer, keyboard and touch events const canvas = gl.domElement; canvas.addEventListener("pointerdown", handlePointerDown); canvas.addEventListener("pointerup", handlePointerUp); canvas.addEventListener("pointermove", handlePointerMove); canvas.addEventListener("touchstart", handlePointerDown); canvas.addEventListener("touchmove", handlePointerMove); canvas.addEventListener("touchend", handlePointerUp); window.addEventListener("keydown", handleKeyDown); window.addEventListener("keyup", handleKeyUp); // Remove event listeners return () => { canvas.removeEventListener("pointerdown", handlePointerDown); canvas.removeEventListener("pointerup", handlePointerUp); canvas.removeEventListener("pointermove", handlePointerMove); canvas.removeEventListener("touchstart", handlePointerDown); canvas.removeEventListener("touchmove", handlePointerMove); canvas.removeEventListener("touchend", handlePointerUp); window.removeEventListener("keydown", handleKeyDown); window.removeEventListener("keyup", handleKeyUp); }; }, [gl, handlePointerDown, handlePointerUp, handlePointerMove]);
portfolio_123.mp4
Thank you @ng9000 for this. You are a real one
i want to that my human walk but it does not actions as object like hit run walk etc. what can i do to make my women walk
the app controls rotation with keys and drag, How can i add scroll to it?
Hello! Hope all is well. Rather than use an island, I decided to use a ship for my main center piece for my interactive resume website.
It was all going amazing until it was time to implement the ship rotating when being dragged.
Now whenever I load the website I have a white page, and the errors and my Ship.jsx can be found below:
`/* eslint-disable react/no-unknown-property */
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Author: Eric de Menezes (https://sketchfab.com/ericmvieira28)
License: SKETCHFAB Standard (https://sketchfab.com/licenses)
Source: https://sketchfab.com/3d-models/going-merry-one-piece-518566a3846c4b10ae45ea0794b46fe7
Title: Going Merry One Piece
*/
import { useRef, useEffect } from "react";
import { useGLTF, useAnimations } from "@react-three/drei";
import {useFrame, useThree } from '@react-three/fiber';
import shipScene from '../assets/3d/going_merry_one_piece.glb';
import { a } from '@react-spring/three';
const Ship = ({isRotating, setIsRotating, ...props}) => {
const {gl , viewport} = useThree();
const shipRef = useRef();
const group = useRef();
const { nodes, materials, animations } = useGLTF(shipScene);
const { actions } = useAnimations(animations, group);
const lastX = useRef(0);
const rotationSpeed = useRef(0);
const dampingFactor = 0.95;
const handlePointerDown = (e) => {
e.stopPropagation();
e.preventDefault();
setIsRotating(true);
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
lastX.current = clientX;
}
const handlePointerUp = (e) => {
e.stopPropagation();
e.preventDefault();
setIsRotating(false);
}
const handlePointerMove = (e) => {
e.stopPropagation();
e.preventDefault();
if(isRotating){
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const delta = (clientX - lastX.current) / viewport.width;
shipRef.current.rotation.y += delta * 0.01 * Math.PI;
lastX.current = clientX;
rotationSpeed.current = delta * 0.01 * Math.PI;
}
}
const handleKeyDown = (e) => {
if(e.key === 'ArrowLeft') {
if(!isRotating) setIsRotating(true);
shipRef.current.rotation.y += 0.01 * Math.PI;
} else if (e.key === 'ArrowRight') {
if(!isRotating) setIsRotating(true);
shipRef.current.rotation.y -= 0.01 * Math.PI;
}
}
const handleKeyUp = (e) => {
if(e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
setIsRotating(false);
}
}
useEffect(() => {
const canvas = gl.domElement;
canvas.addEventListener('pointerdown', handlePointerDown);
canvas.addEventListener('pointerup', handlePointerUp);
canvas.addEventListener('pointermove', handlePointerMove);
document.addEventListener('keydown', handleKeyDown)
document.addEventListener('keyup', handleKeyUp)
return () => {
canvas.removeEventListener('pointerdown', handlePointerDown);
canvas.removeEventListener('pointerup', handlePointerUp);
canvas.removeEventListener('pointermove', handlePointerMove);
document.removeEventListener('keydown', handleKeyDown)
document.removeEventListener('keyup', handleKeyUp)
}
}, [gl, handlePointerDown, handlePointerUp, handlePointerMove]);
useFrame(() => {
if(!isRotating) {
rotationSpeed.current = { ...rotationSpeed.current, y: rotationSpeed.current.y * dampingFactor };
if(Math.abs(rotationSpeed.current) < 0.001){
rotationSpeed.current = { ...rotationSpeed.current, y: 0 };
const currentRotation = rotation.y;
}
} else {
const {rotation} = shipRef.current;
}
})
const normalizedRotation =
((rotation % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);
// Set the current stage based on the island's orientation
switch (true) {
case normalizedRotation >= 5.45 && normalizedRotation <= 5.85:
setCurrentStage(4);
break;
case normalizedRotation >= 0.85 && normalizedRotation <= 1.3:
setCurrentStage(3);
break;
case normalizedRotation >= 2.4 && normalizedRotation <= 2.6:
setCurrentStage(2);
break;
case normalizedRotation >= 4.25 && normalizedRotation <= 4.75:
setCurrentStage(1);
break;
default:
setCurrentStage(null);
}
return (
<a.group ref={shipRef} {...props} dispose={null}>
<group name="Sketchfab_Scene">
<group name="Sketchfab_model" rotation={[-Math.PI / 2, 0, 0]}>
<group name="root">
<group name="GLTF_SceneRootNode" rotation={[Math.PI / 2, 0, 0]}>
<group name="Empty_0" position={[133.633, 3.843, 8.289]} />
<group
name="CameraShakifyv2_Camera_0_4"
position={[-12308.8, -11100.4, -3524]}
/>
<group name="GoingMerry_5">
<mesh
name="Object_6"
geometry={nodes.Object_6.geometry}
material={materials.UV_04}
/>
<mesh
name="Object_7"
geometry={nodes.Object_7.geometry}
material={materials.UV_04}
/>
<mesh
name="Object_8"
geometry={nodes.Object_8.geometry}
material={materials.UV_03}
/>
<mesh
name="Object_9"
geometry={nodes.Object_9.geometry}
material={materials.UV_01}
/>
<mesh
name="Object_10"
geometry={nodes.Object_10.geometry}
material={materials.UV_02}
/>
</group>
<group
name="Trees_8"
position={[2.576, 4.768, 0.02]}
rotation={[0.004, 0, 0.028]}
scale={1.127}
>
<mesh
name="Object_12"
geometry={nodes.Object_12.geometry}
material={materials["Material.003"]}
/>
<mesh
name="Object_13"
geometry={nodes.Object_13.geometry}
material={materials["Material.004"]}
/>
<mesh
name="Object_14"
geometry={nodes.Object_14.geometry}
material={materials["Material.004"]}
/>
<mesh
name="Object_15"
geometry={nodes.Object_15.geometry}
material={materials["Material.004"]}
/>
<mesh
name="Object_16"
geometry={nodes.Object_16.geometry}
material={materials["Material.004"]}
/>
<mesh
name="Object_17"
geometry={nodes.Object_17.geometry}
material={materials["Material.004"]}
/>
</group>
</group>
</group>
</group>
</group>
</a.group>
);
}
export default Ship;
`
@Yashpatole81 Hi! For me your problem seems to be located in Island.jsx on line 25. Check it or show as the Island.jsx.
Thanks a lot for your tutorial, it's a cool project.
Here is my finished version, had a little bit of modification.
https://jishen027.github.io/3d_portfolio/
Island.jsx:23 Uncaught TypeError: Cannot read properties of undefined (reading 'geometry')
Hello! Hope all is well. Rather than use an island, I decided to use a ship for my main center piece for my interactive resume website.
It was all going amazing until it was time to implement the ship rotating when being dragged.
Now whenever I load the website I have a white page, and the errors and my Ship.jsx can be found below:
````/* eslint-disable react/no-unknown-property /
/
Auto-generated by: https://github.com/pmndrs/gltfjsx
Author: Eric de Menezes (https://sketchfab.com/ericmvieira28)
License: SKETCHFAB Standard (https://sketchfab.com/licenses)
Source: https://sketchfab.com/3d-models/going-merry-one-piece-518566a3846c4b10ae45ea0794b46fe7
Title: Going Merry One Piece
*/import { useRef, useEffect } from "react";
import { useGLTF, useAnimations } from "@react-three/drei";
import {useFrame, useThree } from '@react-three/fiber';
import shipScene from '../assets/3d/going_merry_one_piece.glb';
import { a } from '@react-spring/three';const Ship = ({isRotating, setIsRotating, ...props}) => {
const {gl , viewport} = useThree();
const shipRef = useRef();
const group = useRef();
const { nodes, materials, animations } = useGLTF(shipScene);
const { actions } = useAnimations(animations, group);
const lastX = useRef(0);
const rotationSpeed = useRef(0);
const dampingFactor = 0.95;const handlePointerDown = (e) => {
e.stopPropagation();
e.preventDefault();
setIsRotating(true);const clientX = e.touches ? e.touches[0].clientX : e.clientX; lastX.current = clientX;
}
const handlePointerUp = (e) => {
e.stopPropagation();
e.preventDefault();
setIsRotating(false);
}
const handlePointerMove = (e) => {
e.stopPropagation();
e.preventDefault();
if(isRotating){
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const delta = (clientX - lastX.current) / viewport.width;
shipRef.current.rotation.y += delta * 0.01 * Math.PI;
lastX.current = clientX;
rotationSpeed.current = delta * 0.01 * Math.PI;
}}
const handleKeyDown = (e) => {
if(e.key === 'ArrowLeft') {
if(!isRotating) setIsRotating(true);
shipRef.current.rotation.y += 0.01 * Math.PI;
} else if (e.key === 'ArrowRight') {
if(!isRotating) setIsRotating(true);
shipRef.current.rotation.y -= 0.01 * Math.PI;}
}
const handleKeyUp = (e) => {
if(e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
setIsRotating(false);
}
}
useEffect(() => {
const canvas = gl.domElement;
canvas.addEventListener('pointerdown', handlePointerDown);
canvas.addEventListener('pointerup', handlePointerUp);
canvas.addEventListener('pointermove', handlePointerMove);
document.addEventListener('keydown', handleKeyDown)
document.addEventListener('keyup', handleKeyUp)return () => { canvas.removeEventListener('pointerdown', handlePointerDown); canvas.removeEventListener('pointerup', handlePointerUp); canvas.removeEventListener('pointermove', handlePointerMove); document.removeEventListener('keydown', handleKeyDown) document.removeEventListener('keyup', handleKeyUp) }
}, [gl, handlePointerDown, handlePointerUp, handlePointerMove]);
useFrame(() => {
if(!isRotating) {
rotationSpeed.current = { ...rotationSpeed.current, y: rotationSpeed.current.y * dampingFactor };
if(Math.abs(rotationSpeed.current) < 0.001){
rotationSpeed.current = { ...rotationSpeed.current, y: 0 };
const currentRotation = rotation.y;
}
} else {
const {rotation} = shipRef.current;
}
})
const normalizedRotation =
((rotation % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);// Set the current stage based on the island's orientation
switch (true) {
case normalizedRotation >= 5.45 && normalizedRotation <= 5.85:
setCurrentStage(4);
break;
case normalizedRotation >= 0.85 && normalizedRotation <= 1.3:
setCurrentStage(3);
break;
case normalizedRotation >= 2.4 && normalizedRotation <= 2.6:
setCurrentStage(2);
break;
case normalizedRotation >= 4.25 && normalizedRotation <= 4.75:
setCurrentStage(1);
break;
default:
setCurrentStage(null);
}return (
<a.group ref={shipRef} {...props} dispose={null}> <group name="Sketchfab_Scene"> <group name="Sketchfab_model" rotation={[-Math.PI / 2, 0, 0]}> <group name="root"> <group name="GLTF_SceneRootNode" rotation={[Math.PI / 2, 0, 0]}> <group name="Empty_0" position={[133.633, 3.843, 8.289]} /> <group name="CameraShakifyv2_Camera_0_4" position={[-12308.8, -11100.4, -3524]} /> <group name="GoingMerry_5"> <mesh name="Object_6" geometry={nodes.Object_6.geometry} material={materials.UV_04} /> <mesh name="Object_7" geometry={nodes.Object_7.geometry} material={materials.UV_04} /> <mesh name="Object_8" geometry={nodes.Object_8.geometry} material={materials.UV_03} /> <mesh name="Object_9" geometry={nodes.Object_9.geometry} material={materials.UV_01} /> <mesh name="Object_10" geometry={nodes.Object_10.geometry} material={materials.UV_02} /> </group> <group name="Trees_8" position={[2.576, 4.768, 0.02]} rotation={[0.004, 0, 0.028]} scale={1.127} > <mesh name="Object_12" geometry={nodes.Object_12.geometry} material={materials["Material.003"]} /> <mesh name="Object_13" geometry={nodes.Object_13.geometry} material={materials["Material.004"]} /> <mesh name="Object_14" geometry={nodes.Object_14.geometry} material={materials["Material.004"]} /> <mesh name="Object_15" geometry={nodes.Object_15.geometry} material={materials["Material.004"]} /> <mesh name="Object_16" geometry={nodes.Object_16.geometry} material={materials["Material.004"]} /> <mesh name="Object_17" geometry={nodes.Object_17.geometry} material={materials["Material.004"]} /> </group> </group> </group> </group> </group> </a.group>
);
}
export default Ship;
`
I have also got this error.Have u solved this error then please help me to solve this.
Thanks a lot for your tutorial, it's a cool project. Here is my finished version, had a little bit of modification. https://jishen027.github.io/3d_portfolio/
Heyy Jishen, I was having trouble in deploying this project on github . Can you please give me the steps to deploy this 3d portfolio? I have deployed it on github but not loading 3d island. I am giving my deployed link too. Please check it and help me. Thanks in advance.
https://sainathgaikwad.github.io/Sainath-Gaikwad-Portfolio/
HI i am getting issues in HomeInfo.jsx . As in the video when you rotate the island you get different stages but when I followed the same I am just getting the 1st stage that is introduction and not the other stages. Also when i inspect I get this error "chunk-25Y2DYCY.js?v=91d39a21:16442 Text is not allowed in the R3F tree! This could be stray whitespace or characters."
Do let me know what is the issue.
import React from "react"
import { Link } from "react-router-dom";
import { arrow } from "../assets/icons";
const InfoBox = ({ text, link, btnText }) => (
);const renderContent = {
1: (
Hi, I am Arpit👋
A Software Engineer from India
),
2: (
),
3: (
),
4: (
),
};
const HomeInfo = ({ currentStage }) => {
return renderContent[currentStage] || null;
}
export default HomeInfo;
import { useState, Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import Island from "../models/Island";
import Loader from "../components/Loader";
import Sky from "../models/Sky";
import Bird from "../models/Bird";
import Plane from "../models/Plane";
import HomeInfo from "../components/HomeInfo";
const Home = () => {
const [isRotating, setIsRotating] = useState(false);
const [currentStage, setcurrentStage] = useState(1);
const adjustIslandForScreenSize = () => {
let screenScale = null;
let screenPosition = [0, -6.5, -43];
let rotation = [0.1, 4.7, 0];
if (window.innerWidth < 768) {
screenScale = [0.9, 0.9, 0.9];
} else {
screenScale = [1, 1, 1];
}
return [screenScale, screenPosition, rotation];
};
const adjustPlaneForScreenSize = () => {
let screenScale, screenPosition;
if (window.innerWidth < 768) {
screenScale = [1.5, 1.5, 1.5];
screenPosition = [0, -1.5, 0];
} else {
screenScale = [3, 3, 3];
screenPosition = [0, -4, -4];
}
return [screenScale, screenPosition];
};
const [islandScale, islandPosition, islandRotation] =
adjustIslandForScreenSize();
const [planeScale, planePosition] = adjustPlaneForScreenSize();
return (
{currentStage && }
<Canvas
className={`w-full h-screen bg-transparent ${
isRotating ? "cursor-grabbing" : "cursor-grab"
}`}
camera={{ near: 0.1, far: 1000 }}
>
<Suspense fallback={<Loader />}>
<directionalLight position={[1, 1, 1]} intensity={2} />
<ambientLight intensity={0.5} />
<hemisphereLight
skyColor="#b1e1ff"
groundColor="#000000"
intensity={1}
/>
<Bird />
<Sky isRotating={isRotating} />
<Island
position={islandPosition}
scale={islandScale}
rotation={islandRotation}
isRotating={isRotating}
setIsRotating={setIsRotating}
setcurrentStage={setcurrentStage}
/>
<Plane
isRotating={isRotating}
planePosition={planePosition}
planeScale={planeScale}
rotation={[0, 20, 0]}
/>
</Suspense>
</Canvas>
</section>
);
};
export default Home;
please can you help me the arrow does not appear and when i scroll on the screen, it is not appear the about , contectand projects page
import React from "react";
import { Link } from "react-router-dom";
import { arrow } from "../assets/icons";
// Functional component InfoBox to display information with a link and button
const InfoBox = ({ text, link, btnText }) => (
{/* Create a link with specified destination and button text */} {btnText} {/* Display an arrow image when hovered over */}
// Object containing different content to render based on currentStage
const renderContent = {
1: (
Hi, I am Muaz 👋
A Software Engineer from Eibtikar Tech
),
2: (
),
3: (
),
4: (
),
};
// Functional component HomeInfo to render content based on currentStage
const HomeInfo = ({ currentStage }) => {
return renderContent[currentStage] || null;
};
export default HomeInfo;
Hello I am getting this error when I click on the 3D object to move it. As soon as I click and drag on the webpage it pops the error message of:
There is an error regarding a TypeError: Cannot read properties of undefined (reading 'rotation').
The specific lines of code that are not working are using the "current.rotation.y".
Any Help Would be Greatly Appreciated!!
Thank you
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Author: nimzu (https://sketchfab.com/nimzuk)
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)
Source: https://sketchfab.com/3d-models/foxs-islands-163b68e09fcc47618450150be7785907
Title: Fox's islands
*/
import {a} from '@react-spring/three';
import React, { useRef, useEffect } from 'react';
import { useGLTF } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import islandScene from '../assets/3d/island.glb';
const Island = (props) => {
const isLandRef = useRef();
const { nodes, materials } = useGLTF(islandScene)
return (
<a.group ref={isLandRef}{...props} >
</a.group>
)
}
export default Island;
my 3d models not showing
hey @ng9000 !
maybe something in the handlePointerMove is wrong
check the math again .... I guess that will fix the problem
also, check the dampingFactor, which is also really sensitive to a float value