refactor: 얇게 남아있던 별의 꼬리가 사라지도록 수정
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
shouldRecycleFlightStar,
|
||||
} from "@/features/flight-starfield/model/starfieldModel";
|
||||
import { FlightStar } from "@/features/flight-starfield/model/types";
|
||||
import { FLIGHT_STARFIELD_TUNING } from "@/shared/config/starfield";
|
||||
import { clamp } from "@/shared/lib/math/number";
|
||||
import { getPrefersReducedMotionMediaQuery } from "@/shared/lib/motion/prefersReducedMotion";
|
||||
|
||||
@@ -39,6 +40,7 @@ export function FlightStarfieldCanvas({
|
||||
let width = window.innerWidth;
|
||||
let height = window.innerHeight;
|
||||
let animationFrameId = 0;
|
||||
let dpr = 1;
|
||||
|
||||
const motionQuery = getPrefersReducedMotionMediaQuery();
|
||||
let prefersReducedMotion = motionQuery.matches;
|
||||
@@ -48,12 +50,21 @@ export function FlightStarfieldCanvas({
|
||||
const vanishXJitter = vanishXJitterRef.current ?? 0;
|
||||
|
||||
const setCanvasSize = () => {
|
||||
width = window.innerWidth;
|
||||
height = window.innerHeight;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
const viewportWidth = window.visualViewport?.width ?? window.innerWidth;
|
||||
const viewportHeight = window.visualViewport?.height ?? window.innerHeight;
|
||||
width = Math.max(1, Math.floor(viewportWidth));
|
||||
height = Math.max(1, Math.floor(viewportHeight));
|
||||
canvas.style.width = `${width}px`;
|
||||
canvas.style.height = `${height}px`;
|
||||
dpr = window.devicePixelRatio || 1;
|
||||
canvas.width = Math.max(1, Math.floor(width * dpr));
|
||||
canvas.height = Math.max(1, Math.floor(height * dpr));
|
||||
context.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
context.imageSmoothingEnabled = false;
|
||||
};
|
||||
|
||||
const snapToDevicePixel = (value: number) => Math.round(value * dpr) / dpr;
|
||||
|
||||
const getVanishingPoint = () =>
|
||||
createVanishingPoint({
|
||||
width,
|
||||
@@ -102,12 +113,20 @@ export function FlightStarfieldCanvas({
|
||||
const deltaX = toX - fromX;
|
||||
const deltaY = toY - fromY;
|
||||
const movementLength = Math.hypot(deltaX, deltaY);
|
||||
const tailLineWidth = clamp(star.radius * 0.9, 0.65, 1.6);
|
||||
const canDrawTail =
|
||||
star.tailLength >= FLIGHT_STARFIELD_TUNING.tail.cleanup.minTailLengthToDraw &&
|
||||
movementLength >= FLIGHT_STARFIELD_TUNING.tail.cleanup.minMovementToDraw &&
|
||||
visibleAlpha >= FLIGHT_STARFIELD_TUNING.tail.cleanup.minAlphaToDraw &&
|
||||
tailLineWidth >= FLIGHT_STARFIELD_TUNING.tail.cleanup.minLineWidthToDraw;
|
||||
|
||||
if (star.tailLength < 1 || movementLength < 0.001) {
|
||||
if (!canDrawTail) {
|
||||
const snappedToX = snapToDevicePixel(toX);
|
||||
const snappedToY = snapToDevicePixel(toY);
|
||||
context.globalAlpha = visibleAlpha;
|
||||
context.fillStyle = "#f8fbff";
|
||||
context.beginPath();
|
||||
context.arc(toX, toY, star.radius, 0, Math.PI * 2);
|
||||
context.arc(snappedToX, snappedToY, star.radius, 0, Math.PI * 2);
|
||||
context.fill();
|
||||
context.globalAlpha = 1;
|
||||
return;
|
||||
@@ -115,26 +134,33 @@ export function FlightStarfieldCanvas({
|
||||
|
||||
const directionX = deltaX / movementLength;
|
||||
const directionY = deltaY / movementLength;
|
||||
const tailX = toX - directionX * star.tailLength;
|
||||
const tailY = toY - directionY * star.tailLength;
|
||||
const tailX = snapToDevicePixel(toX - directionX * star.tailLength);
|
||||
const tailY = snapToDevicePixel(toY - directionY * star.tailLength);
|
||||
const snappedToX = snapToDevicePixel(toX);
|
||||
const snappedToY = snapToDevicePixel(toY);
|
||||
|
||||
const gradient = context.createLinearGradient(tailX, tailY, toX, toY);
|
||||
const gradient = context.createLinearGradient(
|
||||
tailX,
|
||||
tailY,
|
||||
snappedToX,
|
||||
snappedToY,
|
||||
);
|
||||
gradient.addColorStop(0, "rgba(248, 251, 255, 0)");
|
||||
gradient.addColorStop(1, `rgba(248, 251, 255, ${visibleAlpha})`);
|
||||
|
||||
context.strokeStyle = gradient;
|
||||
context.lineWidth = clamp(star.radius * 0.9, 0.65, 1.6);
|
||||
context.lineWidth = tailLineWidth;
|
||||
context.beginPath();
|
||||
context.moveTo(tailX, tailY);
|
||||
context.lineTo(toX, toY);
|
||||
context.lineTo(snappedToX, snappedToY);
|
||||
context.stroke();
|
||||
|
||||
context.globalAlpha = Math.min(1, visibleAlpha + 0.08);
|
||||
context.fillStyle = "#f8fbff";
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
toX,
|
||||
toY,
|
||||
snappedToX,
|
||||
snappedToY,
|
||||
clamp(star.radius * 0.72, 0.6, 1.45),
|
||||
0,
|
||||
Math.PI * 2,
|
||||
@@ -177,7 +203,12 @@ export function FlightStarfieldCanvas({
|
||||
};
|
||||
|
||||
const drawFrame = (moveStars: boolean) => {
|
||||
context.fillStyle = "rgba(2, 5, 10, 0.3)";
|
||||
context.setTransform(1, 0, 0, 1, 0, 0);
|
||||
context.globalAlpha = 1;
|
||||
context.globalCompositeOperation = "source-over";
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
context.fillStyle = "rgb(2, 5, 10)";
|
||||
context.fillRect(0, 0, width, height);
|
||||
|
||||
drawCenterVeil();
|
||||
@@ -235,7 +266,6 @@ export function FlightStarfieldCanvas({
|
||||
};
|
||||
|
||||
const renderStatic = () => {
|
||||
context.clearRect(0, 0, width, height);
|
||||
drawFrame(false);
|
||||
};
|
||||
|
||||
@@ -264,6 +294,7 @@ export function FlightStarfieldCanvas({
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
window.visualViewport?.addEventListener("resize", handleResize);
|
||||
motionQuery.addEventListener("change", handleMotionChange);
|
||||
|
||||
if (prefersReducedMotion || isPaused) {
|
||||
@@ -274,6 +305,7 @@ export function FlightStarfieldCanvas({
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
window.visualViewport?.removeEventListener("resize", handleResize);
|
||||
motionQuery.removeEventListener("change", handleMotionChange);
|
||||
stopAnimation();
|
||||
};
|
||||
@@ -282,7 +314,7 @@ export function FlightStarfieldCanvas({
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="fixed inset-0 z-0 bg-black pointer-events-none"
|
||||
className="fixed inset-0 z-0 h-screen w-screen bg-black pointer-events-none"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ export const FLIGHT_STARFIELD_TUNING = {
|
||||
pointRange: { min: 0, max: 2.5 },
|
||||
shortRange: { min: 2.5, max: 3.8 },
|
||||
longRange: { min: 4, max: 10 },
|
||||
cleanup: {
|
||||
minAlphaToDraw: 0.09,
|
||||
minMovementToDraw: 0.18,
|
||||
minLineWidthToDraw: 1,
|
||||
minTailLengthToDraw: 1,
|
||||
},
|
||||
},
|
||||
spawnRadius: {
|
||||
centerChance: 0.08,
|
||||
|
||||
Reference in New Issue
Block a user