감상

반딧불이 동기화

제각각 깜빡이던 반딧불이 420마리가 이웃의 빛을 따라 박자를 맞추다, 어느 순간 화면 전체가 한 번에 번쩍인다.

반딧불이 동기화 실행 화면
새 탭에서 보기

실제 코드로 재생되는 미리보기입니다

프롬프트 설정

Claude 가 읽는 제작 지시문입니다. 직접 읽지 않아도 됩니다.

여름밤 풀숲 위 반딧불이 수백 마리가 제각각 깜빡이다가 서로 박자를 맞춰 끝내 한꺼번에 번쩍이는 시뮬레이션을 HTML 파일 하나로 만들어 줘. 미리보기에서 바로 돌아가게. 길게 설명할 테니 숫자는 그대로 지켜 줘.

핵심 아이디어: 반딧불이 한 마리는 박자(위상)를 가진 시계 하나다. 시계 바늘이 한 바퀴를 돌아 0 을 지날 때마다 한 번 깜빡인다. 각자 타고난 빠르기가 조금씩 달라서 처음에는 화면 가득 제각각 깜빡인다. 그런데 이웃의 빛을 보면 그 박자 쪽으로 자기 바늘을 조금씩 당긴다(결합 진동자 — 구라모토 모형). 처음에는 가까운 이웃만 보므로 동네마다 작은 무리가 먼저 맞춰지고, 무리끼리는 박자가 어긋나 빛이 물결처럼 화면을 건너간다. 17초부터 무리 전체의 평균 박자까지 따라가기 시작하면 물결이 잦아들고, 약 21초에 화면 전체가 한 박자로 「번쩍」 한다. 그 빛에 풀숲 실루엣이 잠깐 드러난다. 맞춰지는 것은 타이머가 아니라 아래 식에서 저절로 생긴다 — 동기화 정도 r 이 실제로 0.9 를 넘는 순간이 이 작품의 시그니처다. 그 뒤 바람이 왼쪽에서 오른쪽으로 풀을 쓸고 지나가며 박자를 흩어 놓아, 제각각인 화면으로 이음매 없이 돌아간다. 재생은 장면 19초(모아짐)에서 시작한다 — 첫 화면부터 무리가 모여들고, 2.2초 안에 번쩍임이 30% → 57% → 91% 로 세 번 커진다. 한 바퀴를 돌면 제각각 → 동네 → 물결을 지나 다시 이 자리로 온다.

[바꿀 곳]
- 시드: 11 (바꾸면 반딧불이 배치와 박자가 달라진다 — 아래 검산값은 시드 11 기준)
- 색: 하늘 위 #03050A → 지평 #0A1317 · 먼 산 #070B0D → 앞쪽 논 #0C1417 · 풀 어두울 때 #020403 · 풀이 빛 받을 때 #22381C
- 반딧불이 빛: 중심 #FFFFE1 · 속 #ECFC96 · 바깥 #BEEC5A · 번쩍일 때 화면에 도는 빛 rgb(150,205,90)
- 깜빡임 기본 빠르기: 1초에 한 번(1.0Hz), 마리마다 ±6% 차이
- 한 바퀴 길이: 36초 (끝나면 처음으로 이어서 반복)
- 재생 시작 장면 시각 startAt: 19.0초 (0 으로 두면 제각각부터 시작한다)
- 화면비: 16:9 (기준 캔버스 1920×1080)

