diff --git a/apps/site/design.md b/apps/site/design.md index 27b5baf..80316f1 100644 --- a/apps/site/design.md +++ b/apps/site/design.md @@ -37,6 +37,28 @@ **접근 실패 기록** — `iglooinc.com` 은 hugedomains 파킹으로 302, `lasvit.com` 은 403. `reference-method.md` §3-b 가 경고한 그대로였다. 왕복 세 번에서 끊고 우회했다. +### 히어로 국소 레퍼런스 (1′) + +R1~R3 로 구조를 잡은 뒤에도 히어로가 어색해서 **국소 브리프 표**로 두 곳을 더 실측했다. +`design.md` 는 "3D 는 액자 안"까지만 답하고 **액자가 화면의 몇 %여야 하는지는 답하지 않는다.** + +| 사이트 | 3D 영역 | 텍스트 위치 | h1 | +|---|---|---|---| +| lusion.co | 1440×645 = 첫 화면의 **71%** | 캔버스 **위**, 조밀하게 | 36px | +| basement.studio | 1425×900 = **100%** | 캔버스 **아래**(y=916) | 87px, weight 600 | +| railway.com | SVG 1062×755, h1 아래 | 중앙 상단 | 54px, **1줄** | +| **우리(고치기 전)** | 1352×465 = **52%** | 위 380px | 41.5px | + +셋 다 3D 와 텍스트를 세로로 완전히 분리하고, 3D 가 첫 화면의 **70% 이상**을 먹는다. +우리는 텍스트 43% / 3D 52% 로 **둘 다 어중간했다.** basement 형(첫 화면 전체 3D)은 CTA 가 +첫 화면에서 밀려나므로 전환이 목적인 우리에게 맞지 않는다. lusion 비율을 택했다. + +**현행: 텍스트 24% · 액자 59% · 캡션과 링크가 액자 아래 한 줄.** +링크(저장소·npm)를 텍스트 블록에서 액자 캡션 줄로 내려 상단을 비웠다. + +**레퍼런스를 보기 전에 네 번 고쳤다.** 판 폭 7.4 → 15, 액자 비율 16/7 → 16/5.5 → 16/6.6 → 16/6, +sway 0.5 → 0.9 → 0.16. 전부 계산이지 근거가 아니었다. 레퍼런스 두 곳을 재자 한 번에 정리됐다. + ## 한 문장 컨셉 > **검사대 위의 물체.** 액자가 게이트고, 안에 든 것이 검사 중인 디자인이고, 밖의 글자가 판정 기록이다. @@ -146,6 +168,15 @@ WebGL 게이트: `prefers-reduced-motion` 이면 **아예 시작하지 않는다 - **언어 자동 리다이렉트 / 국기 아이콘** — 사용자를 놀라게 하고, 언어는 국가가 아니다 - **두 판을 번역으로 만들기** — 각 언어판을 따로 썼다 +## 히어로 3D 의 형태 결정 + +- 판 **15 × 6** (액자 비율 2.5:1 과 일치). 첫 판이 화면을 완전히 덮어 이미 첫 게이트 안에 들어와 있다 +- 판이 화면보다 좁으면 통과하는 내내 좌우 테두리가 남아 **세로 기둥 두 개**로 보인다. 실제로 그렇게 보였다 +- 판 높이가 시야보다 작으면 위아래 테두리가 액자 경계에 겹쳐 **이중선**이 된다 +- 어긋남(sway)은 `0.16 + 0.05i` 로 아주 작게. 키우면 '통과하는 문'이 아니라 **쌓아둔 사각형**이 된다. + 중심축이 살아야 원근이 터널로 읽힌다 +- `GATE_GAP` 6.4, 카메라 시작 z 7.2 + ## 다음 실행이 해야 할 일 1. **배포 후 Lighthouse 로 첫 인터랙션·LCP·CLS 를 재고 "미측정" 을 채운다.** 채우기 전까지 비워둔다 diff --git a/apps/site/src/components/Hero.astro b/apps/site/src/components/Hero.astro index 3b41d22..ff406d8 100644 --- a/apps/site/src/components/Hero.astro +++ b/apps/site/src/components/Hero.astro @@ -31,9 +31,6 @@ const { c, ui } = Astro.props; copiedLabel={ui.copied} note={c.installNote} /> - @@ -52,7 +49,12 @@ const { c, ui } = Astro.props; {c.stage.pass}

