diff --git a/.env.example b/.env.example deleted file mode 100644 index 41def0f..0000000 --- a/.env.example +++ /dev/null @@ -1,62 +0,0 @@ -# designpaca 배포 환경 -# -# 이 파일은 커밋된다. 실제 값은 `.env` 에 넣어라 (.gitignore 에 있다). -# cp .env.example .env -# -# 채워진 값은 실측으로 확인한 것이고, 빈 값은 사람이 발급해야 하는 것이다. - -# ── NAS ────────────────────────────────────────────────────── -# Synology DS420+ · Linux 4.4.302+ · Tailscale 로 접근한다. -# SSH 키(id_ed25519)로 이미 붙는다. 비밀번호가 필요 없다. -NAS_HOST=100.116.83.60 -NAS_HOST_LAN=192.168.0.39 -NAS_USER=yunchan - -# ── Forgejo ────────────────────────────────────────────────── -# 컨테이너 kd-forgejo (codeberg.org/forgejo/forgejo:11) + postgres:16-alpine -# 웹 3000 → Cloudflare 프록시로 https://git.chanpaca.net -# git SSH 2222 → 컨테이너 내부 22 -# -# 주의: git.chanpaca.net 은 Cloudflare 뒤라 22/2222 가 막혀 있다. -# git push 는 도메인이 아니라 Tailscale 주소로 해야 한다. -FORGEJO_URL=https://git.chanpaca.net -FORGEJO_SSH_HOST=100.116.83.60 -FORGEJO_SSH_PORT=2222 -FORGEJO_CONTAINER=kd-forgejo - -# 등록된 SSH 키 이름: encep-win (yunchan 계정) -FORGEJO_OWNER=yunchan -FORGEJO_REPO=designpaca - -# 완성되는 remote URL: -# ssh://git@100.116.83.60:2222/yunchan/designpaca.git - -# ── 사람이 발급해야 하는 것 ────────────────────────────────── -# 아래는 전부 비워둔다. 값을 아는 사람만 채울 수 있다. - -# Forgejo API 토큰. 저장소 생성·시크릿 등록에 쓴다. -# git.chanpaca.net → 설정 → 애플리케이션 → 토큰 생성 -# 권한: repository(write), user(read) -FORGEJO_TOKEN= - -# npmjs 배포 토큰 (Automation 타입). -# npmjs.com → Access Tokens → Generate → Automation -NPM_TOKEN= - -# Forgejo 사설 npm 레지스트리 미러용 토큰. -# FORGEJO_TOKEN 과 같은 값을 써도 되지만, 권한을 나누려면 따로 발급한다. -FORGEJO_NPM_TOKEN= - -# Forgejo 릴리스 생성용 토큰. 워크플로가 draft 릴리스를 만든다. -RELEASE_TOKEN= - -# Cloudflare Pages 배포. -# dash.cloudflare.com → My Profile → API Tokens -# 권한: Account / Cloudflare Pages / Edit -CF_API_TOKEN= -CF_ACCOUNT_ID= - -# Cloudflare Pages 프로젝트 이름 (아직 만들지 않았다) -CF_PAGES_PROJECT= -# 연결할 도메인 -SITE_DOMAIN=designpaca.chanpaca.net diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 20b5441..0000000 --- a/.gitattributes +++ /dev/null @@ -1,6 +0,0 @@ -# 배포되는 텍스트는 어느 OS 에서 체크아웃하든 LF 다. -# SKILL.md 의 YAML 프론트매터가 CRLF 에서 파서에 따라 깨진다. -* text=auto eol=lf -*.png binary -*.webp binary -*.ico binary diff --git a/apps/site/design.md b/apps/site/design.md index b513a46..fe35366 100644 --- a/apps/site/design.md +++ b/apps/site/design.md @@ -189,33 +189,6 @@ WebGL 게이트: `prefers-reduced-motion` 이면 **아예 시작하지 않는다 `ResizeObserver` 로 캔버스를 따라가게 했다. `window.resize` 만 듣던 동안 히어로 높이 변화를 놓쳐 배경이 화면의 3분의 2만 덮고 아래가 검게 비었다. -## 패럴랙스 지도 (실측) - -깊이가 다른 층을 겹쳐 시차를 만든다. **한 층은 반드시 고정이다** — -전부 움직이면 기준이 없어 그냥 흔들리는 페이지가 된다. - -| 자리 | 층 | 방식 | 실측 이동 | -|---|---|---|---| -| 히어로 배경 | 셰이더 흐름 필드 | `scroll(root)` | **+56px** ↓ | -| 히어로 글자 | | `scroll(root)` | **−88px** ↑ (반대 방향) | -| 파이프라인 | 게이트 씬(three.js) | `sticky` + 카메라 | 6단계를 통과 | -| ㅤ└ 단계명 | | — | **0** 고정 | -| ㅤ└ 산출물 | | `view()` | ±14px | -| 재료 · 설치 · 프리플라이트 | 배경 사진 | `fixed` | **0 — 원경** | -| 사례 | 배경 사진 | `drift` 0.4 | 이미지 높이의 28.6% | -| 조판 | 종이 | `drift` 0.25 | −122px (근경) | -| 재료 타일 | | `view()` | ±26 / ±58px | -| 프리플라이트 항목 | | `view()` | 6 → 10px (뒤일수록 늦게) | -| **수치** | | **없음** | 의도적 정지 | - -세 가지 깊이가 다 있다 — **원경**(fixed) · **중경**(drift) · **근경**(콘텐츠와 함께). -종이를 원경으로 두지 않은 이유는 손에 닿는 거리의 재질이기 때문이다. - -모바일(390px)에서도 `fixed` 가 유지된다. `background-attachment: fixed` 를 안 쓴 덕이다. - -`prefers-reduced-motion` 에서는 게이트 씬이 아예 시작하지 않고, 고정 배경은 -`position: absolute` 로 흐름에 돌아가며, 모든 `view()` 애니메이션이 꺼진다. - ## 모션 문법 — 섹션마다 다른 말 같은 패럴랙스를 전부에 걸면 벽지다. 각 섹션의 주장을 움직임으로 옮겼다. @@ -240,185 +213,14 @@ WebGL 게이트: `prefers-reduced-motion` 이면 **아예 시작하지 않는다 | 레이어 | 무엇 | 어디 | 근거 | |---|---|---|---| -기준면은 `BgPhoto` 컴포넌트가 만든다(아래 표). +| `.bg-grid` | 간격 눈금 격자. 셀이 `--grid-cell = --space-6` | 파이프라인 · 수치 | "모든 값이 토큰에서 나온다"가 배경에서도 성립해야 한다. 계기판의 눈금이기도 하다 | +| `.bg-glow` | 광원 블롭 두 개. 섹션마다 `--glow-x` 로 자리를 옮긴다 | 재료 · 설치 | 히어로의 빛이 페이지를 관통해 마지막 CTA 에서 돌아온다 | -**CSS 격자를 한동안 같이 깔았다가 걷어냈다.** 사진이 들어온 뒤로 배경이 두 겹이 되어 -서로 경쟁했고, 격자는 배경이라기보다 **표**로 읽혔다. 배경도 한 섹션에 하나다. +격자는 가장자리를 마스크로 지운다 — 화면 끝까지 가면 배경이 아니라 **표**가 된다. +배경이 가장 적게 움직인다. 앞의 것보다 크게 움직이면 앞으로 튀어나와 보인다. -한 층은 반드시 고정이다 — 파이프라인의 단계명은 움직이지 않는다. -전부 움직이면 기준이 없어 그냥 흔들리는 페이지가 된다. - -### 패럴랙스를 "고정"으로 바꿨다 - -세 번 고친 뒤에도 티가 나지 않았다. 원인은 **방식 자체**였다 — -느리게 같이 움직이는 것으로는 원경이 안 된다. 속도만 다를 뿐 방향이 같기 때문이다. - -**배경을 뷰포트에 고정한다.** `background-attachment: fixed` 는 iOS Safari 가 throttle 하므로 -쓰지 않고, 섹션에 `clip-path: inset(0)` 을 걸어 **`position: fixed` 의 컨테이닝 블록**으로 만든다. -그러면 배경이 화면에 멈춘 채 그 섹션 안에서만 보인다. - -실측: 스크롤 1000px 구간에서 배경의 `viewportTop` 이 계속 **0**. - -대가가 둘 있고 둘 다 받아들였다. - -- **조상에 `transform`·`filter`·`mask` 를 못 쓴다.** 그것들도 컨테이닝 블록을 만들어 - 고정을 깨뜨린다. 그래서 위아래 페이드 마스크를 포기하고 경계는 clip 으로 딱 자른다 -- `prefers-reduced-motion` 에서는 `position: absolute` 로 되돌린다 - -**전부 고정하지는 않았다.** 원경과 중경을 나눴다. - -| 섹션 | 모드 | 왜 | -|---|---|---| -| 재료 · 설치 · 프리플라이트 | `fixed` | 원경. 콘텐츠만 그 위를 지나간다 | -| 사례 | `drift` 0.4 | 두 결과물이 흐르는 자리라 배경도 같이 흐른다 | -| 조판 | `drift` 0.25 | **종이는 손에 닿는 거리다.** 원경으로 두면 거짓말이 된다 | - -### 유리 테두리는 conic 이 아니라 linear 로 돈다 - -헤더의 헤어라인이 **변마다 끊겨** 보였다. `conic-gradient` 로 만들었기 때문이다. -conic 은 중심에서 각도로 도는데, 1180×54 처럼 납작한 형태에서는 각도가 급변해서 -긴 변에서 색이 거의 안 변하고 짧은 변에서 한꺼번에 바뀐다. 실제로 아래쪽만 절반 밝았다. - -`linear-gradient(100deg, …)` 로 바꾸면 네 변이 같은 그라디언트를 공유해 -**테두리를 따라 이어진다.** 마스크로 1px 만 남기는 구조는 그대로다. - -그리고 아주 얕은 글로우를 얹었다 — `0 0 22px -8px` 에 강조색을 42% 섞었다. -유리가 차갑게만 보이지 않게 하는 정도이고, 밝은 밴드에서는 흰빛 대신 -그림자로 뒤집는다(`--glass-rim`·`--glass-bloom` 을 `.band-inverse` 에서 재정의). - -### 테두리 광을 회전시켰다 - -정지한 헤어라인 위에 **도는 빛**을 얹었다. `conic` 의 각도를 `@property` 로 돌리면 -매 프레임 배경을 다시 칠하므로(하드 게이트 #8), **정사각형 원뿔 레이어를 마스크 안에서 -`rotate` 시킨다.** 움직이는 것은 transform 뿐이다. - -`aspect-ratio: 1` 로 정사각형을 유지해야 회전 중 밝기가 일정하고, -`width: 200%` 로 크게 잡아야 1178×52 짜리 헤더에서도 모서리까지 닿는다. 주기 11초. - -### three.js 모바일 대응 - -**세로 화면에서 게이트가 통째로 안 보이고 있었다.** 수직 시야는 화면 비율과 무관하지만 -수평 시야는 aspect 에 비례한다 — 데스크톱(2.5:1)에서 정한 판 폭 15 가 -세로 화면(0.45:1)의 수평 시야 2.5 에 비하면 **여섯 배**라, 첫 판이 화면을 완전히 덮었다. - -`fit()` 에서 `camera.aspect` 를 갱신할 때 판의 `scale.x` 도 같이 잡는다. - -그리고 저사양 판정을 고쳤다. `hardwareConcurrency <= 4` 만 보면 **요즘 폰이 전부 -고사양으로 잡힌다**(8코어가 흔하다). `innerWidth < 760` 을 함께 본다 — -좁은 화면은 대개 배터리로 돌고 열이 더 난다. DPR 도 1.5 → **1.25**, -캔버스 불투명도도 0.7 → **0.45**(세로에서는 화면 전체를 덮으므로). - -### three.js 씬 셋은 서로 다른 것이어야 한다 - -게이트 씬을 파이프라인으로 옮기면서 히어로에도 그대로 남겨뒀더니 -**같은 그림이 페이지에 두 번** 나왔다. 히어로를 다른 것으로 바꿨다. - -| 자리 | 씬 | 무엇 | -|---|---|---| -| 히어로 | `shader-plane` 흐름 필드 | 노이즈를 두 번 접어 빛이 유리를 지난 결을 만든다. 공간을 만드는 **재질** | -| 파이프라인 | `gate-scene` 유리판 여섯 장 | 스크롤하면 통과하고 그 단계가 켜진다. 의미를 가진 **주인공** | -| 재료 | `shader-plane` 스테이지 | SVG 필터 타일이 앉는 무대 | - -히어로에는 무거운 씬을 임포트하지 않는다 — `three.md` §0 이 권하는 대로 -**셰이더 플레인 하나**다. 파일 이름도 `hero-scene.ts` → `gate-scene.ts` 로 고쳤다. -이름이 실제 용도와 다르면 다음 사람이 히어로 것인 줄 알고 고친다. - -캔버스 배경 위 본문 대비 실측(스크린샷 픽셀): 최악 **8.46:1**(가장 밝은 중앙 여백), -h1 자리 14.83:1. - -> `readPixels` 로 재려다 전부 0 이 나왔다. `preserveDrawingBuffer: false` 면 버퍼가 -> 비워져 있다. **WebGL 위 대비는 스크린샷 픽셀로 재라.** - -### 게이트 씬을 파이프라인으로 옮겼다 - -히어로에서 뺐던 유리판 여섯 장을 여기로 되살렸다. **같은 씬인데 자막이 필요 없어졌다.** - -| | 히어로에 뒀을 때 | 파이프라인으로 옮긴 뒤 | -|---|---|---| -| 옆에 있는 것 | 헤드라인과 CTA | **여섯 단계의 실제 이름** | -| 의미 전달 | `게이트 01 / 06` 판독기 — 자막 | 판을 통과하면 그 단계가 켜진다 | - -캔버스는 `position: sticky; height: 100dvh` 로 화면에 머물고 섹션이 지나간다. -**진행도는 섹션 높이가 아니라 (섹션 높이 − 뷰포트 높이)로 잰다.** -섹션 높이로 나눴더니 캔버스가 사라진 뒤에도 진행이 남아 6단계 중 **3단계에서 멈췄다.** -그리고 기준 요소는 캔버스가 아니라 섹션이다 — sticky 캔버스는 자기 rect 가 변하지 않는다. - -캔버스 위 텍스트 대비 실측 **14.2:1**(캔버스 불투명도 0.7). - -### 패럴랙스가 세 번 실패한 경위 - -**1. 이동량이 모자랐다.** 여유를 28% 잡아놓고 `±46px`(총 92px)만 움직였다. -스크롤 1800px 구간에서 이동 비율 5% — 아무도 시차를 느끼지 못했다. -공식은 **이미지를 컨테이너보다 크게 만들고 그 초과분 전체를 움직이는 것**이다. -`depth 0.45` → 이미지 145%, 이동 `translateY(-31.03%)`. 같은 구간에서 **374px**. - -**2. `overflow: hidden` 이 `view()` 타임라인을 죽이고 있었다.** -`overflow: hidden` 은 스크롤 컨테이너를 만들고, 그러면 자식의 `view()` 가 문서가 아니라 -그 상자를 기준으로 잡힌다. 이미지는 상자 안에서 늘 같은 자리라 진행도가 고정된다. -**콘솔 에러도 없고 computed 값도 정상이라** 두 스크롤 위치에서 `transform` 을 재보고서야 -이동 0px 인 것을 알았다. 잘라내는 일은 섹션의 `overflow: clip` 에 맡겼다 — -`clip` 은 스크롤 컨테이너를 만들지 않는다. - -**3. `opacity` 로 눌러 이미지를 지웠다.** 어두운 광원 사진을 `opacity: 0.5` 로 깔면 -검정도 빛도 같이 죽어 **있는지조차 보이지 않는다.** `mix-blend-mode: screen` 으로 바꿨다 — -검정은 투명해지고 밝은 곳만 더해지므로 불투명도를 0.85~1.0 으로 유지해도 본문 대비가 안전하다. -밝은 종이만 `normal` 이다. - -**생성 프롬프트에도 같은 함정이 있었다.** "본문 뒤에 깔리니 어둡게"를 너무 강하게 넣어서 -안전한 이미지가 아니라 **없는 이미지**를 만들었다. 대비는 합성 방식으로 풀 문제였다. - -### 배경 사진 넉 장 (gpt-image-2 로 생성) - -CSS 그라디언트 광원만으로는 기준면이 약해서, 굴절과 그레인이 실제로 들어 있는 이미지를 넣었다. -Codex CLI 의 내장 `image_gen`(gpt-image-2)을 ChatGPT 구독 인증으로 호출해 만들었다 — 스톡 이미지가 아니다. - -**섹션마다 다른 그림을 쓴다.** 같은 배경을 전부에 깔면 그건 벽지고, -모션에 적용한 규칙("섹션마다 다른 말을 해야 한다")이 배경에서만 면제될 이유가 없다. - -| 이미지 | 무엇 | 어디 | 그 섹션의 주장 | -|---|---|---|---| -| `bg-refraction` | 겹친 유리판을 통과한 빛 | 재료 · 설치(flip) | 표면은 한 겹이 아니다 | -| `bg-split` | 한 빔이 둘로 갈라진다 | 사례 | 같은 파이프라인, 다른 결과 | -| `bg-align` | 정렬선 여럿 중 **하나가 어긋나 끊겨 있다** | 프리플라이트 | 자기 결과물을 남의 것처럼 본다 | -| `bg-paper` | 무광 인쇄용지, 섬유와 데클 엣지 | 조판(밝은 밴드) | 한글이 종이 위에 있어야 한다 | - -**격자를 쓰는 파이프라인·수치에는 사진을 넣지 않았다.** 거기서는 격자가 그 섹션의 주장이다. -규칙·히어로도 그대로 뒀다 — 히어로에는 three.js 가 있고, 규칙 목록은 담백해야 한다. - -프롬프트는 **이 페이지의 토큰 값을 그대로** 넣었다: - -- 바탕 `#0B0E12` — 순흑도 네이비도 아니게 -- 광원 **둘만**: 좌상단 딥 틸 `#4FD6C4`, 우하단 채도 낮은 파랑 `#3D7BD6`. - 보라·마젠타·바이올렛·무지개·따뜻한 색 **금지** (슬롭 지문) -- 프로스티드 글래스 판이 거의 옆에서 보이게 겹쳐, 가장자리만 얇게 빛나고 가운데는 거의 안 보이게 -- **대비를 아주 낮고 고르게** — "이 이미지는 흰 본문 텍스트 뒤에 깔린다. 활자와 경쟁할 만큼 - 밝은 곳이 있으면 안 된다. 중앙 띠는 조용하고 어둡게, 밝기는 모서리 쪽에" -- 미세 필름 그레인, 밴딩 없이 -- 금지: 사물·로고·글자·숫자·사람·렌즈 플레어·보케·딱딱한 도형·비네트 - -`components/BgPhoto.astro` 로 감쌌다. CSS `background-image` 가 아니라 `` 를 -절대배치한다 — background-image 로 깔면 **항상 받고 최적화도 안 된다.** -같은 이미지를 설치 섹션에서는 `flip` 으로 좌우 반전해 같은 그림으로 읽히지 않게 했다. - -소스 WebP: `refraction` 37KB · `split` 14KB · `align` 11KB · `paper` 112KB -(종이만 큰 이유는 섬유 질감이 고주파라 압축이 안 붙기 때문이다) - -빌드 결과 12개 파일 합계 **276KB**. 실제로는 뷰포트에 맞는 크기 하나씩만, -그것도 `loading="lazy"` 로 받는다. - -**절대배치 배경이 그리드 안에서 561px 로 잘렸다.** `.section` 은 subgrid 이고 -`.section > * { grid-column: main; }` 이 걸려 있는데, 절대배치 요소라도 그리드 영역이 -잡히면 **그 영역이 컨테이닝 블록**이 된다. 그래서 배경이 화면 가운데 561px 띠로만 깔렸고, -`overflow: visible` 이라 위아래 14% 여유분이 이웃 섹션 위로 넘쳐 조판 섹션의 종이가 -프리플라이트 하단에 밝은 띠로 나타났다. -`.bg-photo { grid-column: full }` + `.has-bg { overflow: clip }` 으로 고쳤다. -**`position: absolute` 는 그리드에서 배치를 면제해주지 않는다.** - -**codex 0.147.0 메모** — `codex-image` 스킬의 `extract_imagegen.py` 는 rollout JSONL 의 -`image_generation_call` base64 를 찾는데, 0.147.0 은 다시 **파일**로 저장한다 -(`~/.codex/generated_images//exec-*.png`, 이벤트는 `custom_tool_call` + `image_generation_end`). -그래서 추출이 fail-loud 로 죽는다 — 이미지는 실제로 생성돼 있다. -그리고 `$imagegen` 은 **프롬프트 맨 앞**에 있어야 내장 도구가 발동한다. +**실측 3층** (스크롤 1000 → 1600): 격자 **+14.9px** · 산출물 **-14px** · 단계명 **0**. +한 층은 반드시 고정이다. 전부 움직이면 기준이 없어 그냥 흔들리는 페이지가 된다. ## 그리드의 `wide` 트랙을 좁은 화면에서 닫는다 diff --git a/apps/site/src/assets/bg/bg-align.webp b/apps/site/src/assets/bg/bg-align.webp deleted file mode 100644 index 6283669..0000000 Binary files a/apps/site/src/assets/bg/bg-align.webp and /dev/null differ diff --git a/apps/site/src/assets/bg/bg-paper.webp b/apps/site/src/assets/bg/bg-paper.webp deleted file mode 100644 index 5fae845..0000000 Binary files a/apps/site/src/assets/bg/bg-paper.webp and /dev/null differ diff --git a/apps/site/src/assets/bg/bg-refraction.webp b/apps/site/src/assets/bg/bg-refraction.webp deleted file mode 100644 index b48ccaa..0000000 Binary files a/apps/site/src/assets/bg/bg-refraction.webp and /dev/null differ diff --git a/apps/site/src/assets/bg/bg-split.webp b/apps/site/src/assets/bg/bg-split.webp deleted file mode 100644 index 8354953..0000000 Binary files a/apps/site/src/assets/bg/bg-split.webp and /dev/null differ diff --git a/apps/site/src/components/BgPhoto.astro b/apps/site/src/components/BgPhoto.astro deleted file mode 100644 index a1ee278..0000000 --- a/apps/site/src/components/BgPhoto.astro +++ /dev/null @@ -1,138 +0,0 @@ ---- -import { Image } from "astro:assets"; -import refraction from "../assets/bg/bg-refraction.webp"; -import paper from "../assets/bg/bg-paper.webp"; -import split from "../assets/bg/bg-split.webp"; -import align from "../assets/bg/bg-align.webp"; - -/** - * 배경은 섹션마다 다른 말을 해야 한다. 같은 그림을 전부에 깔면 그건 벽지다. - * 넷 다 gpt-image-2 로 만들었고, 프롬프트에 이 페이지의 토큰 값을 그대로 넣었다. - */ -const SOURCES = { refraction, paper, split, align } as const; - -interface Props { - variant?: keyof typeof SOURCES; - /** - * `fixed` — 뷰포트에 고정. 콘텐츠만 그 위를 지나간다. 무한히 먼 원경. - * `drift` — 스크롤보다 느리게 따라온다. 중경. 종이처럼 가까운 재질에 쓴다. - */ - mode?: "fixed" | "drift"; - /** drift 전용. 이미지를 컨테이너보다 이 비율만큼 키우고 그 초과분 전체를 움직인다 */ - depth?: number; - opacity?: number; - flip?: boolean; -} -const { - variant = "refraction", - mode = "fixed", - depth = 0.35, - opacity = 0.9, - flip = false, -} = Astro.props; -const src = SOURCES[variant]; - -// 밝은 종이만 그대로 얹고, 어두운 광원 사진은 더하기 합성한다. -const additive = variant !== "paper"; - -const scale = 1 + depth; -const shift = -(depth / scale) * 100; ---- - -{/* - 패럴랙스의 원형은 "배경이 고정되어 원경처럼 보이는 것"이다. - 느리게 같이 움직이는 것으로는 그 인상이 안 나온다 — 속도만 다를 뿐 같은 방향이다. - - `background-attachment: fixed` 는 쓰지 않는다. iOS Safari 가 GPU 메모리 때문에 - 그것을 throttle 해서 스크롤 중 배경이 튀거나 리셋된다. - 대신 부모에 `clip-path: inset(0)` 을 걸어 **fixed 의 컨테이닝 블록**으로 만든다. - 그러면 배경은 뷰포트에 고정되면서 그 섹션 영역에서만 보인다. - - 주의: 조상에 `transform`·`filter`·`mask` 가 있으면 그게 컨테이닝 블록이 되어 - 이 기법이 통째로 깨진다. 그래서 위아래 페이드 마스크를 포기했다 — - 마스크를 걸면 고정이 사라진다. 경계는 clip 으로 딱 자른다. -*/} - - - diff --git a/apps/site/src/components/Hero.astro b/apps/site/src/components/Hero.astro index c625e94..7f01df0 100644 --- a/apps/site/src/components/Hero.astro +++ b/apps/site/src/components/Hero.astro @@ -162,70 +162,12 @@ const { c, ui } = Astro.props; diff --git a/apps/site/src/components/Install.astro b/apps/site/src/components/Install.astro index 9b19919..5568e42 100644 --- a/apps/site/src/components/Install.astro +++ b/apps/site/src/components/Install.astro @@ -1,6 +1,5 @@ --- import CopyCommand from "./CopyCommand.astro"; -import BgPhoto from "./BgPhoto.astro"; import type { Content } from "../i18n/content"; interface Props { c: Content["install"]; ui: Content["ui"]; } @@ -8,8 +7,7 @@ const { c, ui } = Astro.props; --- -
- +

