소개 페이지 전면 재디자인 — Ethereal Glass

design-taste-frontend, high-end-visual-design, redesign-existing-projects 를
로드해 리디자인 모드로 진행했다. 이전 페이지는 디자인 스킬을 파는 자리가
문서처럼 생겼다는 지적을 받았다.

Design Read
- redesign-overhaul / 개발자 대상 / 정밀기기 언어
- DESIGN_VARIANCE 8 · MOTION_INTENSITY 6 · VISUAL_DENSITY 3

방향
- 다크 잉크 바탕에 three.js 셰이더 광원. 유리 패널이 그 위에 뜬다
- 리퀴드 글래스는 이 브리프에서 장식이 아니라 제품 시연이다.
  SVG 필터와 three.js 의 결합 그 자체이기 때문이다
- 밝은 밴드는 조판 섹션 하나뿐. 한글이 종이 위에 있어야 하는 자리다

제품 증명
- 히어로 배경에 셰이더(초기 번들 밖, 첫 페인트 후 지연 로드)
- 재료 섹션에 SVG 필터 3종을 실제로 먹인 타일: 그레인, 굴절, 듀오톤
- 도그푸딩 산출물 2개를 실제 스크린샷으로. 가짜 목업이 아니다

감사에서 걸려 고친 것
- backdrop-filter 에 SVG 를 얹으면 Chrome 이 선언 전체를 버린다.
  CSS.supports 는 참을 주면서 computed 는 none 이 된다
- main 에서 그리드 클래스가 빠져 subgrid 가 붕괴, 가로 444px 오버플로
- 진입 연출이 두 번 콘텐츠를 삼켰다. opacity 를 버리고 transform 만 남겼다
- eyebrow 4개, 제목 em-dash 2건

수치는 불리해진 것도 그대로 싣는다
- 반투명 패널 1개 -> 29개. 유리가 주제가 됐으므로
- three.js 185KB(gzip). 데모라서 JS 예산을 올렸고 그 사실을 페이지에 적었다
This commit is contained in:
Yun Chan 2026-08-20 11:45:38 +09:00
parent 6e05e69ca4
commit be343cdab5
22 changed files with 1695 additions and 439 deletions

View file

@ -1,39 +1,70 @@
---
import type { Content } from "../i18n/content";
interface Props {
c: Content["preflight"];
}
interface Props { c: Content["preflight"]; }
const { c } = Astro.props;
---
<section class="section" aria-labelledby="preflight-h">
<h2 id="preflight-h">{c.h2}</h2>
<p class="lead pf-lead">{c.lead}</p>
{/* 레이아웃 패밀리: 2열 대비. 왼쪽이 걸린 것, 오른쪽이 고친 것 */}
<section class="section preflight" aria-labelledby="pf-h">
<h2 id="pf-h" class="reveal">{c.h2}</h2>
<p class="lead pf-lead reveal">{c.lead}</p>
<ul class="log">
<div class="full log">
{
c.items.map((i) => (
<li class="entry">
<p class="caught">{i.caught}</p>
c.items.map((i, idx) => (
<article class="entry glass reveal" style={`--reveal-delay:${idx * 60}ms`}>
<p class="caught">
<span class="tick" aria-hidden="true" />
{i.caught}
</p>
<p class="fixed muted">{i.fixed}</p>
</li>
</article>
))
}
</ul>
</div>
{c.note && <p class="pf-note muted">{c.note}</p>}
<p class="pf-note muted reveal">{c.note}</p>
</section>
<style>
.pf-lead { margin-bottom: var(--space-5); }
.log { margin: 0; padding: 0; list-style: none; }
.entry {
padding-block: var(--space-3);
border-top: 1px solid var(--line);
.pf-lead { margin-block: var(--space-4) var(--space-6); }
.log {
max-width: 1180px;
margin-inline: auto;
padding-inline: var(--space-4);
display: grid;
gap: var(--space-3);
}
.entry {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
gap: var(--space-5);
padding: var(--space-4);
align-items: start;
}
.caught {
margin: 0;
font-weight: 500;
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: var(--space-2);
align-items: start;
}
/* 걸린 항목을 표시하는 짧은 획. 상태 점이 아니라 획이다 */
.tick {
width: 3px;
height: 1.1em;
margin-top: 0.2em;
border-radius: var(--radius-sm);
background: var(--accent);
}
.entry:last-child { border-bottom: 1px solid var(--line); }
.caught { margin: 0 0 var(--space-1); }
.fixed { margin: 0; font-size: var(--step-0); }
.pf-note { margin-top: var(--space-4); font-size: var(--step-0); }
.pf-note { margin-top: var(--space-5); font-size: var(--step-0); }
@media (max-width: 760px) {
.entry { grid-template-columns: 1fr; gap: var(--space-2); }
}
</style>