[크기]
W = 화면 폭 1920, H = 화면 높이 1080. 크기는 전부 이 둘의 비율로 쓴다.
- 반딧불이 420마리가 가로 28 × 세로 15 칸에 한 마리씩 흩어져 화면의 x 0.03W~0.97W, y 0.07H~0.95H(폭 94% · 높이 88%)를 고르게 채운다. 칸 하나는 약 64×63px.
- 빛 번짐 반지름 R_i = 0.040H(약 43px) × s_i × (0.45 + 0.95·b_i). s_i(거리감)는 0.6~1.4, b_i 는 아래 깜빡임 밝기 0~1. 꺼져 있을 때는 반지름 약 19px(s = 1)의 희미한 점, 번쩍일 때는 약 60px 로 커진다. 빛 한 장은 반지름의 60% 지점까지 눈에 보이므로 번쩍일 때 보이는 반지름은 약 36px — 칸 간격 64px 의 절반을 넘어 이웃 빛과 맞붙는다. 모두가 함께 번쩍이면 화면이 한 장의 빛으로 차오른다(시드 11, 21.2초: 화면 평균 밝기가 제각각일 때의 약 4배, 밝기 60/255 를 넘는 화소 54%, 순백 화소 0.1% 안팎). 계수를 0.55 로 낮추면 보이는 반지름이 약 26px 로 줄어 빛끼리 닿지 않고, 번쩍임이 「한 장의 빛」이 아니라 「녹회색 안개 위 점밭」으로 읽힌다.
- 이웃 반지름: 집 자리(아래) 사이 거리 0.13H(140.4px) 안. 이웃 수는 마리마다 4~18, 평균 12.9.
- 떠다님: 집 자리를 중심으로 가로 0.012W(23px) · 세로 0.016H(17px) 진폭으로 천천히 흔들린다.
- 먼 산 능선은 0.52H~0.60H 사이의 낮은 선 하나, 앞쪽 풀은 화면 아래에서 0.06H~0.20H 높이까지만. 풀은 반딧불이를 가리지 않는다(반딧불이를 풀 위에 그린다).

[반딧불이 만들기 — 이 순서로만 난수를 부른다]
- 난수: mulberry32. 정확히 이 코드:
  function mulberry32(a){return function(){a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296}}
  반딧불이 R = mulberry32(시드) · 풀 G = mulberry32(시드 + 1) · 누를 때 C_k = mulberry32(시드·7919 + k)(k = 몇 번째 누름인지, 0부터). 줄기를 섞지 않는다.
- 반딧불이 i = 행·28 + 열(행 0~14, 열 0~27, 행 우선)마다 R 을 정확히 10번, 이 순서로 부른다:
  ① jx = R() − 0.5 ② jy = R() − 0.5 → 집 자리 hx = 0.03W + (열 + 0.5 + 0.9·jx)·(0.94W/28), hy = 0.07H + (행 + 0.5 + 0.9·jy)·(0.88H/15)
  ③ 처음 위상 θ0 = 2π·R()
  ④ u1 = R() ⑤ u2 = R() → g = √(−2·ln(1 − u1))·cos(2π·u2), g 를 −2.5~2.5 로 자른 뒤 타고난 빠르기 ω = 2π·1.0·(1 + 0.06·g) (라디안/초). 그래서 0.85~1.15Hz, 평균 약 1.0Hz.
  ⑥ s = 0.6 + 0.8·R() ⑦ kx = 2 + floor(4·R()) ⑧ ky = 2 + floor(4·R()) ⑨ px = 2π·R() ⑩ py = 2π·R()
- 이웃 목록은 시작할 때 집 자리로 한 번만 만든다(자기 자신 제외). 떠다니는 위치로 매번 다시 만들지 않는다.
- 화면 위치(닫힌 식, τ = 아래 장면 시각): x = hx + 0.012W·sin(2π·kx·τ/36 + px), y = hy + 0.016H·sin(2π·ky·τ/36 + py). kx·ky 가 정수라 36초 뒤 정확히 제자리다.

