폰 알림 쌓이기
아침 하늘 배경화면 위로 유리 알림 카드가 툭툭 떨어져 쌓이다가, 넘치는 순간 「+9」 묶음으로 착 접히며 가려졌던 해가 드러난다.
설정값 미리보기
바꾼 문구·색으로 다시 재생합니다
프롬프트 설정
Claude 가 읽는 제작 지시문입니다. 직접 읽지 않아도 됩니다.
아침 하늘 배경화면이 깔린 잠금 화면 위로 유리 같은 알림 카드가 툭툭 떨어져 쌓이다가, 넘치는 순간 아래 카드들이 「+9」 묶음으로 착 접히며 가려졌던 아침 해가 드러나는 세로 영상을 HTML 파일 하나로 만들어 줘. 미리보기에서 바로 재생되게. 길게 설명할 테니 숫자는 그대로 지켜 줘.
핵심 아이디어: 알림은 무게가 있다. 첫 프레임부터 잠금 화면에는 알림 카드 여섯 장이 위에서 아래까지 꽉 차 있고, 새 카드 한 장이 화면 위에서 떨어지고 있다. 새 카드는 가속하며 떨어져 맨 위에 「툭」 얹힌다. 그 충격이 아래로 전해져 카드 사이 틈이 위에서부터 눌렸다가 펴진다. 아래 카드일수록 조금 늦게 따라 내려오는 아코디언 같은 탄성이다. 알림이 점점 빨리 쏟아지다가 넘치는 순간, 맨 위 두 장 아래의 카드 전부가 0.25초 만에 위로 빨려 올라가 셋째 카드 뒤에 겹겹이 접힌다(화면 밖으로 밀려난 카드까지 포함한다). 그 아래에 「+9」 알약이 튀어 오른다. 그 뒤 새 알림이 묶음을 한 칸씩 밀어 화면 밖으로 내보내면 처음 화면이 된다. 새 카드는 위에서 떨어지고(최신이 맨 위), 쌓인 카드는 아래로 밀린다. 말풍선이 아래에서 솟아 위로 밀리는 메신저 화면과 반대 방향이다.
무대는 아침 7시 반의 잠금 화면이다. 배경화면은 코드로 그린 해 뜨는 하늘이다. 위는 자두빛 새벽이고, 아래로 빛바랜 장밋빛·옅은 살구빛으로 차분하게 밝아진다. 해 둘레의 아래 띠만 조금 더 따뜻하다. 화면 아래쪽에는 가장자리가 선명한 해 원과 능선 세 겹이 있다. 카드는 젖빛 유리다. 카드 뒤의 배경화면이 흐리고 밝게 비쳐서, 카드가 밀려 내려가는 동안 카드 색이 옅은 라벤더에서 옅은 살구로 은은하게 바뀐다. 카드 사이 틈과 양옆 여백으로는 선명한 하늘이 보이고, 카드 아래로는 같은 해가 흐린 빛으로만 비친다. 3.55초에 묶음이 접혀 화면 아래가 비면, 알림에 가려 흐리게만 보이던 해와 능선이 처음으로 선명하게 드러난다. 알림을 정리하자 아침이 보이는 것이다.
[바꿀 곳]
- 알림 10개(이 순서로 떨어진다. 앱 이름 · 제목 · 본문 — 제목은 한글 약 12자, 본문은 약 14자 안):
1. 모임방 · 동기 단체방 · 오늘 저녁 다들 시간 돼?
2. 택배함 · 배송 출발 · 오늘 오후 도착 예정이에요
3. 모임방 · 동기 단체방 · 7시 강남역 어때?
4. 살림은행 · 입금 2,850,000원 · 이번 달 월급이 들어왔어요
5. 모임방 · 동기 단체방 · 콜! 나도 간다
6. 일정 · 10시 팀 회의 · 15분 뒤에 시작해요
7. 지갑 · 결제 4,500원 · 모퉁이 커피
8. 모임방 · 동기 단체방 · 예약은 내가 할게
9. 하늘 · 오후에 비 소식 · 우산 챙기세요
10. 모임방 · 동기 단체방 · 사진 12장을 보냈어요
(반복 영상이라 0초 화면에 쌓여 있는 여섯 장은 지난 회차의 10·9·8·7·6·5번이다. 그래서 문구만 바꾸면 되고, 개수를 바꾸려면 아래 장면 시간표도 함께 바꿔야 한다.)
- 앱 아이콘 색(원 안에 앱 이름 첫 글자를 흰색으로): 모임방 #7B61FF · 택배함 #FF8A1F · 살림은행 #12A07A · 일정 #D9468F · 지갑 #2B6BFF · 하늘 #22A5D6. 목록에 없는 앱 이름이 나오면 #6B7080 으로 그리고 console.warn 으로 알린다.
- 카드 머리줄 오른쪽 글자: 지금
- 잠금 화면 글자: 날짜 「10월 5일 월요일」 · 시각 「07:30」(멈춰 있는 글자다. 실제 시계가 아니다)
- 배경화면 색: 하늘(위에서 아래로 세로 정지점) 0 #2B1C3B · 0.45 #724769 · 0.75 #C98C87 · 1.00 #F4B48A · 해 #FFE3A3 · 능선(뒤 → 앞) #BE7378 · #85506A · #563553
바탕은 차분한 면이다. 채도는 OKLCH 의 C 로 잰다. 화면 위 0.75H 까지의 하늘은 C 0.08 이하다(정지점 0.059 · 0.076 · 0.075, 사이 값도 최대 0.076). C 0.08 을 넘는 색은 해 둘레의 아래 띠(0.75H~1.0H, 화면 높이의 25%)에만 있고, 거기서도 0.10 이하다(하늘 끝 #F4B48A 0.093 · 해 0.087 · 뒤 능선 0.095). 그래서 C > 0.08 인 바탕 면적은 화면의 25%를 넘을 수 없다. 기본 색에서 실제로는 약 8.6% 다. 강한 채도는 앱 아이콘·알약처럼 화면 15% 이하의 작은 것에만 쓴다.
- 유리와 글자 색: 유리 베일 #FFFFFF 불투명도 0.72 · 유리 가장자리 빛 #FFFFFF 불투명도 0.65 · 접힌 겹 1 베일 0.56 · 접힌 겹 2 베일 0.42 · 날짜와 시각 #FFFFFF(날짜는 불투명도 0.85) · 제목 #17181C · 본문 #3A3C44 · 머리줄(앱 이름·지금) #44474F · 알약 #2B1C3B · 알약 글자 #FFFFFF
- 길이: 9초 (끝나면 처음으로 이어서 반복)
- 화면비: 9:16 (캔버스 1080×1920)
[크기]
W = 화면 폭, H = 화면 높이. 글자의 「잉크」는 measureText 의 actualBoundingBox 로 잰 실제 획의 상자다(폭 = actualBoundingBoxLeft + actualBoundingBoxRight). 글꼴마다 폭이 달라서, 맞추는 규칙은 전부 잉크로 재고 advance(width)로 재지 않는다.
- 카드: 폭 0.92W(왼쪽 끝 0.04W, 오른쪽 끝 0.96W), 높이 Hc = 0.118H, 모서리 반지름 0.045W. 카드 사이 틈 g = 0.022H. 한 칸 P = Hc + g = 0.140H.
- 맨 위 카드의 위끝 y0 = 0.215H. 쌓인 카드 k번째(0 = 맨 위)의 위끝 = y0 + k·P → 0.215 · 0.355 · 0.495 · 0.635 · 0.775 · 0.915H. 여섯째 카드는 아래가 화면 밖으로 잘린다. 0초 화면에서 카드가 화면의 약 72%를 덮는다.
- 카드 안: 아이콘 원 지름 0.11W, 중심 x = 0.14W, 중심 y = 카드 가운데. 아이콘 글자 = 앱 이름 첫 글자, 굵기 700, 잉크 높이가 지름의 0.42 가 되는 크기, 잉크 중심을 원 중심에.
글자 열: x 0.23W ~ 0.915W(폭 0.685W). 세 줄, 각 줄의 세로 중심 = 카드 위끝 + 0.24Hc(머리줄) · 0.50Hc(제목) · 0.76Hc(본문).
머리줄: 굵기 600, 글자 크기 0.034W. 왼쪽에 앱 이름, 오른쪽에 「지금」(잉크 오른끝 = 0.915W).
제목: 굵기 700, 글자 크기 0.047W. 본문: 굵기 400, 글자 크기 0.043W.
줄의 기준선: 각 글자 크기·굵기마다 '한' 의 actualBoundingBoxAscent(a)·Descent(d)를 재 두고 기준선 = 줄 세로 중심 + (a − d) / 2. 글자는 왼쪽 정렬.
- 넘침(최후에만, 경고와 함께): 한 줄의 잉크 폭이 쓸 수 있는 폭보다 크면 뒤에서 한 글자씩 지우고 「…」를 붙여 들어갈 때까지 줄이고 console.warn 으로 알린다. 쓸 수 있는 폭은 제목·본문이 0.685W, 앱 이름이 0.685W − 「지금」 잉크 폭 − 0.03W 다. 글자 크기를 줄여 맞추지 않는다. 기본 문구는 말줄임 0개가 정상이다. 가장 긴 본문의 잉크 폭은 열 폭의 약 0.64~0.75(글꼴에 따라)이고, 가장 긴 제목은 약 0.50~0.55 다.
- 날짜: 굵기 600, 잉크 높이 0.021H, 잉크 왼끝 0.06W, 잉크 위끝 0.045H.
- 시각: 굵기 700, 잉크 높이 0.085H(그때 잉크 폭이 0.80W 를 넘으면 0.80W 에 맞춘다), 잉크 왼끝 0.06W, 잉크 위끝 0.080H. 「07:30」이면 잉크 폭 약 0.50~0.53W.
- 묶음(접힌 뒤): 앞면 = 4번 카드 그대로. 그 뒤에 겹 1·겹 2 가 앞면 아래로 0.016H 씩 비어져 나온다. 겹 l 의 아래끝 = 앞면 아래끝 + l·0.016H, 크기 배율 0.94(겹 1)·0.88(겹 2), 배율 중심 = 그 카드의 아래끝 가운데. 접히는 순간 화면에서 묶음은 세로 0.495H~0.645H, 폭 0.92W.
- 알약: 높이 0.080H, 가운데 x = 0.5W, 위끝 = 겹 2 아래끝 + 0.018H(접힌 순간 0.663H~0.743H). 글자 「+9」 굵기 800, 잉크 높이 0.046H, 잉크 중심을 알약 중심에. 알약 폭 = max(0.34W, 글자 잉크 폭 + 0.12W), 양 끝이 반원인 둥근 막대.
- 배경화면(전부 화면 좌표로 정한다. 한 함수 drawWallpaper(ctx, t)가 그린다):
하늘 = 세로 선형 그라디언트(y = 0 에서 y = H 까지, 정지점은 [바꿀 곳]). 사각형은 y −0.15H ~ 1.15H 를 덮는다(그라디언트는 범위 밖에서 끝 색으로 이어진다).
해 = 중심 (0.5W, 0.86H), 반지름 0.15W(= 0.084H, 화면 0.776H~0.944H)인 단색 원, 가장자리는 선명하다. 움직이지 않는다.
능선 k(k = 1 뒤 · 2 가운데 · 3 앞, 해보다 나중에 그린다) = 위끝 곡선 y_k(x, t) = b_k + a_k·sin(2π·f_k·x / W + φ_k + 0.35·sin(2π·t / 9 + ψ_k)) 아래를 y = 1.15H 까지 채운 다각형이다. x 는 −0.02W ~ 1.02W 를 48등분한 49점이다.
b = 0.885H · 0.920H · 0.955H, a = 0.020H · 0.016H · 0.012H, f = 1.1 · 1.7 · 2.4, φ = 0.6 · 2.1 · 4.0, ψ = 0 · 2.09 · 4.19(라디안). 그래서 해의 아래쪽(약 0.87H 아래)이 능선 뒤에 숨는다. 해의 위쪽 0.776H~0.87H 는 하늘 위로 보인다. 능선은 좌우로 천천히 흔들린다. 뒤 능선이 최대 약 55px 움직이고, 가장 빠를 때 초당 약 38px 다. 식 안의 9 는 길이(CONFIG.timing.loop)다. 그래서 9초 화면 = 0초 화면이다.
- 유리 카드(젖빛 유리처럼 보이지만 실제로는 불투명한 판이다):
작은 캔버스 하나(54×125)를 둔다. 프레임마다 그 위에 drawWallpaper 를 한 번 더 그린다. 변환은 setTransform(k, 0, 0, k, 0, 0.15H·k), k = 54 / W = 0.05 다. 그러면 화면 y −0.15H ~ 1.15H 가 작은 캔버스 세로 125px 에 담긴다. 작은 캔버스의 1px 가 화면 20px 이라서, 키워 그리면 해의 선명한 가장자리가 약 40px 에 걸쳐 흐려진다. 이것이 유리 너머의 흐림이다.
카드 한 장 그리기: ① 카드 모양(둥근 사각형, 배율 반영)으로 clip 한다. ② 그 카드의 화면 사각형 (x, y, w, h)에 해당하는 작은 캔버스의 원본 사각형 (x·k, (y + 0.15H)·k, w·k, h·k)을 잘라 카드 사각형에 drawImage 로 키워 그린다(imageSmoothingEnabled = true, imageSmoothingQuality = 'high'). ③ 흰색을 베일 불투명도 v 로 카드 전체에 덮는다. ④ 같은 카드 경로를 lineWidth 4, 흰색 불투명도 0.65 로 stroke 한다(clip 때문에 안쪽 2px 만 남는다 — 유리 가장자리 빛). ⑤ clip 을 풀고 아이콘·글자를 그린다.
원본 사각형이 작은 캔버스 밖으로 나가면(최후에만, 경고와 함께) 안쪽으로 잘라 맞추고 console.warn 으로 알린다. 범위 밖을 읽는 drawImage 는 브라우저마다 결과가 달라서, 어떤 브라우저에서는 그 카드가 통째로 안 그려진다. 기본 시간표에서는 0번이 정상이다. 그려지는 카드의 위끝은 −0.125H 이상이고 아래끝은 H + Hc = 1.118H 이하다.
보통 카드의 베일 v = 0.72 다. 가장 어두운 바탕(#2B1C3B) 위에서도 카드가 #C4BFC8 근처라 제목 대비 약 9.85, 본문 약 6.1, 머리줄 약 5.2 다(모두 4.5:1 이상).
- 결 무늬: 시작할 때 128×128 캔버스에 시드 고정 난수로 점마다 흰색 또는 검정(반반)을 불투명도 0~0.04 로 찍어 둔다. createPattern('repeat') 로 화면 전체를 한 번 덮는다. 순서는 배경화면 바로 뒤, 날짜·시각·카드보다 먼저다. 녹화 압축에서 하늘 그라디언트에 띠가 지는 것을 막는다. 작은 캔버스에는 넣지 않는다.
[움직임 — 전부 닫힌 식]
기호: 카드 n 의 착지 시각 t_n(장면 표). 지난 회차 카드는 색인 n = −5 … 0(문구 = 5·6·7·8·9·10번, n = 0 이 10번), 이번 회차는 n = 1 … 10. 지난 회차 카드는 t_n = −∞ 로 본다.
- 밀기 스프링: B(τ) = 1 − e^(−14τ)·cos(18τ), τ < 0 이면 0. τ≈0.138초에 1.115 로 넘쳤다가 τ≈0.31초에 0.990, 0.25초 뒤로는 ±1% 안. B 의 처음 속도는 14 (칸/초).
- 틈 눌림: c(τ) = 1.17·e^(−6τ)·sin(12τ), τ < 0 이면 0. τ≈0.092초에 0.60(틈이 40% 로 줄어든다), τ≈0.354초에 −0.125(틈이 12.5% 늘어난다), 0.67초 뒤로는 ±0.02 안. τ = 0 에서 정확히 0 이다(cos 꼴 금지 — 착지 순간 한 프레임 튐).
- 쌓인 카드 n 의 위끝:
y_n(t) = y0 − P + P·Σ_{j ≥ n} B(t − t_j) − g·Σ_{j > n} min(j − n, 4)·c(t − t_j)
(j 는 지난 회차와 이번 회차의 모든 카드. 지난 회차 카드는 B = 1, c = 0. 아직 닿지 않은 카드는 B = c = 0. 다음 회차 1번은 합에 넣지 않는다.)
뜻: 새 카드 j 가 닿으면 그 아래 카드 전부가 한 칸 P 만큼 B 로 밀려 내려간다. 동시에 새 카드에서 k 번째 아래 카드는 k 개의 틈이 눌린 만큼 늦게 따라온다. 넷째 아래부터는 넷째와 함께 움직인다. 넷째 카드는 최대 약 0.053H(101px) 늦었다가 따라잡는다. 이웃 카드끼리는 절대 겹치지 않는다(가장 좁을 때 틈 약 0.37g ≈ 16px). 그 틈으로 선명한 하늘이 가늘게 비친다.
- 낙하(착지 전): t_n − T_f ≤ t < t_n 이면 u = 1 + (t − t_n) / T_f, 위끝 = y0 − P − D·(1 − u²). D = 0.20H, T_f = 2D / (14·P) ≈ 0.204초.
출발 위끝 = −0.125H(카드 전체가 화면 위 밖), 닿는 위끝 = y0 − P = 0.075H(그때 카드 아래끝과 맨 위 카드 사이가 정확히 g).
가속 낙하라 닿는 순간 속도 2D / T_f = 14·P ≈ 3763 px/s 가 밀기 스프링의 처음 속도와 같다. 그래서 떨어지던 카드가 멈칫 없이 그대로 아래 카드들을 밀고 내려간다. 착지 시각에 낙하 식과 y_n 식은 같은 값(0.075H)이다.
t < t_n − T_f 이면 그리지 않는다. 0초 화면에 떨어지는 카드가 있으려면 1번 착지 시각이 T_f(≈0.204초)보다 빨라야 한다(기본 0.05초).
- 접힘: t_F = 3.30초, 길이 0.25초. F(t) = 0(t < t_F), easeInCubic((t − t_F) / 0.25)(그 사이), 1(t ≥ 3.55). 처음엔 천천히 모이고, 끝에서 가장 빠르게 묶음에 박힌다.
접히는 카드 = 색인 n ≤ 3(이번 회차 1·2·3번 + 지난 회차 여섯 장). n = 3 은 겹 1 자리로 간다. n ≤ 2 는 전부 겹 2 자리로 간다(겹 2 자리에 겹쳐 쌓여 하나로 보인다).
앞면 아래끝 fb(t) = y_4(t) + Hc + J(t). 접히는 카드에는 다음을 적용한다.
· 아래끝 = (y_n(t) + Hc)·(1 − F) + (fb + l·0.016H)·F
· 크기 배율 = 1 + (s_l − 1)·F(s_1 = 0.94, s_2 = 0.88, 배율 중심 = 아래끝 가운데)
· 베일 불투명도 = 0.72 + (v_l − 0.72)·F(v_1 = 0.56, v_2 = 0.42). 접힐수록 베일이 얇아져 뒤 하늘의 빛바랜 장밋빛이 조금 더 비친다.
· 아이콘과 글자의 불투명도 = clamp((0.32 − F) / 0.16, 0, 1). F ≤ 0.16 이면 1, F ≥ 0.32 면 0 이고 그 사이는 연속이다.
글자 불투명도의 이유: 카드 사이 간격 P·(1 − F)가 카드 높이보다 줄어드는 F≈0.16 부터 옅어지기 시작한다. 그리고 위 카드가 아래 카드의 머리줄을 자르기 시작하는 F≈0.32(약 3.47초) 전에 다 지워진다. 그 뒤 아코디언은 글자 없는 유리판만 겹친다. 1 − F 로 하면 3.48~3.53초에 위 카드가 글자 줄을 가운데에서 잘라, 반쪽 글자가 줄무늬로 겹겹이 남는다.
유리판 사이의 경계는 위 카드의 가장자리 빛(안쪽 2px)이 그린다. 겹친 판들은 모두 같은 자리의 배경을 옮겨 담는다. 그래서 가장자리 빛이 없으면 아홉 장이 한 장의 판으로 뭉개져 보인다. 이 빛은 접히는 동안에도 옅어지지 않는다.
화면에서는 이렇게 보인다. 3.30초에 0.635·0.775·0.915H 에 있던 세 장과 화면 아래 밖의 여섯 장이, 이웃 간격 P·(1 − F)로 간격을 똑같이 좁히며 위로 쏠린다. 위 카드가 아래 카드를 덮어 가는 아코디언처럼 접힌다. 맨 아래 카드는 0.25초에 1.23H 를 올라온다. 카드가 빠져나간 화면 아래 약 0.26H(0.743H~1.0H)에는 그때까지 유리 너머로 흐리게만 보이던 해와 능선이 선명하게 드러난다.
- 착(3.55초, 시그니처 순간): u = t − 3.55 ≥ 0 일 때 J(t) = −0.02H·e^(−10u)·sin(26u)(음수 = 위로). 앞면과 겹들과 알약이 함께 u≈0.046초에 위로 약 23px(0.012H) 튕긴다. 이어 u≈0.167초에 아래로 약 7px 내려가고, 0.33초 뒤에는 1px 안으로 가라앉는다. 접힌 카드들의 마지막 충격을 묶음 전체가 받는 것이다. 앞면 위의 두 장은 J 를 받지 않는다(틈 g = 42px 라 튕겨도 닿지 않는다). u < 0 이면 J = 0.
- 알약: 3.55초부터 크기 배율 Q = B(u)(0 에서 출발, u≈0.138초에 1.115, 배율 중심 = 알약 중심). 3.55초 전에는 그리지 않는다. 알약은 앞면을 따라 움직인다(위끝 = fb + 0.032H + 0.018H). 알약 아래끝(0.743H)과 해 위끝(0.776H) 사이는 약 63px 이라 겹치지 않는다.
알약의 퇴장: 8번이 닿으면(t_8 = 5.60초, τ = t − t_8) 알약은 묶음을 따라 밀려 내려가면서 Q = max(0, 1 − B(τ)) 로 줄어든다. τ = π/36 ≈ 0.087초에 B 가 처음 1 이 되어 Q = 0 이 되고, 그 뒤로는(이번 회차 끝까지) 그리지 않는다. B 는 그 뒤 1 아래로 잠깐 내려오므로 식을 그대로 두면 2px 짜리 알약이 다시 나타난다. 그래서 「처음 0 이 된 뒤로는 그리지 않는다」를 지킨다. t_8 직전 Q = B(2.05) ≈ 1, t_8 에서 1 − B(0) = 1 이라 이어진다. 줄어드는 동안 알약 아래끝(배율 반영)은 최대 약 0.983H 라 화면 아래끝에 잘리지 않는다. 이 규칙이 없으면 알약이 화면 아래끝(0.943~1.023H)에 잘린 채 5.76~6.56초 동안 멈춰 있다.
- 배경화면의 움직임은 능선의 흔들림 하나뿐이다([크기]의 식). 하늘과 해는 멈춰 있다. 착지·접힘·착에 반응하지 않는다.
[장면]
- 0.00 화면: 지난 회차 여섯 장(위에서부터 10·9·8·7·6·5번)이 y0 + k·P 에 쌓여 있다. 1번 카드가 자두빛 하늘 위를 떨어지는 중이다(위끝 약 −0.011H, 아래끝 약 0.107H — 거의 다 보인다). 시각 「07:30」 위로 카드가 지나간다. 아래쪽 카드들 뒤로 해가 흐린 금빛으로 비치고, 카드 틈으로 선명한 하늘이 가늘게 보인다. 빈 화면·정지 화면으로 시작하지 않는다.
- 착지 시각(점점 빨라지는 알림 폭탄): 1번 0.05 · 2번 0.80 · 3번 1.45 · 4번 2.00 · 5번 2.45 · 6번 2.80초(간격 0.75 · 0.65 · 0.55 · 0.45 · 0.35). 착지할 때마다 아래 카드들이 한 칸씩 눌려 밀리고, 맨 아래 카드는 화면 밖으로 밀려난다. 밀려 내려가는 카드는 자기 뒤 하늘을 따라 옅은 라벤더에서 옅은 살구로 은은하게 물든다.
- 3.30–3.55 접힘. 6·5번이 위 두 장으로 남고, 4번이 앞면이 되며, 그 아래 전부가 위로 접힌다. 글자가 지워진 유리판들이 가장자리 빛을 겹치며 장밋빛을 머금은 채 빨려 올라간다.
- 3.55 착 + 「+9」 알약이 튀어 오른다(9 = 4번 뒤에 접힌 카드 수: 1·2·3번 + 지난 회차 여섯 장). 같은 순간 화면 아래 0.743H~1.0H 에 선명한 해와 능선이 드러난다.
- 3.55–4.70 머묾. 알약의 반동과 J 가 0.33초 안에 가라앉는다. 나머지는 「+9」와 아침 해를 보는 시간이다.
- 착지 시각(고른 박자): 7번 4.70 · 8번 5.60 · 9번 6.50 · 10번 7.40초. 착지할 때마다 묶음과 알약도 한 칸씩 밀려 내려간다. 해는 다시 유리 뒤로 들어간다. 10번 착지 뒤 묶음의 위끝이 1.055H 로 화면 밖에 나간다. 이때 화면은 위에서부터 10·9·8·7·6·5번이다. 0초 화면과 같은 여섯 장이다.
- 7.9–8.846 머묾.
- 8.846–9.00: 다음 회차의 1번 카드가 떨어지기 시작한다(t_n = 9 + 0.05 로 보고 낙하 식으로 그린다). 9.00초 화면 = 0.00초 화면(능선 위상도 같다).
- 카드가 화면의 절반 넘게 덮는 시간이 9초 중 약 76% 이다(묶음이 화면 가운데에 있는 3.3~5.6초만 절반 아래). 배경화면은 늘 화면 전체다.
[구현]
- 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)은 스크립트 맨 끝에서 한 번만 호출한다. 정의되기 전에 쓰면 첫 화면에서 멈춘다.
이 작품에만 해당하는 구현:
- 기준 크기 1080×1920. t = (경과 시간) mod 9. 화면 밖 남는 곳의 배경색은 하늘 맨 위 색 #2B1C3B.
- CONFIG 에 들어갈 것:
· notices: [{ app: '모임방', title: '동기 단체방', body: '오늘 저녁 다들 시간 돼?' }, …], appColors, nowLabel, date, time, colors
· wallpaper({ sky: [[0, '#2B1C3B'], [0.45, '#724769'], [0.75, '#C98C87'], [1, '#F4B48A']], sun: { x: 0.5, y: 0.86, r: 0.15, color: '#FFE3A3' }, ridges: [{ b: 0.885, a: 0.020, f: 1.1, phi: 0.6, psi: 0, color: '#BE7378' }, …], sway: 0.35, pad: 0.15 })
· glass({ smallW: 54, smallH: 125, veil: 0.72, rim: 0.65, rimWidth: 4, layerVeils: [0.56, 0.42] }), grain({ size: 128, alpha: 0.04 })
· size(카드 0.92·0.118·0.022·y0 0.215·반지름 0.045·아이콘 0.11·글자 크기 0.034·0.047·0.043 등)
· timing({ land: [0.05, 0.80, 1.45, 2.00, 2.45, 2.80, 4.70, 5.60, 6.50, 7.40], fold: 3.30, foldLen: 0.25, loop: 9 })
· spring({ push: [14, 18], squeeze: [1.17, 6, 12], squeezeRankCap: 4, jolt: [0.02, 10, 26] }), fall({ D: 0.20 }), fade({ end: 0.32, len: 0.16 })
· bundle({ peek: 0.016, scales: [0.94, 0.88], pillGap: 0.018, pillH: 0.080, pillInk: 0.046, pillMinW: 0.34 })
- 시작할 때 한 번만 만드는 것: 줄마다 말줄임 처리한 문자열과 x 위치, 글자 크기별 '한' 의 a·d, 시각·날짜·「+9」의 글자 크기(잉크 높이로 구한다 — 글꼴 크기 100 으로 재서 비례), 카드 16장(색인 −5 … 10)의 문구·아이콘 색·착지 시각 표, 작은 캔버스, 결 무늬 패턴. render(t) 는 그 표와 t 만 쓴다. 프레임 사이에 쌓이는 상태는 없다.
- 프레임 비용 상한: 배경화면은 큰 캔버스에 한 번, 작은 캔버스에 한 번 그린다. 한 번에 들어가는 것은 그라디언트 사각형 1개, 원 1개, 능선 다각형 3개(꼭짓점 각 51개)다. 카드는 많아야 17장이고, 장마다 drawImage 1번·베일 사각형 1번·가장자리 stroke 1번을 쓴다. 결 무늬는 fillRect 1번이다. ctx.filter·shadowBlur·getImageData·CSS backdrop-filter 는 쓰지 않는다.
- 그리는 순서:
· 작은 캔버스 갱신 → 배경화면(하늘 → 해 → 능선 1·2·3) → 결 무늬 → 날짜·시각
· → 카드를 색인이 작은 것부터. 오래된 카드가 아래에 깔리고, 접히는 카드는 앞면 4번보다 먼저 그려져 뒤에 숨는다.
· → 알약 → 다음 회차 1번(떨어지는 중일 때)
화면 밖(위끝 > H 또는 아래끝 < 0) 카드는 건너뛴다. 작은 캔버스에는 배경화면만 그린다(날짜·시각·결 무늬는 넣지 않는다).
- 시작할 때 콘솔에 「합격 기준」 표를 한 번 출력하고 칸마다 PASS/FAIL 을 붙인다(그 기기의 글꼴로 잰 값). FAIL 이 하나라도 있으면 console.warn 으로 한 번 더 적는다(화면에는 아무것도 띄우지 않는다):
① 0초에 그려지는 카드 = 쌓인 6장 + 떨어지는 1장, 떨어지는 카드 아래끝 ≈ 0.107H
② 기본 문구 말줄임 0개 · 가장 긴 본문 잉크 폭 ÷ 0.685W ≤ 0.85(기대 약 0.64~0.75)
③ 낙하 끝 속도 2D / T_f 와 밀기 처음 속도 14·P 의 차 < 1 px/s
④ 0~9초를 1/240초 간격으로 훑어 위아래로 이웃한 쌓인 카드 사이 틈의 최솟값 ≥ 0.30g(기대 약 0.37g, 2.09초 근처). 틈은 J 를 뺀 y_n 으로 잰다. 3.30초부터는 색인 ≤ 3 의 접히는 카드를 빼고 앞면 4번은 넣는다.
⑤ 알약 숫자 = 9
⑥ t = 9 − 0.000001 과 t = 0 에서 화면에 보이는 카드(쌓인 여섯 장 + 떨어지는 1번)의 (문구, 위끝 y) 목록이 같고 y 차 < 0.5px. 능선 세 개의 위상 차 < 0.001 rad
⑦ 9초 직전 앞면(4번) 위끝 ≥ H(기대 1.055H)
⑧ 시각·날짜 대비 ≥ 4.5. 잉크 상자의 위끝 y 와 아래끝 y 에서 하늘 색을 CONFIG 정지점으로 계산해 잰다. 날짜는 흰색을 불투명도 0.85 로 하늘에 섞은 색으로 잰다. 기대값은 시각 약 12.2~14.0, 날짜 약 10.7~11.1 이다.
⑨ 카드 글자 대비 ≥ 4.5. 배경화면 색(하늘 정지점·해·능선) 중 상대 휘도가 가장 낮은 색에 흰 베일 0.72 를 섞은 카드 색을 바탕으로 잰다. 기대값은 제목 약 9.85, 본문 약 6.1, 머리줄 약 5.2 다.
⑩ ④와 같은 훑기에서 그려지는 모든 카드(낙하·접힘·묶음 포함)의 작은 캔버스 원본 사각형이 범위를 벗어난 횟수 = 0. 자르기 전 값으로 센다.
⑪ 바탕 채도 — C>0.08 면적 비율(기대 ≤ 25%, 기본 색에서 약 8.6%). 픽셀을 읽지 않는다. 화면을 108×192 격자로 나눈 칸 가운데마다 drawWallpaper 와 같은 규칙(하늘 정지점 보간 → 해 원 안이면 해 색 → 능선 1·2·3 아래면 그 색, t = 0)으로 그 자리 색을 구한다. 그 색을 sRGB → 선형 → OKLab 로 바꿔 C = √(a² + b²) 를 잰다. 함께 적을 값: 0.75H 위 하늘의 C 최댓값(기대 ≤ 0.08, 약 0.076) · 바탕 전체 C 최댓값(기대 ≤ 0.10, 약 0.095).
⑫ ④와 같은 훑기에서 그려지는 알약의 아래끝(배율 반영) 최댓값 < H(기대 약 0.983H, 5.687초 직전) · 5.69초부터 9초까지 알약을 그리는 프레임 0.
[하지 말 것]
각 줄의 「—」 뒤가 이유다.
- 0초 화면을 비우거나 카드가 한 장씩 처음부터 쌓이게 하지 않는다 — 영상의 첫 1초에 보는 사람이 넘길지 정한다. 0초부터 여섯 장이 화면을 채우고 한 장이 떨어지고 있어야 한다.
- 기기 테두리·노치·카메라 구멍·상태 표시줄(통신사·신호·배터리)·자물쇠 그림·손전등이나 카메라 단추·아래쪽 막대·잠금 해제 안내 글을 그리지 않는다 — 특정 휴대폰이나 운영체제 화면을 베낀 것으로 읽히고, 테두리만큼 화면이 작아져 카드 자리가 줄어든다. 9:16 화면 전체가 곧 잠금 화면이다.
- 실제 앱 이름·로고·아이콘 모양을 쓰거나 흉내 내지 않는다 — 상표다. 실존 앱 모양이 들어간 알림 화면은 진짜 제품 화면이나 진짜 알림으로 오인될 수 있다. 아이콘은 단색 원에 앱 이름 첫 글자뿐이다.
- 카드를 실제로 비치게 그리지 않는다(globalAlpha 나 반투명 채움으로 뒤 카드가 보이게 하지 않는다) — 접힐 때와 묶음에서 뒤 카드의 몸통이 겹쳐 비쳐 지저분해진다. 유리 느낌은 「작은 캔버스의 배경화면을 옮겨 담은 불투명 판 + 흰 베일」 하나로만 낸다. 그래서 카드끼리 겹친 곳에서는 늘 위 카드만 보인다.
- 흐림을 ctx.filter('blur …')·shadowBlur·CSS backdrop-filter·getImageData 로 만들지 않는다 — 어떤 브라우저에서는 ctx.filter 가 먹지 않아 유리가 그냥 흰 판이 된다. 프레임마다 수십 ms 가 들어 낙하가 끊기기도 한다. 흐림은 작은 캔버스를 키워 그리는 것뿐이다.
- 카드에 그림자·사선 광택·반짝 지나가는 빛줄기를 넣지 않는다 — 그림자는 접힐 때 겹겹이 쌓여 탁해진다. 광택 띠는 흔한 유리 템플릿처럼 보이고, 접힐 때 줄무늬로 쌓인다. 유리의 표지는 흐린 배경과 안쪽 2px 가장자리 빛뿐이다.
- 가장자리 빛을 빼거나 접힐 때 옅게 하지 않는다 — 겹친 유리판들이 같은 자리의 배경을 옮겨 담아서, 빛이 없으면 접히는 아홉 장이 경계 없는 한 장의 판으로 뭉개진다.
- 배경화면에 구름·별·새·나무·건물·사람·물결·빛 입자를 더하지 않는다 — 지어내기 쉬운 장식이다. 흐린 유리 너머에서 정체 모를 얼룩이 되고, 그림체가 생긴다. 하늘·해·능선 셋뿐이다.
- 해에 후광·광선·렌즈 플레어·빛 번짐을 넣지 않는다 — 발광 장식은 흔한 템플릿처럼 보이고, 3.55초에 「+9」보다 해가 눈을 끈다. 해는 가장자리가 선명한 단색 원이다. 유리 너머에서만 흐려지고, 그 차이가 유리를 보여 준다.
- 배경을 빠르게 움직이거나 착지·접힘·착에 반응시키지 않는다 — 주인공은 카드다. 배경의 움직임은 능선의 좌우 흔들림(가장 빠른 곳 초당 약 38px)뿐이고 하늘과 해는 멈춰 있다.
- 결 무늬를 프레임마다 새로 뿌리거나 움직이지 않는다 — 화면 전체가 지글거린다. 시작할 때 한 번 만든 고정 무늬다.
- 하늘을 검정·남색으로 어둡게 바꾸지 않는다 — 아침 7시 반의 하늘이 이 작품의 무대다. 맨 위만 자두빛으로 어둡다. 그래서 흰 시각이 읽히고, 아래로 갈수록 밝아져 해가 산다.
- 하늘·능선을 채도 높은 붉은 산호·진분홍·주황 면으로 칠하지 않는다(위 0.75H 는 C 0.08 이하, 아래 띠도 0.10 이하) — 바탕이 화면 절반을 넘게 드러나는 3.55~5.6초에 강한 색 면이 깔린다. 그러면 「+9」와 해보다 바탕이 먼저 눈을 끌고, 화면이 시뻘겋게 보인다. 강한 채도는 화면 15% 이하의 아이콘·알약에만 쓴다.
- 카드를 페이드로 나타내거나 등속으로 미끄러져 내려오게 하지 않는다 — 가속 낙하와 착지 충격이 있어야 「툭」 떨어지는 무게가 보인다.
- 아래 카드들을 시차(지연 시간)를 두고 하나씩 밀지 않는다 — 한 칸이 0.14H 라 0.01초만 늦어도 위 카드가 아래 카드를 덮는다. 늦게 따라오는 느낌은 틈 눌림 c 하나로만 낸다.
- 반대로 아래 카드 전부를 한 덩어리로만 밀지 않는다 — 틈이 눌렸다 펴지는 탄성이 이 작품의 손맛이다.
- min(j − n, 4) 의 상한 4 를 빼지 않는다 — 상한이 없으면 아래로 갈수록 끝없이 늦어져 탄성이 아니라 늘어진 고무줄처럼 보인다.
- 접히는 카드를 투명도로 사라지게 하거나, 순위(몇 번째 카드인가)로 불투명도·보임 여부를 정하지 않는다 — 순위는 정수라 바뀌는 프레임에 카드가 한 번에 꺼져 깜빡인다. 가려짐은 그리는 순서가 맡는다. 글자의 불투명도만 F 의 연속 함수 clamp((0.32 − F) / 0.16, 0, 1) 로 옅어지고, 베일만 F 의 연속 함수로 얇아진다.
- 움직이는 카드에 잔상·모션 블러를 여러 장 겹쳐 그리지 않는다 — 접힘 끝에서 카드는 프레임마다 수백 px 를 움직인다. 그래서 장 간격이 글자 획 두께의 1/3 을 넘으면 줄무늬가 된다. 빠른 순간은 그대로 선명하게 둔다.
- 「+9」를 0 부터 세어 올리거나 숫자를 깜빡이게 하지 않는다 — 숫자가 프레임마다 바뀌면 소음이 된다. 알약은 완성된 숫자를 단 채 한 번 튀어 오른다.
- 틈 눌림 c 와 묶음 반동 J 를 e^(−kτ)·cos 꼴로 바꾸지 않는다 — τ = 0 에서 0 이 아니게 되어 착지와 착의 순간에 카드가 한 프레임 튄다. (B 는 1 − e^(−14τ)·cos(18τ) 라서 τ = 0 에서 정확히 0 이다. 이 꼴은 그대로 둔다.)
- 화면 흔들기·회전·3D 기울기·카드 뒤집기·배경화면 시차 이동을 쓰지 않는다 — 한글 판독이 떨어지고, 충격은 J 의 23px 로 충분하다.
- 카드에 「답장」 같은 단추·사진 미리보기·진행 막대·읽지 않음 점을 더하지 않는다 — 지어내기 쉬운 장식이고, 바꿀 수 없는 글자가 되며, 카드 속 글자가 작아진다.
- 파티클·반짝임·발광·이모지·알림 빨간 점을 넣지 않는다 — 착의 충격은 접힘 속도와 J 와 알약의 튐, 그리고 드러나는 해가 맡는다. 장식이 끼면 흔한 템플릿처럼 보인다.
- 시각을 실제 현재 시각으로 움직이지 않는다 — 반복 이음매가 깨지고 녹화할 때마다 화면이 달라진다.
- 넘치는 문구의 글자 크기를 줄여 맞추지 않는다 — 카드마다 글자 크기가 달라져 목록이 들쭉날쭉해진다. 줄이는 것은 「…」 말줄임뿐이고, 그것도 경고와 함께다.
- 화면에 설명 문구·시간·카드 번호를 쓰지 않는다 — 알림 말고 다른 글자가 있으면 잠금 화면이 가짜처럼 보인다.
- 소리를 넣지 않는다 — 미리보기에서 자동 재생이 막히고, 박자는 화면만으로 보여야 한다.
- 프레임 사이에 위치·속도를 누적하지 않는다 — t = 9.00 화면이 t = 0.00 화면과 같아야 한다. 누적하면 프레임률에 따라 카드 자리가 어긋난다.
사용 방법
필요한 것: claude.ai 계정 — 무료 계정에서도 Claude Opus 5.5 를 고를 수 있습니다
- claude.ai 에서 새 대화를 엽니다.
- 모델 메뉴에서 Claude Opus 5.5 를 고르고, 같은 메뉴의 Effort(답변 깊이)를 High 로 둡니다.
- 복사한 프롬프트를 붙여 넣고 전송합니다. 결과로 나온 HTML 파일을 브라우저로 열면 재생됩니다.
- 권장 모델
- Claude Opus 5.5 · Effort High
- 화면비
- 9:16 (세로)
- 재생 길이
- 9초
- 결과물
- HTML 파일 하나 · 따로 설치할 것 없음
- 영상 파일
- 위 「MP4 저장 기능 포함」을 켜면 결과 화면에 녹화 단추가 생깁니다 1080 기준 · 12 Mbps · 브라우저에 따라 MP4 또는 WebM
추가 요청 예시
결과가 나온 뒤 같은 대화에서 이어서 요청하면 해당 부분만 수정됩니다.
- 알림 10개를 「다이어트 첫날」 이야기로 바꿔 줘. 앱은 운동·배달·체중계·모임방 네 개를 쓰고, 마지막 10번은 배달 앱의 「주문이 접수됐어요」로 끝내 줘.
- 배경화면을 초여름 저녁으로 바꿔 줘. 하늘은 위에서부터 #1F3B2E(맨 위) · #45705A(45% 지점) · #C9A37E(75% 지점) · #F2CB92(맨 아래), 해는 #FFF1C9, 산 능선은 뒤에서부터 #C08A5E · #7A5440 · #3B2A22, 「+9」 배지는 #1F3B2E 로. 바꾼 뒤에도 알림 글자가 잘 읽히는지, 배경이 프롬프트에 적힌 채도 상한보다 진해지지 않는지 확인해 줘.
- 처음 여섯 장이 떨어지는 간격을 0.70 · 0.55 · 0.40 · 0.30 · 0.25초로 점점 좁혀서 알림이 정신없이 쏟아지다 접히게 하고, 그 뒤 장면 시각은 줄어든 만큼 앞으로 당겨 줘.
SNS