Build a single self-contained HTML page (no build step) showing an interactive 3D "Fluffy Watermelon" covered in long fur, rendered with WebGL using three.js r147 (UMD build: https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js). All UI text in English.
SCENE & LOOK
- Full-screen canvas on a soft watermelon-flesh pink studio background: vertical gradient #ECB3AB → #F7CFC7 (lighter band in the middle) → #E8A9A0, used as the scene background.
- A big oblong watermelon lying on its side along the X axis: half-length 1.38, radius 0.98, blunt barrel-like ends, small dimples at both ends, slightly flattened belly, subtle surface unevenness. Start in a 3/4 view (about -0.32 rad around Y, 0.1 rad tilt), camera FOV 30°, framed to fill ~80% of the height.
- Rind pattern under the fur: light green (#A8D66B) with 16 dark green (#1C4D1C) stripes running stem to blossom, with ragged finger-like edges (sine meander + value noise), plus a pale cream "field spot" on the underside. Each hair takes the colour of its own root, so the stripes stay crisp through the fur.
- A short, dried, ribbed stem stub at one end with a slightly domed pale cut cap, and a thin curly helical tendril springing from beside it.
- One directional light from upper-left-front, wrap diffuse, Kajiya-Kay anisotropic highlight along the hair tangent, darker roots (occlusion by hair height), slight per-hair brightness variation.
FUR (most important: it must look crisp, never blurry)
- Fur length 0.2 units. Hairs grow out along the normal, then bend: combed from the stem end toward the blossom end and draped down the flanks (no whorls at the ends), plus slight gravity.
- Undercoat: shell texturing with ~64 instanced shells of the body mesh that reach only 50% of the fur length. Procedural hair cells in UV space (density scaled so one cell is ~3.4 device pixels at the default view), two hair populations (long + fine underfur), hairs gathering into locks toward their tips, analytic anti-aliased coverage, alpha blending, shells write depth. Fade shells out where the surface is seen edge-on and discard faint fragments, so no dotted rim appears at the outline.
- Guard hairs: ~90,000 individual tapered, camera-facing ribbon strands (instanced, 7 segments each) that follow exactly the same bend function, with a minimum width of ~0.75 px so they stay sharp. Draw them twice: once before the shells and once after (depth-tested), so faint edge fur never hides them and they always lie crisply on top.
- Always render at the device's full pixel ratio (capped at 2) and NEVER lower it for performance. If frames are slow, reduce the shell count first (down to 32), then the guard-hair count.
INTERACTION
- Drag to rotate freely (trackball style) with inertia after a flick. The fur lags behind the rotation through a damped spring and flops back. Gentle idle breeze in the fur; after 3 s without input, a slow auto-turn.
- Mouse wheel / pinch to zoom (smooth dolly). Double-click or "0" resets with an eased animation. Arrow keys rotate.
- Custom cursor: the native grab hand plus a thin dark 46 px ring that follows the pointer and shrinks while dragging. Hovering gently parts the fur under the cursor, as if stroking it.
- Respect prefers-reduced-motion (no idle spin, no breeze).
UI & ROBUSTNESS
- Bottom-left caption: "Fluffy Watermelon" and a hint "Drag to rotate · Scroll to zoom · Double-click to reset" (on touch devices: "Drag to rotate · Pinch to zoom") that fades after the first interaction. Font: Onest from Google Fonts with system fallbacks.
- Guard against a zero-sized container at load: clamp width/height to at least 1 and, every frame, recover from any non-finite camera distance or rotation state.
- Show a small on-page note if the WebGL context is lost or a shader fails to compile, and a fallback message if WebGL is unavailable.
한국어 번역
빌드 단계 없이, 긴 털로 덮인 인터랙티브 3D "Fluffy Watermelon"을 보여주는 단일 자체 포함 HTML 페이지를 만드세요. three.js r147(UMD 빌드: https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js)을 사용해 WebGL로 렌더링합니다. 모든 UI 텍스트는 영어로 작성합니다.
장면 & 룩
- 부드러운 수박 과육 분홍색 스튜디오 배경의 전체 화면 캔버스: 수직 그라데이션 #ECB3AB → #F7CFC7(중간의 더 밝은 띠) → #E8A9A0을 장면 배경으로 사용합니다.
- X축을 따라 옆으로 누운 크고 길쭉한 수박: 반길이 1.38, 반지름 0.98, 뭉툭한 통 모양의 끝, 양 끝의 작은 움푹 들어간 자국, 약간 납작한 배, 미세한 표면 요철. Y축 기준 약 -0.32 rad, 기울기 0.1 rad의 3/4 뷰에서 시작하고, 카메라 FOV 30°, 높이의 약 80%를 채우도록 프레이밍합니다.
- 털 아래의 껍질 무늬: 연녹색(#A8D66B) 바탕에 꼭지에서 꽃자리까지 이어지는 16개의 진녹색(#1C4D1C) 줄무늬가 있고, 가장자리는 손가락처럼 너덜너덜하며(사인 곡선 + 밸류 노이즈), 아래쪽에는 옅은 크림색 "field spot"이 있습니다. 각 털은 자기 뿌리의 색을 띠므로 줄무늬는 털을 통해서도 선명하게 유지됩니다.
- 한쪽 끝에는 짧고 마른, 골이 진 꼭지 조각이 있고 그 위에 살짝 둥글게 솟은 옅은 절단면이 있으며, 그 옆에서 가는 나선형 덩굴손이 뻗어 나옵니다.
- 왼쪽 위 앞쪽에서 오는 방향광 하나, 랩 디퓨즈, 털 접선을 따르는 Kajiya-Kay 이방성 하이라이트, 더 어두운 뿌리(털 높이에 의한 오클루전), 털마다 약간씩 다른 밝기.
털 (가장 중요: 선명하게 보여야 하며, 절대 흐릿해서는 안 됨)
- 털 길이는 0.2 단위. 털은 법선을 따라 자라난 뒤 휘어집니다: 꼭지 쪽 끝에서 꽃자리 쪽 끝으로 빗질되어 옆면으로 늘어지고(끝부분에는 소용돌이가 없음), 약간의 중력이 더해집니다.
- 속털: 본체 메시의 약 64개 인스턴스 셸을 사용하는 셸 텍스처링으로, 털 길이의 50%까지만 도달합니다. UV 공간의 절차적 털 셀(기본 뷰에서 한 셀이 약 3.4 기기 픽셀이 되도록 밀도를 조정), 두 가지 털 집단(긴 털 + 가는 속털), 끝으로 갈수록 다발로 모이는 털, 해석적 안티에일리어싱 커버리지, 알파 블렌딩, 셸은 깊이를 기록합니다. 표면이 측면으로 보이는 곳에서는 셸을 페이드 아웃하고 희미한 조각은 버려서, 윤곽선에 점선 테두리가 나타나지 않게 합니다.
- 가드 헤어: 약 90,000개의 개별적이고 가늘어지는, 카메라를 향한 리본 가닥(인스턴싱, 각각 7 세그먼트)으로, 완전히 동일한 굽힘 함수를 따르며, 선명함을 유지하도록 최소 너비 약 0.75 px를 가집니다. 두 번 그립니다: 셸 앞에 한 번, 셸 뒤에 한 번(깊이 테스트), 그래서 희미한 가장자리 털이 이들을 가리지 않고 항상 선명하게 위에 놓입니다.
- 항상 기기의 전체 픽셀 비율(최대 2로 제한)로 렌더링하고, 성능을 위해 절대 낮추지 마세요. 프레임이 느리면 먼저 셸 개수를 줄이고(32까지), 그다음 가드 헤어 개수를 줄이세요.
인터랙션
- 드래그하여 자유롭게 회전(트랙볼 스타일), 튕기면 관성이 붙습니다. 털은 감쇠 스프링을 통해 회전을 뒤늦게 따라가며 다시 툭 내려앉습니다. 털에는 은은한 대기 중 미풍이 있고, 입력이 3초 동안 없으면 느리게 자동 회전합니다.
- 마우스 휠 / 핀치로 확대·축소(부드러운 돌리). 더블클릭 또는 "0" 키로 이징 애니메이션과 함께 초기화합니다. 화살표 키로 회전합니다.
- 커스텀 커서: 기본 잡기 손 모양에, 포인터를 따라가며 드래그 중에는 작아지는 얇고 어두운 46 px 링을 더합니다. 호버하면 커서 아래의 털이 부드럽게 갈라지며, 마치 쓰다듬는 것처럼 보입니다.
- prefers-reduced-motion을 존중합니다(대기 중 회전 없음, 미풍 없음).
UI & 견고성
- 왼쪽 아래 캡션: "Fluffy Watermelon"과, 첫 인터랙션 후 사라지는 힌트 "Drag to rotate · Scroll to zoom · Double-click to reset"(터치 기기에서는 "Drag to rotate · Pinch to zoom"). 폰트: Google Fonts의 Onest, 시스템 폴백 포함.
- 로드 시 컨테이너 크기가 0인 경우에 대비하세요: 너비/높이를 최소 1로 클램프하고, 매 프레임마다 유한하지 않은 카메라 거리나 회전 상태에서 복구합니다.
- WebGL 컨텍스트를 잃거나 셰이더 컴파일이 실패하면 페이지에 작은 안내를 표시하고, WebGL을 사용할 수 없으면 폴백 메시지를 표시합니다.