Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .yarn/install-state.gz
Binary file not shown.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
"devDependencies": {
"prettier": "^3.1.0",
"typescript": "^5.2.2"
},
"dependencies": {
"@emotion/react": "^11.11.1"
}
}
75 changes: 38 additions & 37 deletions packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
{
"name": "client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@react-three/drei": "^9.88.13",
"@react-three/fiber": "^8.15.10",
"@types/react-router-dom": "^5.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"three": "^0.158.0"
},
"devDependencies": {
"@react-three/postprocessing": "^2.15.11",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/three": "^0.158.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"leva": "^0.9.35",
"three-stdlib": "^2.28.5",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-tsconfig-paths": "^4.2.1",
"zustand": "^4.4.6"
}
"name": "client",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@emotion/styled": "^11.11.0",
"@react-three/drei": "^9.88.13",
"@react-three/fiber": "^8.15.10",
"@types/react-router-dom": "^5.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.18.0",
"three": "^0.158.0"
},
"devDependencies": {
"@react-three/postprocessing": "^2.15.11",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/three": "^0.158.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"leva": "^0.9.35",
"three-stdlib": "^2.28.5",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vite-tsconfig-paths": "^4.2.1",
"zustand": "^4.4.6"
}
}
83 changes: 83 additions & 0 deletions packages/client/src/components/feature/PostStars/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Star from '../Star';
import * as THREE from 'three';
import { ThreeEvent } from '@react-three/fiber';
import { Html } from '@react-three/drei';
import { useCameraStore } from 'store/useCameraStore';
import { useRef } from 'react';
import styled from '@emotion/styled';

const Label = styled.div`
transform: translate3d(calc(60%), calc(-30%), 0);
background: #fff;
color: #000;
padding: 10px 15px;
border-radius: 5px;
font-family: 'Noto Sans KR', sans-serif;
width: 100%;
text-align: center;
&::before {
content: '';
position: absolute;
top: 20px;
left: -30px;
height: 2px;
width: 50px;
background: #fff;
}
`;

const dummyData = [
{
position: new THREE.Vector3(1000, 1000, 1800),
size: 100,
color: 'red',
},
{
position: new THREE.Vector3(1300, 500, 1000),
size: 200,
color: 'blue',
},
{
position: new THREE.Vector3(3000, 1000, 2500),
size: 150,
color: 'yellow',
},
]; // TODO: 서버로부터 받아온 데이터로 변경 필요

export default function PostStars() {
const { targetView, setTargetView } = useCameraStore();
const stars: JSX.Element[] = [];

dummyData.forEach((data, index) => {
const meshRef = useRef<THREE.Mesh>(null!);

const handleMeshClick = (e: ThreeEvent<MouseEvent>) => {
e.stopPropagation();

if (meshRef.current !== targetView) {
setTargetView(meshRef.current);
return;
}

setTargetView(null);
};

stars.push(
<Star
key={index}
position={data.position}
size={data.size}
color={data.color}
ref={meshRef}
onClick={handleMeshClick}
>
<Html>
<Label>별글 입니당</Label>
</Html>
</Star>,
);
});

return <group>{stars}</group>;
}
3 changes: 2 additions & 1 deletion packages/client/src/components/feature/Screen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EffectComposer, Bloom } from '@react-three/postprocessing';
import { useControls } from 'leva';
import { CAMERA_POSITION, CAMERA_ROTATION, CAMERA_FAR } from 'constants/camera';
import Controls from '../Controls/Controls.tsx';
import PostStars from '../PostStars/index.tsx';
import { useCameraStore } from 'store/useCameraStore.ts';

export default function Screen() {
Expand Down Expand Up @@ -45,9 +46,9 @@ export default function Screen() {
<ambientLight color="#fff" intensity={5} />
<axesHelper args={[20000]} />
<Controls />

<BackgroundStars />
<Galaxy />
<PostStars />
</Canvas>
</div>
);
Expand Down
58 changes: 33 additions & 25 deletions packages/client/src/components/feature/Star/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import { useRef } from 'react';
import { useRef, forwardRef, useEffect, ForwardedRef } from 'react';
import * as THREE from 'three';
import { ThreeEvent, useFrame } from '@react-three/fiber';
import { useFrame, ThreeEvent } from '@react-three/fiber';
import { DIST_LIMIT } from 'constants/star';
import { useCameraStore } from 'store/useCameraStore';

interface PropsType {
children?: React.ReactNode;
onClick?: (e: ThreeEvent<MouseEvent>) => void;
position: THREE.Vector3;
size: number;
color: string;
}

export default function Star({ position, size, color }: PropsType) {
const meshRef = useRef<THREE.Mesh>(null!);
const { targetView, setTargetView } = useCameraStore();
const useForwardRef = <T,>(ref: ForwardedRef<T>, initialValue: any = null) => {
const targetRef = useRef<T>(initialValue);

useEffect(() => {
if (!ref) return;

if (typeof ref === 'function') {
ref(targetRef.current);
} else {
ref.current = targetRef.current;
}
}, [ref]);

return targetRef;
};

const Star = forwardRef<THREE.Mesh, PropsType>((props, ref) => {
const innerRef = useForwardRef(ref);

useFrame((state, delta) => {
const cameraDistance = new THREE.Vector3(0, 0, 0).distanceTo(
Expand All @@ -21,31 +37,23 @@ export default function Star({ position, size, color }: PropsType) {
const scale = cameraDistance / DIST_LIMIT;

if (cameraDistance > DIST_LIMIT) {
meshRef.current.scale.x = scale;
meshRef.current.scale.y = scale;
meshRef.current.scale.z = scale;
innerRef.current!.scale.x = scale;
innerRef.current!.scale.y = scale;
innerRef.current!.scale.z = scale;
}
});

const handleMeshClick = (e: ThreeEvent<MouseEvent>) => {
e.stopPropagation();

if (meshRef.current !== targetView) {
setTargetView(meshRef.current);
return;
}

setTargetView(null);
};

return (
<mesh ref={meshRef} position={position} onClick={(e) => handleMeshClick(e)}>
<sphereGeometry args={[size, 32, 16]} />
<mesh ref={innerRef} position={props.position} onClick={props.onClick}>
<sphereGeometry args={[props.size, 32, 16]} />
<meshStandardMaterial
color={color}
emissive={color}
color={props.color}
emissive={props.color}
emissiveIntensity={2}
/>
{props.children}
</mesh>
);
}
});

export default Star;
Loading