자모 비
자모 조각 비가 젖은 길에 문장으로 쌓이면 가로등이 켜진다
설정값 미리보기
바꾼 문구·색으로 다시 재생합니다
프롬프트 설정
Claude 가 읽는 제작 지시문입니다. 직접 읽지 않아도 됩니다.
비 오는 밤 가로등 아래 젖은 길에서, 한글 자모 조각이 비처럼 쏟아지다 바닥에 문장으로 쌓이는 세로 영상을 HTML 파일 하나로 만들어 줘. 미리보기에서 바로 재생되게. 길게 설명할 테니 숫자는 그대로 지켜 줘.
핵심 아이디어: 비 오는 밤 골목이다. 하늘은 흐린 자두빛에서 바닥 쪽으로 도시 불빛이 번진 장밋빛으로 내려오고(검은 밤이 아니라 불빛이 구름에 번진 도시의 밤), 화면 위 밖의 가로등이 가운데로 은은한 빛 기둥을 내린다. 바닥은 젖은 아스팔트라 그 위의 것이 거꾸로 비친다. 화면 위쪽까지 자모 조각이 비처럼 쏟아진다 — 빛 기둥 안을 지나는 조각만 따뜻하게 빛나고, 밖의 조각은 어두운 자줏빛 회색이다. 대부분은 바닥에 부딪혀 두 번 튀고 사라진다. 크고 선명한 조각 몇 개만 남는데, 바로 아래에 받쳐 줄 것(바닥이나 먼저 쌓인 글자)이 있으면 거기 부딪혀 한 번 튀고 옆으로 미끄러져 들어간다. 받쳐 줄 것이 없으면 떨어지던 기세 그대로 비스듬히 제자리에 끼워진다. 아랫줄부터 쌓이고, 마지막 조각이 끼워지는 순간 문장 전체가 차례로 「딸깍」 맞물리고, 바로 그때 가로등이 환하게 켜진다: 빛 기둥이 짙어지며 그 안의 빗조각이 한꺼번에 따뜻한 빛 조각으로 바뀌고, 젖은 바닥의 문장 반사와 빛 웅덩이가 선명해진다. 조각은 완성 글자를 그린 픽셀에서 잘라 낸 것이라, 다 모인 글자는 처음부터 통째로 그린 글자와 픽셀까지 똑같다.
[바꿀 곳]
- 문장(두 줄, 아래에서 위로 쌓인다): 윗줄 「비가 와도」 / 아랫줄 「괜찮아」 (한 줄만 주면 그 줄이 바닥에 앉는다)
- 색: 하늘 위 #3A2436 · 하늘 바닥(바닥선 높이) #653A4A · 젖은 바닥 #2A1A24 · 가로등 빛 #FFC56E · 빗조각 #9C8494 · 빛 받은 빗조각 #FFE2B0 · 윗줄 글자 #FFF6EA · 아랫줄 글자 #FFD27A
- 글자 대비: 두 줄 글자 모두 그 뒤 가장 밝은 배경(빛이 가장 셀 때 빛 기둥 가운데)과 4.5:1 이상. 기본 색이면 빛이 최대일 때 윗줄 최저 약 6.3:1, 아랫줄 최저 약 4.85:1(빛이 기본 세기일 때는 각각 약 8.2:1 · 5.9:1)이다. 색을 바꾸면 이 대비를 다시 지킨다. 바탕을 밝히면 아랫줄 색도 한 단 밝게 함께 옮긴다.
- 화면 밝기: 0초 화면에서 OKLab 밝기 L < 0.35 인 픽셀은 화면의 70% 이하여야 한다(기본 색이면 약 40%) — 「검은 방」으로 읽히지 않는 밤이다. 바탕(하늘·젖은 바닥)은 채도를 올리지 않는다(OKLCH C ≤ 0.08).
- 길이: 11초 (끝나면 처음으로 이어서 반복)
- 화면비: 9:16 (기준 캔버스 1080×1920)
- 빗조각 양: 1초에 45개(먼 층 24 · 중간 층 14 · 가까운 층 7)
[크기]
H = 화면 높이, W = 화면 폭(기준 1080×1920). 모든 크기·속도는 H·W 의 배수로 계산한다.
- 바닥선 y = 0.86H. 바닥선 위(0~0.86H)는 하늘 — 「하늘 위」 색(y = 0)에서 「하늘 바닥」 색(y = 0.86H)으로 가는 세로 선형 그라디언트. 바닥선 아래(0.86H~1.0H)는 「젖은 바닥」 색으로 칠한다 — 앞으로 펼쳐진 젖은 땅바닥 면이다. 바닥선 = 폭 전체, 두께 3px, 빗조각 색 45% 불투명도.
- 빛 기둥: 꼭짓점 (0.5W, −0.35H)(화면 위 밖)에서 바닥선까지 곧게 퍼지는 삼각형. 높이 y 에서의 반폭 hw(y) = 0.44W × (y + 0.35H) ÷ 1.21H — 화면 맨 위에서 약 0.127W, 바닥선에서 0.44W. 그래서 빛 기둥이 화면(0~0.86H)의 약 49% 를 덮고 문장 가운데를 비춘다.
- 젖은 바닥 반사 띠 = 바닥 아래 띠 전체(0.86H~1.0H, 높이 0.14H). 비치는 원본 = 바닥선 바로 위 같은 높이의 띠(0.72H~0.86H).
- 줄마다 따로 크기를 맞춘다: 글자 크기(em)를 100px 로 measureText 해서 그 줄의 폭이 0.88W 가 되게 키운다. 단 em ≤ 0.20H. 기본 문장이면 글꼴에 따라 「괜찮아」 0.165~0.19H, 「비가 와도」 0.114~0.134H 가 나온다(짧은 줄이 더 크다).
- 아랫줄: 그 줄 음절들의 잉크 바닥 중 가장 낮은 것이 바닥선에 닿는다. 윗줄: 그 줄의 가장 낮은 잉크 바닥 = 아랫줄의 가장 높은 잉크 꼭대기 − 0.025H(아랫줄 위에 얹힌다). 두 줄 모두 가로 가운데. 문장 덩어리는 글꼴에 따라 대략 0.54~0.59H 에서 0.86H 까지를 차지하고, 그 위 절반 넘는 화면이 비가 쏟아지는 공간이다.
- 빗조각 크기(조각 잉크 상자의 긴 변): 먼 층 0.030H · 중간 층 0.045H · 가까운 층 0.070H. 문장 조각은 축소하지 않은 제 크기(0.08~0.19H)라서 빗조각보다 확연히 크다 — 이 크기 차이가 「어느 조각이 남을지」를 알려 준다.
[조각 — 완성 글자에서 잘라 낸다. 호환 자모 글자(ㄱ, ㅏ 같은 낱자)를 fillText 해서 조각을 만드는 것은 금지]
분할은 1배(기준 1080 좌표) 칸에서 하고, 그리는 비트맵만 실제 픽셀 크기로 만든다. 백킹 배율 s = 캔버스 실제 픽셀 폭 ÷ 1080(devicePixelRatio 반영, 최대 2). 음절마다 시작할 때 한 번만 계산해 캐시한다.
1) 1배 칸: 한 변 n1 = round(1.4 × em) 의 오프스크린 캔버스. 글꼴 굵기 400, textAlign 'center', textBaseline 'middle' 로 칸 한가운데에 완성 음절을 fillText 한다. 알파 ≥ 128 인 픽셀을 잉크로 본다(분할용 — 덧칠하지 않은 상태).
2) 잉크를 8-이웃 연결 성분으로 나눈다. 전체 잉크의 0.4% 미만인 성분은 버린다. 좌표는 그 음절 잉크 상자 기준 0~1 로 정규화한다.
모음 분류: 세로(ㅏㅐㅑㅒㅓㅔㅕㅖㅣ) / 가로(ㅗㅛㅜㅠㅡ) / 겹(ㅘㅙㅚㅝㅞㅟㅢ).
2-a) 겹모음에 받침이 있으면 받침부터 뗀다: 가장 키 큰 성분의 바닥보다 무게중심 y 가 아래인 성분 = 종성. 남은 성분으로 아래 2-b·2-c 를 한다.
2-b) 모음 성분: 세로 = 무게중심 x > 0.5 인 성분 중 가장 키 큰 것(+ 키가 그것의 60% 이상인 오른쪽 성분) · 가로 = 가장 넓은 성분 · 겹 = 가장 넓은 성분 + x > 0.6 에서 가장 키 큰 성분(+ x > 0.6 이고 키가 그것의 60% 이상인 성분 — ㅙ·ㅞ 처럼 오른쪽 기둥이 둘인 겹모음에서 두 기둥을 함께 모음으로 묶는다. 「괜」의 ㅙ 가 이 경우이고, 다른 기본 음절에서는 작동하지 않는다).
종성(2-a 로 아직 안 정했으면) = 무게중심 y 가 모음 성분들의 바닥보다 아래인 성분(받침이 있을 때만). 초성 = 나머지 전부(ㅎ·ㅊ 의 꼭지, ㄲ·ㅆ 의 두 짝도 한 역할로 묶는다).
2-c) 붙은 성분 자르기: 세로·가로 모음은 초성이 비었거나, 가로 모음 묶음 높이 > 0.6(ㅜ·ㅠ 는 0.75) 또는 세로 모음 묶음 폭 > 0.5 이면 모음 성분을 한 번 자른다. **겹모음도 초성이 비었으면 반드시 자른다**(높이·폭 조건은 보지 않는다). 자를 성분: 가로·겹 = 가장 넓은 모음 성분(가로획이 든 덩어리), 세로 = 가장 키 큰 모음 성분.
· 가로획 위로 짧은 기둥이 서는 모음(ㅗ·ㅛ, 그리고 그것이 든 ㅘ·ㅙ·ㅚ): 가로획(그 줄 잉크 폭 ≥ 성분 폭의 80%)의 바로 위 줄에서 잉크가 있는 열들을 기준으로 삼고, 한 줄씩 위로 올라가다 잉크가 그 열(±2px) 밖으로 처음 퍼지는 줄에서 가른다. 그 위는 초성.
· 가로획 위에 기둥이 없는 모음(ㅜ·ㅠ·ㅡ, 그리고 그것이 든 ㅝ·ㅞ·ㅟ·ㅢ): 가로획 꼭대기 바로 위 줄에서 곧게 가른다. 그 위는 초성.
· 세로 모음: 기둥(열 잉크 높이 ≥ 70%) 바로 왼쪽 열에서 위 첫째 방식처럼 왼쪽으로 가다 처음 퍼지는 열에서 가른다.
「가장 좁은 줄에서 자르기」는 쓰지 않는다(ㄷ 을 반으로 가른다).
기본 문장의 「와」는 Pretendard·맑은 고딕·Noto Sans KR 모두 ㅇ 의 아래 끝이 ㅗ 의 짧은 기둥에 붙어 있다. 8-이웃 성분이 2개(「ㅇ+ㅗ」 덩어리, ㅏ)뿐이라 겹모음 규칙이 둘 다 모음으로 잡고 초성이 빈다. 그래서 이 겹모음 자르기가 반드시 일어나야 ㅇ·ㅘ 2조각이 된다. 「도」도 ㄷ 과 ㅗ 가 붙은 1성분이라 가로 자르기가 일어난다.
2-d) 물러서는 순서: 그래도 역할이 비거나 모음이 과대하면 — 받침이 있는 음절은 「받침 1조각 + 나머지 1조각」의 2조각으로 한다. 받침이 없는 음절은 자를 성분을 가로획 꼭대기 바로 위 줄(가로·겹) 또는 기둥 바로 왼쪽 열(세로)에서 곧게 갈라 「초성 1조각 + 중성 1조각」의 2조각으로 한다. 음절 통째 1조각은 그 곧은 자르기마저 한쪽이 비어 버릴 때만 쓰고, 그때는 console.warn 으로 그 음절을 알린다. 낱자로 대체하는 일은 어떤 경우에도 없다.
콘솔에 음절별 [성분 수, 역할별 개수, 자르기 여부, 물러섬(없음/2조각/통째)] 표를 출력한다.
합격 기준(기본 문장): 괜 3(ㄱ·ㅙ·ㄴ) · 찮 3(ㅊ·ㅏ·ㄶ) · 아 2 · 비 2 · 가 2 · 와 2(ㅇ·ㅘ, 성분 2, 자르기 예) · 도 2(ㄷ·ㅗ, 성분 1, 자르기 예) = 16조각, 통째 0, 2조각 0. Pretendard·맑은 고딕·Noto Sans KR 에서 이렇게 나와야 한다. 「와」가 통째 1조각으로 나오면 겹모음 자르기를 빠뜨린 결함이다 — 쌓이는 장면에서 「와」만 통째로 떨어지고, 빗조각에도 읽히는 「와」가 섞인다. 문장이 기본값이면 시작할 때 이 기대값(조각 수·자르기 여부·물러섬)과 실제 표를 대조해 콘솔에 「일치」 또는 다른 음절 목록을 console.warn 으로 찍는다.
3) 영역: 1배 칸의 모든 픽셀을 가장 가까운 잉크 성분의 역할로 배정한다(다중 출발 BFS). 결과는 1배 역할표(Uint8Array n1×n1) 하나. 역할표는 칸을 겹침 없이 빈틈없이 나눈다.
4) 실제 칸: 한 변 n = round(1.4 × em × s). 역할 마스크는 1배 역할표를 최근접으로 확대해 만든다 — 실제 칸의 픽셀 (x, y) 의 역할 = 역할표[floor(y·n1/n)][floor(x·n1/n)]. ImageData 로 역할마다 마스크 1장(알파 255/0). 확대해도 마스크는 실제 칸을 빈틈없이 나눈다.
5) 완성 비트맵: 실제 칸에 같은 자리로 fillText(굵기 400, 글꼴 크기 em × s) 한 뒤 같은 색 strokeText(lineWidth = 0.03 × em × s, lineJoin 'round')로 살짝 굵힌다. 색마다 한 장씩: 그 줄의 글자 색 1장 + 빗조각 색 1장 + 빛 받은 빗조각 색 1장. 글자 색 판은 빛과 무관하다 — 가로등이 켜져도 문장 조각·완성 글자의 픽셀은 바뀌지 않는다.
6) 조각 비트맵: 완성 비트맵을 복사하고 globalCompositeOperation 'destination-in' 으로 역할 마스크를 덮는다. 마스크가 칸을 나누므로, 조각들을 같은 자리에 겹쳐 그리면 완성 비트맵과 픽셀이 같다.
7) 조각마다 1배 잉크(알파 ≥ 128) 픽셀 목록·잉크 상자·무게중심을 저장한다(아래 착지 검사에 쓴다). 회전·찌그러짐의 기준점은 무게중심, 착지·찌그러짐의 기준선은 잉크 바닥.
8) D 키: 디버그 — 쉬는 자리의 글자를 역할별 색(초성 주황 / 중성 하늘 / 종성 연두 / 2조각·통째 보라)으로 보여 준다.
[문장 조각 — 떨어지기·튀기·끼워 맞춤]
중력 g = 2.6H/초²(= 4992px/초²). 공기저항은 속도에 비례(계수 k). 종단 속도 vt = g/k.
떨어지는 속도 v(τ) = vt + (v0 − vt)·e^(−kτ), 떨어진 거리 d(τ) = vt·τ − (vt − v0)·(1 − e^(−kτ))/k. 모든 낙하는 이 두 식으로 닫힌 꼴로 계산한다.
- 문장 조각: k = 1.2/초(vt ≈ 2.17H/초), 출발 속도 v0 = 0.35H/초, 출발 높이 = 무게중심 y −0.10H(화면 위 밖). 낙하 끝(아래 「착지 방식」의 높이)까지의 시간 D 는 d(D) = 거리 를 이분법 40회로 풀어 둔다. 기본 문장에서 약 0.69~0.90초, 낙하 끝 속도 약 1.37~1.52H/초.
- 착지 순서: 아랫줄 음절 왼쪽부터 → 윗줄 음절 왼쪽부터. 한 음절 안에서는 잉크 바닥이 낮은 조각부터(받침 → 모음 → 초성 순으로 쌓인다).
- 낙하 끝 시각: k번째 조각(0부터, 전체 N개) L_k = 1.0 + k·Δ초, Δ = 4.4 ÷ (N − 1) 을 0.22~0.45초로 자른 값. 출발 시각 = L_k − D_k.
- 격자 둘: 착지를 정할 때 1배 화면 크기 Uint8Array(1080×1920)를 두 장 쓴다. 착지 순서대로 조각을 하나씩 정하고, 정한 뒤 격자에 찍고 다음 조각으로 넘어간다. 시작할 때 한 번 계산해 표에 넣는다.
ⓐ 겹침 격자 — 비키는 폭을 고를 때만 쓴다. 정한 조각의 착지 자리(①이면 쉬는 높이, ②면 그 위 0.06H 의 실제 낙하 끝 높이)와 쉬는 자리의 잉크를 찍는다(앞선 조각은 그 시각에 이미 와 있거나 오는 중이므로 보수적으로 둘 다).
ⓑ 받침 격자 — 받침 틈을 잴 때만 쓴다. 지금 정하는 조각의 낙하 끝 시각 L 보다 먼저 제자리에 도착한 조각의 쉬는 자리 잉크만 찍혀 있는 상태로 잰다. 착지 자리와 아직 오는 중인 조각은 받침이 아니다(그 시각 그 자리에는 아무것도 없다). 그래서 조각마다 「제자리 도착 시각」을 먼저 정하고, 받침 격자는 도착 시각 순으로 채운다.
- 비키는 폭 Δx(착지 자리 = 쉬는 자리 x + Δx): |Δx| = 0.035~0.09W, 부호와 함께 시드 난수로 먼저 고른다. 착지 자리(쉬는 높이와 그 위 0.06H 두 곳)에서 조각 잉크가 겹침 격자와 한 픽셀이라도 겹치거나 0.04W~0.96W 를 벗어나면 반대 부호를 시험한다. 둘 다 안 되면 |Δx| 를 0.005W 씩 0.035W 까지 줄여 가며 다시 시험한다. 그래도 겹치면 Δx = 0(제자리로 곧게 떨어진다). 떨어지는 열 = 착지 자리 x.
- 낙하 중: 흔들림 x += 0.015W·sin(2π·1.1·τ + φ)·(1 − u)², 기울기 θ = θ0·(1 − u)², θ0 = ±8~22°(u = τ/D). 낙하 끝에서 흔들림과 기울기는 정확히 0.
- 착지 방식 — 받침 틈으로 가른다. 받침 틈 = 착지 자리에서 조각 잉크의 x 범위 안 열들마다, 조각 잉크 바닥 아래로 처음 만나는 받침 격자 잉크 또는 바닥선까지의 거리 중 가장 작은 값.
① 받침 틈 ≤ 0.012H(23px): 받쳐 줄 것이 있다. 쉬는 높이에서 낙하가 끝나고(부딪힘), 거기서 튀고 미끄러진다.
튀기: 반발 계수 0.22. 튀어 오르는 속도 vb = 0.22 × 부딪는 속도, 높이 vb²/(2g) ≈ 0.019~0.021H(36~41px), 공중 시간 tb = 2·vb/g ≈ 0.24~0.26초. 튀는 동안은 중력만(공기저항 없음).
부딪는 찌그러짐(잉크 바닥 가운데 기준): sy(τ) = 1 − 0.16·e^(−14τ)·cos(28τ), sx = 1 + 0.5·(1 − sy). 부딪는 순간 0.84 로 납작해졌다가 τ ≈ 0.096초에 1.04 로 늘고 0.15초 뒤 ±1% 안에 든다. τ > 0.5초면 정확히 1.
미끄러짐: 튀기가 끝난 순간(L + tb)부터 0.40초 동안 x = 쉬는 자리 x + Δx·(1 − easeOutBack(u)). 쉬는 자리를 Δx 의 6.2% 만큼 지나쳤다가(u ≈ 0.62) 정확히 멈춘다. y 는 쉬는 높이 그대로. 제자리 도착 = L + tb + 0.40.
② 받침 틈 > 0.012H: 받쳐 줄 것이 없다. 쉬는 높이 위 0.06H 에서 낙하가 끝나고, 튀지 않는다. 거기서부터 0.20초 동안 x 는 쉬는 자리 x + Δx·(1 − easeOutBack(u)), y 는 쉬는 높이 − 0.06H·(1 − easeOutBack(u)) 로 비스듬히 끼워 들어간다(넘침 6.2% — 제자리를 살짝 지나 아래로 눌렸다 돌아온다). 끼움 시작 속도 = 4.3 × 0.06H ÷ 0.20초 ≈ 1.3H/초로 낙하 속도(약 1.4H/초)와 끊김 없이 이어진다. 부딪는 찌그러짐 없음. 제자리 도착 = L + 0.20.
easeOutBack(u) = 1 + 2.3·(u − 1)³ + 1.3·(u − 1)² (u = 0→1, 출발 기울기 4.3, 최대 넘침 6.15% @u ≈ 0.62).
- 쉬는 자리: 제자리에 도착한 조각은 변환 없이(setTransform(1,0,0,1,0,0)) 실제 칸의 정수 픽셀 좌표에 drawImage 한다. 확대·회전·소수 좌표가 하나라도 남으면 합쳤을 때 이음매가 생긴다.
- 음절 완성: 그 음절의 모든 조각이 제자리에 도착한 바로 그 프레임에 조각들을 지우고 완성 비트맵 1장으로 바꿔 끼운다(겹치는 프레임 없음, 바뀌는 것이 보이지 않아야 한다). 동시에 「딸깍」: 잉크 바닥 가운데 기준으로 sy(τ) = 1 − 0.08·e^(−8τ)·sin(24τ), sx = 1 + 0.5·(1 − sy). τ ≈ 0.052초에 0.95 로 눌렸다가 1.018 로 살짝 솟고 0.34초 뒤 ±0.5% 안. τ > 0.40초면 다시 변환 없는 정수 좌표.
- 문장 완성의 맞물림: 마지막으로 완성되는 음절의 딸깍 시각을 T★ 라 하면, 나머지 음절이 아랫줄 왼쪽부터 윗줄 오른쪽 순서로 T★ + 0.05·j 초(j = 1, 2, …)에 딸깍을 한 번 더 하되 진폭을 0.12 로 키운다: sy(τ) = 1 − 0.12·e^(−8τ)·sin(24τ) — τ ≈ 0.052초에 0.925, 정점 1.026, 0.36초 뒤 ±0.5% 안, τ > 0.40초면 변환 없는 정수 좌표. 문장 전체가 한 번 「딸깍」 맞물린다. 끝나면 변환 없는 정수 좌표.
[빗조각 — 수많은 조각, 튀며 사라진다]
- 빗조각 = 문장 음절들의 조각 비트맵 가운데 시드 난수로 고른 것. 잉크 상자의 긴 변이 층 크기가 되게 축소한 비트맵을 조각·층마다 두 장(빗조각 색 판 · 빛 받은 빗조각 색 판) 시작할 때 만들어 둔다.
- 층 세 개(먼 / 중간 / 가까운): 불투명도 0.30 / 0.50 / 0.75 · 공기저항 k 3.6 / 2.6 / 1.8(vt 0.72 / 1.00 / 1.44H/초) · 출발 속도 0.5·vt · 1초당 24 / 14 / 7개 · 부딪는 바닥 = 0.86H / 0.930H / 0.965H. 먼 층은 바닥선에서 튄다(글자 뒤에 있어도 앞뒤가 맞는다). 중간·가까운 층은 땅바닥 면의 앞쪽에서 튀고, 튀어 오른 최고점에서도 조각 위끝이 바닥선(0.86H) 아래에 머문다 — 부딪는 바닥 = 0.86H + 층 크기 + 첫 튀는 높이. 그래서 글자 뒤로 숨는 일 없이 문장 앞에 있는 것으로 읽힌다. 낙하 시간 약 1.43 / 1.20 / 0.96초.
- 출발: 무게중심 y = −0.06H − 층 크기. x = (frac(0.5 + i·0.6180340 + 층번호·0.33) + 시드 지터 ±0.02) × 1.1W − 0.05W (i = 그 층의 조각 번호). 부딪는 시각 t_i = (i + 0.5 + 시드 지터 ±0.35) × 길이 ÷ (그 층의 개수), 그 층의 개수 = 1초당 개수 × 길이(11초). 부딪는 순간 = 무게중심 y + 층 크기/2 가 그 층의 부딪는 바닥에 닿을 때.
- 낙하 중: 기울기 θ0 = ±40°(시드), 회전 속도 ±30~120°/초. 속도에 비례해 화면 세로 방향으로 늘인다: 늘임 = 1 + 0.2·v/vt(최대 약 1.2배, 면적 유지 위해 가로는 1/√늘임). 그리는 순서 = translate → scale(가로, 세로) → rotate → drawImage(무게중심 기준).
- 튀기: 두 번. 첫 튀는 높이 먼 / 중간 / 가까운 층 = 0.020H(39px) / 0.025H(48px) / 0.035H(67px). 반발 계수 = √(2g × 첫 튀는 높이) ÷ 부딪는 속도로 층마다 거꾸로 구한다(약 0.45 / 0.37 / 0.32 — 부딪는 속도 약 0.72 / 0.98 / 1.32H/초). 두 번째는 같은 반발 계수로 약 8 / 7 / 7px. 첫 공중 시간 약 0.25 / 0.28 / 0.33초, 두 번째 0.11 / 0.10 / 0.11초. 튀는 동안 중력만, 늘임 없음, 가로 속도 ±0.04~0.12W/초, 회전 속도 ±240~600°/초(시드).
- 사라짐: 첫 부딪힘부터 두 번째 착지까지 불투명도가 층 값 → 0, 크기가 1 → 0.6 으로 선형으로 줄고, 두 번째 착지에서 끝난다. 수명 ≤ 1.8초. 이 줄어드는 비율을 f(낙하 중 1, 사라짐 동안 1 → 0)라 한다.
- 빛 받기: 빗조각마다 무게중심 (x, y)에서 빛 무게 w = clamp(0.5 + (hw(y) − |x − 0.5W|) ÷ 0.06W, 0, 1) × I(t) 를 구한다(hw 는 [크기]의 빛 기둥 반폭, y < 0 이면 hw = 0.127W 를 쓴다. I 는 아래 [빛과 젖은 바닥]의 빛 세기). 같은 변환으로 빗조각 색 판을 불투명도 층 값 × f × (1 − w)로, 빛 받은 판을 빛 불투명도 × f × w 로 겹쳐 그린다(w = 0 이면 첫째만, w = 1 이면 둘째만). 빛 불투명도 먼 / 중간 / 가까운 = 0.55 / 0.80 / 0.95. 빛 기둥 가장자리 0.06W 폭에서 조각 색이 부드럽게 바뀐다.
- 문장 띠에서는 빛을 거둔다: 문장 띠 = 윗줄 잉크 꼭대기 − 0.02H ~ 바닥선(시작할 때 표에서 구한다). b 는 조각 중심 한 점이 아니라 「조각의 어느 부분이라도 띠에 걸치는가」로 판정한다. 조각의 아래끝 yb = 무게중심 y + 층 크기, 위끝 yt = 무게중심 y − 층 크기(층 크기 = 조각 긴 변이라 회전해도 잉크는 중심에서 이 거리 안에 있다). 두 경계를 서로 다른 끝으로 잰다:
· 띠 꼭대기 쪽은 **아래끝**으로: b = clamp((yb − (띠 꼭대기 − 0.03H)) ÷ 0.03H, 0, 1). 위에서 내려오는 조각은 아래끝이 띠 꼭대기 0.03H 위에 닿을 때부터 어두워지기 시작해, 아래끝이 띠에 들어가면 이미 b = 1 이다. 위끝으로 재면 아래쪽이 이미 윗줄 글자 뒤에 들어간 조각이 빛을 다 받은 채 「비가ㅇ 와도」처럼 글자에 붙는다.
· 바닥선 쪽은 **위끝**으로: yt ≥ 바닥선(조각 전체가 바닥선 아래로 내려감)이면 b = 0. 위끝이 바닥선 위에 남아 있는 한 b 는 위 식 그대로(곧 1)다 — 바닥선을 막 지난 중간·가까운 층 조각도 위쪽이 아직 아랫줄 글자 밑동 뒤에 있기 때문이다. 바닥선 아래로 완전히 내려간 조각만 땅바닥 면에서 빛나며 튄다. 빛 무게 w ← w × (1 − 0.8·b), 빗조각 불투명도(두 판 모두) ← × (1 − 0.4·b)(띠 안에서 층 값의 0.6 배). 빛 받은 빗조각은 윗줄 글자와 같은 계열의 밝은 색이라, 글자 바로 뒤에서 빛나면 「비가ㅊ와도」처럼 글자에 달라붙어 읽힌다. 글자 둘레의 빗조각은 어둡고 옅게 지나가고, 빛나는 조각은 문장 위 하늘에서만 보인다. 합격: 6.1~9.0초에 상대 휘도 0.45 이상인 빗조각 픽셀이 글자 4px 안에 300px 넘게 붙는 프레임이 없다(이 판정이면 1px 이라도 붙는 프레임도 0 이 정상이다 — 바닥선 아래 땅바닥 면에서 튀는 빛 조각이 글자 밑동 아래에 몇 px 닿는 것만 설계대로다).
- 한 화면에 보이는 빗조각은 약 75개(먼 43 · 중간 22 · 가까운 10)다. 위쪽 절반(0~0.53H)에도 늘 50개 안팎이 떨어지고 있어서 첫 프레임부터 비가 화면을 채운다.
- 반복 이음매: 각 빗조각은 부딪는 시각 t_i 기준 상대 시간 r = t − t_i 를 길이(11초) 주기로 감싸 [−길이/2, 길이/2) 로 만든 뒤 r 이 [−낙하 시간, 튀기 끝] 안에 있을 때만 그린다. 그래서 t = 0 에 이미 비가 내리고 있고, 11초와 0초가 같은 화면이다.
- 바람(7.0~8.6초): 가로 바람 속도 a(t) = 0.22W/초 · sin²(π(t − 7.0)/1.6). 빗조각 x 에 바람 변위 X(t) − X(출발 시각) 를 더한다. X(t) = 0.22W·(s/2 − (1.6/(4π))·sin(2πs/1.6)), s = t − 7.0 을 [0, 1.6] 로 자른 값(끝나면 0.176W 로 고정). 문장 조각에는 바람이 없다.
[빛과 젖은 바닥]
- 빛 세기 I(t): 기본 0.40(켜지기 전에도 빛 기둥이 보인다). 가로등은 T★(아래 [장면], 마지막 음절의 딸깍 시각 — 시작할 때 표에서 구한다)에 환하게 켜진다: T★ ~ T★ + 0.5초 동안 I = 0.40 + 0.60 × easeOutCubic(u), 그 뒤 9.0초까지 1.0. 9.0 ~ 10.0초에 I = 1.0 − 0.60 × easeOutCubic((t − 9.0) ÷ 1.0)로 다시 0.40. 10.0초부터 11.0초(= 0초)까지 0.40. 그래서 0초와 11초의 빛이 같다.
- 빛 기둥: [크기]의 삼각형 하나를 가로등 빛 색으로. 픽셀마다 불투명도 = I × 세로(y) × 가로(u), u = |x − 0.5W| ÷ hw(y).
· 세로(최대값): 꼭짓점 0.50 → 문장 띠 꼭대기 높이(0.54H) 0.21 → 바닥선 0.13, 두 구간 모두 선형. 글자가 없는 위 하늘에서 빛이 가장 짙고, 글자 뒤에서는 대비를 지킬 만큼만 짙다.
· 가로: u ≤ 0.6 이면 1(평평 — 기둥 폭의 60% 가 한꺼번에 밝아진다), 0.6 < u < 1 이면 (1 − u) ÷ 0.4(가장자리에서 0), u ≥ 1 이면 0. 가장자리가 계단 없이 사라진다.
· 대비 검산: 글자 뒤 가장 밝은 바탕은 빛 기둥 가운데(가로 1)이고, 거기 세로 값이 글자 띠에서 0.21 → 0.13 이다. 하늘 색과 섞어 계산하면 빛이 최대일 때 아랫줄(0.68H 아래) 바탕 대비 최저 약 4.88:1, 윗줄(0.54~0.67H) 약 6.34:1 이다. 꼭짓점 0.50 은 글자가 없는 위 하늘(0.54H 위)에만 쓰인다. 빛 웅덩이는 바닥선 아래에만 칠하므로(그리는 순서 ⑥) 글자 밑동 뒤를 밝히지 않는다.
· 이 판은 I = 1 기준으로 시작할 때 한 번 픽셀을 계산해 만든다(기준 좌표 1/4 해상도 — 270 × 바닥선까지 높이 ÷ 4 — ImageData 로 칠한 뒤 화면 크기로 늘여 그린다. 매끄러운 그라디언트라 늘여도 계단이 없다). 매 프레임은 globalAlpha = I 로 drawImage 한 번. 다각형을 겹쳐 칠해 부드러움을 흉내 내지 않는다(겹 수만큼 계단이 생긴다).
- 젖은 바닥 반사: 바닥선 위의 그림(하늘·빛·빗조각·문장)을 다 그린 뒤, 캔버스 자신을 원본으로 바닥선 바로 위 띠(실제 픽셀 높이 = 캔버스 높이 − 바닥선 픽셀 y)를 위아래 뒤집어 바닥 아래 띠에 drawImage 한다(setTransform(1, 0, 0, −1, 0, 2 × 바닥선 픽셀 y) 로 뒤집고, 원본 사각형과 그릴 사각형은 둘 다 바닥선 바로 위 띠로 준다). 바닥선 픽셀 y = round(0.86H × 백킹 배율). 불투명도 = 0.20 + 0.35 × (I − 0.40) ÷ 0.60(빛이 기본일 때 0.20, 켜졌을 때 0.55). 바닥이 열린 동안(9.0~10.40초)은 갈라진 자리(|x − 0.5W| < 갈라진 반폭)를 클립으로 빼서 비치지 않는다 — 구멍에는 물이 없다.
- 바닥 어둠: 반사 위에 「젖은 바닥」 색의 세로 그라디언트를 덮는다 — 바닥선 0 → 0.93H 0.15 → 화면 맨 아래 0.60(1.0 이 아니다). 반사가 바닥 띠 아래쪽까지 보이고, 아래로 갈수록 조금씩 잠긴다.
- 빛 웅덩이: 가운데 (0.5W, 0.89H), 반지름 (0.462W, 0.05H) 인 타원 안에서 불투명도 = a × (1 − r)(r = 타원 정규화 거리, 밖은 0), a = 0.05 + 0.15 × (I − 0.40) ÷ 0.60. 이것도 시작할 때 1/4 해상도 판 한 장으로 만들어 매 프레임 drawImage 한 번.
- 시작 점검(콘솔 한 줄): 분할을 마치고 render(0) 을 그린 직후, 캔버스를 1/8 크기 오프스크린에 줄여 그려 픽셀마다 OKLab L 을 구하고, L < 0.35 인 비율을 「[자모 비] 0초 어두운 면적(L < 0.35) = 41% (기대 ≤ 70%, 기본 색 약 40%)」처럼 찍는다. 70% 를 넘으면 console.warn.
- 하늘 그라디언트와 젖은 바닥 바탕은 움직이지 않으므로 시작할 때 실제 픽셀 크기 오프스크린 캔버스 한 장에 한 번 그려 두고 매 프레임 drawImage 한 번으로 깐다. 프레임당 더해지는 비용 상한: 빛 판 두 장(빛 기둥·빛 웅덩이) drawImage 2번 + 캔버스 띠 복사 1번 + 바닥 어둠 그라디언트 1번 + 빗조각 빛 판 겹쳐 그리기(빛 무게가 0 보다 큰 조각만). 그 밖의 빛 효과는 없다.
[장면]
- 0.0초 — 비가 이미 화면 위쪽까지 쏟아지고 있다(바닥선은 닫혀 있다). 가로등은 기본 세기(I = 0.40)로 켜져 있어 빛 기둥이 보이고, 문장 위 하늘의 기둥 안 빗조각이 따뜻하다. 화면은 불빛이 번진 자두빛 밤이다(0초 어두운 면적 L < 0.35 약 40%).
- 0.3초 — 첫 문장 조각(괜의 받침 ㄴ)이 화면 위에서 들어온다(0.105초에 화면 위 밖에서 출발). 크기가 빗조각의 3배 가까이라 바로 눈에 띈다.
- 1.0~5.4초 — 문장 조각의 낙하 끝(기본 문장 N = 16, Δ ≈ 0.293초). 아랫줄 「괜찮아」 8조각이 1.0~3.05초, 윗줄 「비가 와도」 8조각이 3.35~5.40초. 바닥과 바로 아래 글자에 닿는 조각은 튀고 미끄러지고, 공중의 조각은 비스듬히 끼워진다. 음절 완성(딸깍) 시각은 글꼴과 착지 방식에 따라 조금 다르다 — 대략 괜 1.8~2.2 · 찮 2.7 · 아 3.4 · 비 3.8 · 가 4.4~4.9 · 와 5.5 · 도 6.0(도의 ㄷ 은 먼저 와 있는 ㅗ 위에 부딪혀 튀고 미끄러지므로 L + 0.24 + 0.40).
- ★ 약 6.04초(T★) — 마지막 음절 「도」가 끼워지며 딸깍, 이어서 괜 → 찮 → 아 → 비 → 가 → 와 가 0.05초 간격(6.09~6.34초)으로 진폭 0.12 의 딸깍을 해 문장 전체가 한 번 맞물린다(꼬리까지 6.74초). 같은 T★ 에 가로등이 켜진다: 0.5초(약 6.54초까지) 동안 빛 세기가 0.40 → 1.0 으로 오르며 빛 기둥이 짙어지고, 기둥 안 빗조각이 한꺼번에 따뜻한 빛 조각으로 바뀌고, 젖은 바닥의 문장 반사(불투명도 0.20 → 0.55)와 빛 웅덩이가 선명해진다 — 화면의 약 60%(빛 기둥 약 49% + 바닥 14%)가 0.5초 안에 달라지고, 가장 크게 바뀌는 곳은 글자가 없는 위 하늘의 빛 기둥이다(꼭짓점 쪽 불투명도 0.20 → 0.50, 기둥 폭의 60% 가 고르게). 이 순간이 작품의 중심이다: 화면 아래 0.54H~0.86H 에 문장이 꽉 차 있고, 그 위로 빛 속의 비가 쏟아지고, 그 아래 젖은 바닥에 문장이 거꾸로 비친다.
- 6.75~7.0초 — 머묾(비만 움직인다. 빛은 켜진 채).
- 7.0~8.6초 — 바람 한 줄기: 빗줄기가 오른쪽으로 쏠렸다가 다시 곧게 선다.
- 8.6~9.0초 — 머묾.
- 9.0~10.0초 — 가로등이 1초에 걸쳐 다시 희미해진다(I 1.0 → 0.40, 깜빡임 없이 한 번).
- 9.0~9.25초 — 바닥이 열린다: 바닥선이 가운데에서 갈라져 양 끝으로 물러난다. 갈라진 반폭 = 0.5W·((t − 9.0)/0.25)³. 바닥선 끝이 어떤 음절의 가운데 x 를 지나는 순간 그 음절이 다시 조각으로 갈라져(바뀌는 것이 보이지 않게) 떨어진다. 그 시각 = 9.0 + 0.25·r^(1/3), r = |음절 중심 x − 0.5W| ÷ 0.5W. 윗줄은 같은 식 + 0.10초.
- 떨어지는 조각: 정지 상태(v0 = 0)에서 문장 조각의 낙하 식(k = 1.2)으로, 음절 중심에서 바깥쪽으로 가로 속도 0.03~0.08W/초, 회전 ±40~120°/초. 잉크 꼭대기가 화면 아래(1.0H)를 넘으면 그리지 않는다. 가장 늦은 조각도 약 10.07초에 화면을 빠져나간다.
- 9.0~10.40초 사이에, 바닥이 열린 자리(|x − 0.5W| < 갈라진 반폭)에서 자기 층의 부딪는 바닥에 닿는 빗조각은 튀지 않고 같은 낙하 식으로 계속 떨어져 화면 아래로 빠진다.
- 10.10~10.40초 — 바닥이 닫힌다: 갈라진 반폭 = 0.5W·(1 − easeOutCubic((t − 10.10)/0.30)).
- 10.40~11.0초 — 비만 내린다. 11.0초 = 0.0초 화면.
- 그리는 순서(매 프레임):
① 하늘·젖은 바닥 바탕(캐시 한 장) → ② 빛 기둥 판 →
③ 바닥선 위로 클립(0 ~ 바닥선 픽셀 y): 빗조각(먼 → 중간 → 가까운) → 쉬는 글자·조각 → 떨어지는 문장 조각 → 클립 풀기 →
④ 젖은 바닥 반사(캔버스 띠 뒤집어 복사) → ⑤ 바닥 어둠 그라디언트 → ⑥ 빛 웅덩이 판(바닥선 아래로 클립한 안에서만 — 웅덩이 타원은 0.84H~0.94H 라 클립이 없으면 바닥선 위 0.02H 까지 번져 아랫줄 글자 밑동 뒤와 글자 위를 밝히고 대비를 4.4:1 로 떨어뜨린다. 웅덩이는 땅에 고인 빛이라 하늘·글자에 닿지 않는다) → ⑦ 바닥선 →
⑧ 바닥선 아래로 클립: ③과 같은 빗조각·문장 그리기를 한 번 더 → 클립 풀기.
③과 ⑧은 같은 위치 계산을 쓴다 — 바닥선에 걸친 조각은 위아래로 나뉘어 그려져 하나로 보인다. ③에서는 무게중심 y − 최대 반지름 < 바닥선인 것만, ⑧에서는 무게중심 y + 최대 반지름 > 바닥선인 것만 그려 호출 수를 줄인다. ⑧ 덕분에 땅바닥 면에서 튀는 중간·가까운 층 빗조각과 바닥이 열릴 때 떨어지는 문장 조각이 반사·어둠 앞에 온전히 보인다.
[구현]
- HTML 파일 하나로 만든다. 외부 파일·글꼴·라이브러리·네트워크 요청을 쓰지 않는다(미리보기에서 막히거나 느려진다).
- 첫 <script> 맨 앞에 CONFIG 객체를 두고 [바꿀 곳]의 값과 이 글에 나온 숫자(시간표·크기·색·세기)를 이름 붙여 모은다. 나중에 숫자만 바꿔 다듬을 수 있게.
- 그림은 시간 t(초)만으로 계산하는 함수 render(t) 로 그린다. requestAnimationFrame 의 타임스탬프나 performance.now() 로 t 를 구한다. setTimeout·setInterval·CSS 애니메이션·transition 으로 움직이지 않는다(프레임마다 속도가 달라지고, 다시 재생할 때 어긋난다). 시뮬레이션처럼 상태가 쌓이는 작품은 고정 시간 간격으로 상태를 진행하되 그 진행도 타임스탬프로만 정한다.
- 난수는 시드 고정 난수(mulberry32 등)만 쓴다. Math.random 은 쓰지 않는다(매번 다른 화면이 나온다).
- 캔버스 내부 해상도는 화면비에 맞춘 기준 크기로 고정하고, 창 크기에 맞춰 화면비를 지키며 가운데에 꽉 차게 보이게 한다(남는 곳은 배경색). 스크롤이 생기지 않게 한다. devicePixelRatio 는 그리는 선명도에만 반영한다.
- 글자는 시스템 글꼴만 쓴다: 'Pretendard', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', sans-serif. 붓글씨·손글씨 느낌은 글꼴이 아니라 획을 그려서 낸다.
- 길이가 정해진 작품은 끝나면 처음과 같은 화면으로 돌아가 이음매 없이 반복한다.
- 모든 함수·상수·셰이더 문자열을 먼저 정의하고, 시작(초기화와 첫 requestAnimationFrame)은 스크립트 맨 끝에서 한 번만 호출한다. 정의되기 전에 쓰면 첫 화면에서 멈춘다.
- 이 작품은 상태가 쌓이지 않는다: 문장 조각의 비키는 폭·착지 방식·시각, 빗조각의 출발 x·부딪는 시각·종류·회전은 시작할 때 시드 난수와 두 격자로 한 번 표를 만들어 두고, 매 프레임은 그 표와 t 만으로 닫힌 꼴 식을 계산한다. 물리 엔진이나 프레임마다 위치를 누적하는 적분은 쓰지 않는다.
- 남는 곳의 배경색(body)과 캔버스 바깥은 「하늘 위」 색이다.
- 시작 순서: 스크립트 맨 끝에서 하늘·젖은 바닥 바탕·빛 기둥(I = 0.40)·바닥선을 곧바로 한 번 그린다. 이 화면은 글꼴을 실제로 기다릴 때만 보이면 되므로, 보여 주려고 프레임을 따로 기다리지 않는다. 첫 requestAnimationFrame 콜백에서 분할과 표 만들기를 한다. 글꼴이 이미 준비돼 있으면(document.fonts.status === 'loaded') 곧바로 하고, 아니면 document.fonts.ready 를 최대 1초 기다린 뒤에 한다(글꼴이 늦게 잡혀 다른 글꼴로 잘리면 조각이 틀어진다).
- 시계의 0초: 분할을 마친 그 콜백 안에서 render(0) 을 그리고, 그 콜백의 타임스탬프를 0초로 잡는다. 분할이 끝난 뒤 0초 화면보다 먼저 그려지는 프레임은 없다 — 반복 이음매(11초 = 0초)가 첫 바퀴부터 맞는다.
- 빗조각은 미리 만든 조각 비트맵을 drawImage 로만 그린다(매 프레임 마스크 합성 금지). 화면 밖(y < −0.2H 또는 > 1.05H)은 건너뛴다.
- 빗조각 비용 상한(프레임 무게의 대부분이 여기 있다): 층마다 그 층 크기로 줄인 조각 스프라이트(빗조각 판·빛 받은 판 × 조각 16개)를 시작할 때 아틀라스 캔버스 한 장(층당 1장, 격자 배치, 칸 사이 2px 여백)에 구워 두고, 매 프레임 빗조각 하나는 setTransform 1번 + globalAlpha + drawImage(아틀라스, 원본 사각형 → 대상 사각형) 1~2번만 쓴다. 빗조각 루프 안에서는 save/restore·beginPath·clip·새 캔버스·filter·그라디언트를 쓰지 않는다(클립은 ③·⑧ 패스 시작에 한 번씩). 불투명도 0.02 미만인 판은 그리지 않는다. 그래서 프레임당 빗조각 drawImage 는 ③·⑧ 합쳐 약 160번 이하다(보이는 조각 약 75개 × 평균 약 1.5판 + 바닥선에 걸친 조각의 ⑧ 재호출).
[하지 말 것]
- 낱자(ㄱ, ㅏ 같은 호환 자모)를 fillText 해서 조각이나 빗조각을 만들지 말 것 — 음절 속 자모와 굵기·모양·비율이 달라서, 합쳐지는 순간 글자가 툭 튄다.
- 겹모음+받침 음절을 처음부터 통째 1조각으로 돌리지 말 것 — 첫 착지이자 가장 큰 조각이 자모가 아닌 완성 글자가 되어 작품의 생각이 첫 장면에서 깨진다. 받침 떼기 → 2조각 → 통째(경고) 순서로만 물러선다.
- 받침 없는 겹모음 음절(「와」 등)을 「자르기 규칙이 가로·세로 모음만 말한다」며 통째 1조각으로 돌리지 말 것 — 기본 문장의 「와」는 세 글꼴 모두 ㅇ 이 ㅗ 에 붙어 있어서, 겹모음 자르기를 빼면 「와」만 통째로 떨어지고 빗조각에도 읽히는 「와」가 섞인다. 겹모음은 초성이 비면 2-c 대로 자르고, 안 되면 2-d 의 곧은 자르기 2조각으로 물러선다.
- 분할(연결 성분·BFS)을 실제 픽셀 배율에서 하지 말 것 — 2배 화면에서 계산이 4배가 되어 폰에서 검은 화면이 몇 초씩 이어진다. 분할은 1배, 비트맵만 실제 크기.
- 조각마다 다른 굵기·글꼴·색 필터를 주지 말 것 — 완성 비트맵에서 잘라 낸 픽셀 그대로여야 바꿔 끼울 때 보이지 않는다.
- 쉬는 자리의 조각과 완성 글자를 겹쳐 그리거나 크로스페이드하지 말 것 — 반투명 가장자리가 두 번 칠해져 그 프레임만 글자가 굵어진다.
- 문장 조각을 이미 쉬는 글자 위에 겹쳐 내려앉히지 말 것 — 같은 색 획이 붙어 「괜ㅊ」 같은 한 덩어리로 읽혀 쌓이는 동안 글이 깨진다. 겹침 격자 검사로 비키는 방향을 고른다.
- 받쳐 줄 것이 없는 자리에서 조각을 부딪혀 튀게 하지 말 것(잠깐 들렀다 떠난 착지 자리나 아직 오는 중인 조각의 쉬는 자리는 받침이 아니다) — 허공의 보이지 않는 선반에 부딪히는 것으로 읽힌다. 튀기는 받침 틈 0.012H 이하에서만.
- 물방울 입자·튀는 물보라·물웅덩이 모양·파문·물결을 넣지 말 것 — 이 작품의 비는 자모 조각뿐이다. 진짜 물 효과를 섞으면 「글자로 된 비」라는 생각이 흐려진다. 젖은 바닥은 바닥선 위 그림을 뒤집어 비친 반사 하나로만 낸다(반사도 글자로 되어 있다).
- 반사를 흔들거나 일그러뜨리거나 늘이지 말 것 — 뒤집힌 글자가 일렁이면 문장을 다시 읽게 되고, 반사 계산이 프레임마다 달라진다. 뒤집어 복사 한 번, 불투명도와 어둠 그라디언트만.
- 빗줄기 선(가는 사선)·구름·우산·번개 섬광·블러·모션 블러·그림자를 넣지 말 것 — 프롬프트에 없는 장식이고, 섬광은 반복 영상에서 눈을 피로하게 한다.
- 가로등 기둥·전등갓·전구·달·건물 실루엣을 그리지 말 것 — 광원은 화면 위 밖에 있다. 소품이 생기면 문장과 시선을 다툰다.
- 하늘·바닥을 숫자보다 어둡게(검정·짙은 남색 쪽으로) 내리거나 젖은 바닥을 검정 띠로 덮지 말 것 — 어두운 바탕에 빛나는 조각만 뜨는 짜임이 되어 0초 화면이 「검은 방」으로 읽힌다. 0초 어두운 면적 ≤ 70%(콘솔 줄로 확인), 바닥 어둠은 최대 0.60.
- 빛을 깜빡이거나 번쩍이게 하지 말 것 — 켜짐은 T★ 에 0.5초 한 번, 꺼짐은 9.0초에 1초 한 번이다. 반복 영상의 섬광은 눈을 피로하게 한다.
- 빛을 shadowBlur·글자 주위 발광·렌즈 플레어·빛 입자로 내지 말 것 — 빛은 빛 기둥 판, 빛 웅덩이 판, 빗조각 판 바꾸기 세 가지뿐이다. shadowBlur 는 폰에서 프레임을 떨어뜨린다.
- 빛에 따라 문장 글자(조각·완성 비트맵)의 색이나 밝기를 바꾸지 말 것 — 조각과 완성 글자의 픽셀이 같아야 끼울 때 보이지 않는다. 빛 기둥은 문장 뒤에만 칠하고, 문장은 빛 위에 그대로 얹힌다.
- 빗조각을 문장 앞에 그리지 말 것 — 완성된 문장을 가려 읽히지 않는다. 빗조각은 항상 글자 뒤로 지나간다(앞쪽 깊이는 바닥선 아래 땅바닥 면에서 튀는 자리로만 낸다).
- 빗조각끼리, 빗조각과 글자 사이의 충돌을 계산하지 말 것 — 표와 t 만으로 그린다는 원칙이 깨지고, 프레임마다 결과가 달라진다.
- 문장 조각을 화면 아무 데서나 떨어뜨리거나 사방에서 날아오게 하지 말 것 — 정해진 열(착지 자리 x)에서 곧게 떨어져 제자리로 들어가야 「쌓여서 맞춰진다」가 읽힌다.
- 문장 조각을 쉬는 자리에서 축소·확대해 「또잉」 튀게 하지 말 것 — 완성의 표시는 아래로 눌리는 「딸깍」 하나다. 크기를 바꾸면 픽셀이 같다는 이 작품의 핵심이 흐려진다.
- 대기 화면을 보여 주려고 프레임을 기다렸다가 분할하지 말 것 — 0초보다 앞선 빈 프레임이 끼어 첫 바퀴의 이음매가 어긋난다. 분할한 그 콜백에서 바로 0초를 그린다.
- 화면 구석에 제목·시간·안내 문구를 쓰지 말 것 — 화면의 글자는 문장 하나뿐이다.
사용 방법
필요한 것: claude.ai 계정 — 무료 계정에서도 Claude Opus 5.5 를 고를 수 있습니다
- claude.ai 에서 새 대화를 엽니다.
- 모델 메뉴에서 Claude Opus 5.5 를 고르고, 같은 메뉴의 Effort(답변 깊이)를 High 로 둡니다.
- 복사한 프롬프트를 붙여 넣고 전송합니다. 결과로 나온 HTML 파일을 브라우저로 열면 재생됩니다.
- 권장 모델
- Claude Opus 5.5 · Effort High
- 화면비
- 9:16 (세로)
- 재생 길이
- 11초
- 결과물
- HTML 파일 하나 · 따로 설치할 것 없음
- 영상 파일
- 위 「MP4 저장 기능 포함」을 켜면 결과 화면에 녹화 단추가 생깁니다 1080 기준 · 12 Mbps · 브라우저에 따라 MP4 또는 WebM
추가 요청 예시
결과가 나온 뒤 같은 대화에서 이어서 요청하면 해당 부분만 수정됩니다.
- 문장을 윗줄 「오늘도」 / 아랫줄 「수고했어」로 바꾸고, 두 줄 모두 #FFF6EA 한 색으로 해 줘.
- 가로등을 분홍 네온 간판 빛으로 바꿔 줘: 가로등 빛 #FF6F9C, 빛 받은 빗조각 #FFC7D8, 아랫줄 글자 #FFE07A. 글자가 잘 읽히는 대비(4.5:1 이상)는 그대로 지켜 줘.
- 소나기처럼 세게 해 줘: 빗조각 양을 층마다 2배로 늘리고, 공기저항을 층마다 0.75배로 낮춰 더 빨리 떨어지게 하고, 옆바람은 1초에 화면 폭의 35%만큼으로 세게 해 줘.
한글