Washing Line Hero은(는) 무엇을 하나요?
웹사이트의 첫 화면: 상단에 브랜드 바와 네비게이션, 하나의 컬러 문구가 들어간 큰 헤드라인, 소개 문장, 하나 또는 두 개의 버튼과 작은 노트, 그리고 그 옆에 하늘을 가로지르는 빨랫줄이 있습니다. 빨랫줄에는 나무 빨래집게로 고정된 면 천이 걸려 있고, 천에는 브랜드 자체 포스터(이름, 작은 한 줄, 두 개의 큰 단어, 스펙 열, 작은 막대 차트)가 인쇄되어 있습니다. 산들바람이 때때로 천을 살짝 들어 올리고 구름은 뒤에서 흘러갑니다.
만질 수 있도록 설계되었습니다. 포인터를 천 위로 움직이면 손가락 끝이 천을 움푹 누릅니다. 누르고 드래그하면 천이 손을 따라옵니다: 모서리를 위로 당기고, 줄 위로 접고, 앞으로 늘입니다. 놓으면 천이 떨어지고, 흔들리다가 멈춥니다. 휴대폰에서도 손가락으로 동일하게 조작할 수 있으며, 천을 잡고 있는 동안 페이지는 스크롤되지 않습니다. 천은 시뮬레이션됩니다(늘어짐, 전단, 굽힘 제약 조건으로 결합된 입자 그리드가 120Hz 고정 스텝으로 움직임). 따라서 미리 녹화된 애니메이션을 재생하는 것이 아니라, 잡힌 위치에 따라 천처럼 실제로 움직입니다.
히어로와 인쇄 내용을 hero.json에 설명합니다. 빌드가 모든 것을 확인하고, 하나의 파일로 된 전체 페이지 out/index.html과 이미 있는 사이트에 붙여넣을 수 있는 동일한 섹션 out/embed.html을 생성합니다. 시뮬레이션이 정지된 상태에서 고정 스텝으로 실행되기 때문에 record.mjs가 프레임별로 스텝을 진행할 수 있습니다: 비디오에서 그려진 포인터가 모서리를 잡아당기고, 놓고, 천 위로 손가락 끝을 움직여 방문자가 할 수 있는 동작을 모든 기기에서 동일하게 보여줍니다.
이것이 아닌 것: 천은 찢어지거나, 서로 엉키거나, 줄에서 날아가지 않습니다(자체 충돌이 없어 강하게 접으면 통과하여 떨어집니다). 또한 인쇄 내용은 업로드한 사진이 아니라 사용자가 작성한 텍스트로 페이지가 그립니다.
필요한 것
- Node.js 18 이상. 설치할 것은 없습니다.
- Chrome, Chromium 또는 Edge: 검사 및 녹화용(스크립트가 찾습니다. 찾지 못하면
CHROME_PATH를 설정하세요.) - ffmpeg: 비디오용(
brew install ffmpeg,winget install ffmpeg,apt install ffmpeg; 또는FFMPEG_PATH설정). - 페이지가 열릴 때 인터넷 접속: three.js와 폰트가 고정된 버전과 무결성 해시와 함께 jsDelivr에서 로드됩니다. 인터넷이 없으면 방문자는 정지 이미지(동일한 줄과 천, 평평하게 그려짐)와 시스템 폰트를 보게 됩니다. 페이지는 여전히 작동합니다.
이 스킬의 폴더는 아래에 <skill>입니다: 이 SKILL.md가 있는 폴더입니다.
단계
1. 브랜드와 단어 수집
사람에게 물어보거나 현재 사이트에서 다음을 찾으세요:
- 이름, 그리고 로고를 SVG 파일로(정사각형 또는 거의 정사각형; 스크립트가 없는 일반 파일). 로고가 없으면 세 글자 이하로 모노그램을 만듭니다.
- 색상: 배경색(수평선의 하늘색이기도 함. 텍스트 색상은 배경과 7:1 대비를 이루어야 함), 그리고 하나의 악센트 색상. 연한 파란색은 짙은 텍스트가 있는 한낮의 하늘을 제공합니다. 진한 네이비 또는 자두색은 밝은 텍스트와 낮고 따뜻한 태양이 있는 황혼의 하늘을 제공합니다.
- 폰트: 헤드라인과 천 위의 큰 단어를 위한 디스플레이 폰트, 그리고 나머지 텍스트를 위한 본문 폰트. 고정 및 검증된 폰트 로드: Space Grotesk, Inter, Instrument Sans, Instrument Serif, DM Sans, Manrope, Fraunces, Sora, Outfit, Bricolage Grotesque, IBM Plex Sans, JetBrains Mono, Plus Jakarta Sans, Newsreader, Playfair Display. 다른 Google Fonts 패밀리도 작동하지만(고정되지 않음).
- 페이지 위의 단어: 컬러로 표시할 구문이 있는 몇 단어로 된 헤드라인, 무엇이고 누구를 위한 것인지에 대한 한두 문장, 메인 버튼과 선택적 두 번째 버튼(이동할 위치 포함), 바에 있는 최대 5개의 네비게이션 링크와 버튼. 헤드라인 위의 작은 배지와 버튼 아래의 노트는 선택 사항입니다.
- 천 위의 단어: 상단에 인쇄할 이름(종종 제품 및 버전), 그 아래 작은 한 줄, 두세 개의 큰 단어(두 줄이 가장 잘 읽힘), 최대 6개의 짧은 스펙 쌍(레이블과 값), 차트의 캡션, 모서리의 웹 주소.
모든 이름, 숫자, 주장 및 날짜는 사람에게서 직접 받아야 합니다. 스펙이나 수치를 임의로 만들지 말고 대신 빼세요. 차트의 막대는 시드를 기반으로 장식으로 그려지며, 데이터가 아닙니다: 숫자를 주장하지 않는 캡션을 제공하거나 차트를 끄세요.
2. hero.json 작성
더 가까운 예제 폴더를 복사하고 모든 것을 교체하세요: examples/paperwind/ (노트 앱, 밝은 한낮 하늘, 4개의 집게) 또는 examples/halden/ (린넨 브랜드, 황혼 하늘, 3개의 집게, 더 정사각형 천).
| 필드 | 설명 | 제한 |
|---|---|---|
brand.name, brand.href | 좌측 상단의 이름과 링크 대상(기본 /) | 28 |
brand.logo | hero.json 옆에 있는 .svg 파일, 페이지에 인라인됨; 또는 모노그램용 3글자 이하 | – |
nav[] | 필 스타일의 최대 5개 { "label", "href" } (휴대폰에서 숨김) | 18 |
action | 우측 상단의 버튼, { "label", "href" }; 없으면 false | 22 |
hero.badge | 헤드라인 위의 작은 대문자 줄 | 40 |
hero.title | 헤드라인. *phrase*는 악센트 색상으로 표시됨; \n은 줄바꿈(최대 3줄) | 72 |
hero.lede | 무엇이고 누구를 위한 것인지. 인라인 Markdown: code, links, bold, italic | 220 |
hero.actions[] | 1 또는 2개의 { "label", "href" }: 첫 번째는 화살표가 있는 솔리드 메인 버튼, 두 번째는 아웃라인 버튼 | 26 |
hero.note | 버튼 아래의 작은 줄 | 90 |
hero.align | left (줄과 천이 오른쪽, 기본값) 또는 right (반전). center는 천을 카피 뒤에 배치; 권장하지 않음 | – |
theme.background, theme.ink, theme.accent | Hex 색상. ink는 background와 7:1 대비를 이루어야 함 | – |
theme.mode | light 또는 dark; 생략하면 배경에서 계산 | – |
theme.fonts | { "display", "body", "weight" }: 패밀리 이름(false는 시스템 폰트) 및 헤드라인 두께, 300–800 (기본 500) | – |
theme.scrim | 0–1: 카피 뒤 하늘이 배경색으로 얼마나 강하게 희석되는지. 기본값 0.3 | – |
effect | 아래의 하늘, 줄 및 천 설정 | – |
motion.speed | 0.25–2, 기본값 1: 모든 움직임의 속도 | – |
motion.pointer | true (기본값) | – |
meta | title (70) 및 description (170) (검색 및 링크 미리보기용); url 및 image (전체 https 주소), lang (기본 en) | – |
인쇄 내용 (effect): printTitle 또는 printHeadline 중 하나는 필수입니다.
| 설정 | 제한 | 기본값 | 설명 |
|---|---|---|---|
printTitle | 28자 | 없음 | 인쇄물 상단의 이름 |
printLine | 64자 | 없음 | 이름 아래의 작은 한 줄 |
printHeadline | 48자 | 없음 | 큰 단어; \n은 줄바꿈. 열에 맞게 축소됨 |
printSpecs | 0~6 { "label", "value" }, 12 및 14자 | 없음 | 오른쪽의 스펙 열; 레이블은 대문자로 인쇄됨 |
printChart | true / false | true | 스펙 아래의 작은 막대 차트, 가장 높은 막대는 theme.accent 색상 |
printChartLabel | 32자 | 없음 | 차트 아래 캡션 |
printFoot | 40자 | 없음 | 하단 모서리의 작은 텍스트 (예: 웹 주소) |
cloth | 색상 | #ecebe6 | 천 색상 |
printInk | 색상 | #15181d | 인쇄 잉크 색상. cloth와 7:1 대비 필요 |
씬 (effect), 모든 설정은 선택 사항:
| 설정 | 범위 | 기본값 | 설명 |
|---|---|---|---|
seed | 1–9999 | 7 | 구름과 차트 막대의 시드 |
skyTop | 색상 | #5f9be0 (라이트 모드), 어두운 모드에서 배경을 어둡게 함 | 히어로 상단의 하늘 색상 |
skyBottom | 색상 | theme.background | 수평선의 하늘 색상 |
clouds | 0–1 | 0.6 | 하늘에서 구름이 차지하는 비율; 0은 맑음 |
cloudColor | 색상 | 흰색(라이트 모드), 부드러운 보라색 회색(다크 모드) | 구름 색상 |
drift | 0–1 | 0.35 | 구름이 떠다니는 속도 |
light | day, dusk | 라이트 모드 day, 다크 모드 dusk | 위에서 내리쬐는 한낮의 태양, 또는 낮고 따뜻한 태양과 시원한 하늘 빛 |
aspect | 0.8–1.7 | 1.35 | 천의 너비 대 높이 비율 |
pegs | 2–6 | 4 | 상단 가장자리를 따라 있는 나무 빨래집게 수 |
peg | 색상 | #c39a64 | 빨래집게 색상 |
rope | 색상 | #6f6a62 (라이트 모드), #cfc6b8 (다크 모드) | 줄 색상 |
breeze | 0–1 | 0.45 | 산들바람이 천을 들어 올리는 강도 |
weave | 0–1 | 0.5 | 평직 패턴이 근접에서 얼마나 강하게 보이는지 |
poke | 0–1 | 1 | 포인터 아래 움푹 들어간 깊이; 0은 끔 |
drag | true / false | true | 방문자가 천을 잡고 당길 수 있도록 허용 |
size | 0.6–1 | 0.76 | 카피 옆 공간에서 천이 차지하는 비율 (당길 여유 공간 확보) |
hint | 40자 | "Press it · pull it · let go" | 넓은 화면에서 방문자에게 만질 수 있다고 알리는 하단 모서리의 작은 캡션; " · "로 부분 구분; 비우면 없음 |
작성 팁: 페이지의 헤드라인과 천 위의 큰 단어는 다른 내용을 말해야 합니다. 천은 포스터처럼 읽히므로 단어 수를 적게 유지하고 크게 하세요. 두세 개의 스펙 쌍이 여섯 개보다 더 잘 읽힙니다. 브랜드에 가볍고, 날고, 건조하거나 걸려 있다는 재치 있는 문구가 있다면 천이 그 문구를 넣기에 좋은 장소입니다.
3. 빌드
node <skill>/scripts/build.mjs hero.json out
hero.json의 모든 문제(누락된 필드, 제한 초과 텍스트, 범위를 벗어난 설정, 대비가 맞지 않는 색상, 천에 너무 희미한 인쇄 잉크)를 한 번에 나열하고 수정될 때까지 아무것도 쓰지 않습니다. 그런 다음 사용된 설정과 주목할 만한 사항(예: 헤드라인이 4.5:1로 읽히도록 어두워진 악센트)을 출력합니다.
다음을 생성합니다: out/index.html (CSS, 스크립트, 로고 및 정지 이미지가 인라인됨), out/embed.html 및 out/assets/logo.svg (탭 아이콘).
4. 검사
node <skill>/scripts/check.mjs out/index.html
390, 768, 1024 및 1440 px에서 페이지를 로드하고 각각 ok라고 말해야 합니다: 화면보다 넓거나 잘린 부분이 없고, 배경 하늘에 대해 모든 텍스트 줄의 대비가 읽을 수 있으며, 모든 링크와 버튼에 이름이 있고, h1은 하나입니다. ·로 표시된 줄은 주목할 만하지만 실패로 간주하지 않습니다.
5. 살펴보고, 만져보기
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 3.5 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 390x844 --scale 2
node <skill>/scripts/screenshot.mjs out/index.html
첫 번째는 정지된 천, 두 번째는 당겨지는 중간(스크립트된 손이 모서리를 올리고 있음), 세 번째는 휴대폰 화면입니다. 살펴보세요: 천 전체가 주변에 여유 공간을 두고 화면에 표시되는지, 인쇄 내용이 읽히는지, 빨래집게가 줄에 잘 앉아 있는지? screenshot.mjs는 GPU 없이 Chrome을 실행하므로 WebGL이 없거나 네트워크가 실패할 때 방문자가 보게 될 정지 이미지(out/screens/에 저장)를 보여줍니다. 이것도 읽을 수 있는지 확인하세요.
그런 다음 out/index.html을 브라우저에서 열고 가지고 놀아보세요: 호버, 누르기, 줄 위로 모서리 당기기, 놓기. 휴대폰에서는 손가락으로 드래그하고 천 옆을 스와이프할 때 페이지가 여전히 스크롤되는지 확인하세요.
6. 비디오 녹화
node <skill>/scripts/record.mjs out/index.html --seconds 10
히어로를 30fps, 1920×1080 해상도로 10초 동안 스텝 진행하고 out/preview.mp4와 out/poster.png(3.5초 프레임, 당겨지는 중간)를 생성합니다. 비디오에서 그려진 포인터가 2.2초에 아래쪽 모서리를 잡고, 위쪽으로 당기고, 4.4초에 놓고, 6초부터 천 위로 손가락 끝을 움직입니다. 옵션: --size 1080x1350 (세로), --size 1080x1920, --fps 60, --poster 1.6. 프레임은 항상 0부터 시작하므로 모든 기기에서 동일합니다.
7. 라이브로 배포
- 페이지로:
out/index.html과out/assets/를 정적 호스트(Cloudflare Pages, Netlify, Vercel, GitHub Pages, S3)에 업로드하세요.out/poster.png(또는 1200×630 크롭)을meta.image로 사용하고 사이트와 함께 업로드하세요. - 기존 사이트에: 히어로가 들어갈 곳에
out/embed.html을 붙여넣으세요. 모든 것은#mh-washing-line아래로 범위가 지정됩니다. 원하면 폰트<link>를<head>로 이동하세요. 사이트에 이미<script type="importmap">가 있으면 임베드의imports및integrity항목을 병합하세요. 섹션은 전체 뷰포트 높이입니다.--mh-height를 설정(예:style="--mh-height:760px")하여 줄이세요. React 또는 다른 프레임워크에서는 마크업을 컴포넌트에 넣고<script>태그는 페이지에 넣거나 iframe으로 렌더링하세요. - 인쇄 내용을 변경하려면
hero.json을 편집하고 다시 빌드하세요.
문제 해결
build: fix hero.json first: 각 줄은 필드와 변경해야 할 사항을 알려줍니다. 색상 문제는 작동하는 색상을 제안합니다.- 천이 가장자리에서 잘림:
size를 낮추거나 천을 더 정사각형으로 만드세요(aspect를 1에 가깝게). - 천 위의 큰 단어가 작음: 스펙 열 옆에 맞게 축소됩니다. 더 적은 단어를 사용하거나,
\n을 사용하거나, 더 적은 스펙과 차트 없음(단어가 전체 너비를 차지함)을 시도하세요. - 천이 안정되지 않거나 너무 많이 흔들림:
breeze를 낮추세요. - 움푹 들어간 자국이 너무 강하거나 희미함:
poke(0은 끔, 드래그는 여전히 작동). record: the effect didn't start: 페이지가 정지 이미지로 폴백되었습니다: Chrome이 jsDelivr에서 three.js를 로드할 수 없거나(연결 또는 프록시 확인) WebGL이 없습니다.ffmpeg not found: 설치하거나FFMPEG_PATH를 설정하세요.- 방문자가 정지된 천을 봄: 브라우저가 WebGL을 껐거나 CDN이 차단되었거나(평면 그림), Reduced motion을 요청했습니다(움직이지 않는 정지된 라이브 천의 한 프레임). 의도된 동작입니다.
- 휴대폰에서 페이지가 스크롤되지 않음: 손가락이 천을 잡고 있는 동안에만 스크롤이 중지됩니다. 천 옆을 스와이프하세요. 천이 휴대폰 화면을 가득 채우면
size를 낮추세요.
파일
scripts/build.mjs,scripts/record.mjs: 실행하는 파일. Motion Heroes 키트를 호출합니다.scripts/kit/: 모든 Motion Heroes 스킬이 공유하는 키트: 빌드 및 검사(build.mjs), 섹션의 CSS(shell.css), 브라우저 런타임(runtime.js: 클록, 일시 중지, 픽셀 비율, Reduced motion, 폴백), 레코더(record.mjs,cdp.mjs), 고정된 three.js 및 폰트(three.json,fonts.json) 및 이들을 설명하는KIT.md.scripts/effect/: 빨랫줄 자체:effect.mjs(설정, 검사 및 정지 이미지),effect.js(하늘 셰이더, 천...
(원문이 잘려서 이하 생략)