kotsa-spot-game-widget 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # 한국교통안전공단 교통안전 틀린그림찾기 — 임베드 위젯
2
+
3
+ 외부 사이트에 `<script>` 한 줄로 삽입하는 **교통안전 틀린그림찾기 게임 위젯**입니다.
4
+ Vite 라이브러리 모드로 단일 JS 파일 하나(IIFE)로 빌드되며, Shadow DOM 으로
5
+ 스타일이 완전히 격리되어 host 사이트와 서로 영향을 주지 않습니다.
6
+
7
+ ## 기술 스택
8
+
9
+ - **Vite 8** (라이브러리 모드 · IIFE 단일 번들)
10
+ - **React 19** · **TypeScript**
11
+ - **Tailwind CSS v4** · **shadcn/ui** (radix-nova)
12
+ - **Shadow DOM** 스타일 격리 — 별도 CSS 파일 없이 JS 한 개로 자체 완결
13
+
14
+ ## 빌드
15
+
16
+ ```bash
17
+ pnpm install
18
+ pnpm build # → dist/kotsa-spot-the-difference.js (단일 파일)
19
+ ```
20
+
21
+ 개발 미리보기:
22
+
23
+ ```bash
24
+ pnpm dev # 외부 사이트를 흉내 낸 index.html 로 위젯 확인
25
+ ```
26
+
27
+ ## npm 배포 · CDN(unpkg) 임베드
28
+
29
+ ```bash
30
+ pnpm build # dist/ 생성
31
+ npm publish # prepublishOnly 가 build 를 다시 실행해 dist 를 최신화
32
+ ```
33
+
34
+ - `package.json` 의 `files: ["dist"]` 로 배포 패키지에는 `dist/` 만 포함됩니다.
35
+ (`.npmignore` 가 있어 `.gitignore` 의 `dist` 무시 규칙은 적용되지 않습니다.)
36
+ - 배포 후에는 별도 호스팅 없이 **unpkg** 로 바로 임베드할 수 있습니다:
37
+
38
+ ```html
39
+ <script src="https://unpkg.com/kotsa-spot-game-widget@1.0.0"></script>
40
+ ```
41
+
42
+ - 버전 고정(`@1.0.0`)을 권장합니다. 버전을 생략하면(`.../kotsa-spot-game-widget`)
43
+ 항상 최신 버전을 받습니다. `package.json` 의 `unpkg` 필드가 번들 파일을
44
+ 가리키므로 경로를 적지 않아도 됩니다. (`jsdelivr` 도 동일)
45
+ - npm 에 동일한 패키지 이름이 이미 있으면 게시할 수 없습니다 — 그럴 땐
46
+ `name` 을 스코프(`@조직/kotsa-spot-game-widget`)로 바꾸세요.
47
+
48
+ ## 사용 방법 (외부 사이트에서 임베드)
49
+
50
+ ### 1) 자동 삽입 — `<main>` 안에 append
51
+
52
+ 스크립트만 넣으면 host 페이지의 `<main>` 태그 안에 게임이 자동으로 삽입됩니다.
53
+
54
+ ```html
55
+ <main></main>
56
+
57
+ <script src="https://unpkg.com/kotsa-spot-game-widget@1.0.0"></script>
58
+ ```
59
+
60
+ ### 2) 특정 위치에 삽입
61
+
62
+ 원하는 자리에 `data-kotsa-game` 요소를 두면 그 자리에 마운트됩니다.
63
+ (이 속성을 가진 요소가 하나라도 있으면 `<main>` 자동 삽입은 건너뜁니다.)
64
+
65
+ ```html
66
+ <div data-kotsa-game></div>
67
+
68
+ <script src="https://unpkg.com/kotsa-spot-game-widget@1.0.0"></script>
69
+ ```
70
+
71
+ ### 3) 수동 제어 (JavaScript API)
72
+
73
+ ```html
74
+ <div id="game-here"></div>
75
+
76
+ <script src="https://unpkg.com/kotsa-spot-game-widget@1.0.0"></script>
77
+ <script>
78
+ // mount 는 위젯을 제거하는 unmount 함수를 반환합니다.
79
+ const unmount = KotsaSpotTheDifference.mount("#game-here");
80
+ // unmount();
81
+ </script>
82
+ ```
83
+
84
+ > `demo.html` 을 빌드 후 브라우저로 열어 실제 임베드 동작을 확인할 수 있습니다.
85
+
86
+ ## 게임 구성
87
+
88
+ - 총 **5단계**, 단계마다 숨은 차이 **5곳** (전체 25곳)
89
+ - 제한 시간 · 점수 · 콤보 보너스 · 힌트 3회 · 단계별 결과 · 최종 등급(S~D)
90
+ - 어린이 보호구역 / 전동킥보드 / 기차역 승강장 / 공항 보안검색 / 패러글라이딩
91
+ - 시작 인트로 3종: 시작 화면 · 개인정보 수집 동의 · 정보 입력(호스트 폼 제출)
92
+
93
+ ## 프로젝트 구조
94
+
95
+ ```
96
+ src/
97
+ ├─ embed.tsx # 라이브러리 진입점 (IIFE) — 자동 마운트 + 전역 API
98
+ ├─ mount.tsx # Shadow DOM 마운트 로직 (스타일 격리)
99
+ ├─ dev.tsx # 개발 서버 전용 진입점
100
+ ├─ index.css # Tailwind v4 + 테마 + 게임 애니메이션 (?inline 로 번들 내장)
101
+ ├─ components/
102
+ │ ├─ game/ # 게임 화면·로직 UI
103
+ │ │ ├─ game-app.tsx # 전체 흐름 (타이머·상태·토스트)
104
+ │ │ ├─ start-screen.tsx # 시작 인트로 3종 (시작·개인정보 동의·정보 입력)
105
+ │ │ ├─ game-hud.tsx # 점수·시간·힌트 HUD
106
+ │ │ ├─ difference-board.tsx # 두 그림 보드 + 클릭 판정
107
+ │ │ ├─ image-panel.tsx # 한 장의 그림 + 마커
108
+ │ │ ├─ stage-transition-overlay.tsx # 단계 결과(포털 없는 자체 오버레이)
109
+ │ │ ├─ result-screen.tsx # 최종 결과·등급
110
+ │ │ └─ game-toast.tsx # 위젯 내부 전용 토스트
111
+ │ └─ site/kotsa-mark.tsx # 엠블럼
112
+ └─ lib/
113
+ ├─ stages.ts # 스테이지 정의
114
+ ├─ game-types.ts # 공통 타입
115
+ ├─ game-config.ts # 점수 규칙·등급
116
+ ├─ game-reducer.ts # 게임 상태 머신
117
+ ├─ hit-test.ts # 클릭 정답 판정
118
+ ├─ host-form.ts # 호스트 사이트 입력 폼 채우기·제출
119
+ └─ assets.ts # asset/ 이미지 인라인
120
+ ```
121
+
122
+ ## 동작 원리 — 스타일 격리
123
+
124
+ - 위젯은 대상 요소에 **Shadow DOM** 을 붙이고 그 안에 렌더링합니다. host 사이트의
125
+ CSS 가 위젯에 스며들지 않고, 위젯 CSS 도 host 로 새어 나가지 않습니다.
126
+ - `index.css` 는 `?inline` 로 import 되어 **JS 번들 안에 문자열로 내장**됩니다.
127
+ (배포 파일은 JS 하나뿐 — 별도 CSS 링크 불필요)
128
+ - Tailwind v4 의 `@property` 규칙은 문서 전역 등록이 필요하므로 `document.head`
129
+ 로 한 번만 옮겨 주입하고, 나머지 규칙은 Shadow DOM 안에 둡니다.
130
+ - 반응형은 뷰포트가 아닌 **위젯 컨테이너 너비**(CSS container query)를 기준으로
131
+ 동작하므로, 좁은 칼럼에 임베드해도 레이아웃이 자연스럽게 맞춰집니다.
132
+
133
+ ## 그림·차이점 교체하기
134
+
135
+ 장면은 `asset/stageN-a.png`(원본) · `asset/stageN-b.png`(다른그림) 이미지를
136
+ 사용합니다. 그림을 바꾸려면 `asset/` 의 파일을 교체하고, `src/lib/stages.ts`
137
+ 의 `differences` 좌표(`x`·`y`·`r`, 이미지 기준 %)를 새 이미지에 맞게 잡으면
138
+ 됩니다. 개발 모드(`pnpm dev`)에서 그림을 클릭하면 콘솔에 클릭 좌표가
139
+ 출력되므로 그 값으로 보정하면 됩니다. (이미지는 빌드 시 base64 로 번들에
140
+ 인라인됩니다 — `asset/README.md` 참고.)
141
+
142
+ ---
143
+
144
+ > 본 프로젝트는 교통안전 교육용 데모입니다.