feat: 일시정지 버튼을 눌렀을 때 별의 움직임이 함께 멈춤

This commit is contained in:
2026-02-14 02:19:34 +09:00
parent 6640962573
commit f32b7ee615
8 changed files with 67 additions and 162 deletions

View File

@@ -16,11 +16,15 @@ import { getPrefersReducedMotionMediaQuery } from '@/shared/lib/motion/prefersRe
export function FlightStarfieldCanvas({
vanishYOffset = -68,
centerProtectRadius = 200,
isPaused = false,
}: {
vanishYOffset?: number;
centerProtectRadius?: number;
isPaused?: boolean;
}) {
const canvasRef = useRef<HTMLCanvasElement>(null);
const starsRef = useRef<FlightStar[]>([]);
const vanishXJitterRef = useRef<number | null>(null);
useEffect(() => {
const canvas = canvasRef.current;
@@ -35,7 +39,10 @@ export function FlightStarfieldCanvas({
const motionQuery = getPrefersReducedMotionMediaQuery();
let prefersReducedMotion = motionQuery.matches;
const vanishXJitter = createFlightVanishXJitter();
if (vanishXJitterRef.current === null) {
vanishXJitterRef.current = createFlightVanishXJitter();
}
const vanishXJitter = vanishXJitterRef.current ?? 0;
const setCanvasSize = () => {
width = window.innerWidth;
@@ -58,7 +65,10 @@ export function FlightStarfieldCanvas({
);
setCanvasSize();
let stars: FlightStar[] = createStars();
if (starsRef.current.length === 0) {
starsRef.current = createStars();
}
let stars = starsRef.current;
const applyCenterProtection = (x: number, y: number, alpha: number) => {
const centerX = width / 2;
@@ -183,6 +193,7 @@ export function FlightStarfieldCanvas({
})
) {
stars[index] = createFlightStar({ width, height, isRespawn: true });
starsRef.current = stars;
return;
}
@@ -198,7 +209,18 @@ export function FlightStarfieldCanvas({
drawVignette();
};
const stopAnimation = () => {
if (!animationFrameId) return;
cancelAnimationFrame(animationFrameId);
animationFrameId = 0;
};
const render = () => {
if (prefersReducedMotion || isPaused) {
animationFrameId = 0;
return;
}
drawFrame(true);
animationFrameId = requestAnimationFrame(render);
};
@@ -211,8 +233,9 @@ export function FlightStarfieldCanvas({
const handleResize = () => {
setCanvasSize();
stars = createStars();
starsRef.current = stars;
if (prefersReducedMotion) {
if (prefersReducedMotion || isPaused) {
renderStatic();
}
};
@@ -221,18 +244,20 @@ export function FlightStarfieldCanvas({
prefersReducedMotion = event.matches;
if (prefersReducedMotion) {
cancelAnimationFrame(animationFrameId);
stopAnimation();
renderStatic();
return;
}
render();
if (!isPaused && !animationFrameId) {
render();
}
};
window.addEventListener('resize', handleResize);
motionQuery.addEventListener('change', handleMotionChange);
if (prefersReducedMotion) {
if (prefersReducedMotion || isPaused) {
renderStatic();
} else {
render();
@@ -241,9 +266,9 @@ export function FlightStarfieldCanvas({
return () => {
window.removeEventListener('resize', handleResize);
motionQuery.removeEventListener('change', handleMotionChange);
cancelAnimationFrame(animationFrameId);
stopAnimation();
};
}, [vanishYOffset, centerProtectRadius]);
}, [vanishYOffset, centerProtectRadius, isPaused]);
return <canvas ref={canvasRef} className="fixed inset-0 z-0 bg-black pointer-events-none" />;
}