[박자 — 고정 시간 간격 dt = 1/120초, 이 식 그대로]
- 한 스텝은 모든 반딧불이를 옛 값으로 계산한 뒤 한꺼번에 갱신한다(동기 갱신). 갱신 뒤 θ 는 [0, 2π) 로 접는다. τ = 스텝 번호 × dt(장면 시각, 0~36).
- 전체 평균: Z = (1/420)·Σ e^(iθ_j) → r = |Z|(동기화 정도 0~1), ψ = Z 의 각도. 실제로는 C = Σcosθ_j/420, S = Σsinθ_j/420, r = √(C² + S²), ψ = atan2(S, C).
- 이웃 끌림: L_i = (1/n_i)·Σ_(j∈이웃) sin(θ_j − θ_i), n_i = 이웃 수. 계산은 스텝마다 sinθ·cosθ 를 420개씩 한 번 구해 두고 L_i = (cosθ_i·Σ sinθ_j − sinθ_i·Σ cosθ_j)/n_i 로 한다(같은 값이고, 쌍마다 sin 을 부르지 않아 빠르다).
- 결합 세기: KL(τ) = 3.0·ss(0, 6, τ) (가까운 이웃), KG(τ) = 2.0·ss(17, 22, τ) (무리 전체). ss(a, b, x) = 먼저 x 를 (x − a)/(b − a) 로 바꿔 0~1 로 자른 뒤 x²·(3 − 2x).
- 바람: 반딧불이 i 는 바람이 집 자리를 지나는 시각 τw_i = 29.0 + 2.5·hx/W 를 갖는다(왼쪽 끝 29.0초 → 오른쪽 끝 31.5초). off_i = ss(0, 0.6, τ − τw_i).
- 되돌림: 목표 위상 θ*_i(τ) = θ0_i + ω_i·(τ − 36), d_i = θ*_i − θ_i 를 (−π, π] 로 접은 값, P_i = 6.0·off_i·(1 − ss(33, 34, τ)).
- 누름 회복: c_i = 1, 단 최근에 눌려 흩어진 반딧불이는 c_i = ss(0.8, 2.4, τ − 눌린 시각).
- 갱신: θ_i ← θ_i + dt·[ ω_i + c_i·(1 − off_i)·( KL·L_i + KG·r·sin(ψ − θ_i) ) + P_i·d_i ]
- 왜 이렇게 되는가: 바람이 지나가면 결합이 꺼지고 위상이 「36초에 θ0 에 도착하는 제각각의 박자」로 끌려간다. 34초에 끌림을 끄면 그 뒤는 자유롭게 돌아 36초에 처음 위상과 0.0001 라디안 안으로 같아진다. 그래서 한 바퀴 끝에서 θ 를 θ0 으로 되돌려도(스텝 번호 0, 눌린 기록 지움) 화면이 튀지 않는다.

[깜빡임 — 위상에서 바로 나오는 연속 밝기]
- x = θ/(2π) (0~1), u = x/0.07, b = u²·e^(2(1 − u)). 바늘이 0 을 지난 뒤 0.07 바퀴(약 0.07초)에 b = 1 로 가장 밝고, b > 0.5 인 시간은 한 바퀴의 11.9%(약 0.12초), b > 0.1 은 x 0.009~0.236. x 가 1 에 가까울 때 b 는 사실상 0 이라 바퀴가 넘어갈 때 끊기지 않는다.
- 화면 밝기 B = 420마리 b 의 평균. 제각각일 때 B ≈ 0.13 으로 거의 일정하고, 다 맞춰지면 깜빡일 때마다 0 → 0.96 → 0 으로 크게 뛴다.

