@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/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Peek
|
|
2
|
+
|
|
3
|
+
A name in, a face out. Deterministic SVG avatars by Doan Labs.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @doan-labs/peek
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## React 19
|
|
10
|
+
|
|
11
|
+
Install React 19 or newer in your app, then render a face:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Peek } from '@doan-labs/peek'
|
|
15
|
+
|
|
16
|
+
<Peek name='Linh' size={96} expression='happy' />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Use `animate` for blinking and expression transitions, and
|
|
20
|
+
`gaze='pointer'` to follow the pointer. Animation respects reduced motion.
|
|
21
|
+
|
|
22
|
+
## Plain SVG, without React
|
|
23
|
+
|
|
24
|
+
The SVG and identity entry points have no runtime dependencies:
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
import { toSvg } from '@doan-labs/peek/svg'
|
|
28
|
+
import { identify } from '@doan-labs/peek/identity'
|
|
29
|
+
|
|
30
|
+
const svg = toSvg('Linh', { size: 96, expression: 'happy' })
|
|
31
|
+
const identity = identify('Linh')
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The root entry point also exports `toSvg` and `identify` for React apps.
|
|
35
|
+
The same normalized name and options produce the same SVG every time.
|
|
36
|
+
|
|
37
|
+
See the [documentation](https://peek.doan-labs.com/docs) for options,
|
|
38
|
+
expressions, identity axes and versioned styles.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type Drawable, type DrawOptions, type Gaze, type Node } from './draw.js';
|
|
2
|
+
import { type Expression } from './tables.js';
|
|
3
|
+
/**
|
|
4
|
+
* One live avatar bound to an SVG that already shows `tree`. Starts settled
|
|
5
|
+
* in `expression`, the same pose the server painted.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Live {
|
|
8
|
+
private svg;
|
|
9
|
+
private who;
|
|
10
|
+
private opts;
|
|
11
|
+
visible: boolean;
|
|
12
|
+
private state;
|
|
13
|
+
private reduced;
|
|
14
|
+
private nodes;
|
|
15
|
+
private prev;
|
|
16
|
+
private io;
|
|
17
|
+
private clock;
|
|
18
|
+
private enteredAt;
|
|
19
|
+
private val;
|
|
20
|
+
private vel;
|
|
21
|
+
private base;
|
|
22
|
+
private spr;
|
|
23
|
+
private out;
|
|
24
|
+
private queue;
|
|
25
|
+
private bumps;
|
|
26
|
+
private blinkAt;
|
|
27
|
+
private blinkT;
|
|
28
|
+
private blinkDur;
|
|
29
|
+
private blinkV;
|
|
30
|
+
private doubleBlink;
|
|
31
|
+
private saccAt;
|
|
32
|
+
private sacc;
|
|
33
|
+
private nodAt;
|
|
34
|
+
private lookThing;
|
|
35
|
+
private lag;
|
|
36
|
+
private fixed;
|
|
37
|
+
private watch;
|
|
38
|
+
private rect;
|
|
39
|
+
constructor(svg: SVGSVGElement, tree: Node, who: Drawable, opts: DrawOptions, expression: Expression, gaze?: Gaze | 'pointer');
|
|
40
|
+
destroy(): void;
|
|
41
|
+
/** Reduced motion turned on or off while the page is open. */
|
|
42
|
+
setReduced(reduced: boolean): void;
|
|
43
|
+
/** Read before any face writes this frame; see tick(). */
|
|
44
|
+
measure(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Pairs every node in the tree with the element React rendered for it,
|
|
47
|
+
* and remembers what that element shows now, which is not always `node`.
|
|
48
|
+
*/
|
|
49
|
+
private bind;
|
|
50
|
+
private write;
|
|
51
|
+
setGaze(gaze?: Gaze | 'pointer'): void;
|
|
52
|
+
setExpression(name: Expression): void;
|
|
53
|
+
/** Straight to the rest pose of the current state, no motion. */
|
|
54
|
+
private snap;
|
|
55
|
+
private bump;
|
|
56
|
+
step(dt: number): void;
|
|
57
|
+
private paint;
|
|
58
|
+
}
|
package/dist/draw.d.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Axes, Persona } from './identity.js';
|
|
2
|
+
import { type Channels, type Expression, type FaceGeom } from './tables.js';
|
|
3
|
+
export type Node = {
|
|
4
|
+
tag: string;
|
|
5
|
+
key: string;
|
|
6
|
+
attrs: Record<string, string>;
|
|
7
|
+
children: Node[];
|
|
8
|
+
};
|
|
9
|
+
export type Frame = 'ink' | 'bone' | 'paper' | 'none';
|
|
10
|
+
export type Gaze = readonly [x: number, y: number];
|
|
11
|
+
export type Pose = Channels & {
|
|
12
|
+
/** 0..1, the blink closing both lids. */
|
|
13
|
+
blink: number;
|
|
14
|
+
/** The trait's lag behind the body, frame units, clamped to 16. */
|
|
15
|
+
lag: number;
|
|
16
|
+
/** The ring thickens when angry: the one place a state is read by name. */
|
|
17
|
+
expression: Expression;
|
|
18
|
+
};
|
|
19
|
+
export type DrawOptions = {
|
|
20
|
+
/** Prefix for every id in the tree. Unique per avatar on a page. */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Rendered size in px: drives the stroke ramp and the riso print. */
|
|
23
|
+
size: number;
|
|
24
|
+
frame: Frame;
|
|
25
|
+
/** false clips the frame to a circle. */
|
|
26
|
+
square: boolean;
|
|
27
|
+
/** Riso plates, misregistration and grain. Fades out below 120px. */
|
|
28
|
+
riso: boolean;
|
|
29
|
+
/** The accessible name; false marks the avatar decorative. */
|
|
30
|
+
title: string | false;
|
|
31
|
+
/** Keep invisible nodes so an animator can write into them. */
|
|
32
|
+
live?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type Drawable = Axes & {
|
|
35
|
+
persona: Persona;
|
|
36
|
+
};
|
|
37
|
+
export declare const VB: readonly [-30, -30, 400, 400];
|
|
38
|
+
export declare const clamp: (v: number, a: number, b: number) => number;
|
|
39
|
+
export declare const smooth: (a: number, b: number, v: number) => number;
|
|
40
|
+
/** Where a face rests: the body offset, the eye line, one altitude unit. */
|
|
41
|
+
export declare function frameOf(face: FaceGeom): {
|
|
42
|
+
baseY: number;
|
|
43
|
+
eyeY: number;
|
|
44
|
+
R: number;
|
|
45
|
+
};
|
|
46
|
+
/** The eyes' aim at the thing in the corner, from wherever they are. */
|
|
47
|
+
export declare function thingGaze(face: FaceGeom, x: number, alt: number): Gaze;
|
|
48
|
+
/**
|
|
49
|
+
* The pose an expression settles to. A curious face ends up looking at the
|
|
50
|
+
* thing in the corner; an explicit gaze wins over both.
|
|
51
|
+
*/
|
|
52
|
+
export declare function restPose(who: Pick<Axes, 'face'>, expression: Expression, gaze?: Gaze): Pose;
|
|
53
|
+
/**
|
|
54
|
+
* A point on the crown outline grown by `d`, reached by walking `u` along it
|
|
55
|
+
* from the top (where the outward normal points straight up); u > 0 walks
|
|
56
|
+
* right. Returns the point and the normal's bearing in degrees.
|
|
57
|
+
*/
|
|
58
|
+
export declare function seat(crown: FaceGeom['crown'], d: number, u: number): {
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
a: number;
|
|
62
|
+
};
|
|
63
|
+
/** Signed distance from a point to the crown outline, negative inside. */
|
|
64
|
+
export declare function depth(crown: FaceGeom['crown'], x: number, y: number): number;
|
|
65
|
+
export declare function ringWalk(sh: FaceGeom): {
|
|
66
|
+
rest: number;
|
|
67
|
+
min: number;
|
|
68
|
+
};
|
|
69
|
+
export declare function draw(who: Drawable, pose: Pose, o: DrawOptions): Node;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Axis, type Brows, type Cheeks, type Color, type Eyes, type Face, type Mouth, type Trait } from './tables.js';
|
|
2
|
+
export declare const STYLE = "peek";
|
|
3
|
+
export declare const tidy: (s: string) => string;
|
|
4
|
+
/** FNV-1a over the UTF-8 bytes. */
|
|
5
|
+
export declare function fnv1a(str: string): number;
|
|
6
|
+
export declare function mulberry32(a: number): () => number;
|
|
7
|
+
export type Persona = {
|
|
8
|
+
/** Eye gap offset, in frame units, per side. */
|
|
9
|
+
spread: number;
|
|
10
|
+
/** Blink interval factor (animation only). */
|
|
11
|
+
blink: number;
|
|
12
|
+
add: {
|
|
13
|
+
browY: number;
|
|
14
|
+
browTilt: number;
|
|
15
|
+
browArch: number;
|
|
16
|
+
rot: number;
|
|
17
|
+
hair: number;
|
|
18
|
+
gx: number;
|
|
19
|
+
my: number;
|
|
20
|
+
};
|
|
21
|
+
mul: {
|
|
22
|
+
eyeS: number;
|
|
23
|
+
pupil: number;
|
|
24
|
+
browW: number;
|
|
25
|
+
mw: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
/** The axes a caller may override. Everything a face is. */
|
|
29
|
+
export type Axes = {
|
|
30
|
+
face: Face;
|
|
31
|
+
color: Color;
|
|
32
|
+
eyes: Eyes;
|
|
33
|
+
brows: Brows;
|
|
34
|
+
mouth: Mouth;
|
|
35
|
+
cheeks: Cheeks;
|
|
36
|
+
trait: Trait;
|
|
37
|
+
};
|
|
38
|
+
export type Identity = Axes & {
|
|
39
|
+
/** The tidied name. */
|
|
40
|
+
key: string;
|
|
41
|
+
/** fnv1a of the tidied name, version-free: a fingerprint for display. */
|
|
42
|
+
hash: number;
|
|
43
|
+
version: number;
|
|
44
|
+
persona: Persona;
|
|
45
|
+
};
|
|
46
|
+
/** What each axis picks from, in list order. Append-only. */
|
|
47
|
+
export declare const LISTS: {
|
|
48
|
+
readonly [A in Axis]: readonly Axes[A][];
|
|
49
|
+
};
|
|
50
|
+
/** The axes in readout order. */
|
|
51
|
+
export declare const AXES: Axis[];
|
|
52
|
+
export declare function seed(name: string, axis: string, version?: number): number;
|
|
53
|
+
export declare function identify(name: string, { version }?: {
|
|
54
|
+
version?: number;
|
|
55
|
+
}): Identity;
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
// src/tables.ts
|
|
2
|
+
var FACES = {
|
|
3
|
+
diamond: {
|
|
4
|
+
body: { d: "M170 20L320 170L170 320L20 170Z" },
|
|
5
|
+
bottom: 320,
|
|
6
|
+
sink: 30,
|
|
7
|
+
eyes: [
|
|
8
|
+
[132.5, 155],
|
|
9
|
+
[207.5, 155]
|
|
10
|
+
],
|
|
11
|
+
rx: 20,
|
|
12
|
+
ry: 27.5,
|
|
13
|
+
pr: 10,
|
|
14
|
+
brow: { y: 102.5, hw: 18.75, arch: 15, w: 5.62 },
|
|
15
|
+
cheeks: [
|
|
16
|
+
[117.5, 200],
|
|
17
|
+
[222.5, 200]
|
|
18
|
+
],
|
|
19
|
+
crx: 11.25,
|
|
20
|
+
cry: 5.62,
|
|
21
|
+
mouth: { x: 170, y: 218.75, w: 15, d: 16.25, sw: 4.38 },
|
|
22
|
+
crown: {
|
|
23
|
+
poly: [
|
|
24
|
+
[170, 20],
|
|
25
|
+
[320, 170],
|
|
26
|
+
[170, 320],
|
|
27
|
+
[20, 170]
|
|
28
|
+
],
|
|
29
|
+
r: 0
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
semicircle: {
|
|
33
|
+
body: { d: "M0 255A170 170 0 0 1 340 255Z" },
|
|
34
|
+
bottom: 255,
|
|
35
|
+
sink: 0,
|
|
36
|
+
eyes: [
|
|
37
|
+
[102.5, 175],
|
|
38
|
+
[237.5, 175]
|
|
39
|
+
],
|
|
40
|
+
rx: 30,
|
|
41
|
+
ry: 25,
|
|
42
|
+
pr: 11.25,
|
|
43
|
+
brow: { y: 127.5, hw: 25, arch: 15, w: 5.62 },
|
|
44
|
+
cheeks: [
|
|
45
|
+
[55, 212.5],
|
|
46
|
+
[285, 212.5]
|
|
47
|
+
],
|
|
48
|
+
crx: 11.25,
|
|
49
|
+
cry: 5.62,
|
|
50
|
+
mouth: { x: 170, y: 221.25, w: 16.25, d: 16.25, sw: 4.38 },
|
|
51
|
+
crown: { poly: [[170, 255]], r: 170 }
|
|
52
|
+
},
|
|
53
|
+
circle: {
|
|
54
|
+
body: { circle: [170, 170, 150] },
|
|
55
|
+
bottom: 320,
|
|
56
|
+
sink: 20,
|
|
57
|
+
eyes: [
|
|
58
|
+
[112.8, 162.2],
|
|
59
|
+
[227.2, 162.2]
|
|
60
|
+
],
|
|
61
|
+
rx: 29.9,
|
|
62
|
+
ry: 29.9,
|
|
63
|
+
pr: 13,
|
|
64
|
+
brow: { y: 110.2, hw: 23.4, arch: 15.6, w: 5.85 },
|
|
65
|
+
cheeks: [
|
|
66
|
+
[84.2, 203.8],
|
|
67
|
+
[255.8, 203.8]
|
|
68
|
+
],
|
|
69
|
+
crx: 11.7,
|
|
70
|
+
cry: 5.85,
|
|
71
|
+
mouth: { x: 170, y: 223.3, w: 16.9, d: 16.9, sw: 4.55 },
|
|
72
|
+
crown: { poly: [[170, 170]], r: 150 }
|
|
73
|
+
},
|
|
74
|
+
triangle: {
|
|
75
|
+
body: { d: "M170 40.8L312.8 299.2L27.2 299.2Z", stroke: 27.2 },
|
|
76
|
+
bottom: 312.8,
|
|
77
|
+
sink: 0,
|
|
78
|
+
eyes: [
|
|
79
|
+
[132.6, 210.8],
|
|
80
|
+
[207.4, 210.8]
|
|
81
|
+
],
|
|
82
|
+
rx: 20.4,
|
|
83
|
+
ry: 27.2,
|
|
84
|
+
pr: 10,
|
|
85
|
+
brow: { y: 166.6, hw: 18.7, arch: 15.3, w: 5.62 },
|
|
86
|
+
cheeks: [
|
|
87
|
+
[98.6, 238],
|
|
88
|
+
[241.4, 238]
|
|
89
|
+
],
|
|
90
|
+
crx: 11.5,
|
|
91
|
+
cry: 5.75,
|
|
92
|
+
mouth: { x: 170, y: 254, w: 17, d: 16.25, sw: 4.38 },
|
|
93
|
+
crown: {
|
|
94
|
+
poly: [
|
|
95
|
+
[170, 40.8],
|
|
96
|
+
[312.8, 299.2],
|
|
97
|
+
[27.2, 299.2]
|
|
98
|
+
],
|
|
99
|
+
r: 13.6
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
var COLORS = {
|
|
104
|
+
lavender: { body: "#D8CDF0", deep: "#BDAEE6" },
|
|
105
|
+
fog: { body: "#C8D6E8", deep: "#A8BCDC" },
|
|
106
|
+
clay: { body: "#F1CDBF", deep: "#E2A893" },
|
|
107
|
+
mint: { body: "#CFE7D6", deep: "#A5CDB1" },
|
|
108
|
+
butter: { body: "#ECE2B9", deep: "#D9C284" },
|
|
109
|
+
rose: { body: "#EFCAD7", deep: "#DFA4BA" },
|
|
110
|
+
aqua: { body: "#BDE1E5", deep: "#8FC7D1" }
|
|
111
|
+
};
|
|
112
|
+
var PARTS = {
|
|
113
|
+
eyes: ["oval", "bead", "ring"],
|
|
114
|
+
brows: ["arch", "bar", "wedge", "dash"],
|
|
115
|
+
mouth: ["poly", "round", "line", "box"],
|
|
116
|
+
cheeks: ["oval", "dots", "lines"],
|
|
117
|
+
trait: ["square", "fin", "ring", "dot", "peak"]
|
|
118
|
+
};
|
|
119
|
+
var VERSIONS = {
|
|
120
|
+
1: { face: 4, color: 7, eyes: 3, brows: 4, mouth: 4, cheeks: 3, trait: 5 }
|
|
121
|
+
};
|
|
122
|
+
var LATEST = 1;
|
|
123
|
+
var BASE = {
|
|
124
|
+
alt: 0,
|
|
125
|
+
rot: 0,
|
|
126
|
+
x: 0,
|
|
127
|
+
sx: 1,
|
|
128
|
+
sy: 1,
|
|
129
|
+
lid: 0.1,
|
|
130
|
+
lower: 0,
|
|
131
|
+
lidTilt: 0,
|
|
132
|
+
eyeS: 1,
|
|
133
|
+
lidAsym: 0,
|
|
134
|
+
pupil: 1,
|
|
135
|
+
gx: 0,
|
|
136
|
+
gy: 0,
|
|
137
|
+
shine: 0.7,
|
|
138
|
+
browY: 0,
|
|
139
|
+
browTilt: 0,
|
|
140
|
+
browArch: 0.4,
|
|
141
|
+
browW: 1,
|
|
142
|
+
browAsym: 0,
|
|
143
|
+
mw: 0.72,
|
|
144
|
+
mt: 0,
|
|
145
|
+
mb: 0.5,
|
|
146
|
+
mx: 0,
|
|
147
|
+
my: 0,
|
|
148
|
+
mk: 0,
|
|
149
|
+
blush: 0,
|
|
150
|
+
hair: 0,
|
|
151
|
+
dim: 0,
|
|
152
|
+
thing: 0
|
|
153
|
+
};
|
|
154
|
+
var S = (o) => ({ ...BASE, ...o });
|
|
155
|
+
var EXPRESSIONS = {
|
|
156
|
+
normal: S({}),
|
|
157
|
+
happy: S({
|
|
158
|
+
lid: 0,
|
|
159
|
+
lower: 0.42,
|
|
160
|
+
shine: 1,
|
|
161
|
+
gy: -0.05,
|
|
162
|
+
browY: -5,
|
|
163
|
+
browArch: 1,
|
|
164
|
+
mw: 1,
|
|
165
|
+
mb: 1,
|
|
166
|
+
blush: 1,
|
|
167
|
+
hair: 0.45,
|
|
168
|
+
alt: 0.05
|
|
169
|
+
}),
|
|
170
|
+
sad: S({
|
|
171
|
+
lid: 0.42,
|
|
172
|
+
lidTilt: 16,
|
|
173
|
+
pupil: 0.95,
|
|
174
|
+
gy: 0.8,
|
|
175
|
+
shine: 0,
|
|
176
|
+
browY: 3,
|
|
177
|
+
browTilt: 14,
|
|
178
|
+
browArch: 0,
|
|
179
|
+
mw: 0.8,
|
|
180
|
+
mt: -0.55,
|
|
181
|
+
mb: -0.55,
|
|
182
|
+
my: 6,
|
|
183
|
+
alt: -0.16,
|
|
184
|
+
sy: 0.985,
|
|
185
|
+
hair: -0.75
|
|
186
|
+
}),
|
|
187
|
+
angry: S({
|
|
188
|
+
lid: 0.34,
|
|
189
|
+
lidTilt: -22,
|
|
190
|
+
lower: 0.12,
|
|
191
|
+
pupil: 0.82,
|
|
192
|
+
gy: 0.1,
|
|
193
|
+
shine: 0,
|
|
194
|
+
browY: 5,
|
|
195
|
+
browTilt: -21,
|
|
196
|
+
browArch: 0,
|
|
197
|
+
browW: 1.3,
|
|
198
|
+
mw: 0.8,
|
|
199
|
+
mt: -0.08,
|
|
200
|
+
mb: -0.08,
|
|
201
|
+
my: 3,
|
|
202
|
+
sx: 1.02,
|
|
203
|
+
sy: 0.98,
|
|
204
|
+
hair: 0.25
|
|
205
|
+
}),
|
|
206
|
+
sleepy: S({
|
|
207
|
+
lid: 1,
|
|
208
|
+
lidTilt: 4,
|
|
209
|
+
pupil: 0.9,
|
|
210
|
+
gy: 0.5,
|
|
211
|
+
shine: 0,
|
|
212
|
+
browY: 6,
|
|
213
|
+
browTilt: 3,
|
|
214
|
+
browArch: 0.15,
|
|
215
|
+
browW: 0.9,
|
|
216
|
+
mw: 0.35,
|
|
217
|
+
mt: -0.3,
|
|
218
|
+
mb: 0.3,
|
|
219
|
+
my: 2,
|
|
220
|
+
alt: -1.12,
|
|
221
|
+
rot: -3,
|
|
222
|
+
hair: -1
|
|
223
|
+
}),
|
|
224
|
+
curious: S({
|
|
225
|
+
lid: 0,
|
|
226
|
+
eyeS: 1.06,
|
|
227
|
+
pupil: 1.05,
|
|
228
|
+
shine: 1,
|
|
229
|
+
browY: -3,
|
|
230
|
+
browAsym: 9,
|
|
231
|
+
browArch: 0.8,
|
|
232
|
+
mw: 0.38,
|
|
233
|
+
mt: -0.36,
|
|
234
|
+
mb: 0.36,
|
|
235
|
+
rot: 6,
|
|
236
|
+
alt: -0.32,
|
|
237
|
+
hair: 0.3,
|
|
238
|
+
thing: 1
|
|
239
|
+
}),
|
|
240
|
+
surprised: S({
|
|
241
|
+
lid: 0,
|
|
242
|
+
eyeS: 1.2,
|
|
243
|
+
pupil: 0.66,
|
|
244
|
+
shine: 0.8,
|
|
245
|
+
browY: -13,
|
|
246
|
+
browArch: 1,
|
|
247
|
+
mw: 0.55,
|
|
248
|
+
mt: -0.62,
|
|
249
|
+
mb: 0.62,
|
|
250
|
+
alt: 0.36,
|
|
251
|
+
hair: 1
|
|
252
|
+
}),
|
|
253
|
+
excited: S({
|
|
254
|
+
lid: 0,
|
|
255
|
+
lower: 0.5,
|
|
256
|
+
eyeS: 1.08,
|
|
257
|
+
pupil: 1.08,
|
|
258
|
+
shine: 1,
|
|
259
|
+
browY: -9,
|
|
260
|
+
browArch: 1,
|
|
261
|
+
mw: 1.15,
|
|
262
|
+
mb: 1.3,
|
|
263
|
+
blush: 1,
|
|
264
|
+
hair: 1,
|
|
265
|
+
alt: 0.12
|
|
266
|
+
}),
|
|
267
|
+
confused: S({
|
|
268
|
+
lid: 0.22,
|
|
269
|
+
lidAsym: 0.28,
|
|
270
|
+
lidTilt: -4,
|
|
271
|
+
pupil: 0.92,
|
|
272
|
+
gx: -0.35,
|
|
273
|
+
gy: -0.45,
|
|
274
|
+
shine: 0.3,
|
|
275
|
+
browY: -2,
|
|
276
|
+
browAsym: 11,
|
|
277
|
+
browTilt: -5,
|
|
278
|
+
browArch: 0.3,
|
|
279
|
+
mw: 0.6,
|
|
280
|
+
mt: -0.1,
|
|
281
|
+
mb: 0.12,
|
|
282
|
+
mx: 5,
|
|
283
|
+
mk: 13,
|
|
284
|
+
rot: -7,
|
|
285
|
+
alt: -0.05,
|
|
286
|
+
hair: 0.1
|
|
287
|
+
}),
|
|
288
|
+
bored: S({
|
|
289
|
+
lid: 0.5,
|
|
290
|
+
pupil: 0.9,
|
|
291
|
+
gx: -0.55,
|
|
292
|
+
gy: 0.25,
|
|
293
|
+
shine: 0,
|
|
294
|
+
browY: 3,
|
|
295
|
+
browArch: 0.1,
|
|
296
|
+
mw: 0.55,
|
|
297
|
+
mt: 0,
|
|
298
|
+
mb: 0.04,
|
|
299
|
+
mx: -5,
|
|
300
|
+
alt: -0.34,
|
|
301
|
+
hair: -0.45,
|
|
302
|
+
dim: 1
|
|
303
|
+
}),
|
|
304
|
+
attentive: S({
|
|
305
|
+
lid: 0,
|
|
306
|
+
eyeS: 1.1,
|
|
307
|
+
pupil: 0.8,
|
|
308
|
+
gy: -0.1,
|
|
309
|
+
shine: 1,
|
|
310
|
+
browY: -7,
|
|
311
|
+
browArch: 0.7,
|
|
312
|
+
mw: 0.55,
|
|
313
|
+
mb: 0.4,
|
|
314
|
+
alt: 0.15,
|
|
315
|
+
sy: 1.03,
|
|
316
|
+
hair: 0.65
|
|
317
|
+
})
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/identity.ts
|
|
321
|
+
var STYLE = "peek";
|
|
322
|
+
var tidy = (s) => s.normalize("NFC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
323
|
+
function fnv1a(str) {
|
|
324
|
+
let h = 2166136261;
|
|
325
|
+
for (const b of new TextEncoder().encode(str)) {
|
|
326
|
+
h ^= b;
|
|
327
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
328
|
+
}
|
|
329
|
+
return h >>> 0;
|
|
330
|
+
}
|
|
331
|
+
function mulberry32(a) {
|
|
332
|
+
return () => {
|
|
333
|
+
a = a + 1831565813 | 0;
|
|
334
|
+
let t = Math.imul(a ^ a >>> 15, 1 | a);
|
|
335
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
336
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
var LISTS = {
|
|
340
|
+
face: Object.keys(FACES),
|
|
341
|
+
color: Object.keys(COLORS),
|
|
342
|
+
...PARTS
|
|
343
|
+
};
|
|
344
|
+
var AXES = Object.keys(LISTS);
|
|
345
|
+
function seed(name, axis, version = LATEST) {
|
|
346
|
+
return fnv1a(`${STYLE}@${version}:${axis}:${tidy(name)}`);
|
|
347
|
+
}
|
|
348
|
+
function identify(name, { version = LATEST } = {}) {
|
|
349
|
+
const lengths = VERSIONS[version];
|
|
350
|
+
if (!lengths)
|
|
351
|
+
throw new Error(`peek@${version} does not exist`);
|
|
352
|
+
const pick = (axis) => LISTS[axis][seed(name, axis, version) % lengths[axis]];
|
|
353
|
+
const rnd = mulberry32(seed(name, "persona", version));
|
|
354
|
+
const r = (a, b) => Math.round((a + rnd() * (b - a)) * 100) / 100;
|
|
355
|
+
const persona = {
|
|
356
|
+
spread: r(-7, 7),
|
|
357
|
+
blink: r(0.75, 1.4),
|
|
358
|
+
add: {
|
|
359
|
+
browY: r(-4, 4),
|
|
360
|
+
browTilt: r(-5, 5),
|
|
361
|
+
browArch: r(-0.2, 0.3),
|
|
362
|
+
rot: r(-3, 3),
|
|
363
|
+
hair: r(-0.2, 0.35),
|
|
364
|
+
gx: r(-0.12, 0.12),
|
|
365
|
+
my: r(-2, 3)
|
|
366
|
+
},
|
|
367
|
+
mul: {
|
|
368
|
+
eyeS: r(0.92, 1.08),
|
|
369
|
+
pupil: r(0.9, 1.12),
|
|
370
|
+
browW: r(0.85, 1.2),
|
|
371
|
+
mw: r(0.85, 1.18)
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
const key = tidy(name);
|
|
375
|
+
return {
|
|
376
|
+
key,
|
|
377
|
+
hash: fnv1a(key),
|
|
378
|
+
version,
|
|
379
|
+
face: pick("face"),
|
|
380
|
+
color: pick("color"),
|
|
381
|
+
eyes: pick("eyes"),
|
|
382
|
+
brows: pick("brows"),
|
|
383
|
+
mouth: pick("mouth"),
|
|
384
|
+
cheeks: pick("cheeks"),
|
|
385
|
+
trait: pick("trait"),
|
|
386
|
+
persona
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
export {
|
|
390
|
+
AXES,
|
|
391
|
+
LISTS,
|
|
392
|
+
STYLE,
|
|
393
|
+
fnv1a,
|
|
394
|
+
identify,
|
|
395
|
+
mulberry32,
|
|
396
|
+
seed,
|
|
397
|
+
tidy
|
|
398
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { Frame, Gaze } from './draw.js';
|
|
2
|
+
export type { Axes, Identity, Persona } from './identity.js';
|
|
3
|
+
export { AXES, identify, LISTS, tidy } from './identity.js';
|
|
4
|
+
export type { PeekProps } from './peek.js';
|
|
5
|
+
export { Peek } from './peek.js';
|
|
6
|
+
export type { PeekOptions } from './svg.js';
|
|
7
|
+
export { toSvg } from './svg.js';
|
|
8
|
+
export type { Axis, Brows, Channel, Cheeks, Color, Expression, Eyes, Face, Mouth, Trait, } from './tables.js';
|
|
9
|
+
export { COLORS, EXPRESSIONS, FACES, GROUPS, LATEST, PARTS, VERSIONS, } from './tables.js';
|