[fix] landing: 히어로 구도 좌측 쏠림 · 순환 링 정원화 · Playfair self-host
- 군집 좌표를 투영 후 위치에서 역산하도록 변경. sx = 0.5 + (x−0.5)·k 라 깊이마다 당겨지는 양이 다르고, 가장 깊은 협력사가 중앙으로 제일 많이 끌려와 구도가 왼쪽으로 쏠렸다. 이제 화면 19/50/81% 에 대칭으로 놓인다 — 라벨도 같은 값을 써서 어긋나지 않는다. - 순환 링을 원근 타원에서 정원으로 교체(orbit-ring). 점선 궤도만 회전하고 마디·라벨은 고정이다. 눕힌 타원은 깊이는 생기지만 "닫힌 루프"의 완결감이 없다. - 학습 단계 입자 궤도 제거. 화면을 가로지르는 큰 선이 순환 링과 의미가 겹치고 시선을 뺏었다. 순환은 링이 맡고 입자는 안쪽으로 흡수만 한다. - Playfair Display self-host(latin 서브셋 39KB). 구글 폰트 CDN 제거 — 서드파티 요청이 LCP 를 흔들고 방문자 IP 가 외부로 나간다. - 히어로 CTA "협상 시연 보기" → "직접 협상해 보기". 데모는 실제로 동작한다(앵커 이하 낙찰 · 카드 소모 역제안 · 소진 시 개찰 확인). 수동태 문구는 인터랙티브 기능을 영상처럼 보이게 해 전환을 깎는다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6785c8a6f4
commit
87b896fc2f
@ -36,7 +36,7 @@ export function HeroDataFlow() {
|
||||
className={`absolute -translate-x-1/2 -translate-y-1/2 whitespace-nowrap text-[13px] font-semibold text-on-stage-soft/80 transition-opacity duration-500 ${
|
||||
phase === "cluster" ? "opacity-100" : "opacity-0"
|
||||
}`}
|
||||
style={{ left: `${anchor.x * 100}%`, top: `${anchor.labelY * 100}%` }}
|
||||
style={{ left: `${anchor.screenX * 100}%`, top: `${anchor.labelY * 100}%` }}
|
||||
>
|
||||
{anchor.label}
|
||||
</span>
|
||||
@ -44,7 +44,7 @@ export function HeroDataFlow() {
|
||||
</div>
|
||||
|
||||
{/* 카피는 상단 55%, 데이터 흐름은 하단 밴드. 둘이 겹치지 않게 층을 나눈다. */}
|
||||
<div className="relative z-10 max-w-4xl mx-auto px-6 w-full text-center pt-[11vh]">
|
||||
<div className="relative z-10 max-w-4xl mx-auto px-6 w-full text-center pt-[7vh]">
|
||||
{/* 히어로 카피에는 진입 애니메이션을 걸지 않는다.
|
||||
여기가 LCP 요소라 opacity:0 으로 시작하면 하이드레이션 전까지 첫 화면이 비고,
|
||||
광고 유입처럼 JS 가 느린 환경에서 그대로 손실이 된다. 모션은 배경 캔버스가 맡는다. */}
|
||||
|
||||
@ -70,13 +70,25 @@ export const perspective = (z: number) => 0.42 + 0.58 * z
|
||||
|
||||
/* 분류 단계에서 각 무리가 앉는 자리와 깊이.
|
||||
무리마다 z 평면을 하나씩 준다 — 입자마다 z 를 따로 주면 격자가 3D 로 뒤틀려
|
||||
표로 안 읽힌다. 무리 단위로 주면 격자는 온전한 채 그룹 사이에만 깊이가 생긴다. */
|
||||
export const CLUSTER_ANCHORS = [
|
||||
{ key: "item", x: 0.17, z: 0.9, labelY: 0.525, label: "거래 품목" },
|
||||
{ key: "user", x: 0.45, z: 0.66, labelY: 0.525, label: "사용자" },
|
||||
{ key: "partner", x: 0.76, z: 0.44, labelY: 0.525, label: "협력사" },
|
||||
표로 안 읽힌다. 무리 단위로 주면 격자는 온전한 채 그룹 사이에만 깊이가 생긴다.
|
||||
|
||||
x 는 "투영된 뒤 어디에 놓일지"를 먼저 정하고 역산한 값이다.
|
||||
투영은 깊이마다 다른 배율로 중앙으로 당기기 때문에(k = 0.42+0.58z), 세계 좌표를
|
||||
눈대중으로 고르면 가장 깊은 무리가 제일 많이 끌려와 구도가 한쪽으로 쏠린다. */
|
||||
const CLUSTER_PLAN = [
|
||||
{ key: "item", screenX: 0.19, z: 0.9, label: "거래 품목" },
|
||||
{ key: "user", screenX: 0.5, z: 0.66, label: "사용자" },
|
||||
{ key: "partner", screenX: 0.81, z: 0.44, label: "협력사" },
|
||||
] as const
|
||||
|
||||
export const CLUSTER_ANCHORS = CLUSTER_PLAN.map((c) => ({
|
||||
...c,
|
||||
/** 투영 전 세계 좌표 — 투영을 거치면 screenX 에 놓인다 */
|
||||
x: VANISH_X + (c.screenX - VANISH_X) / perspective(c.z),
|
||||
/** 라벨은 격자 위. 투영 후 y 라서 화면 좌표 그대로 쓴다 */
|
||||
labelY: VANISH_Y + (0.5 - VANISH_Y) * perspective(c.z),
|
||||
}))
|
||||
|
||||
/* 격자 배치 — 종류별 [열, 열간격(x, 화면비), 행간격(y, 밴드지역비)].
|
||||
간격은 글리프보다 확실히 커야 한다. 붙으면 표가 아니라 노이즈로 읽힌다. */
|
||||
const GRID = [
|
||||
|
||||
Loading…
Reference in New Issue
Block a user