[그리기 — 매 프레임 이 순서]
- ① 하늘: 위 #03050A → 0.60H #0A1317 세로 그라디언트.
- ② 먼 산·논: 능선 y = 0.56H + 0.025H·sin(2π·1.3·x/W + 0.7) + 0.012H·sin(2π·3.1·x/W + 2.1) 아래를 세로 그라디언트로 채운다 — 0.52H #070B0D → 화면 아래 끝 #0C1417(앞쪽 논이 하늘빛을 조금 받아 산보다 밝다). 논에는 무늬를 넣지 않는다. 앞쪽 논을 밝히는 이유: 풀 #020403 이 그 앞에서 검은 실루엣으로 읽혀야 바람에 눕는 모습이 보인다(#070B0D 그대로면 풀과 땅의 밝기 차가 너무 작아 폰에서 풀이 사라진다).
- ③ 앞쪽 풀 150포기: 풀 j 마다 G 를 이 순서로 부른다 — 뿌리 x = W·(j + G())/150, 높이 h = 0.06H + 0.14H·G(), 뿌리 폭 0.0035W·(0.7 + 0.6·G()), 기울기 lean = (G() − 0.5)·0.04H, 흔들림 위상 φ = 2π·G(), 흔들림 횟수 k = 9 + floor(6·G()). 끝 가로 이동 = lean + 0.004H·sin(2π·k·τ/36 + φ) + 0.035H·e^(−((τ − (29.0 + 2.5·뿌리x/W))/0.45)²). 마지막 항이 바람이다 — 반딧불이를 흩어 놓는 바로 그 시각에 풀이 왼쪽부터 차례로 기운다. 모양은 뿌리 양끝에서 끝점까지 2차 베지어 두 줄(조절점 = 뿌리 x + 끝 이동×0.3, 높이 0.55h)로 닫은 가는 잎. 색 = #020403 과 #22381C 를 min(1, 0.7·B) 로 섞은 것 — 제각각일 때는 거의 검은 실루엣, 번쩍이면 풀숲이 초록으로 드러난다.
- ④ 반딧불이: 시작할 때 128×128 화면 밖 캔버스에 빛 하나를 한 번만 그린다 — 원형 그라디언트 0 rgba(255,255,225,1) · 0.10 rgba(236,252,150,0.95) · 0.30 rgba(190,236,90,0.35) · 0.60 rgba(140,205,70,0.10) · 1.0 rgba(120,190,60,0). globalCompositeOperation = 'lighter' 로 마리마다 drawImage 한 번: 크기 지름 2·R_i, globalAlpha = (0.10 + 0.90·b_i)·(0.55 + 0.45·(s_i − 0.6)/0.8). 더하기 섞기라 그리는 순서는 상관없다.
- ⑤ 번쩍임 빛: 같은 'lighter' 로 화면 전체에 rgb(150,205,90) 을 globalAlpha = 0.16·B 로 한 번 덮는다. 제각각일 때 0.02, 다 맞춰진 번쩍임에서 약 0.15.
- 반딧불이 몸통·날개는 그리지 않는다. 빛이 곧 반딧불이다.

