접히는 우산
GPT-6.1 기준으로 만들었습니다
GPT-6.1 Sol · 추론 강도 High · Codex CLI 기준
우산의 살과 천이 함께 접히는 모습을 돌려 살펴봅니다.
같은 프롬프트를 아래 안내하는 화면에서 실행하세요.
- 만든 모델
- GPT-6.1 Sol
- 추론 강도
- High
- 제작 도구
- Codex CLI
- 화면비
- 화면 맞춤 (넓은 화면 16:9 · 폰 3:4)
- 조작
- 끌어서 시점 돌리기 · 펼침 정도 · 자동 재생 · 처음으로
- 결과물
- HTML 파일 하나 · three.js 를 인터넷에서 불러옵니다
프롬프트
AI가 읽는 제작 지시문입니다. 맨 위 [바꿀 곳]의 값을 바꿔 붙여 넣어도 됩니다.
완성된 HTML 파일 하나의 원문만 답하세요. 설명과 코드 울타리는 붙이지 마세요. 코드를 실행하지 말고 아래 조건에 맞는 HTML 소스만 작성하세요. 파일을 읽거나 쓰고 검색하거나 다른 도구를 호출하지 마세요. 이 답변 지시는 작품 화면에 표시하지 마세요.
[핵심 아이디어]
우산의 살과 천이 함께 접히는 모습을 돌려 살펴봅니다.
[바꿀 곳]
제목: 접히는 우산
부제: 여덟 개의 우산살, 하나의 곡면
강조 색: #796879
[크기]
창 전체에 맞추는 화면. 1440×900에서는 넓고 정돈된 배치, 390×844에서는 넉넉한 세로 배치입니다. 폭 350~390·높이 460~520인 작은 프레임에서도 글씨와 조작부가 잘리지 않도록 높이에 맞춰 여백·도형·조작부를 함께 줄이거나 재배치합니다. 스크롤은 없습니다.
주요 형상은 화면 폭의 65% 이상으로 크게 보입니다. 첫 화면부터 작품이 충분히 보이고 첫 1초 안에 분명히 움직입니다. 글씨와 형상 사이에 여백을 두고 모든 한글이 잘리지 않게 합니다. 시스템 글꼴의 굵기와 크기 차이로 차분한 타이포를 만듭니다.
[장면]
차가운 연회보라 바탕 #ECEAF0 위에 자줏빛 회색 천 #A397AA와 밝은 은색 우산살, 짙은 자주 먹색 기둥의 우산 한 개를 크게 배치합니다. 크림·갈색·세이지 색 조합은 쓰지 않습니다. 우산은 화면 폭의 65% 이상이고 손잡이까지 보입니다. PC에서는 왼쪽 위에 작은 편집 글처럼 왼쪽 정렬한 제목·부제를 두고 중앙 오른쪽에 큰 우산, 아래에는 낮고 긴 조절부를 둡니다. 폰에서는 왼쪽 정렬한 짧은 제목, 큰 우산, 두 줄 조절부로 화면 높이를 알차게 씁니다. 제목을 가운데 위에 두지 않습니다. 여덟 살은 각자 9개 표본점을 가진 실제 THREE.Line이며 이름은 rib-0부터 rib-7입니다. 실제 천 Mesh의 이름은 canopy입니다. 실제 THREE.Scene을 window.scene으로도 공개합니다.
슬라이더 input#fold의 min=0,max=1,step=.01입니다. 펼침 정도 f(0=접힘, 1=폄)에서 살의 각도 a=.08+1.17*f 라디안, 중앙 허브는 (0,180,0), 살 끝 반경은 280*sin(a), 살 끝 높이는 180-280*cos(a)입니다. 여덟 살의 방위각은 2π*i/8입니다. 각 살을 허브에서 끝까지 9점으로 나누고, 천의 각 조각 양쪽 경계는 그 살의 동일한 9점 배열을 공유합니다. 천이 살에서 떠 있거나 관통하지 않게 실제 버텍스를 매번 갱신합니다. 살 끝 기준 값은 f=0/.25/.5/.75/1에서 정확히 위 식을 따릅니다. 기둥은 (0,-220,0)부터 허브까지, 천은 무광·양면으로 그려 가림이 자연스럽게 보입니다.
처음 f=.7에서 즉시 보이고 자동 재생가 첫 1초에 f를 .35 이상 바꾸며 천과 살이 함께 움직입니다. #demo-toggle은 자동일 때 aria-pressed=true이며 누르면 현재 접힘을 멈춥니다. #reset은 f=.7과 초기 시점을 복원하고 자동 재생를 다시 시작합니다. 슬라이더 조작은 즉시 자동 접힘을 멈춥니다. 마우스·손가락 드래그로 카메라를 돌려 뒤쪽 연결과 내부 살도 볼 수 있습니다. 슬라이더에 Home을 누르고 ArrowRight 25회를 누르면 f=.25가 됩니다.
three.js 스크립트 불러오기 실패는 '화면에 필요한 파일을 불러오지 못했습니다. 다시 시도해 주세요.', WebGL 생성 실패·contextlost는 '이 기기에서 3D 화면을 표시하지 못했습니다. 다시 시도해 주세요.'로 구분하고 각각 '다시 시도' 단추를 제공합니다. 스크립트 로딩은 onerror로, WebGL 생성은 try/catch로 처리하고 webglcontextlost에는 preventDefault로 복구 기회를 줍니다. 재시도는 해당 원인에 맞게 렌더러를 다시 만들거나 같은 라이브러리를 다시 요청합니다. WebGL 오류를 인터넷 문제라고 안내하지 않습니다. 외부 라이브러리는 아래 고정 문단의 r128 한 줄뿐입니다. 창 크기에 따라 카메라 거리를 맞춰 폰에서도 우산이 크게 보이면서 잘리지 않게 합니다.
바탕은 #ECEAF0, 글씨는 #302C35, 천은 #A397AA, 작은 강조는 #796879입니다. 화면의 40% 이상은 밝은 저채도 면이며 강조는 10% 이내입니다. 짙은 파랑 바탕과 큰 고채도 면을 쓰지 않습니다. 그림과 재질의 완성도를 높이고 설명 배지나 장식 문구는 줄입니다.
우산의 월드 좌표는 위 수식을 유지하며 회전 조작은 카메라 위치를 바꿉니다. 가로·세로 끌기에 바로 반응하고 손가락 한 개로도 같은 조작이 됩니다. 자동 재생의 카메라 회전은 천천히 진행하고, 직접 끌면 즉시 손의 움직임을 따릅니다.
[사용감과 마무리]
- 제목은 ‘접히는 우산’, 부제는 위 문장만. 제작 방식·내부 용어·사람 이름은 화면에 적지 않습니다. 부제 자간은 자연스럽게 0~.02em입니다.
- 자동 재생 단추는 아이콘 없이 글자 ‘자동 재생’ 하나와 aria-pressed 상태로 표현합니다. 별도 짧은 상태 문장은 ‘재생 중’ 또는 ‘멈춤’입니다. 터치 기기에는 ‘끌어서 돌리기 · 막대로 펼치기’만 보이고 키보드 안내는 보이지 않습니다.
- 바닥 그림자는 손잡이 끝 바로 아래에 붙은 작고 부드러운 접촉 그림자 한 개입니다. CanvasTexture 원형 그라데이션을 바닥 Plane에 얹고 불투명도 .12~.18, 가로 크기는 펼친 우산 폭의 .35 이내입니다. 우산에서 떨어진 오른쪽 아래 큰 덩어리나 화면 끝 잘림이 없도록 카메라와 그림자 크기를 함께 잡습니다. 큰 방향광 그림자는 끕니다.
- 천 아래 우산살이 분명히 읽히도록 옆으로 약간 기울여 보는 기본 카메라, 천과 대비되는 은색 살, 부드러운 두 방향 조명을 씁니다. 살은 천의 실제 경계에 정확히 붙습니다. 접힘 0%에도 긴 기둥·천 묶음·우산살이 화면 높이의 절반 이상을 차지해 작아 보이지 않게 합니다. 접힘에 따라 카메라가 과하게 멀어지지 않습니다.
- input#fold의 손잡이와 누르는 영역은 최소44px 높이. native input 이벤트뿐 아니라 pointerdown/move와 touchstart/move(수동 TouchEvent 포함)에서도 clientX를 트랙의 boundingClientRect에 매핑해 값을 0~1로 갱신합니다. 두 이벤트 경로의 중복은 막고, 실제 값·퍼센트·천·살을 같은 함수에서 동기화합니다. 슬라이더의 touch-action:none 및 passive:false, preventDefault, 이벤트 전파 중지로 카메라 회전과 충돌하지 않습니다. pointercapture를 쓸 때 합성 입력의 활성 포인터 부재로 예외가 나지 않게 합니다. Home/ArrowRight의 기본 키보드 조절도 유지합니다.
- 첫3초에 천이 접혔다 펴지며 은색 살이 드러나는 선명한 변화가 있고, 큰 우산과 정돈된 여백으로 한 장의 포스터처럼 보입니다. 조절부는 반투명 큰 카드 대신 가는 선·단정한 숫자로 마무리합니다.
[구현]
- 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 으로만 낸다.
[하지 말 것]
실존 인물·사진·개인 이름, 사람 캐릭터·막대 인간, 남청색·검푸른색·고채도 바탕, 외부 글꼴·이미지·오디오, 시작 전 빈 화면, 스크롤, 잘린 글자, 타이머 기반 애니메이션은 넣지 마세요.
ChatGPT에서 사용
- 새 대화에 위 프롬프트 전체를 붙여 넣습니다.
- 완성된 HTML 파일을 받아 PC 브라우저로 엽니다. 코드로 나오면 전체를 UTF-8 result.html로 저장해 엽니다.
- 대화 안에 미리보기가 있으면 그 자리에서 볼 수 있습니다. 지원 여부는 앱과 버전에 따라 다릅니다.
이 작품은 ChatGPT에서 직접 돌려 보지는 않았습니다. 모델과 추론 강도 선택 화면도 확인하지 않았습니다. 폰에서는 미리보기가 없으면 PC에서 파일을 여세요.
Codex에서 사용
새 빈 작업 폴더의 새 요청에 같은 프롬프트를 넣고 GPT-6.1 Sol · High로 실행합니다. 완성 HTML을 저장해 브라우저로 엽니다. Codex CLI 자체에는 시각 미리보기가 없습니다.
Claude에서 사용
새 대화에 같은 프롬프트를 붙이고 결과 HTML을 브라우저로 엽니다. Claude에서 같은 결과가 나오는지는 확인하지 않았습니다.
three.js를 불러오므로 인터넷 연결이 필요합니다. 대화 안 미리보기에서 CDN과 WebGL이 동작하는지는 직접 확인하지 않았습니다.
추가 요청 예시
결과가 나온 뒤 같은 대화에서 이어서 요청하면 해당 부분만 수정됩니다.
- 제목과 부제를 짧게 바꿔 주세요.
- 회보라색 천을 차분한 회녹색으로 바꿔 주세요.
- 자동으로 접히고 펴지는 속도를 조금 낮춰 주세요.
3D