얼음 녹는 물잔
유리잔 속 얼음이 녹으며 테이블보 위에 빛무늬가 일렁인다.
프롬프트를 복사해 claude.ai 에 붙여 넣으면 바로 실행됩니다 · Opus 5.5 · Effort High 기준
- 권장 모델
- Claude Opus 5.5 · Effort High
- 화면비
- 16:9 (가로)
- 조작
- 시간 슬라이더 · 잔을 누르면 살짝 흔들림 · 끌어서 돌려 보기
- 결과물
- HTML 파일 하나 · three.js 를 인터넷에서 불러옵니다
프롬프트
Claude 가 읽는 제작 지시문입니다. 맨 위 [바꿀 곳]의 값을 바꿔 붙여 넣어도 됩니다.
창가 식탁 위 물잔 속 얼음이 녹는 동안, 잔을 지나온 햇빛이 리넨 테이블보 위에 일렁이는 빛무늬(커스틱)를 드리우는 여름 오후 장면을 HTML 파일 하나로 만들어 줘.
핵심 아이디어: 진짜 굴절은 계산하지 않는다. 잔 그림자 자리에 「흐르는 빛 그물」 셰이더를 얹은 판 하나가 이 작품의 전부다. 얼음 세 조각이 녹을수록 빛 그물은 잔잔해지고 초점 띠는 밝아진다. 해는 오후로 기울며 그림자와 빛무늬가 길어진다. 시그니처 순간: 시작 1초 안에, (가로 화면 기준) 화면 가운데 조금 왼쪽의 잔에서 오른쪽으로 길이 약 0.5S 의 타원 빛무늬가 테이블보 위에서 일렁인다. 밝은 선 그물이 천천히 흐르고 가장자리에는 얇은 무지개 띠가 생긴다. 잔을 탭하면 잔이 살짝 흔들리고, 빛무늬가 1초 동안 크게 출렁이다가 가라앉는다. 얼음은 제목의 주인공이다. 첫 화면에서 모서리가 선 얼음 세 조각이 수면 위로 또렷이 솟아 보여야 한다. 슬라이더를 끝까지 밀면 그 얼음이 작고 둥근 조약돌이 된다. 이 변화가 한눈에 읽혀야 한다. 장면 전체는 하얗게 날리지 않는다. 바랜 귀리색 천이 햇빛을 받아야 유리·얼음의 흰 테와 빛 그물이 그 위에서 도드라진다.
[바꿀 곳]
- meltStart = 0.12 — 시작할 때 녹은 정도(0 = 막 넣은 얼음, 1 = 거의 다 녹음)
- meltDuration = 90 — 손대지 않을 때 0에서 1까지 녹는 데 걸리는 초
- iceCount = 3 — 얼음 조각 수
- sunElevStart = 38, sunElevEnd = 30 — 해 고도(도). 녹는 정도 m 에 따라 선형으로 바뀐다
- causticStrength = 0.9 — 빛무늬 밝기 배율
- causticSpeed = 0.35 — 빛 그물이 흐르는 속도
- wobbleAmp = 0.05 — 탭했을 때 잔이 기우는 최대 각(라디안)
- clothColor = #d6c9b0(바랜 귀리색 리넨), stripeColor = #8fa3a8, bgColor = #bdb19b(안개·배경, 그늘진 천 색)
- iceBody = #9fbcc6, glassEdge = #5f6b6c
- sunColorStart = #fff0d2, sunColorEnd = #ffd6a0
[크기]
월드 단위는 cm 다. S = 화면 짧은 변. 잔: 바깥 반지름 4, 높이 12, 바닥 두께 1, 벽 두께 0.25. 물 높이는 바닥에서 7.5로 고정한다(뜬 얼음은 녹아도 수위가 그대로라는 실제 원리를 따른다). 얼음 한 조각의 한 변은 2.4 × (1 − 0.75m) 이다. m = 0 이면 2.4, m = 1 이면 0.6 이다. 겉보기로는 잔 폭의 약 0.3배에서 0.08배로 줄어든다.
- 첫 화면에서 잔의 겉보기 높이는 0.33S~0.5S 다(목표 약 0.4S).
- 빛무늬 타원의 겉보기 긴 지름은 0.4S 이상이다(시작 때 약 0.5S, m = 1 이면 약 0.7S).
- 빛의 수평 방향 d = (0.92, 0, 0.38) 이다(해는 왼쪽 약간 뒤에 있다). 가로 화면에서 빛무늬는 잔 오른쪽으로 화면을 가로질러 뻗는다.
- 테이블보는 300 × 300 이다. 화면 위쪽 끝까지 천이 이어지다가 안개 속으로 흐려진다. 벽은 두지 않는다.
- 가로 화면의 카메라 거리는 40 이다. 세로 화면의 거리와 시점은 아래 카메라 절에 따로 정한다.
[장면]
- 테이블보: 300 × 300 판(y = 0). CanvasTexture 1024 × 1024 로 리넨을 그린다. 바탕은 clothColor, 가로세로 실결은 밝기 ±5% 잡음으로 넣는다. 24cm마다 stripeColor 의 가는 줄 두 개(폭 0.4cm, 간격 1.2cm)를 넣는다. 반복은 월드 24cm에 한 번, anisotropy 는 renderer 최댓값. MeshStandardMaterial roughness 0.9, metalness 0. 햇빛 받은 천의 화면 색은 대략 #ddd0b8 이어야 한다. 천이 거의 흰색(#f0ece4 이상)으로 보이면 빛이 너무 센 것이다.
- 창 그림자(그림 판): 실제 그림자 맵은 쓰지 않는다. 테이블 위 y = 0.005 에 240 × 240 판을 깔고, 512 × 512 DataTexture 로 알파를 직접 계산해 창 모양 그늘을 그린다. 판 중심은 잔에서 d 쪽으로 6 떨어진 곳이고, 판은 d 방향에 맞춰 돈다. 판 좌표 (u, v)(cm, 판 중심 기준)에서 계산은 이렇다.
- lit = box(|u| < 55, |v| < 40) 이고, 테두리 12cm 에 걸쳐 smoothstep 으로 흐린다.
- bars = 창살 두 줄이다. u = −26 의 세로 띠와 v = −20 의 가로 띠이고, 폭은 각 3, 양옆 2.5cm 에 걸쳐 흐린다.
- alpha = 0.34 × max(1 − lit, bars × lit)
- 색은 #4a4032, transparent, depthWrite false 다.
- 결과로 잔과 빛무늬를 감싼 햇빛 사각형이 생기고, 바깥은 부드럽게 어두워진다. 잔 뒤쪽으로 흐린 창살 그림자 두 줄이 지나는데, 잔과 빛무늬 위는 지나지 않는다. 딱딱한 경계선은 없다.
- 잔: 원점에 선다. LatheGeometry(단면: 바깥벽, 입술 둥글림, 안벽, 두꺼운 바닥, 64분할)로 만든다. 잔은 두 겹으로 그린다.
- 몸: MeshPhysicalMaterial(color #ffffff, roughness 0.04, metalness 0, clearcoat 1, clearcoatRoughness 0.03, transparent, opacity 0.18, side DoubleSide, depthWrite false, envMapIntensity 2.2). 잔 표면에 창이 또렷이 비친다.
- 윤곽 막: 같은 형상에 ShaderMaterial 을 씌운다. f = pow(1 − |dot(N, V)|, 3) 이고, 색은 glassEdge, alpha = 0.7f 다. 흰 천 위의 실제 유리처럼 잔의 양 옆선과 바닥 둘레가 회색 선으로 읽힌다.
- 입술: TorusGeometry(반지름 3.88, 관 0.12), 흰색 opacity 0.85.
- 바닥: 두께 1 부분은 opacity 0.35 로 몸보다 진하게 한다.
- 물: 반지름 3.72, 높이 7.5 의 원기둥. MeshPhysicalMaterial(color #8fb8bc, opacity 0.32, roughness 0.05, transparent, depthWrite false). 물 아래 부분은 잔 윗부분보다 눈에 띄게 푸르스름하게 어둡다. 수위선에는 반지름 3.72, 관 0.06 의 흰 토러스(opacity 0.7)를 둘러 물높이가 선으로 보이게 한다. 수면은 CircleGeometry(48분할 링)로 만들고 꼭짓점을 매 프레임 물결로 흔든다. 평소 진폭은 0.04, 탭 직후에는 0.3 이고 1.5초에 걸쳐 가라앉는다.
- 얼음: iceCount 개. BoxGeometry(1,1,1,6,6,6)의 원래 꼭짓점 p 를 저장해 두고, 매 프레임 p' = mix(p, normalize(p) × 0.62, r) 로 둥글린 뒤 한 변 크기로 늘린다. 둥글림 r = 0.2 + 0.65m 이고, 녹을수록 모서리가 사라져 조약돌처럼 된다. 시드 난수로 조각마다 ±8% 찌그러짐과 ±20° 기울기를 준다. 기울어진 면이 빛을 받아 입체가 드러난다.
- 재질은 ShaderMaterial(transparent, depthWrite false, 유니폼 uSunDir, uSunColor)이다.
- 몸 색은 iceBody × (0.5 + 0.5·max(dot(N, L), 0)) 이라서 면마다 밝기가 다르다.
- 윤곽 rim = pow(1 − |dot(N, V)|, 2) 로 흰색에 섞는다(mix 0.85·rim). 햇빛 반사 pow(max(dot(reflect(−L, N), V), 0), 40) × 1.2 를 더한다.
- alpha = 0.7 + 0.25·rim
- 그래서 얼음은 천보다 푸르고 어두운 몸에 흰 테가 둘린 모양으로 늘 또렷하다.
- 배치: 세 조각을 잔 축에서 반지름 1.5 인 원 위에 120°씩 둔다. 조각 하나의 바깥 끝은 1.5 + 2.4 × 0.71 ≈ 3.2 로 잔 안벽(3.75) 안에 들어온다. 서로 밀려 떠 있는 모습이라 각 조각 높이의 30%가 수면 위로 나온다.
- 0.15 진폭으로 느리게 오르내리고 천천히 맴돈다.
- 김서림 물방울: 잔 바깥면 수위 아래에 지름 0.12~0.3 의 반구 140개를 InstancedMesh 로 붙인다(시드 난수, roughness 0.05, opacity 0.6).
- 가짜 잔 그림자: 테이블 위 y = 0.01 에 빛 반대 방향으로 늘어난 부드러운 타원 판을 깐다. 색 #4a3f30, opacity 0.36 이고, 가장자리는 CanvasTexture 방사 그라데이션으로 흐린다. L = 12 / tan(해 고도) 로 두면, 그림자는 d 축을 따라 잔 중심 −4 에서 +(6 + 0.95L) 까지 뻗고 반 폭은 5.5 다. 빛무늬 타원 전체가 이 그림자 안에 들어온다. 그래서 빛 그물 선 사이의 바탕은 주변 햇빛 천보다 어둡고, 선만 천보다 밝다. 실제 물잔 그림자가 이렇게 생겼다.
- 빛무늬 판(핵심): y = 0.02 의 판. ShaderMaterial, AdditiveBlending, transparent, depthWrite false. 빛의 수평 방향을 d 라 할 때 판의 중심은 잔 중심에서 d 쪽으로 4 + 0.47L 떨어진 곳이다. 반 길이는 0.45L, 반 폭은 4.6 이다. 해 고도 38° 에서 L = 15.4, 긴 지름 13.8, 가로 화면 겉보기 ≈ 0.52S 다(거리 40 에서 화면 높이 25.2). 30° 에서는 L = 20.8, 긴 지름 18.7, 겉보기 ≈ 0.70S 다.
- 무늬: 판 위 월드 좌표(cm)를 7로 나누고 무늬 크기 배율을 곱한 값을 uv 로 삼아(긴 판에서도 무늬가 늘어나지 않는다) 아래 반복식에 넣는다. 초깃값: n = 0..4, inten = 0.005, p = mod(uv·6.2832, 6.2832) − 250, i = p, c = 1.
tt = time·(1 − 3.5/(n+1)); i = p + vec2(cos(tt − i.x) + sin(tt + i.y), sin(tt − i.y) + cos(tt + i.x)); c += 1/length(vec2(p.x/(sin(i.x+tt)/inten), p.y/(cos(i.y+tt)/inten)));
마지막에 c /= 5; c = 1.17 − pow(c, 1.4); v = pow(abs(c), 8).
- 선 다듬기: line = smoothstep(0.2, 0.85, clamp(v, 0, 1)). 패치 넓이의 약 70%는 0 근처이고, 밝은 선은 폭 0.2~0.5cm 로 이어진 그물이어야 한다. 선이 뭉쳐 하얀 얼룩이 되면 안 된다.
- 색 갈라짐: 패치 중심 기준으로 uv 를 R 은 ×1.035, G 는 ×1, B 는 ×0.965 로 늘여 line 을 세 번 구한다. 가장자리로 갈수록 선이 무지개로 갈라진다.
- 무지개 테: 타원 정규 반지름 ρ(중심 0, 가장자리 1)에서 R = exp(−((ρ − 0.93)/0.035)²), G = exp(−((ρ − 0.87)/0.035)²), B = exp(−((ρ − 0.81)/0.035)²) 의 띠를 0.45 세기로 더한다. 잔에서 먼 쪽 절반에만 넣는다.
- 가림막: 타원 안쪽은 1, 가장자리 15%는 smoothstep 으로 흐린다. 잔에서 먼 쪽 끝 20% 지점에는 초승달 모양 초점 띠(폭 1.2cm)를 더한다. 이 띠의 밝기는 0.4 + 0.5m 이다.
- 녹는 정도 연동: 무늬 크기 배율은 1.4 − 0.5m 이다(얼음이 많으면 잘고 어지럽고, 녹으면 굵고 잔잔하다).
- 최종 색 = (line·마스크 + 초점 띠 + 무지개 테) × causticStrength × 햇빛색 × fadeIn 이고, 가장 밝은 선은 1.0 을 넘지 않게 자른다. fadeIn 은 0~0.8초에 0→1 로 올라간다. time 은 t × causticSpeed × 흔들림 배율로 쌓는다.
- 빛무늬 판은 톤 매핑을 받지 않는다(toneMapped false). 그래야 선 색이 그대로 나온다.
- 시간 슬라이더: 화면 아래 가운데, 아래 여백 3vh 에 반투명 알약(배경 rgba(255,250,240,0.6), 모서리 999px, blur 없음)을 둔다. 그 안에 input range(폭 min(60vw, 420px), 0~1, 손잡이 색 #d99a3e)와 시계 글자(m 0 → 14:00, m 1 → 15:30, 13px, #5a5246)를 넣는다. 손대지 않으면 m 이 1/meltDuration 씩 늘다가 1에서 멈춘다. 슬라이더를 끌면 그 값부터 다시 흐른다. 이것이 화면의 유일한 글자다.
- 탭: 포인터를 누르고 뗄 때 이동이 6px 미만이고 300ms 안이면 탭이다. 잔을 감싼 보이지 않는 원기둥(반지름 5, 높이 13)에 Raycaster 를 쏴서 맞으면 흔들림을 시작한다.
- 잔 묶음(잔·물·얼음·물방울)은 바닥 중심을 축으로 기운다. 각도는 θ(τ) = wobbleAmp · e^(−τ/0.9) · sin(2π·2.2τ), 축은 탭 방향에 수직인 수평축이다.
- 수면 물결이 커지고 얼음 오르내림이 3배가 된다.
- 빛무늬는 흔들림 배율 1 + 3e^(−τ/1.0) 로 빨라지고, 판 중심이 θ × L × 2 만큼 기운 쪽으로 밀린다.
- 가짜 그림자도 같은 양만큼 밀린다.
[카메라]
- PerspectiveCamera fov 35, near 0.5, far 400.
- 바라보는 점: 잔 중심에서 d 쪽으로 0.35L(시작 약 5.4, m = 1 이면 약 7.3), 높이 3. 가로 화면에서는 잔이 가운데보다 조금 왼쪽에, 빛무늬가 가운데에서 오른쪽으로 놓인다. 해 고도 30° 일 때 빛무늬 끝은 바라보는 점에서 약 15.8 떨어지는데, 가로 반폭 16.8 안에 들어온다.
- 카메라 위치는 window.__view 의 yaw(수평, 0 = 잔 정면 +z 쪽, 카메라 수평 방향 = (sin yaw, cos yaw))와 pitch(내려다보는 각)로 정한다. 기준값 yaw0·pitch0·거리 D 는 화면 방향마다 다르다.
- 가로 화면(폭 ≥ 높이): yaw0 = 0, pitch0 = 0.55, D = 40. 이때 잔의 겉보기 높이는 12 × cos(0.55) ≈ 10.2 / 25.2 ≈ 0.40S 다. 해는 화면 왼쪽 약간 뒤에 있고, 빛무늬는 잔 오른쪽으로 화면을 가로지른다.
- 세로 화면(폭 < 높이): yaw0 = 1.0, pitch0 = 0.8, D = min(80, 33 / aspect). 카메라가 해를 마주 보는 역광 쪽으로 돌아서 빛무늬가 잔에서 화면 아래쪽(카메라 쪽)으로 뻗는다. 좁은 폭을 가로지르지 않고 긴 세로를 채운다. 390 × 844 에서 D ≈ 71.4, 화면 폭 ≈ 20.8 이다. 잔은 ≈ 0.40S, 빛무늬는 ≈ 0.49S 이고, 화면 위쪽 끝까지 천이다. 이 시점에서 잔은 화면 가로 가운데쯤, 세로로는 가운데보다 조금 위에 놓이고, 빛무늬가 그 아래를 채운다.
- 자동 움직임: yaw = yaw0 + 0.35·sin(2πt/40), pitch = pitch0 + 0.06·sin(2πt/55).
- 끌기: 화면 폭 전체를 끌면 yaw 2.4 라디안, 화면 높이 전체를 끌면 pitch 1.2 라디안이 바뀐다. yaw 는 yaw0 ± 1.2, pitch 는 0.25~1.1 로 제한한다. 창 비율이 바뀌어 화면 방향이 뒤집히면 기준값을 바꿔 자동 궤도로 돌아간다. 손을 떼고 3초 뒤 1.5초 동안 easeInOutCubic 으로 자동 궤도 값에 섞여 돌아간다.
[빛]
- DirectionalLight: 색은 sunColorStart → sunColorEnd(m 따라 보간), 세기 1.5. 고도는 sunElevStart → sunElevEnd 이고, 수평으로는 늘 −d 쪽(왼쪽 약간 뒤)에서 비춘다. 위치는 표적 + 빛 방향 × 90.
- 그림자 맵은 쓰지 않는다(renderer.shadowMap.enabled false). 그늘은 [장면]의 창 그림자 판과 가짜 잔 그림자가 맡는다.
- HemisphereLight: 하늘 #e4e8ea, 땅 #b8a88e, 세기 0.5.
- 환경 반사: 512 × 256 CanvasTexture 로 방을 그린다. 바탕은 #7d7364 로 어둡게, 위는 #a39886, 가운데 왼쪽에 아주 밝은 창 사각형 #ffffff 와 어두운 창살 두 줄(#3c362e)을 둔다. 어두운 방과 밝은 창의 대비가 커야 잔·얼음 표면에 세로 하이라이트와 어두운 띠가 생겨 유리가 읽힌다. EquirectangularReflectionMapping 으로 두고 PMREMGenerator.fromEquirectangular 로 scene.environment 에 넣는다. 잔 표면에 창이 비친다.
- renderer.outputEncoding = THREE.sRGBEncoding, toneMapping ACESFilmicToneMapping, exposure 0.95. 안개 Fog(bgColor, 90, 240). 배경색 bgColor.
[구현]
- HTML 파일 하나로 만든다. 라이브러리는 three.js 한 줄만 쓴다: <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> — 이 r128 판에 없는 것(모듈 import, OrbitControls 같은 확장 파일, CapsuleGeometry, outputColorSpace)은 쓰지 않는다. 그 밖의 바깥 파일·글꼴·네트워크 요청은 쓰지 않는다.
- three.js 다음 <script> 맨 앞에 CONFIG 객체를 두고 [바꿀 곳]의 값과 이 글에 나온 숫자(크기·색·빛·속도)를 이름 붙여 모은다.
- 장면은 requestAnimationFrame 의 타임스탬프로 구한 시간 t(초)로 진행한다. 한 프레임에 밀린 시간은 0.1초까지만 반영한다. setTimeout·setInterval·CSS 애니메이션으로 움직이지 않는다.
- 난수는 시드 고정 난수(mulberry32 등)만 쓴다. Math.random 은 쓰지 않는다.
- 텍스처는 코드로 만든다(CanvasTexture·DataTexture). 바깥 그림 파일을 쓰지 않는다.
- 캔버스는 늘 창 전체 크기다. 창 크기가 바뀌면 카메라 비율과 렌더러 크기를 다시 맞춘다. 스크롤이 생기지 않게 한다. renderer.setPixelRatio 는 2 까지만.
- 입력이 없으면 카메라가 스스로 천천히 움직인다. 마우스로 끌거나 손가락으로 끌면 시점이 돈다(가로 = 좌우 회전, 세로 = 위아래 기울기, 범위 제한). 손을 떼고 3초 뒤 자동 움직임으로 부드럽게 돌아간다. 터치는 페이지 스크롤·확대가 일어나지 않게 막는다(touch-action: none).
- 시점 각도를 window.__view = { yaw, pitch } (라디안)에 두고 매 프레임 갱신한다. 카메라는 이 두 각도로 놓는다 — 자동 움직임도 끌기도 이 각도를 바꾼다.
- 브라우저 저장소(localStorage·sessionStorage·IndexedDB·쿠키)를 쓰지 않는다 — 미리보기 칸에서 막혀 오류가 난다.
- 탭이 숨으면 멈추고 돌아오면 이어서 한다.
- WebGL 을 못 쓰는 기기에서는 오류 대신 화면에 짧은 안내 문구를 띄운다.
- 글자를 쓰면 시스템 글꼴만: 'Pretendard', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', sans-serif.
- 모든 함수·상수를 먼저 정의하고, 시작은 스크립트 맨 끝에서 한 번만 부른다.
- 콘솔에 오류가 나지 않게 한다. 스스로 대조하는 표는 console.table, 어긋남은 console.warn 으로만 낸다.
이 작품만의 지시:
- 함수 나눔: makeClothTexture, makeEnvTexture, makeWindowShadeTexture, buildGlass, buildIce, updateIce(m), buildCaustic, updateSun(m), updateCaustic(t, m), startWobble(dir), updateWobble(dt), updateCamera(t, dt), onResize, selfCheck, init, loop.
- 그리는 순서: 테이블보 → 창 그림자 판(renderOrder 1) → 가짜 잔 그림자(2) → 빛무늬(3) → 잔 바닥(4) → 물(5) → 얼음(6) → 수위선(7) → 잔 몸(8) → 윤곽 막(9) → 입술(10). 투명한 것끼리 깜빡이지 않게 renderOrder 를 고정한다.
- 빛무늬 셰이더 유니폼은 uTime, uMelt, uSun(색), uStrength, uFade, uFocus 다. 판의 위치·회전·크기는 JS 에서 매 프레임 L 과 d 로 다시 놓는다. 빛무늬 판 메시는 128 × 64 분할이면 충분하다(평면이다).
- 얼음 꼭짓점 갱신 뒤에는 computeVertexNormals 를 부르고 position.needsUpdate 를 켠다.
- 포인터는 pointerdown/move/up 하나로 마우스와 터치를 함께 처리하고, setPointerCapture 를 쓴다. 슬라이더 위의 포인터는 시점 끌기로 넘기지 않는다(stopPropagation).
- 합격 기준(기본 설정): 시작 1초 안에 빛무늬가 보인다. 잔 겉보기 높이 0.33S~0.5S, 빛무늬 겉보기 긴 지름 ≥ 0.4S(시작 약 0.52S), 빛무늬 판의 양 끝이 화면 안, 얼음 한 조각 겉보기 폭 ≥ 잔 폭의 0.25(시작 m = 0.12 에서 약 0.27), m = 1 의 얼음 변 / m = 0 의 변 = 0.25, 삼각형 ≤ 300000, 그림자 맵 없음, 픽셀 비율 ≤ 2, 얼음 3조각, 90초에 m = 1, 정상 상태 60fps 목표.
- selfCheck: 첫 렌더 직후 한 번 실행한다. 잔 바닥·입술 점, 빛무늬 판의 양 끝 점, 얼음 한 조각의 양 끝 점을 화면에 투영해 겉보기 크기/S 를 구한다. 이것과 renderer.info.render.triangles, 픽셀 비율, 얼음 수, 얼음 변 비율, meltDuration 을 기준값과 함께 console.table 로 낸다. 기준을 벗어난 항목마다 console.warn 한 줄을 낸다.
[하지 말 것]
- MeshPhysicalMaterial 의 transmission 이나 다중 패스 굴절 렌더를 쓰지 않는다 — r128 에서 무겁고 결과가 불안정하다. 빛무늬는 위의 셰이더 판으로만 만든다.
- 그림자 맵과 가림 판을 쓰지 않는다. 판 끝이 보여 딱딱한 사선과 밝은 쐐기가 생기고, 유리가 검은 그림자를 찍어 돌처럼 보인다. 그늘은 계산한 그림 판으로만 그린다.
- 얼음·잔·물을 흰 천과 같은 밝기의 옅은 반투명으로 두지 않는다. 바탕에 묻혀 제목의 주인공이 사라진다. 얼음은 푸른 몸과 흰 테, 잔은 회색 윤곽선과 창 반사로 읽히게 한다.
- 빛 세기·노출·빛무늬 세기를 올려 장면을 밝히지 않는다. 천과 빛무늬가 하얗게 날아가 그물 선이 사라진다. 위 숫자를 지킨다.
- 떠다니는 먼지 입자, 렌즈 플레어, 빛줄기, 블룸, 반짝이 스프라이트를 넣지 않는다 — 빛무늬 하나에 시선이 모여야 한다.
- 빛무늬를 테이블 전체에 깔거나 하늘색·보라색 같은 진한 색으로 칠하지 않는다 — 따뜻한 흰빛과 가장자리의 얇은 무지개만 쓴다.
- 바탕(테이블보·안개)에 남청색이나 고채도 색을 쓰지 않는다 — 여름 오후의 바랜 빛이 사라진다.
- 슬라이더 외의 제목·설명·화면 모서리 라벨·조작 안내 문구를 띄우지 않는다 — 장면을 가린다.
- 레몬·빨대·꽃병 같은 소품을 지어내지 않는다 — 잔과 얼음과 천만으로 충분하다.
- 바깥 글꼴·그림·소리 파일을 불러오지 않는다 — 네트워크 요청은 three.js 한 줄뿐이다.
- 가운데에 작은 잔만 떠 있는 구도로 만들지 않는다 — 테이블보가 화면을 꽉 채워야 한다.
사용 방법
필요한 것: claude.ai 계정 — 무료 계정에서도 Claude Opus 5.5 를 고를 수 있습니다
- claude.ai 에서 새 대화를 엽니다.
- 모델 메뉴에서 Claude Opus 5.5 를 고르고, 같은 메뉴의 Effort(답변 깊이)를 High 로 둡니다.
- 복사한 프롬프트를 붙여 넣고 전송합니다. 결과로 나온 HTML 파일을 브라우저로 열면 바로 해 볼 수 있습니다.
추가 요청 예시
결과가 나온 뒤 같은 대화에서 이어서 요청하면 해당 부분만 수정됩니다.
- 물잔 옆에 레몬 조각을 하나 띄워 줘
- 창밖을 비 오는 오후로 바꿔 줘
- 얼음이 다 녹으면 새 얼음을 넣는 단추를 달아 줘
3D