[장면] 장면 시각 τ(초). 시드 11 에서 아래 식이 실제로 내는 값이다. 화면 재생 시각 t 와의 관계: τ = (t + startAt) mod 36, 기본 startAt 19.0 이라 화면 t = 0 이 τ = 19.0 이다(괄호 안 「화면」 = t). 녹화도 t = 0 부터 한 바퀴다.
- 첫 화면(τ 19.0, 화면 0초): 무리들이 이미 모여들어 17%가 번쩍이는 중이고 r 0.52. 화면 0.23초에 30%, 1.2초에 57%, 2.2초에 91% — 번쩍임이 세 번 커지는 점층이 첫 화면이다. 빈 어둠이나 평평한 반짝임으로 시작하지 않는다.
- 0~4초(화면 17~21초) 제각각: 420마리의 희미한 점이 화면 전체를 떠다니고, 어느 순간이든 약 50마리(12%)가 번쩍이는 중이다. r 0.04, 이웃끼리 맞춘 정도 r_loc(아래 정의) 0.23.
- 4~8초(화면 21~25초) 동네가 맞춰짐: 가까운 이웃 결합이 커지며 서너 마리, 열 마리씩 함께 깜빡이는 무리가 화면 곳곳에서 생긴다. r_loc 0.54 → 0.87. 전체 r 은 0.08 → 0.16 으로 거의 그대로.
- 8~17초(화면 25~34초) 물결: 동네마다 맞춰졌지만 무리끼리는 어긋나 빛이 이웃 동네로 번지듯 화면을 건너간다. r_loc 0.87~0.94, r 은 0.16 → 0.37 로 천천히. 한 순간 번쩍이는 비율은 많아야 24% — 아직 화면 전체가 한꺼번에 켜지는 일은 없다.
- 17~21초(화면 34~36초 → 0~2초) 모아짐: 무리 전체 결합이 켜지며 물결이 느려지고 납작해진다. 20.2초에 처음으로 57%가 함께 켜지고, 20.80초에 r 이 0.9 를 넘는다.
- 21.2초(화면 2.2초) 시그니처: 화면 폭 94%·높이 88%에 흩어진 420마리 중 91%가 같은 0.12초 안에 함께 켜진다. 약 60px 로 커진 빛 번짐이 맞붙어 화면이 한 장의 빛으로 차오르고(B 0.84), 그 빛에 검던 풀숲이 초록 실루엣으로 드러난다.
- 22.2~29.2초(화면 3.2~10.2초) 한 박자: 매초 x.2초마다 99~100%가 함께 번쩍인다(B 0.95~0.96, 22.2·23.2·…·29.2초 8번). r 0.996. 「탁, 탁」 맥박이다 — 매초 한 번 짧게(약 0.12초) 함께 번쩍이고, 그 사이 0.85초는 모두가 꺼져 제각각일 때보다도 어둡다. 그 어둠이 다음 번쩍임을 세운다.
- 29.0~31.5초(화면 10~12.5초) 바람: 바람은 무엇보다 빛으로 보인다 — 왼쪽부터 박자가 흩어져 30.2초 번쩍임은 아직 바람이 닿지 않은 오른쪽만(68%), 31.2초는 오른쪽 끝 무리만 켜진다. 풀은 밝아진 앞쪽 논 앞에서 왼쪽부터 차례로 기울고, 번쩍이는 순간에는 초록으로 비친다. 32초부터 r 0.01~0.04.
- 31.5~36초(화면 12.5~17초) 다시 제각각. 장면 36초 = 장면 0초 프레임(바람 되돌림 덕에 이음매가 없다). 화면 36초 = 화면 0초(장면 19.0초).
- 조작: 화면을 누르면(클릭·탭) 누른 자리에서 0.22H(238px) 안의 반딧불이(지금 화면에 떠 있는 위치 기준 — 23.5초에 가운데를 누르면 48마리)가 C_k 로 위상을 하나씩 θ += π·(2·C_k() − 1) 만큼(반딧불이 번호 순) 흩는다. 흩어진 반딧불이는 c_i 로 0.8초 동안 이웃을 보지 않다가 2.4초에 완전히 다시 본다. 다 맞춰진 구간에서 누르면 그 자리만 두 박자 동안 엇박으로 깜빡이다가, 약 3초 뒤 다시 전체 박자에 합류한다(시드 11, 23.5초(화면 4.5초)에 가운데를 누르면 그 48마리끼리 맞춘 정도 0.19 → 26.0초 0.98 → 26.5초 0.996. 24.2·25.2초 번쩍임에서는 그 자리에 동그란 어둠 구멍이 뚫린다). 결합이 꺼진 구간(장면 0~1초, 31.5~36초)에서는 원래 제각각이라 흩어도 다시 맞춰지지 않는다. 한 바퀴가 끝나면 누른 흔적도 지워진다.

[구현]
- 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)은 스크립트 맨 끝에서 한 번만 호출한다. 정의되기 전에 쓰면 첫 화면에서 멈춘다.

