@doan-labs/peek 0.1.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 +38 -0
- package/dist/animate.d.ts +58 -0
- package/dist/draw.d.ts +69 -0
- package/dist/identity.d.ts +55 -0
- package/dist/identity.js +398 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1700 -0
- package/dist/peek.d.ts +13 -0
- package/dist/svg.d.ts +33 -0
- package/dist/svg.js +1053 -0
- package/dist/tables.d.ts +258 -0
- package/package.json +70 -0
- package/src/animate.ts +670 -0
- package/src/draw.ts +849 -0
- package/src/identity.ts +147 -0
- package/src/index.ts +28 -0
- package/src/peek.tsx +98 -0
- package/src/svg.ts +94 -0
- package/src/tables.ts +414 -0
package/src/tables.ts
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The peek style's tables. Faces, inks and expressions are transcribed from
|
|
3
|
+
* the Peek v1.2 page (peek.html); the new part types are drawn in the same
|
|
4
|
+
* language and driven by the same channels.
|
|
5
|
+
*
|
|
6
|
+
* Every list is append-only and ordered: object key order is list order, and
|
|
7
|
+
* the hash indexes into it. Never reorder or remove an entry. A version pins
|
|
8
|
+
* how much of each list it may pick from (VERSIONS), so growing a list means
|
|
9
|
+
* a new version, never a new result for an old one.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
type Pt = readonly [number, number]
|
|
13
|
+
|
|
14
|
+
/** Structure inks: never a body color. Signal stays in the interface. */
|
|
15
|
+
export const INK = {
|
|
16
|
+
ink: '#1A1918',
|
|
17
|
+
bone: '#F3F0E8',
|
|
18
|
+
paper: '#FFFDF8',
|
|
19
|
+
} as const
|
|
20
|
+
|
|
21
|
+
export type FaceGeom = {
|
|
22
|
+
/** `stroke` rounds the corners: a round-join outline in the body ink. */
|
|
23
|
+
body:
|
|
24
|
+
| { readonly d: string; readonly stroke?: number }
|
|
25
|
+
| { readonly circle: readonly [number, number, number] }
|
|
26
|
+
bottom: number
|
|
27
|
+
/** How far the body sinks below the floor at rest. */
|
|
28
|
+
sink: number
|
|
29
|
+
eyes: readonly [Pt, Pt]
|
|
30
|
+
rx: number
|
|
31
|
+
ry: number
|
|
32
|
+
pr: number
|
|
33
|
+
brow: {
|
|
34
|
+
readonly y: number
|
|
35
|
+
readonly hw: number
|
|
36
|
+
readonly arch: number
|
|
37
|
+
readonly w: number
|
|
38
|
+
}
|
|
39
|
+
cheeks: readonly [Pt, Pt]
|
|
40
|
+
crx: number
|
|
41
|
+
cry: number
|
|
42
|
+
mouth: {
|
|
43
|
+
readonly x: number
|
|
44
|
+
readonly y: number
|
|
45
|
+
readonly w: number
|
|
46
|
+
readonly d: number
|
|
47
|
+
readonly sw: number
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The crown: the visible outline above the eyes, as a convex polygon grown
|
|
51
|
+
* by `r` (a point grown by r is a circle). `poly[0]` is the top and the
|
|
52
|
+
* polygon runs clockwise. Every trait sits on this outline, so any trait
|
|
53
|
+
* fits any face.
|
|
54
|
+
*/
|
|
55
|
+
crown: { readonly poly: readonly Pt[]; readonly r: number }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const FACES = {
|
|
59
|
+
diamond: {
|
|
60
|
+
body: { d: 'M170 20L320 170L170 320L20 170Z' },
|
|
61
|
+
bottom: 320,
|
|
62
|
+
sink: 30,
|
|
63
|
+
eyes: [
|
|
64
|
+
[132.5, 155],
|
|
65
|
+
[207.5, 155],
|
|
66
|
+
],
|
|
67
|
+
rx: 20,
|
|
68
|
+
ry: 27.5,
|
|
69
|
+
pr: 10,
|
|
70
|
+
brow: { y: 102.5, hw: 18.75, arch: 15, w: 5.62 },
|
|
71
|
+
cheeks: [
|
|
72
|
+
[117.5, 200],
|
|
73
|
+
[222.5, 200],
|
|
74
|
+
],
|
|
75
|
+
crx: 11.25,
|
|
76
|
+
cry: 5.62,
|
|
77
|
+
mouth: { x: 170, y: 218.75, w: 15, d: 16.25, sw: 4.38 },
|
|
78
|
+
crown: {
|
|
79
|
+
poly: [
|
|
80
|
+
[170, 20],
|
|
81
|
+
[320, 170],
|
|
82
|
+
[170, 320],
|
|
83
|
+
[20, 170],
|
|
84
|
+
],
|
|
85
|
+
r: 0,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
semicircle: {
|
|
89
|
+
body: { d: 'M0 255A170 170 0 0 1 340 255Z' },
|
|
90
|
+
bottom: 255,
|
|
91
|
+
sink: 0,
|
|
92
|
+
eyes: [
|
|
93
|
+
[102.5, 175],
|
|
94
|
+
[237.5, 175],
|
|
95
|
+
],
|
|
96
|
+
rx: 30,
|
|
97
|
+
ry: 25,
|
|
98
|
+
pr: 11.25,
|
|
99
|
+
brow: { y: 127.5, hw: 25, arch: 15, w: 5.62 },
|
|
100
|
+
cheeks: [
|
|
101
|
+
[55, 212.5],
|
|
102
|
+
[285, 212.5],
|
|
103
|
+
],
|
|
104
|
+
crx: 11.25,
|
|
105
|
+
cry: 5.62,
|
|
106
|
+
mouth: { x: 170, y: 221.25, w: 16.25, d: 16.25, sw: 4.38 },
|
|
107
|
+
crown: { poly: [[170, 255]], r: 170 },
|
|
108
|
+
},
|
|
109
|
+
circle: {
|
|
110
|
+
body: { circle: [170, 170, 150] },
|
|
111
|
+
bottom: 320,
|
|
112
|
+
sink: 20,
|
|
113
|
+
eyes: [
|
|
114
|
+
[112.8, 162.2],
|
|
115
|
+
[227.2, 162.2],
|
|
116
|
+
],
|
|
117
|
+
rx: 29.9,
|
|
118
|
+
ry: 29.9,
|
|
119
|
+
pr: 13,
|
|
120
|
+
brow: { y: 110.2, hw: 23.4, arch: 15.6, w: 5.85 },
|
|
121
|
+
cheeks: [
|
|
122
|
+
[84.2, 203.8],
|
|
123
|
+
[255.8, 203.8],
|
|
124
|
+
],
|
|
125
|
+
crx: 11.7,
|
|
126
|
+
cry: 5.85,
|
|
127
|
+
mouth: { x: 170, y: 223.3, w: 16.9, d: 16.9, sw: 4.55 },
|
|
128
|
+
crown: { poly: [[170, 170]], r: 150 },
|
|
129
|
+
},
|
|
130
|
+
/* The v2.1 spec (M50 12L92 88H8Z on a 100u grid, 8u round joins, eyes at
|
|
131
|
+
* 62u) scaled x3.4 about the centre. */
|
|
132
|
+
triangle: {
|
|
133
|
+
body: { d: 'M170 40.8L312.8 299.2L27.2 299.2Z', stroke: 27.2 },
|
|
134
|
+
bottom: 312.8,
|
|
135
|
+
sink: 0,
|
|
136
|
+
eyes: [
|
|
137
|
+
[132.6, 210.8],
|
|
138
|
+
[207.4, 210.8],
|
|
139
|
+
],
|
|
140
|
+
rx: 20.4,
|
|
141
|
+
ry: 27.2,
|
|
142
|
+
pr: 10,
|
|
143
|
+
brow: { y: 166.6, hw: 18.7, arch: 15.3, w: 5.62 },
|
|
144
|
+
cheeks: [
|
|
145
|
+
[98.6, 238],
|
|
146
|
+
[241.4, 238],
|
|
147
|
+
],
|
|
148
|
+
crx: 11.5,
|
|
149
|
+
cry: 5.75,
|
|
150
|
+
mouth: { x: 170, y: 254, w: 17, d: 16.25, sw: 4.38 },
|
|
151
|
+
crown: {
|
|
152
|
+
poly: [
|
|
153
|
+
[170, 40.8],
|
|
154
|
+
[312.8, 299.2],
|
|
155
|
+
[27.2, 299.2],
|
|
156
|
+
],
|
|
157
|
+
r: 13.6,
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
} as const satisfies Record<string, FaceGeom>
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Body inks, each with a deep partner at the same hue. The body fills the
|
|
164
|
+
* face and the lids, the deep ink carries cheeks and trait. The first four
|
|
165
|
+
* are from v1.2; butter, rose and aqua are provisional, matched to the same
|
|
166
|
+
* OKLCH lightness and chroma.
|
|
167
|
+
*/
|
|
168
|
+
export const COLORS = {
|
|
169
|
+
lavender: { body: '#D8CDF0', deep: '#BDAEE6' },
|
|
170
|
+
fog: { body: '#C8D6E8', deep: '#A8BCDC' },
|
|
171
|
+
clay: { body: '#F1CDBF', deep: '#E2A893' },
|
|
172
|
+
mint: { body: '#CFE7D6', deep: '#A5CDB1' },
|
|
173
|
+
butter: { body: '#ECE2B9', deep: '#D9C284' },
|
|
174
|
+
rose: { body: '#EFCAD7', deep: '#DFA4BA' },
|
|
175
|
+
aqua: { body: '#BDE1E5', deep: '#8FC7D1' },
|
|
176
|
+
} as const
|
|
177
|
+
|
|
178
|
+
/** Discrete anatomy. Each part reads every channel its feature owns. */
|
|
179
|
+
export const PARTS = {
|
|
180
|
+
eyes: ['oval', 'bead', 'ring'],
|
|
181
|
+
brows: ['arch', 'bar', 'wedge', 'dash'],
|
|
182
|
+
mouth: ['poly', 'round', 'line', 'box'],
|
|
183
|
+
cheeks: ['oval', 'dots', 'lines'],
|
|
184
|
+
trait: ['square', 'fin', 'ring', 'dot', 'peak'],
|
|
185
|
+
} as const
|
|
186
|
+
|
|
187
|
+
export type Face = keyof typeof FACES
|
|
188
|
+
export type Color = keyof typeof COLORS
|
|
189
|
+
export type Part = keyof typeof PARTS
|
|
190
|
+
export type Eyes = (typeof PARTS.eyes)[number]
|
|
191
|
+
export type Brows = (typeof PARTS.brows)[number]
|
|
192
|
+
export type Mouth = (typeof PARTS.mouth)[number]
|
|
193
|
+
export type Cheeks = (typeof PARTS.cheeks)[number]
|
|
194
|
+
export type Trait = (typeof PARTS.trait)[number]
|
|
195
|
+
export type Axis = 'face' | 'color' | Part
|
|
196
|
+
|
|
197
|
+
/** How much of each list a version may pick from. Append-only too. */
|
|
198
|
+
export const VERSIONS: Record<number, Record<Axis, number>> = {
|
|
199
|
+
1: { face: 4, color: 7, eyes: 3, brows: 4, mouth: 4, cheeks: 3, trait: 5 },
|
|
200
|
+
}
|
|
201
|
+
export const LATEST = 1
|
|
202
|
+
|
|
203
|
+
/* ---------- state: channels and the 11 expressions ---------- */
|
|
204
|
+
|
|
205
|
+
export const GROUPS = {
|
|
206
|
+
eyes: ['lid', 'lower', 'lidTilt', 'eyeS', 'lidAsym'],
|
|
207
|
+
pupil: ['pupil', 'gx', 'gy', 'shine'],
|
|
208
|
+
brows: ['browY', 'browTilt', 'browArch', 'browW', 'browAsym'],
|
|
209
|
+
mouth: ['mw', 'mt', 'mb', 'mx', 'my', 'mk'],
|
|
210
|
+
body: ['alt', 'rot', 'x', 'sx', 'sy'],
|
|
211
|
+
extra: ['blush', 'hair', 'dim', 'thing'],
|
|
212
|
+
} as const
|
|
213
|
+
export type Group = keyof typeof GROUPS
|
|
214
|
+
export type Channel = (typeof GROUPS)[Group][number]
|
|
215
|
+
export type Channels = Record<Channel, number>
|
|
216
|
+
|
|
217
|
+
const BASE: Channels = {
|
|
218
|
+
alt: 0,
|
|
219
|
+
rot: 0,
|
|
220
|
+
x: 0,
|
|
221
|
+
sx: 1,
|
|
222
|
+
sy: 1,
|
|
223
|
+
lid: 0.1,
|
|
224
|
+
lower: 0,
|
|
225
|
+
lidTilt: 0,
|
|
226
|
+
eyeS: 1,
|
|
227
|
+
lidAsym: 0,
|
|
228
|
+
pupil: 1,
|
|
229
|
+
gx: 0,
|
|
230
|
+
gy: 0,
|
|
231
|
+
shine: 0.7,
|
|
232
|
+
browY: 0,
|
|
233
|
+
browTilt: 0,
|
|
234
|
+
browArch: 0.4,
|
|
235
|
+
browW: 1,
|
|
236
|
+
browAsym: 0,
|
|
237
|
+
mw: 0.72,
|
|
238
|
+
mt: 0,
|
|
239
|
+
mb: 0.5,
|
|
240
|
+
mx: 0,
|
|
241
|
+
my: 0,
|
|
242
|
+
mk: 0,
|
|
243
|
+
blush: 0,
|
|
244
|
+
hair: 0,
|
|
245
|
+
dim: 0,
|
|
246
|
+
thing: 0,
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const S = (o: Partial<Channels>): Readonly<Channels> => ({ ...BASE, ...o })
|
|
250
|
+
export const EXPRESSIONS = {
|
|
251
|
+
normal: S({}),
|
|
252
|
+
happy: S({
|
|
253
|
+
lid: 0,
|
|
254
|
+
lower: 0.42,
|
|
255
|
+
shine: 1,
|
|
256
|
+
gy: -0.05,
|
|
257
|
+
browY: -5,
|
|
258
|
+
browArch: 1,
|
|
259
|
+
mw: 1,
|
|
260
|
+
mb: 1,
|
|
261
|
+
blush: 1,
|
|
262
|
+
hair: 0.45,
|
|
263
|
+
alt: 0.05,
|
|
264
|
+
}),
|
|
265
|
+
sad: S({
|
|
266
|
+
lid: 0.42,
|
|
267
|
+
lidTilt: 16,
|
|
268
|
+
pupil: 0.95,
|
|
269
|
+
gy: 0.8,
|
|
270
|
+
shine: 0,
|
|
271
|
+
browY: 3,
|
|
272
|
+
browTilt: 14,
|
|
273
|
+
browArch: 0,
|
|
274
|
+
mw: 0.8,
|
|
275
|
+
mt: -0.55,
|
|
276
|
+
mb: -0.55,
|
|
277
|
+
my: 6,
|
|
278
|
+
alt: -0.16,
|
|
279
|
+
sy: 0.985,
|
|
280
|
+
hair: -0.75,
|
|
281
|
+
}),
|
|
282
|
+
angry: S({
|
|
283
|
+
lid: 0.34,
|
|
284
|
+
lidTilt: -22,
|
|
285
|
+
lower: 0.12,
|
|
286
|
+
pupil: 0.82,
|
|
287
|
+
gy: 0.1,
|
|
288
|
+
shine: 0,
|
|
289
|
+
browY: 5,
|
|
290
|
+
browTilt: -21,
|
|
291
|
+
browArch: 0,
|
|
292
|
+
browW: 1.3,
|
|
293
|
+
mw: 0.8,
|
|
294
|
+
mt: -0.08,
|
|
295
|
+
mb: -0.08,
|
|
296
|
+
my: 3,
|
|
297
|
+
sx: 1.02,
|
|
298
|
+
sy: 0.98,
|
|
299
|
+
hair: 0.25,
|
|
300
|
+
}),
|
|
301
|
+
sleepy: S({
|
|
302
|
+
lid: 1,
|
|
303
|
+
lidTilt: 4,
|
|
304
|
+
pupil: 0.9,
|
|
305
|
+
gy: 0.5,
|
|
306
|
+
shine: 0,
|
|
307
|
+
browY: 6,
|
|
308
|
+
browTilt: 3,
|
|
309
|
+
browArch: 0.15,
|
|
310
|
+
browW: 0.9,
|
|
311
|
+
mw: 0.35,
|
|
312
|
+
mt: -0.3,
|
|
313
|
+
mb: 0.3,
|
|
314
|
+
my: 2,
|
|
315
|
+
alt: -1.12,
|
|
316
|
+
rot: -3,
|
|
317
|
+
hair: -1,
|
|
318
|
+
}),
|
|
319
|
+
curious: S({
|
|
320
|
+
lid: 0,
|
|
321
|
+
eyeS: 1.06,
|
|
322
|
+
pupil: 1.05,
|
|
323
|
+
shine: 1,
|
|
324
|
+
browY: -3,
|
|
325
|
+
browAsym: 9,
|
|
326
|
+
browArch: 0.8,
|
|
327
|
+
mw: 0.38,
|
|
328
|
+
mt: -0.36,
|
|
329
|
+
mb: 0.36,
|
|
330
|
+
rot: 6,
|
|
331
|
+
alt: -0.32,
|
|
332
|
+
hair: 0.3,
|
|
333
|
+
thing: 1,
|
|
334
|
+
}),
|
|
335
|
+
surprised: S({
|
|
336
|
+
lid: 0,
|
|
337
|
+
eyeS: 1.2,
|
|
338
|
+
pupil: 0.66,
|
|
339
|
+
shine: 0.8,
|
|
340
|
+
browY: -13,
|
|
341
|
+
browArch: 1,
|
|
342
|
+
mw: 0.55,
|
|
343
|
+
mt: -0.62,
|
|
344
|
+
mb: 0.62,
|
|
345
|
+
alt: 0.36,
|
|
346
|
+
hair: 1,
|
|
347
|
+
}),
|
|
348
|
+
excited: S({
|
|
349
|
+
lid: 0,
|
|
350
|
+
lower: 0.5,
|
|
351
|
+
eyeS: 1.08,
|
|
352
|
+
pupil: 1.08,
|
|
353
|
+
shine: 1,
|
|
354
|
+
browY: -9,
|
|
355
|
+
browArch: 1,
|
|
356
|
+
mw: 1.15,
|
|
357
|
+
mb: 1.3,
|
|
358
|
+
blush: 1,
|
|
359
|
+
hair: 1,
|
|
360
|
+
alt: 0.12,
|
|
361
|
+
}),
|
|
362
|
+
confused: S({
|
|
363
|
+
lid: 0.22,
|
|
364
|
+
lidAsym: 0.28,
|
|
365
|
+
lidTilt: -4,
|
|
366
|
+
pupil: 0.92,
|
|
367
|
+
gx: -0.35,
|
|
368
|
+
gy: -0.45,
|
|
369
|
+
shine: 0.3,
|
|
370
|
+
browY: -2,
|
|
371
|
+
browAsym: 11,
|
|
372
|
+
browTilt: -5,
|
|
373
|
+
browArch: 0.3,
|
|
374
|
+
mw: 0.6,
|
|
375
|
+
mt: -0.1,
|
|
376
|
+
mb: 0.12,
|
|
377
|
+
mx: 5,
|
|
378
|
+
mk: 13,
|
|
379
|
+
rot: -7,
|
|
380
|
+
alt: -0.05,
|
|
381
|
+
hair: 0.1,
|
|
382
|
+
}),
|
|
383
|
+
bored: S({
|
|
384
|
+
lid: 0.5,
|
|
385
|
+
pupil: 0.9,
|
|
386
|
+
gx: -0.55,
|
|
387
|
+
gy: 0.25,
|
|
388
|
+
shine: 0,
|
|
389
|
+
browY: 3,
|
|
390
|
+
browArch: 0.1,
|
|
391
|
+
mw: 0.55,
|
|
392
|
+
mt: 0,
|
|
393
|
+
mb: 0.04,
|
|
394
|
+
mx: -5,
|
|
395
|
+
alt: -0.34,
|
|
396
|
+
hair: -0.45,
|
|
397
|
+
dim: 1,
|
|
398
|
+
}),
|
|
399
|
+
attentive: S({
|
|
400
|
+
lid: 0,
|
|
401
|
+
eyeS: 1.1,
|
|
402
|
+
pupil: 0.8,
|
|
403
|
+
gy: -0.1,
|
|
404
|
+
shine: 1,
|
|
405
|
+
browY: -7,
|
|
406
|
+
browArch: 0.7,
|
|
407
|
+
mw: 0.55,
|
|
408
|
+
mb: 0.4,
|
|
409
|
+
alt: 0.15,
|
|
410
|
+
sy: 1.03,
|
|
411
|
+
hair: 0.65,
|
|
412
|
+
}),
|
|
413
|
+
} as const
|
|
414
|
+
export type Expression = keyof typeof EXPRESSIONS
|