# AI 꾸러미 — CSS 3D (카드 뒤집기) — CSS 3D card flip
> 카드 앞 · 뒷면을 겹치고 뒷면을 미리 180° 돌려 두면, perspective 아래에서 카드를 rotateY 로 돌리는 것만으로 진짜처럼 뒤집힌다.  
> 견본: https://ai-techstudio.web.app/#t/u66

이 문서를 코드 도우미(Claude Code · Cursor · ChatGPT 등)에 그대로 주면 돼요. 「## 주문서」 가 할 일, 나머지는 참고 자료예요.

## 주문서

### 만들어 줘: CSS 3D (카드 뒤집기) — CSS 3D card flip

#### 1. 목표
숫자 카드 뒤집기를 CSS 3D 로 뒤집히게 만들어 줘 — 앞면(?)이 돌아가면 뒷면(숫자)이 나오고, 뒤집히는 동안 살짝 떠오르게. 분위기는 초록 펠트 위 트럼프.

#### 2. 핵심 기술 용어
- **CSS 3D card flip** — CSS 3D 카드 뒤집기
- **perspective · transform-style: preserve-3d** — 원근 · 자식도 3D 공간에 두기
- **backface-visibility: hidden** — 뒤돌아선 면은 안 보이게
- **rotateY · rotateX** — 세로축 · 가로축 돌리기

#### 3. 환경
- 플랫폼: TypeScript (브라우저), 라이브러리 없이 — 화면과 떨어진 순수 함수로
- 화면: 브라우저 — PC · 폰 모두

#### 4. 조건
- 뒤집는 상자에 transform-style: preserve-3d, 두 면에 backface-visibility: hidden (+ -webkit-)
- 뒷면은 처음부터 rotateY(180deg) — 안 그러면 뒷면 글자가 거울처럼 뒤집혀 보인다
- 돌리는 값은 transform 하나로 (translateY · rotateX · rotateY 를 한 줄에)
- 여러 장은 0.35초씩 늦춰 차례로

#### 5. 완성 기준 (이게 보이면 성공)
- 카드가 차례로 돌며 「?」 앞면이 숫자 뒷면으로 바뀐다, 뒷면 숫자가 거꾸로 보이지 않는다
- 뒤집히는 중간에 카드가 살짝 떠오른다
- 「내려다보는 각도」 슬라이더(0 ~ 40°)로 카드를 비스듬히 볼 수 있다
- 폰에서도 부드럽다

#### 6. 진행 방식
- 핵심 코드 위주로, 설명은 짧게. 내 프로젝트에 끼워 넣기 쉬운 함수 · 클래스로 나눠 줘.
- 처음 화면에 바로 결과가 보이게, 그리고 켬/끔(또는 전/후) 비교를 할 수 있게 만들어 줘.
- 그림 · 소리 · 모델 파일이 필요하면 코드로 만든 임시 대체물로 먼저 돌아가게 하고, 진짜 파일로 바꿀 자리를 표시해 줘.
- 마지막에 「확인 방법」(무엇을 보면 성공인지)과 「조절할 값」 목록을 짧게 정리해 줘.
- 답변과 코드 주석은 한국어로 해 줘.

## 원리
- 바깥 상자에 perspective(견본 120cqmin)를 주면 안쪽 3D 회전이 원근으로 보인다.
- 카드에 transform-style: preserve-3d 를 줘야 앞 · 뒷면이 각자 3D 공간에 놓인다.
- 앞 · 뒷면을 같은 자리에 겹치고, 뒷면만 rotateY(180deg) 로 미리 돌려 둔다. 두 면 다 backface-visibility: hidden.
- 카드를 rotateY(k × 180°) 로 돌리면 90° 를 넘는 순간 앞면이 사라지고 뒷면이 보인다. 돌 때 sin(k·π) 만큼 띄우면 손으로 뒤집는 맛.

## 핵심 코드 — 카드 뒤집기 CSS + 차례로 돌리기
(발췌: demos/demosDraw2d.ts u66 의 CSS · update() 를 정리)
```ts
const css =
  '.table{display:flex;gap:5cqmin;perspective:120cqmin}' +
  '.card{width:22cqmin;height:32cqmin;position:relative;transform-style:preserve-3d}' +
  '.face{position:absolute;inset:0;border-radius:3cqmin;backface-visibility:hidden;-webkit-backface-visibility:hidden;display:grid;place-items:center}' +
  '.front{background:repeating-linear-gradient(45deg,#2b3f9e 0 2cqmin,#3550b8 2cqmin 4cqmin);color:#ffd23f}' +
  '.back{transform:rotateY(180deg);background:linear-gradient(#fffdf2,#ffeec2);color:#d0342c}';  // 뒷면은 미리 뒤집어 둔다

const html = [7, 3, 9].map((n) => '<div class="card"><div class="face front">?</div><div class="face back">' + n + '</div></div>').join('');

const ease = (x: number) => (x < 0.5 ? 2 * x * x : 1 - (-2 * x + 2) ** 2 / 2);
function update(t: number, cards: HTMLElement[], tilt = 12) {
  cards.forEach((c, i) => {
    const ph = (t - i * 0.35) % 4;                   // 0.35초씩 늦춰 차례로
    const k = ph < 0.6 ? 0 : ph < 1.3 ? ease((ph - 0.6) / 0.7) : ph < 2.8 ? 1 : ph < 3.5 ? 1 - ease((ph - 2.8) / 0.7) : 0;
    const lift = Math.sin(k * Math.PI) * 4;          // 도는 동안 떠오르기
    c.style.transform = 'translateY(' + -lift + 'cqmin) rotateX(' + tilt + 'deg) rotateY(' + k * 180 + 'deg)';
  });
}
```