이 작품에만 해당하는 구현:
- 시작 상태: 장면 스텝 번호 S0 = round(startAt / dt) = 2280 에서 시작한다. θ 는 아래 「스스로 대조」 미리 돌리기가 스텝 2280 을 지날 때 복사해 둔 값을 쓴다(같은 step() 이라 θ0 에서 2280스텝 진행한 것과 똑같다). startAt = 0 이면 θ0 그대로.
- 박자 진행: 위상 상태(Float64Array θ 420개)는 step() 한 함수로만 진행한다. 매 프레임 「재생 시작부터 지나야 할 스텝 수 = floor(경과 시간 / dt)」 와 「재생 시작부터 이미 한 스텝 수」의 차이만큼 step() 을 부른다. 그래서 30fps 기기든 144fps 기기든 1초에 정확히 120스텝이고 같은 시각에 같은 화면이다. 스텝 번호가 4320(= 36초)에 닿으면 θ = θ0 복사, 스텝 번호 0, 눌린 기록을 지운다.
- 탭이 가려졌다 돌아오는 등 한 프레임에 30스텝(0.25초)을 넘게 밀리면, 최후에만 30스텝까지만 하고 나머지는 버리며 시작 기준 시각을 그만큼 뒤로 옮긴다(장면이 건너뛰지 않고 잠깐 멈춘 것처럼 이어진다). 이때 console.warn 으로 버린 스텝 수를 적는다.
- render(t) 는 θ 와 τ 만 읽는다: 위치·풀·하늘은 τ 의 닫힌 식, 밝기는 θ 에서 바로. 프레임 사이 보간은 하지 않는다(dt 1/120 이 프레임보다 짧다).
- 누름: pointerdown 좌표를 기준 캔버스 좌표로 바꿔 다음 step() 직전에 적용한다. 거리는 그 순간 장면 시각 τ 의 화면 위치(떠다니는 위치)로 잰다 — 보이는 자리에서 흩어져야 한다. 눌린 시각은 장면 시각 τ 로 저장한다.
- 이웃끼리 맞춘 정도 r_loc = 420마리 평균 |(e^(iθ_i) + Σ_(j∈이웃) e^(iθ_j)) / (n_i + 1)|.
- 스스로 대조: 시작할 때 화면을 그리기 전에, 실제와 같은 step() 으로 따로 복사한 상태를 누름 없이 4320스텝(한 바퀴) 미리 돌려 재고 console.table 로 찍는다. 이 미리 돌리기는 이웃 합 약 4,700만 번의 덧셈이라 0.1~0.3초다(r_loc 은 표의 시각에서만 잰다). 기준을 벗어나면 console.warn 으로 어느 줄인지 적는다. (괄호 안 = 시드 11 에서 위 mulberry32 와 식 그대로일 때 나오는 값)
  · 반딧불이 420 · 이웃 수 최소 4 / 평균 12.9 / 최대 18 · 빠르기 0.85~1.15Hz, 평균 0.998Hz (다르면 난수 순서나 이웃 반지름이 틀린 것)
  · τ = 0: r ≤ 0.15 (0.036), 번쩍이는 비율(b > 0.5) 0.08~0.20 (0.129)
  · τ = 8: r_loc ≥ 0.80 (0.868) 이고 r ≤ 0.50 (0.163) — 동네만 맞고 전체는 안 맞은 상태
  · τ = 16: r ≤ 0.60 (0.341)
  · 4~17초 사이 번쩍이는 비율의 최댓값 ≤ 0.40 (0.243) — 넘으면 전체 결합이 너무 일찍 켜진 것
  · r 이 처음 0.9 이상이 되는 τ: 19.5~22.5 (20.80) — 이 작품의 시그니처
  · 22~29.5초 번쩍임 꼭대기 8번(22.2~29.2초)마다 번쩍이는 비율 ≥ 0.95 (0.99~1.00), r(26) ≥ 0.98 (0.996)
  · τ = 33: r ≤ 0.15 (0.010)
  · 36초 끝 θ 와 θ0 의 최대 차이 ≤ 0.01 라디안 (0.00004) — 넘으면 바람 되돌림 식이 틀린 것이고 반복 이음매가 튄다
  · 누름(미리 돌리기에서 23.5초 상태를 따로 복사해, 그 복사본에만 가운데 (0.5W, 0.5H) 누름을 C_0 으로 적용하고 26.5초까지 진행 — 본 표와 실제 누름 횟수 k 는 건드리지 않는다): 흩어진 수 40~56 (48), 26.5초 그 무리끼리 맞춘 정도 ≥ 0.95 (0.996)
  · 시작 상태 = 스텝 2280 복사본, 첫 화면의 번쩍이는 비율 0.10~0.25 (0.167)
