clawmate 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.
@@ -0,0 +1,396 @@
1
+ /**
2
+ * 픽셀 아트 랍스터(Claw) 캐릭터 렌더러
3
+ * 16x16 그리드 → CSS div로 렌더링 → 4x 확대 (64x64px)
4
+ *
5
+ * 색상 코드:
6
+ * 0 = 투명, 1 = primary(빨강), 2 = secondary(연빨강),
7
+ * 3 = dark(갈색), 4 = eye, 5 = pupil, 6 = claw 전용
8
+ */
9
+ const Character = (() => {
10
+ const PIXEL = 4;
11
+ const GRID = 16;
12
+ const SIZE = PIXEL * GRID;
13
+
14
+ // --- 프레임 데이터 (16x16 배열) ---
15
+ const FRAMES = {
16
+ idle: [
17
+ // Frame 0: 기본 자세 — 집게 열림
18
+ [
19
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
20
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
21
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
22
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
23
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
24
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
25
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
26
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
27
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
28
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
29
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
30
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
31
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
32
+ [0,0,0,3,3,0,3,3,3,3,0,3,3,0,0,0],
33
+ [0,0,3,3,0,0,0,3,3,0,0,0,3,3,0,0],
34
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
35
+ ],
36
+ // Frame 1: 집게 닫힘 (물결)
37
+ [
38
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
39
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
40
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
41
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
42
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
43
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
44
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
45
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
46
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
47
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
48
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
49
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
50
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
51
+ [0,0,0,3,3,0,3,3,3,3,0,3,3,0,0,0],
52
+ [0,0,3,3,0,0,0,3,3,0,0,0,3,3,0,0],
53
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
54
+ ],
55
+ ],
56
+
57
+ walk: [
58
+ // Frame 0: 왼발 앞
59
+ [
60
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
61
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
62
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
63
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
64
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
65
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
66
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
67
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
68
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
69
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
70
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
71
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
72
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
73
+ [0,0,3,3,0,0,3,3,3,3,0,0,3,3,0,0],
74
+ [0,3,3,0,0,0,0,3,3,0,0,0,0,3,3,0],
75
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
76
+ ],
77
+ // Frame 1: 오른발 앞
78
+ [
79
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
80
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
81
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
82
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
83
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
84
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
85
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
86
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
87
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
88
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
89
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
90
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
91
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
92
+ [0,0,0,3,3,0,0,3,3,0,0,3,3,0,0,0],
93
+ [0,0,0,0,3,3,0,0,0,0,3,3,0,0,0,0],
94
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
95
+ ],
96
+ // Frame 2: 왼발 뒤
97
+ [
98
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
99
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
100
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
101
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
102
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
103
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
104
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
105
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
106
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
107
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
108
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
109
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
110
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
111
+ [0,0,3,3,0,0,3,3,3,3,0,0,3,3,0,0],
112
+ [0,3,3,0,0,0,0,3,3,0,0,0,0,3,3,0],
113
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
114
+ ],
115
+ // Frame 3: 오른발 뒤
116
+ [
117
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
118
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
119
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
120
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
121
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
122
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
123
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
124
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
125
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
126
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
127
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
128
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
129
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
130
+ [0,0,0,3,3,0,0,3,3,0,0,3,3,0,0,0],
131
+ [0,0,0,0,3,3,0,0,0,0,3,3,0,0,0,0],
132
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
133
+ ],
134
+ ],
135
+
136
+ climb: [
137
+ // Frame 0: 기어오르기 포즈 1 (옆모습)
138
+ [
139
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
140
+ [0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0],
141
+ [0,0,0,6,0,0,6,0,0,0,0,0,0,0,0,0],
142
+ [0,0,0,6,0,0,6,0,0,0,0,0,0,0,0,0],
143
+ [0,0,0,0,6,6,1,1,0,0,0,0,0,0,0,0],
144
+ [0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0],
145
+ [0,0,0,0,1,4,5,1,1,0,0,0,0,0,0,0],
146
+ [0,0,0,0,1,4,5,1,1,1,0,0,0,0,0,0],
147
+ [0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0],
148
+ [0,0,0,1,2,1,1,1,1,0,0,0,0,0,0,0],
149
+ [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],
150
+ [0,0,0,0,3,0,3,0,0,0,0,0,0,0,0,0],
151
+ [0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0],
152
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
153
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
154
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
155
+ ],
156
+ // Frame 1: 기어오르기 포즈 2
157
+ [
158
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
159
+ [0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0],
160
+ [0,0,0,6,0,0,6,0,0,0,0,0,0,0,0,0],
161
+ [0,0,0,6,0,0,6,0,0,0,0,0,0,0,0,0],
162
+ [0,0,0,0,6,6,1,1,0,0,0,0,0,0,0,0],
163
+ [0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0],
164
+ [0,0,0,0,1,4,5,1,1,0,0,0,0,0,0,0],
165
+ [0,0,0,0,1,4,5,1,1,1,0,0,0,0,0,0],
166
+ [0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0],
167
+ [0,0,0,1,2,1,1,1,1,0,0,0,0,0,0,0],
168
+ [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0],
169
+ [0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0],
170
+ [0,0,0,0,3,0,3,0,0,0,0,0,0,0,0,0],
171
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
172
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
173
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
174
+ ],
175
+ ],
176
+
177
+ sleep: [
178
+ [
179
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
180
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
181
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
182
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
183
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
184
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
185
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
186
+ [0,0,0,1,1,3,3,1,1,3,3,1,1,0,0,0],
187
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
188
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
189
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
190
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
191
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
192
+ [0,0,0,3,3,0,3,3,3,3,0,3,3,0,0,0],
193
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
194
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
195
+ ],
196
+ ],
197
+
198
+ carry: [
199
+ // Frame 0: 파일 들고 걷기 1
200
+ [
201
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
202
+ [0,0,6,1,1,1,1,0,0,1,1,1,1,6,0,0],
203
+ [0,0,6,1,2,2,1,0,0,1,2,2,1,6,0,0],
204
+ [0,0,6,1,1,1,1,0,0,1,1,1,1,6,0,0],
205
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
206
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
207
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
208
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
209
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
210
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
211
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
212
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
213
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
214
+ [0,0,3,3,0,0,3,3,3,3,0,0,3,3,0,0],
215
+ [0,3,3,0,0,0,0,3,3,0,0,0,0,3,3,0],
216
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
217
+ ],
218
+ // Frame 1: 파일 들고 걷기 2
219
+ [
220
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
221
+ [0,0,6,1,1,1,1,0,0,1,1,1,1,6,0,0],
222
+ [0,0,6,1,2,2,1,0,0,1,2,2,1,6,0,0],
223
+ [0,0,6,1,1,1,1,0,0,1,1,1,1,6,0,0],
224
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
225
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
226
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
227
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
228
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
229
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
230
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
231
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
232
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
233
+ [0,0,0,3,3,0,0,3,3,0,0,3,3,0,0,0],
234
+ [0,0,0,0,3,3,0,0,0,0,3,3,0,0,0,0],
235
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
236
+ ],
237
+ ],
238
+
239
+ scared: [
240
+ // Frame 0: 놀람 — 눈 크게
241
+ [
242
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
243
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
244
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
245
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
246
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
247
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
248
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
249
+ [0,0,0,1,4,4,5,1,1,4,4,5,1,0,0,0],
250
+ [0,0,0,1,4,4,5,1,1,4,4,5,1,0,0,0],
251
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
252
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
253
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
254
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
255
+ [0,0,3,3,0,0,3,3,3,3,0,0,3,3,0,0],
256
+ [0,3,3,0,0,0,0,3,3,0,0,0,0,3,3,0],
257
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
258
+ ],
259
+ // Frame 1: 뒤로 움찔
260
+ [
261
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
262
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
263
+ [0,0,6,0,0,6,0,0,0,0,6,0,0,6,0,0],
264
+ [0,0,6,0,0,6,0,0,0,0,6,0,0,6,0,0],
265
+ [0,0,0,6,6,0,0,0,0,0,0,6,6,0,0,0],
266
+ [0,0,0,0,6,1,1,0,0,1,1,6,0,0,0,0],
267
+ [0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
268
+ [0,0,0,0,1,4,4,5,4,4,5,1,0,0,0,0],
269
+ [0,0,0,0,1,4,4,5,4,4,5,1,0,0,0,0],
270
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
271
+ [0,0,0,1,2,1,1,1,1,1,1,2,1,0,0,0],
272
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
273
+ [0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
274
+ [0,0,0,0,3,3,0,3,3,0,3,3,0,0,0,0],
275
+ [0,0,0,3,3,0,0,0,0,0,0,3,3,0,0,0],
276
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
277
+ ],
278
+ ],
279
+
280
+ excited: [
281
+ // Frame 0: 점프 업
282
+ [
283
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
284
+ [0,6,6,0,0,0,0,0,0,0,0,0,0,6,6,0],
285
+ [6,0,0,6,0,0,0,0,0,0,0,0,6,0,0,6],
286
+ [6,0,0,6,0,0,0,0,0,0,0,0,6,0,0,6],
287
+ [0,6,6,0,0,0,0,0,0,0,0,0,0,6,6,0],
288
+ [0,0,6,1,1,0,0,0,0,0,0,1,1,6,0,0],
289
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
290
+ [0,0,1,1,4,5,1,1,1,1,4,5,1,1,0,0],
291
+ [0,0,1,1,4,5,1,1,1,1,4,5,1,1,0,0],
292
+ [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
293
+ [0,1,2,1,1,1,1,1,1,1,1,1,1,2,1,0],
294
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
295
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
296
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
297
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
298
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
299
+ ],
300
+ // Frame 1: 착지
301
+ [
302
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
303
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
304
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
305
+ [0,6,0,0,6,0,0,0,0,0,0,6,0,0,6,0],
306
+ [0,0,6,6,0,0,0,0,0,0,0,0,6,6,0,0],
307
+ [0,0,0,6,1,1,0,0,0,0,1,1,6,0,0,0],
308
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
309
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
310
+ [0,0,0,1,1,4,5,1,1,4,5,1,1,0,0,0],
311
+ [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0],
312
+ [0,0,1,2,1,1,1,1,1,1,1,1,2,1,0,0],
313
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],
314
+ [0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0],
315
+ [0,3,3,3,3,0,3,3,3,3,0,3,3,3,3,0],
316
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
317
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
318
+ ],
319
+ ],
320
+ };
321
+
322
+ // 상태 → 프레임셋 매핑
323
+ const STATE_FRAMES = {
324
+ idle: 'idle',
325
+ walking: 'walk',
326
+ climbing_up: 'climb',
327
+ climbing_down: 'climb',
328
+ ceiling_walk: 'walk',
329
+ sleeping: 'sleep',
330
+ carrying: 'carry',
331
+ playing: 'idle',
332
+ interacting: 'excited',
333
+ scared: 'scared',
334
+ excited: 'excited',
335
+ };
336
+
337
+ let currentCanvas = null;
338
+ let currentColorMap = null;
339
+
340
+ function createCanvas(container) {
341
+ const canvas = document.createElement('canvas');
342
+ canvas.width = SIZE;
343
+ canvas.height = SIZE;
344
+ canvas.style.width = SIZE + 'px';
345
+ canvas.style.height = SIZE + 'px';
346
+ canvas.style.imageRendering = 'pixelated';
347
+ container.appendChild(canvas);
348
+ currentCanvas = canvas;
349
+ return canvas;
350
+ }
351
+
352
+ function setColorMap(colors) {
353
+ currentColorMap = {
354
+ 0: 'transparent',
355
+ 1: colors.primary,
356
+ 2: colors.secondary,
357
+ 3: colors.dark,
358
+ 4: colors.eye,
359
+ 5: colors.pupil,
360
+ 6: colors.claw || colors.primary,
361
+ };
362
+ }
363
+
364
+ function renderFrame(state, frameIndex, flipX = false) {
365
+ if (!currentCanvas || !currentColorMap) return;
366
+ const ctx = currentCanvas.getContext('2d');
367
+ ctx.clearRect(0, 0, SIZE, SIZE);
368
+
369
+ const frameSet = STATE_FRAMES[state] || 'idle';
370
+ const frames = FRAMES[frameSet];
371
+ if (!frames) return;
372
+
373
+ const frame = frames[frameIndex % frames.length];
374
+ if (!frame) return;
375
+
376
+ for (let y = 0; y < GRID; y++) {
377
+ for (let x = 0; x < GRID; x++) {
378
+ const colorCode = frame[y][x];
379
+ if (colorCode === 0) continue;
380
+ const color = currentColorMap[colorCode] || 'transparent';
381
+ if (color === 'transparent') continue;
382
+
383
+ ctx.fillStyle = color;
384
+ const drawX = flipX ? (GRID - 1 - x) * PIXEL : x * PIXEL;
385
+ ctx.fillRect(drawX, y * PIXEL, PIXEL, PIXEL);
386
+ }
387
+ }
388
+ }
389
+
390
+ function getFrameCount(state) {
391
+ const frameSet = STATE_FRAMES[state] || 'idle';
392
+ return (FRAMES[frameSet] || FRAMES.idle).length;
393
+ }
394
+
395
+ return { createCanvas, setColorMap, renderFrame, getFrameCount, SIZE, FRAMES, STATE_FRAMES };
396
+ })();
@@ -0,0 +1,164 @@
1
+ /**
2
+ * 마우스/클릭/드래그 상호작용 시스템
3
+ *
4
+ * AI 연결 시: 이벤트를 OpenClaw에 전달 → AI가 반응 결정
5
+ * AI 미연결 시: 자율 반응 (랜덤 FSM)
6
+ */
7
+ const Interactions = (() => {
8
+ let isDragging = false;
9
+ let dragOffsetX = 0;
10
+ let dragOffsetY = 0;
11
+ let dragStartPos = null;
12
+ let clickCount = 0;
13
+ let clickTimer = null;
14
+ let lastCursorCheck = 0;
15
+ const CURSOR_CHECK_INTERVAL = 500;
16
+
17
+ function init() {
18
+ const pet = document.getElementById('pet-container');
19
+ if (!pet) return;
20
+
21
+ pet.addEventListener('mouseenter', () => {
22
+ window.clawmate.setClickThrough(false);
23
+ });
24
+
25
+ pet.addEventListener('mouseleave', () => {
26
+ if (!isDragging) {
27
+ window.clawmate.setClickThrough(true);
28
+ }
29
+ });
30
+
31
+ pet.addEventListener('mousedown', onMouseDown);
32
+ document.addEventListener('mousemove', onMouseMove);
33
+ document.addEventListener('mouseup', onMouseUp);
34
+ document.addEventListener('mousemove', onGlobalMouseMove);
35
+ }
36
+
37
+ function onMouseDown(e) {
38
+ e.preventDefault();
39
+ e.stopPropagation();
40
+
41
+ const pos = PetEngine.getPosition();
42
+ dragOffsetX = e.clientX - pos.x;
43
+ dragOffsetY = e.clientY - pos.y;
44
+ dragStartPos = { x: pos.x, y: pos.y };
45
+ isDragging = true;
46
+
47
+ const pet = document.getElementById('pet-container');
48
+ pet.classList.add('dragging');
49
+ PetEngine.stop();
50
+
51
+ clickCount++;
52
+ clearTimeout(clickTimer);
53
+ clickTimer = setTimeout(() => {
54
+ if (clickCount >= 3) {
55
+ onTripleClick();
56
+ } else if (clickCount === 1) {
57
+ onSingleClick();
58
+ }
59
+ clickCount = 0;
60
+ }, 400);
61
+ }
62
+
63
+ function onMouseMove(e) {
64
+ if (!isDragging) return;
65
+ PetEngine.setPosition(e.clientX - dragOffsetX, e.clientY - dragOffsetY);
66
+ }
67
+
68
+ function onMouseUp() {
69
+ if (!isDragging) return;
70
+ isDragging = false;
71
+
72
+ const pet = document.getElementById('pet-container');
73
+ pet.classList.remove('dragging');
74
+
75
+ const endPos = PetEngine.getPosition();
76
+ PetEngine.snapToNearestEdge();
77
+ StateMachine.forceState('idle');
78
+ PetEngine.start();
79
+
80
+ window.clawmate.setClickThrough(true);
81
+
82
+ // AI에 드래그 이벤트 리포트
83
+ if (dragStartPos) {
84
+ AIController.reportDrag(dragStartPos, endPos);
85
+ }
86
+ }
87
+
88
+ function onSingleClick() {
89
+ const pos = PetEngine.getPosition();
90
+
91
+ // AI에 클릭 이벤트 리포트
92
+ AIController.reportClick(pos);
93
+
94
+ // AI 연결 시: AI가 반응 결정 (아무것도 안 함, AI 응답 대기)
95
+ // AI 미연결 시: 자율 반응
96
+ if (AIController.isAutonomous()) {
97
+ StateMachine.forceState('interacting');
98
+ Speech.show(Speech.getReactionMessage());
99
+ }
100
+
101
+ Memory.recordClick();
102
+ spawnHeartEffect();
103
+ }
104
+
105
+ function onTripleClick() {
106
+ if (typeof ModeManager !== 'undefined') {
107
+ ModeManager.toggle();
108
+ }
109
+ }
110
+
111
+ function onGlobalMouseMove(e) {
112
+ if (isDragging) return;
113
+ const now = Date.now();
114
+ if (now - lastCursorCheck < CURSOR_CHECK_INTERVAL) return;
115
+ lastCursorCheck = now;
116
+
117
+ const pos = PetEngine.getPosition();
118
+ const dist = Math.hypot(e.clientX - (pos.x + 32), e.clientY - (pos.y + 32));
119
+
120
+ if (dist < 100) {
121
+ // AI에 커서 접근 리포트
122
+ AIController.reportCursorNear(dist);
123
+
124
+ // AI 미연결 시: 자율 반응
125
+ if (AIController.isAutonomous()) {
126
+ const state = StateMachine.getState();
127
+ if (state === 'idle' || state === 'walking') {
128
+ if (Math.random() < 0.5) {
129
+ StateMachine.forceState('scared');
130
+ PetEngine.setDirection(e.clientX > pos.x + 32 ? -1 : 1);
131
+ } else {
132
+ StateMachine.forceState('excited');
133
+ Speech.show(Speech.getGreetingMessage());
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ function spawnHeartEffect() {
141
+ const pos = PetEngine.getPosition();
142
+ const heart = document.createElement('div');
143
+ heart.className = 'heart-effect';
144
+ heart.textContent = '\u2764\uFE0F';
145
+ heart.style.left = (pos.x + 20 + Math.random() * 24) + 'px';
146
+ heart.style.top = (pos.y - 10) + 'px';
147
+ document.getElementById('world').appendChild(heart);
148
+ setTimeout(() => heart.remove(), 1000);
149
+ }
150
+
151
+ function spawnStarEffect() {
152
+ const pos = PetEngine.getPosition();
153
+ for (let i = 0; i < 4; i++) {
154
+ const star = document.createElement('div');
155
+ star.className = 'star-effect';
156
+ star.style.left = (pos.x + Math.random() * 64) + 'px';
157
+ star.style.top = (pos.y + Math.random() * 64) + 'px';
158
+ document.getElementById('world').appendChild(star);
159
+ setTimeout(() => star.remove(), 600);
160
+ }
161
+ }
162
+
163
+ return { init, spawnHeartEffect, spawnStarEffect };
164
+ })();