{c.h2}

@@ -41,25 +39,10 @@ const { c, ui } = Astro.props;
- - {/* 푸터를 없앴으므로 출처와 라이선스는 여기 한 줄로 남는다. - 링크 하나 없이 배포하면 사용자가 소스를 찾을 방법이 사라진다. */} -

- {c.colophon.repo} - {c.colophon.license} - {c.colophon.made} -

diff --git a/apps/site/src/components/Materials.astro b/apps/site/src/components/Materials.astro index 2dfd10b..e4d902d 100644 --- a/apps/site/src/components/Materials.astro +++ b/apps/site/src/components/Materials.astro @@ -1,5 +1,4 @@ --- -import BgPhoto from "./BgPhoto.astro"; import type { Content } from "../i18n/content"; interface Props { c: Content["materials"]; } @@ -11,13 +10,11 @@ const { c } = Astro.props; 배경은 three.js 셰이더 플레인, 전경은 SVG 필터를 실제로 먹인 타일 3장. 둘 다 설명이 아니라 지금 이 화면에서 돌고 있는 것이다. */} -
- +

{c.h2}

{c.lead}

- {/* GPU 가 만드는 재질. WebGL 이 없으면 위 그라디언트가 그대로 결과물이다 */} diff --git a/apps/site/src/components/Metrics.astro b/apps/site/src/components/Metrics.astro index 4957d1e..64aac25 100644 --- a/apps/site/src/components/Metrics.astro +++ b/apps/site/src/components/Metrics.astro @@ -19,7 +19,7 @@ const rest = c.items.filter((m) => !m.feature); 흔들리면 그 값도 흔들리는 것처럼 읽힌다. 계기판의 바늘은 떨지 않는다. 움직임이 의미를 만드는 자리가 있으면, 움직이지 않는 것이 의미인 자리도 있다. */} -
+