-
{c.stage.caption}
+
+ {c.stage.caption} + + {c.links.map((l) => {l.label})} + +
@@ -69,8 +71,11 @@ const { c, ui } = Astro.props; padding-inline: var(--space-4); display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); - gap: var(--space-6); - align-items: start; + gap: var(--space-5) var(--space-6); + /* 왼쪽 열은 h1 하나(2줄), 오른쪽은 셋이라 높이가 100px 차이 난다. + start 나 end 로 붙이면 그 차이가 한쪽에 몰려 구멍으로 보인다. + 가운데로 두면 위아래로 갈려 여백으로 읽힌다. */ + align-items: center; margin-bottom: var(--space-5); } @@ -110,7 +115,7 @@ const { c, ui } = Astro.props; .stage-frame { position: relative; - aspect-ratio: 16 / 5.5; + aspect-ratio: 16 / 6; border: 1px solid var(--glass-edge); border-radius: var(--radius-frame); background: var(--surface-sunken); @@ -167,15 +172,23 @@ const { c, ui } = Astro.props; } figcaption { - margin-top: var(--space-3); + margin-top: var(--space-2); font-size: var(--step-0); color: var(--ink-muted); - max-width: var(--measure); + display: flex; + flex-wrap: wrap; + align-items: baseline; + justify-content: space-between; + gap: var(--space-3) var(--space-5); } + .cap-text { max-width: var(--measure); } + .cap-links { display: flex; gap: var(--space-4); flex: none; } @media (max-width: 900px) { .hero-head { grid-template-columns: 1fr; gap: var(--space-5); } - .stage-frame { aspect-ratio: 4 / 3; } + /* 4/3 이면 320px 에서 액자가 193px, 화면의 27% 다. 데스크톱이 56% 인데 + 모바일에서만 3D 가 조연이 될 이유가 없다. 정사각으로 36% 를 준다. */ + .stage-frame { aspect-ratio: 1 / 1; } } diff --git a/apps/site/src/lib/hero-scene.ts b/apps/site/src/lib/hero-scene.ts index 45a2b23..284f09e 100644 --- a/apps/site/src/lib/hero-scene.ts +++ b/apps/site/src/lib/hero-scene.ts @@ -223,13 +223,22 @@ async function boot({ canvas, accentVar, glowVar, onGate }: HeroSceneOptions): P }); // 판은 깊이 축에 정면으로 선다. 떠다니는 사각형이 아니라 통과하는 문이다. - const GATE_GAP = 5.2; + // + // 폭이 중요하다. 액자는 가로로 길어(약 2.9:1) 카메라의 수평 시야가 + // 거리 d 에서 2.23*d 인데, 판이 그보다 좁으면 통과하는 내내 좌우 테두리가 + // 화면 안에 남는다. 그러면 "문을 지난다"가 아니라 세로 기둥 두 개가 + // 지나가는 것으로 보인다 — 실제로 그렇게 보였다. + // 판을 액자 비율에 맞춰 첫 판이 화면을 덮게 하면, 가까워질수록 좌우가 + // 화면 밖으로 빠지고 뒤 판들이 원근으로 남아 터널이 된다. + const GATE_GAP = 6.4; const panes: import("three").Mesh[] = []; - const geo = new THREE.PlaneGeometry(7.4, 5.2, 1, 1); + const geo = new THREE.PlaneGeometry(15, 6, 1, 1); for (let i = 0; i < PANE_COUNT; i++) { const m = new THREE.Mesh(geo, paneMat); // 좌우로 조금씩 어긋나게 세워 통과할 때 옆면이 스친다 - const sway = (i % 2 === 0 ? 1 : -1) * (0.5 + i * 0.12); + // 어긋남은 아주 작게. 판이 좌우로 흩어지면 '통과하는 문'이 아니라 + // '쌓아둔 사각형'이 된다. 중심축이 살아야 원근이 터널로 읽힌다. + const sway = (i % 2 === 0 ? 1 : -1) * (0.16 + i * 0.05); m.position.set(sway, Math.sin(i * 1.3) * 0.32, -i * GATE_GAP); m.rotation.set(0, sway * 0.05, sway * 0.018); m.userData["index"] = i; diff --git a/packages/skill/SKILL.md b/packages/skill/SKILL.md index 0d1a80e..0c2fec3 100644 --- a/packages/skill/SKILL.md +++ b/packages/skill/SKILL.md @@ -66,8 +66,22 @@ description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬. | 조건 | 경로 | 도는 단계 | |---|---|---| | (A 또는 B) 이고 C 아니오 | **전체** | 0 → 1 → 2 → 3 → 4 → 5 → 6 | -| (A 또는 B) 이고 C 예 | **연장** | 0 → 3 → 4 → 5 → 6 — 방향은 `design.md` 가 이미 답했다 | -| A·B 둘 다 아니오, 손대는 섹션 2개 이하 | **국소** | 0 → 4 → 5 → 6(한 줄 추기) | +| (A 또는 B) 이고 C 예 | **연장** | 0 → **1′** → 3 → 4 → 5 → 6 — 방향은 `design.md` 가 이미 답했다 | +| A·B 둘 다 아니오, 손대는 섹션 2개 이하 | **국소** | 0 → **1′** → 4 → 5 → 6(한 줄 추기) | + +**1′ — 국소 레퍼런스.** 연장·국소도 레퍼런스를 **완전히 건너뛰지는 않는다.** +`design.md` 는 방향과 토큰까지만 답한다. "히어로를 다시 짜라" 같은 요청에 대해 그 파일은 +**형태를 답하지 않는다** — 액자가 화면의 몇 %여야 하는지, 헤드라인이 몇 px 이어야 하는지는 거기 없다. +그 빈칸을 메우는 것이 기본값이고, 기본값의 총합이 슬롭이다. + +`references/galleries.md` §1 의 **국소 브리프 표**에서 손대는 대상(히어로·내비·푸터·요금제·404·후기)의 +소스를 열고 **사례 1개를 실측한다.** 전체 경로의 3개가 아니라 1개다. 6축을 다 채우지 않아도 된다. +**손대는 축만 숫자로 적으면 통과다.** + +> 실측 사례: designpaca 자신의 히어로를 고칠 때 이 단계를 건너뛰고 수치만 조정하다가 +> 판 폭·액자 비율을 네 번 고쳤다. 레퍼런스 2개를 실제로 재자 한 번에 답이 나왔다 — +> 3D 영역이 첫 화면의 71%(lusion.co)와 100%(basement.studio)인데 우리는 52%였다. +> **"이상한데요" 는 취향이 아니라 측정 가능한 차이였다.** 고른 경로와 근거를 한 줄로 말해라: *"국소 — 새 화면 없음, 토큰 재정의 없음, 섹션 1개."* @@ -242,7 +256,7 @@ HTML-in-Canvas(`drawElementImage`)는 **폴백을 완성한 뒤에만** 얹는 | 파일 | 언제 읽나 | |---|---| -| `references/galleries.md` | 1단계 — 어느 갤러리를 볼지 정할 때 | +| `references/galleries.md` | 1단계 — 어느 갤러리를 볼지 정할 때 / **1′ — 국소 브리프 표** | | `references/reference-method.md` | 1단계 — 레퍼런스를 뜯어볼 때 | | `references/presets/README.md` | 2단계 — 미학 방향을 고를 때 (고른 프리셋 하나만 추가로 읽는다) | | `references/tokens.md` | 3단계 — 토큰을 정할 때 |