## 흔한 실수 · 확인 목록
- [ ] **뒷면을 미리 돌려 두지 않으면 뒤집힌 뒤 숫자가 거울 글씨다** — .back 에 transform: rotateY(180deg) 를 처음부터 준다.
- [ ] **부모에 overflow: hidden 이나 filter 가 있으면 3D 가 납작해진다** — 그런 속성은 preserve-3d 를 끊는다 — 뒤집는 카드의 부모에서 뺀다.
- [ ] **backface-visibility 에 -webkit- 을 빼면 사파리에서 앞뒤가 겹쳐 보인다** — 두 가지를 함께 쓴다.
- [ ] **perspective 를 카드 자신에 주면 카드마다 소실점이 달라 어색하다** — 카드들을 담은 부모 상자에 perspective 를 한 번 준다.

## 완성 기준 체크리스트
- [ ] 카드가 차례로 돌며 「?」 앞면이 숫자 뒷면으로 바뀐다, 뒷면 숫자가 거꾸로 보이지 않는다
- [ ] 뒤집히는 중간에 카드가 살짝 떠오른다
- [ ] 「내려다보는 각도」 슬라이더(0 ~ 40°)로 카드를 비스듬히 볼 수 있다
- [ ] 폰에서도 부드럽다

## 이 기술 정보
- id: `u66` · 분류: 2D · 화면 › CSS · 화면 틀 · 공통 · 난이도 쉬움 · 폰 부담 가벼움 (폰 OK) — transform 만 바꾸므로 GPU 합성으로 처리된다. 카드 몇십 장까지 폰도 가볍다.
- 라이브 견본 (브라우저에서 직접 조작): https://ai-techstudio.web.app/#t/u66
- 쓰면 좋을 때: 정답 · 숫자 공개 / 짝 맞추기 · 카드 게임처럼 DOM 으로 만든 화면
- 쓰지 말 때: 카드 수십 장이 동시에 도는 3D 장면 — three.js 로 그리는 편이 낫다 / overflow: hidden 이 걸린 부모 안 — 3D 가 납작해진다

## 견본 실제 코드 (라이브 견본이 돌리는 코드 — three.js · TypeScript)
### u66 견본 항목 — `src/demos/demosDraw2d.ts:1487`
```ts
  u66: {
    kind: 'dom',
    caption: 'perspective + preserve-3d — 카드가 차례로 뒤집혀 뒷면(숫자)이 나와요',
    make(box) {
      const root = domRoot(
        box,
        'd2-flip',
        `.d2-flip{background:radial-gradient(circle at 50% 40%,#2e7d4f,#123a24);display:flex;align-items:center;justify-content:center;gap:5cqmin;perspective:120cqmin}
         .d2-flip .card{width:22cqmin;height:32cqmin;position:relative;transform-style:preserve-3d}
         .d2-flip .face{position:absolute;inset:0;border-radius:3cqmin;backface-visibility:hidden;-webkit-backface-visibility:hidden;display:grid;place-items:center;box-shadow:0 1.5cqmin 3cqmin #0007}
         .d2-flip .front{background:repeating-linear-gradient(45deg,#2b3f9e 0 2cqmin,#3550b8 2cqmin 4cqmin);border:1.2cqmin solid #fff;box-sizing:border-box;font-family:${TF};font-size:12cqmin;color:#ffd23f}
         .d2-flip .back{transform:rotateY(180deg);background:linear-gradient(#fffdf2,#ffeec2);border:1.2cqmin solid #e8c25a;box-sizing:border-box;font-family:${TF};font-size:14cqmin;color:#d0342c}
         .d2-flip .tag{position:absolute;left:50%;bottom:5%;transform:translateX(-50%);font-size:4.6cqmin;font-weight:800;padding:.2em .8em;border-radius:99px;background:#000a}`,
        `${[7, 3, 9].map((n) => `<div class="card"><div class="face front">?</div><div class="face back">${n}</div></div>`).join('')}<div class="tag">rotateY · backface-visibility</div>`,
      );
      const cards = qa(root, '.card');
      let tilt = 12;
      return {
        update(t) {
          cards.forEach((c, i) => {
            const ph = (t - i * 0.35) % 4;
            const k = ph < 0.6 ? 0 : ph < 1.3 ? ease((ph - 0.6) / 0.7) : ph < 2.8 ? 1 : ph < 3.5 ? 1 - ease((ph - 2.8) / 0.7) : 0;
            const lift = Math.sin(k * Math.PI) * 4;
            c.style.transform = `translateY(${-lift}cqmin) rotateX(${tilt}deg) rotateY(${k * 180}deg)`;
          });
        },
        controls: [{ type: 'range', label: '내려다보는 각도', min: 0, max: 40, step: 1, value: 12, on: (v) => (tilt = v) }] as Control[],
      };
    },
  }
```

## 관련 기술
- 같은 방법으로 만든 효과 예시: [2D 카드 뒤집기 (스케일 흉내)](https://ai-techstudio.web.app/ai/t/i311.md) `i311`
- 먼저 알면 좋은 기술: [CSS 무늬 (그러데이션 · 데이터 SVG)](https://ai-techstudio.web.app/ai/t/u62.md) `u62`
- 다음에 해 볼 기술: [분해도 (exploded view)](https://ai-techstudio.web.app/ai/t/i36.md) `i36`
- 참고 문서: [MDN — backface-visibility](https://developer.mozilla.org/en-US/docs/Web/CSS/backface-visibility) · [MDN — transform-style](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style)