{c.eyebrow}

{c.h2}

diff --git a/apps/site/src/components/Pipeline.astro b/apps/site/src/components/Pipeline.astro index 239c2ce..b65203b 100644 --- a/apps/site/src/components/Pipeline.astro +++ b/apps/site/src/components/Pipeline.astro @@ -14,15 +14,7 @@ const { c } = Astro.props; ③ 의미 —
    — 화면에 번호는 없지만 보조기술은 "6개 중 n번째"로 읽는다 role="list" 는 list-style:none 일 때 Safari/VoiceOver 가 목록 의미를 버리는 것을 되돌린다 */} -
    - {/* 히어로에 있던 게이트 씬을 여기로 옮겼다. - 히어로에서는 그 은유를 판독기가 자막으로 설명해야 했다 — 그림이 스스로 - 말하지 못한다는 뜻이다. 여기서는 옆에 실제 여섯 단계가 적혀 있고, - 판을 통과할 때 그 단계가 켜진다. 자막이 아니라 콘텐츠가 반응한다. */} - +
    {/* 제목·리드·브리프·스파인을 한 컨테이너에 담는다. 섹션 기본 그리드에 두면 제목은 main 칼럼의 음수 마진으로 x=371, 리드는 x=435, 스파인은 x=143 에 서서 정렬선이 셋이 된다. */} @@ -38,8 +30,8 @@ const { c } = Astro.props;
      { - c.stages.map((s, i) => ( -
    1. + c.stages.map((s) => ( +
    2. {s.name}

      {s.does}

      @@ -62,48 +54,6 @@ const { c } = Astro.props; .brief { max-width: var(--measure); } #pipeline-h { max-width: 24ch; } - /* ---- 게이트 배경 ------------------------------------------ - sticky 로 화면에 머물고 음수 마진으로 레이아웃 자리는 차지하지 않는다. - 섹션이 지나가는 동안 카메라가 판 여섯 장을 통과한다. */ - .gate-bg { - position: sticky; - top: 0; - height: 100dvh; - margin-bottom: -100dvh; - z-index: -1; - pointer-events: none; - grid-column: full; - } - .gate-fallback, - .gate-canvas { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - display: block; - } - .gate-fallback { - background: - radial-gradient(46% 54% at 28% 34%, - color-mix(in oklab, var(--accent) 20%, transparent), transparent 70%), - radial-gradient(42% 50% at 76% 68%, - color-mix(in oklab, var(--glow-2) 18%, transparent), transparent 68%); - } - .gate-canvas { opacity: 0; transition: opacity 1s var(--ease-soft); } - .gate-canvas.is-live { opacity: 0.7; } - /* 세로 화면에서는 캔버스가 화면 전체를 덮는다. 같은 밝기면 본문이 묻힌다 */ - @media (max-width: 760px) { - .gate-canvas.is-live { opacity: 0.45; } - } - - /* 통과한 단계가 켜진다. 3D 와 텍스트를 잇는 유일한 연결이다 */ - .stop { transition: opacity var(--dur-quick) var(--ease-out); } - .stop.is-active .stop-name { color: var(--accent); } - .stop.is-active::before { - background: var(--accent); - box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 22%, transparent); - } - /* 스파인은 페이지의 본체다. main 칼럼(561px)에 가두면 페이지에서 가장 긴 섹션이 가장 좁아진다. R1(zed.dev) 실측: 컨테이너 1120px 과 전체폭이 교대한다. */ @@ -223,28 +173,3 @@ const { c } = Astro.props; 이 섹션은 페이지의 본체다. 콘텐츠를 걸고 하는 연출은 하지 않는다. */ - - diff --git a/apps/site/src/components/Preflight.astro b/apps/site/src/components/Preflight.astro index 0da6a2c..825f33d 100644 --- a/apps/site/src/components/Preflight.astro +++ b/apps/site/src/components/Preflight.astro @@ -1,5 +1,4 @@ --- -import BgPhoto from "./BgPhoto.astro"; import type { Content } from "../i18n/content"; interface Props { c: Content["preflight"]; } @@ -11,8 +10,7 @@ const { c } = Astro.props; 걸린 것과 고친 것이 한 줄에서 이어진다. 상자에 담지 않는다. 왼쪽 세로선이 로그라는 형식을 만든다. */} -
      - +

      {c.h2}

      {c.lead}

      diff --git a/apps/site/src/components/Showcase.astro b/apps/site/src/components/Showcase.astro index ae11738..cb9d4fd 100644 --- a/apps/site/src/components/Showcase.astro +++ b/apps/site/src/components/Showcase.astro @@ -2,7 +2,6 @@ import { Image } from "astro:assets"; import shotCoffee from "../assets/shots/shot-coffee.png"; import shotSaas from "../assets/shots/shot-saas.png"; -import BgPhoto from "./BgPhoto.astro"; import type { Content } from "../i18n/content"; interface Props { c: Content["showcase"]; } @@ -11,8 +10,7 @@ const shots = [shotCoffee, shotSaas]; --- {/* 레이아웃 패밀리: Z축 캐스케이드. 두 판이 서로 겹치고 각도가 다르다 */} -
      - +

      {c.h2}

      {c.lead}

      diff --git a/apps/site/src/components/Typography.astro b/apps/site/src/components/Typography.astro index f73d68a..7512ac3 100644 --- a/apps/site/src/components/Typography.astro +++ b/apps/site/src/components/Typography.astro @@ -1,5 +1,4 @@ --- -import BgPhoto from "./BgPhoto.astro"; import type { Content } from "../i18n/content"; interface Props { @@ -8,8 +7,7 @@ interface Props { const { c } = Astro.props; --- -
      - +

      {c.eyebrow}

      {c.h2}

      {c.lead}

      diff --git a/apps/site/src/i18n/content.ts b/apps/site/src/i18n/content.ts index 385d425..fc9293a 100644 --- a/apps/site/src/i18n/content.ts +++ b/apps/site/src/i18n/content.ts @@ -86,8 +86,8 @@ export interface Content { command: string; targets: { name: string; path: string }[]; commands: { cmd: string; what: string }[]; - colophon: { made: string; repo: string; license: string }; }; + footer: { made: string; repo: string; license: string }; nav: { items: { label: string; href: string }[]; menu: string }; ui: { copy: string; copied: string }; } @@ -377,11 +377,11 @@ export const ko: Content = { { cmd: "npx designpaca doctor", what: "설치 상태와 드리프트 진단" }, { cmd: "npx designpaca uninstall", what: "매니페스트 기반 정확한 제거" }, ], - colophon: { - made: "designpaca 로 만들었다", - repo: "git.chanpaca.net/yunchan/designpaca", - license: "MIT", - }, + }, + footer: { + made: "이 페이지는 designpaca 로 만들어졌다.", + repo: "git.chanpaca.net/yunchan/designpaca", + license: "MIT", }, nav: { items: [ @@ -612,11 +612,11 @@ export const en: Content = { { cmd: "npx designpaca doctor", what: "Diagnose install state and drift" }, { cmd: "npx designpaca uninstall", what: "Exact removal, driven by the manifest" }, ], - colophon: { - made: "Built with designpaca", - repo: "git.chanpaca.net/yunchan/designpaca", - license: "MIT", - }, + }, + footer: { + made: "This page was built with designpaca.", + repo: "git.chanpaca.net/yunchan/designpaca", + license: "MIT", }, nav: { items: [ diff --git a/apps/site/src/layouts/Base.astro b/apps/site/src/layouts/Base.astro index 200a643..2049791 100644 --- a/apps/site/src/layouts/Base.astro +++ b/apps/site/src/layouts/Base.astro @@ -87,7 +87,6 @@ const FAVICON =