- 화면에는 글자를 하나도 띄우지 않는다. 대조 결과는 콘솔에만.

[하지 말 것]
- 프레임마다 한 번 step() 하거나 dt 를 프레임 간격으로 쓰지 않는다 — 60fps 기기와 30fps 기기에서 동기화 시각이 두 배로 갈리고, 큰 dt 에서는 결합 항이 튀어 박자가 맞지 않는다. 스텝 수는 경과 시간만이 정한다.
- 21초 무렵 모든 위상을 같은 값으로 맞추거나, 공통 시계 쪽으로 보간하거나, 시각표대로 깜빡이게 해서 동기화를 흉내 내지 않는다 — 그러면 동네 무리와 물결이 생기지 않고, 누른 자리가 다시 맞춰지는 과정도 없다. 맞춰짐은 위 갱신 식에서만 나온다.
- 무리 전체 결합(KG)을 0초부터 켜지 않는다 — 화면 전체가 고르게 한꺼번에 맞춰져 「동네가 먼저」라는 이야기가 사라진다. 반대로 KG 를 빼면 시드 11 에서 r 이 29초까지 많아야 0.63 에 머물러 끝내 한꺼번에 번쩍이지 않는다.
- 깜빡임을 켬/끔 두 값이나 정수로 뛰는 값으로 만들지 않는다 — 한 프레임에 0 에서 1 로 튀는 점 420개는 반딧불이가 아니라 깨진 화면처럼 지글거린다. 밝기는 위상에서 나오는 연속 값 b 하나다.
- 깜빡임에 Math.random 이나 프레임마다 바뀌는 노이즈 떨림을 섞지 않는다 — 같은 시각이 매번 다르게 보이고, 다 맞춰졌을 때의 한 박자가 흐려진다.
- 반딧불이에 잔상·꼬리를 여러 장 겹쳐 그리지 않는다 — 장 간격이 점 크기의 1/3 을 넘으면 줄무늬로 끊겨 보이고, 떠다니는 빛이 벌레가 아니라 혜성처럼 읽힌다.
- 빛을 마리마다 shadowBlur 나 새 그라디언트로 그리지 않는다 — 420마리에서 프레임이 떨어진다. 미리 그린 빛 한 장을 drawImage 로 찍는다.
- 떠다님을 프레임마다 무작위 걸음으로 움직이지 않는다 — 다시 재생할 때 다른 화면이 되고 36초 뒤 제자리로 돌아오지 않는다. 정수 kx·ky 의 닫힌 sin 식만 쓴다.
- 이웃을 떠다니는 위치로 매 스텝 다시 찾지 않는다 — 이웃 수가 들쭉날쭉 바뀌며 L_i 가 튀어 맞춰진 무리가 갑자기 깨진다. 이웃은 집 자리로 한 번.
- startAt 을 「장면 시각에 19를 더해 그리기만」 하는 식으로 흉내 내지 않는다(θ0 에서 바로 시작하고 시계만 19초로 표시) — 첫 화면이 모아짐이 아니라 제각각이 되고, 21.2초 번쩍임 대신 엉뚱한 때 아무 일도 안 일어난다. 위상을 실제로 2280스텝 진행해 둔다.
- 한 바퀴 끝에서 맞춰진 상태를 갑자기 처음 상태로 바꾸지 않는다 — 한 박자로 번쩍이던 화면이 한 프레임에 제각각으로 튀어 이음매가 보인다. 바람 되돌림이 36초에 θ0 으로 데려다 놓는다.
- 번쩍임 빛(⑤)을 0.16·B 보다 세게 하거나 화면을 흰빛으로 채우지 않는다 — 덮기는 화면 전체에 고른 녹색 막이라 세게 하면 대비가 깎여 뿌옇고, 더 세면 하얗게 날아가 반딧불이 하나하나가 안 보인다. 「한 장의 빛」은 덮기가 아니라 빛 번짐 반지름(0.95)이 만든다.
- 빛 번짐 계수를 0.95 에서 0.55 쪽으로 낮추지 않는다 — 번쩍일 때 보이는 반지름이 칸 간격의 절반에 못 미쳐 빛끼리 닿지 않고, 시그니처가 점밭으로 읽힌다.
- 달·별·은하수·렌즈 플레어·십자 반짝임·보케 원을 넣지 않는다 — 달빛은 밤을 밝혀 번쩍임의 대비를 죽이고, 별은 꺼진 반딧불이와 구별되지 않아 「몇 마리가 켜졌나」가 안 읽힌다.
- 논물에 비친 반영을 그리지 않는다 — 빛이 두 벌이 되어 위아래가 따로 깜빡이는 것처럼 보이고, 한 박자의 번쩍임이 흐려진다.
- 반딧불이를 몸통·날개·더듬이가 있는 벌레 그림으로 그리지 않는다 — 이 크기에서는 빛이 주인공이고, 그린 벌레는 클립아트처럼 보인다.
- 풀을 0.20H 보다 높게 키우거나 꽃·나무·초가집·정자 같은 소품을 더하지 않는다 — 반딧불이를 가리고 시선이 박자에서 풍경으로 옮겨 간다.
- 화면에 r 값·그래프·제목·안내 문구를 띄우지 않는다 — 보는 사람은 숫자가 아니라 빛으로 동기화를 알아채야 한다. 대조는 콘솔에만.
- 소리를 넣지 않는다 — 미리보기 자동 재생에서 막히고, 녹화에도 담기지 않는다.
- WebGL·외부 라이브러리를 쓰지 않는다 — Canvas 2D 의 drawImage 420번이면 충분하고, 외부 의존은 미리보기에서 막힌다.

사용 방법

필요한 것: claude.ai 계정 — 무료 계정에서도 Claude Opus 5.5 를 고를 수 있습니다

  1. claude.ai 에서 새 대화를 엽니다.
  2. 모델 메뉴에서 Claude Opus 5.5 를 고르고, 같은 메뉴의 Effort(답변 깊이)를 High 로 둡니다.
  3. 복사한 프롬프트를 붙여 넣고 전송합니다. 결과로 나온 HTML 파일을 브라우저로 열면 재생됩니다.
권장 모델
Claude Opus 5.5 · Effort High
화면비
16:9 (가로)
재생 길이
36초
결과물
HTML 파일 하나 · 따로 설치할 것 없음
영상 파일
해당 없음

추가 요청 예시

결과가 나온 뒤 같은 대화에서 이어서 요청하면 해당 부분만 수정됩니다.

  • 반딧불이 빛을 연두 대신 따뜻한 호박색(중심 #FFF1C8 · 속 #FFC266 · 바깥 #F08A24)으로 바꾸고, 하늘은 조금 더 푸른 밤(#06101C)으로 해 줘.
  • 다 맞춰진 뒤 함께 번쩍이는 시간을 6초 더 길게 해 줘. 무리가 다시 흩어지기 시작하는 시각과 전체 길이를 6초씩 늦추고(전체 42초), 프롬프트 안에서 그 시각에 맞춰 적어 둔 숫자들도 같이 고쳐 줘.
  • 분위기를 더 고요하게 — 깜빡임 기본 빠르기를 1초에 한 번에서 1.6초에 한 번으로 늦추고, 번쩍일 때 화면 전체에 도는 빛의 세기를 절반으로 줄여 줘.

감상

같은 카테고리의 다른 프롬프트

감상 전체 보기

모든 모션 보기 블로그 글 목록 RSS 로 새 글 받기