@doan-labs/peek 1.1.0 → 2.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 +45 -1
- package/dist/bloc.d.ts +2 -0
- package/dist/core.d.ts +9 -0
- package/dist/draw.d.ts +24 -2
- package/dist/index.d.ts +1 -9
- package/dist/index.js +589 -207
- package/dist/peek.svelte +75 -0
- package/dist/peek.svelte.d.ts +5 -0
- package/dist/svelte-peek.d.ts +14 -0
- package/dist/svelte-peek.js +2205 -0
- package/dist/svelte.d.ts +3 -0
- package/dist/svelte.js +1650 -0
- package/dist/svg.d.ts +3 -1
- package/dist/svg.js +546 -168
- package/dist/tables.d.ts +53 -0
- package/dist/vue.d.ts +17 -0
- package/dist/vue.js +2302 -0
- package/package.json +28 -5
- package/src/bloc.ts +326 -0
- package/src/core.ts +39 -0
- package/src/draw.ts +315 -122
- package/src/index.ts +1 -33
- package/src/peek.svelte +75 -0
- package/src/peek.svelte.d.ts +5 -0
- package/src/svelte-peek.ts +18 -0
- package/src/svelte.ts +3 -0
- package/src/svg.ts +15 -1
- package/src/tables.ts +47 -0
- package/src/vue.ts +133 -0
package/dist/index.js
CHANGED
|
@@ -114,6 +114,34 @@ var COLORS = {
|
|
|
114
114
|
rose: { body: "#EFCAD7", deep: "#DFA4BA" },
|
|
115
115
|
aqua: { body: "#BDE1E5", deep: "#8FC7D1" }
|
|
116
116
|
};
|
|
117
|
+
var VARIANTS = ["peek", "haze", "bloc"];
|
|
118
|
+
var HAZE = {
|
|
119
|
+
lavender: { tint: "#C8B1F5", glow: "#F2EDFD" },
|
|
120
|
+
fog: { tint: "#9EC3F2", glow: "#E6F1FF" },
|
|
121
|
+
clay: { tint: "#F4AE93", glow: "#FEECE5" },
|
|
122
|
+
mint: { tint: "#A3DAB5", glow: "#E5F5EA" },
|
|
123
|
+
butter: { tint: "#E1CC7A", glow: "#F4F0E0" },
|
|
124
|
+
rose: { tint: "#F0A9C4", glow: "#FDEAF1" },
|
|
125
|
+
aqua: { tint: "#85D3DC", glow: "#E0F5F7" }
|
|
126
|
+
};
|
|
127
|
+
var WHEEL = [
|
|
128
|
+
"clay",
|
|
129
|
+
"butter",
|
|
130
|
+
"mint",
|
|
131
|
+
"aqua",
|
|
132
|
+
"fog",
|
|
133
|
+
"lavender",
|
|
134
|
+
"rose"
|
|
135
|
+
];
|
|
136
|
+
var BLOC = {
|
|
137
|
+
lavender: "#B093E5",
|
|
138
|
+
fog: "#7BA8DF",
|
|
139
|
+
clay: "#E38A66",
|
|
140
|
+
mint: "#82CB9B",
|
|
141
|
+
butter: "#E2CA6A",
|
|
142
|
+
rose: "#DF84A8",
|
|
143
|
+
aqua: "#5EC3CD"
|
|
144
|
+
};
|
|
117
145
|
var PARTS = {
|
|
118
146
|
eyes: ["oval", "bead", "ring"],
|
|
119
147
|
brows: ["arch", "bar", "wedge", "dash"],
|
|
@@ -347,6 +375,314 @@ var EXPRESSIONS = {
|
|
|
347
375
|
})
|
|
348
376
|
};
|
|
349
377
|
|
|
378
|
+
// src/bloc.ts
|
|
379
|
+
var RAD = Math.PI / 180;
|
|
380
|
+
var TRI = [
|
|
381
|
+
[170, 12.8],
|
|
382
|
+
[320, 312.8],
|
|
383
|
+
[20, 312.8]
|
|
384
|
+
];
|
|
385
|
+
var BODY = {
|
|
386
|
+
diamond: FACES.diamond,
|
|
387
|
+
semicircle: FACES.semicircle,
|
|
388
|
+
circle: FACES.circle,
|
|
389
|
+
triangle: {
|
|
390
|
+
body: { d: `M${TRI.map((p) => p.join(" ")).join("L")}Z` },
|
|
391
|
+
crown: { poly: TRI, r: 0 }
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
var strokeFor = (px) => px >= 96 ? 1 : px >= 56 ? 1.25 : px >= 40 ? 1.6 : px >= 30 ? 2 : 2.6;
|
|
395
|
+
var boostFor = (px) => px < 30 ? 1.25 : px < 56 ? 1.12 : 1;
|
|
396
|
+
var turn = (x, y, deg) => {
|
|
397
|
+
const c = Math.cos(deg * RAD);
|
|
398
|
+
const s = Math.sin(deg * RAD);
|
|
399
|
+
return [x * c - y * s, x * s + y * c];
|
|
400
|
+
};
|
|
401
|
+
var poly = (pts) => `M${pts.map(([x, y]) => `${f2(x)} ${f2(y)}`).join("L")}Z`;
|
|
402
|
+
function blocParts({ who, pose, o, defs, g }) {
|
|
403
|
+
const sh = FACES[who.face];
|
|
404
|
+
const { body, crown } = BODY[who.face];
|
|
405
|
+
const id = o.id;
|
|
406
|
+
const P = who.persona;
|
|
407
|
+
const spread = P.spread;
|
|
408
|
+
const st = strokeFor(o.size);
|
|
409
|
+
const up = boostFor(o.size);
|
|
410
|
+
const strong = BLOC[who.color];
|
|
411
|
+
const light = o.frame === "bone" || o.frame === "paper" ? COLORS[who.color].deep : COLORS[who.color].body;
|
|
412
|
+
const lineW = sh.brow.w * st;
|
|
413
|
+
defs.push(n("clipPath", "half", { id: `${id}-r` }, [
|
|
414
|
+
n("rect", "half.shape", { x: 170, y: -30, width: 200, height: 400 })
|
|
415
|
+
]));
|
|
416
|
+
const block = (key, fill, clip) => ("d" in body) ? n("path", key, { d: body.d, fill, "clip-path": clip }) : n("circle", key, {
|
|
417
|
+
cx: body.circle[0],
|
|
418
|
+
cy: body.circle[1],
|
|
419
|
+
r: body.circle[2],
|
|
420
|
+
fill,
|
|
421
|
+
"clip-path": clip
|
|
422
|
+
});
|
|
423
|
+
const eyeS = g("eyeS");
|
|
424
|
+
const r0 = Math.sqrt(sh.rx * sh.ry) * up;
|
|
425
|
+
const lid0 = g("lid");
|
|
426
|
+
const lidAsym = g("lidAsym");
|
|
427
|
+
const lower = clamp(g("lower"), 0, 1);
|
|
428
|
+
const pupil = g("pupil");
|
|
429
|
+
const gx = clamp(g("gx"), -1.1, 1.1);
|
|
430
|
+
const gy = clamp(g("gy"), -1.1, 1.1);
|
|
431
|
+
const tilt = g("lidTilt");
|
|
432
|
+
const bead = who.eyes === "bead";
|
|
433
|
+
const eyes = sh.eyes.map(([ex, ey], i) => {
|
|
434
|
+
const side = i === 0 ? -1 : 1;
|
|
435
|
+
const kk = `eye${i}`;
|
|
436
|
+
let lid = clamp(lid0 + (i === 0 ? lidAsym : -lidAsym * 0.3), 0, 1);
|
|
437
|
+
lid = lid + (1 - lid) * pose.blink;
|
|
438
|
+
const cut = clamp((lid - 0.1) / 0.9, 0, 1);
|
|
439
|
+
const r = bead ? r0 * 0.7 * eyeS * (0.4 + 0.6 * pupil) : r0 * eyeS;
|
|
440
|
+
const [tx, ty] = bead ? [ex + side * spread + gx * 6, ey + gy * 6] : [ex + side * spread, ey];
|
|
441
|
+
const a = side * tilt;
|
|
442
|
+
const edge = -r - 1 + cut * (2 * r + 2);
|
|
443
|
+
const floor = r + 1 - lower * r * 2.2;
|
|
444
|
+
const W = r + 2;
|
|
445
|
+
const lidAt = (x) => x * Math.tan(a * RAD) + edge / Math.cos(a * RAD);
|
|
446
|
+
const [t0, t1] = [lidAt(-W), lidAt(W)];
|
|
447
|
+
defs.push(n("clipPath", `${kk}.clip`, { id: `${id}-e${i}` }, [
|
|
448
|
+
n("path", `${kk}.clip.shape`, {
|
|
449
|
+
d: poly([
|
|
450
|
+
[-W, t0],
|
|
451
|
+
[W, t1],
|
|
452
|
+
[W, Math.max(floor, t1)],
|
|
453
|
+
[-W, Math.max(floor, t0)]
|
|
454
|
+
])
|
|
455
|
+
})
|
|
456
|
+
]));
|
|
457
|
+
const pr = sh.pr * pupil * up;
|
|
458
|
+
const px = gx * Math.max(0, r - pr) * 0.85;
|
|
459
|
+
const py = gy * Math.max(0, r - pr) * 0.75;
|
|
460
|
+
const rim = Math.min(r * 0.27 * Math.min(st, 1.6), r * 0.4);
|
|
461
|
+
const inner = bead ? [n("circle", `${kk}.bead`, { cx: 0, cy: 0, r: f2(r), fill: INK.ink })] : [
|
|
462
|
+
n("circle", `${kk}.white`, {
|
|
463
|
+
cx: 0,
|
|
464
|
+
cy: 0,
|
|
465
|
+
r: f2(r),
|
|
466
|
+
fill: INK.paper
|
|
467
|
+
}),
|
|
468
|
+
n("circle", `${kk}.pupil`, {
|
|
469
|
+
cx: f2(px),
|
|
470
|
+
cy: f2(py),
|
|
471
|
+
r: f2(pr),
|
|
472
|
+
fill: INK.ink
|
|
473
|
+
})
|
|
474
|
+
];
|
|
475
|
+
if (who.eyes === "ring")
|
|
476
|
+
inner.push(n("circle", `${kk}.rim`, {
|
|
477
|
+
cx: 0,
|
|
478
|
+
cy: 0,
|
|
479
|
+
r: f2(r - rim / 2),
|
|
480
|
+
fill: "none",
|
|
481
|
+
stroke: INK.ink,
|
|
482
|
+
"stroke-width": f2(rim)
|
|
483
|
+
}));
|
|
484
|
+
const co = smooth(0.86, 1, lid);
|
|
485
|
+
const yy = Math.min(edge, r) - lineW / 2;
|
|
486
|
+
return n("g", kk, { transform: `translate(${f2(tx)} ${f2(ty)})` }, [
|
|
487
|
+
n("g", `${kk}.inner`, { "clip-path": `url(#${id}-e${i})` }, inner),
|
|
488
|
+
n("path", `${kk}.closed`, {
|
|
489
|
+
d: `M${f2(-r * 0.95)} ${f2(yy)}H${f2(r * 0.95)}`,
|
|
490
|
+
transform: `rotate(${f2(a * 0.6)})`,
|
|
491
|
+
stroke: INK.ink,
|
|
492
|
+
"stroke-width": f2(lineW * 1.4),
|
|
493
|
+
opacity: co > 0.01 ? f2(co) : 0
|
|
494
|
+
})
|
|
495
|
+
]);
|
|
496
|
+
});
|
|
497
|
+
const bt = pose.browTilt;
|
|
498
|
+
const basym = g("browAsym");
|
|
499
|
+
const th = lineW * 2 * g("browW");
|
|
500
|
+
const hw = sh.eyes[1][0] - 170 + spread + Math.sqrt(sh.rx * sh.ry) * P.mul.eyeS * up;
|
|
501
|
+
const gap = smooth(0, 8, Math.abs(bt)) * th * 0.9;
|
|
502
|
+
const slant = P.add.browTilt * 0.3 - Math.atan(1.3 * basym / (2 * hw)) / RAD;
|
|
503
|
+
const y0 = sh.brow.y + g("browY") - (eyeS - 1) * sh.ry * 0.9 - 0.35 * basym;
|
|
504
|
+
const halves = (dy, len2 = 1) => [-1, 1].map((s2) => {
|
|
505
|
+
const [ox, oy] = turn(s2 * gap / 2, 0, slant);
|
|
506
|
+
const x0 = 170 + ox;
|
|
507
|
+
const yy = y0 + dy + oy;
|
|
508
|
+
const ang = slant + s2 * bt;
|
|
509
|
+
const [ux, uy] = turn(s2 * (hw * len2 - gap / 2), 0, ang);
|
|
510
|
+
const [nx, ny] = turn(0, th / 2, ang);
|
|
511
|
+
return [
|
|
512
|
+
[x0 - nx, yy - ny],
|
|
513
|
+
[x0 + ux - nx, yy + uy - ny],
|
|
514
|
+
[x0 + ux + nx, yy + uy + ny],
|
|
515
|
+
[x0 + nx, yy + ny]
|
|
516
|
+
];
|
|
517
|
+
});
|
|
518
|
+
const inside = (dy, len2 = 1) => halves(dy, len2).every((q) => q.every(([x, y]) => depth(crown, x, y) + 2 < 0));
|
|
519
|
+
let lo = 0;
|
|
520
|
+
let hi = 0;
|
|
521
|
+
if (!inside(0)) {
|
|
522
|
+
hi = 60;
|
|
523
|
+
for (let k = 0;k < 12; k++) {
|
|
524
|
+
const mid2 = (lo + hi) / 2;
|
|
525
|
+
if (inside(mid2))
|
|
526
|
+
hi = mid2;
|
|
527
|
+
else
|
|
528
|
+
lo = mid2;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
let len = 1;
|
|
532
|
+
if (!inside(hi)) {
|
|
533
|
+
let short = 0;
|
|
534
|
+
for (let k = 0;k < 12; k++) {
|
|
535
|
+
const mid2 = (short + len) / 2;
|
|
536
|
+
if (inside(hi, mid2))
|
|
537
|
+
short = mid2;
|
|
538
|
+
else
|
|
539
|
+
len = mid2;
|
|
540
|
+
}
|
|
541
|
+
len = short;
|
|
542
|
+
}
|
|
543
|
+
const bars = halves(hi, len).map((q, i) => n("path", `bar${i}`, { d: poly(q), fill: INK.ink }));
|
|
544
|
+
const m = sh.mouth;
|
|
545
|
+
const big = (who.face === "diamond" || who.face === "triangle" ? 1.25 : 1) * up;
|
|
546
|
+
const mw = m.w * Math.max(0.05, g("mw")) * big;
|
|
547
|
+
const mt = g("mt") * m.d * big;
|
|
548
|
+
const mb = g("mb") * m.d * big;
|
|
549
|
+
const mid = (mt + mb) / 2;
|
|
550
|
+
const kb = 4 / 3;
|
|
551
|
+
let d;
|
|
552
|
+
if (who.mouth === "poly") {
|
|
553
|
+
const s2 = Math.max(mw * 0.9, (mb - mt) / 2);
|
|
554
|
+
d = poly([
|
|
555
|
+
[-s2, mid],
|
|
556
|
+
[0, mid - s2],
|
|
557
|
+
[s2, mid],
|
|
558
|
+
[0, mid + s2]
|
|
559
|
+
]);
|
|
560
|
+
} else if (who.mouth === "box") {
|
|
561
|
+
const h = Math.max(mb - mt, lineW * 1.6) / 2;
|
|
562
|
+
const w = mw * 0.85;
|
|
563
|
+
d = poly([
|
|
564
|
+
[-w, mid - h],
|
|
565
|
+
[w, mid - h],
|
|
566
|
+
[w, mid + h],
|
|
567
|
+
[-w, mid + h]
|
|
568
|
+
]);
|
|
569
|
+
} else if (who.mouth === "line") {
|
|
570
|
+
const h = lineW * 1.4 / 2;
|
|
571
|
+
const w = mw * 1.5;
|
|
572
|
+
const y = mid * 0.5;
|
|
573
|
+
d = poly([
|
|
574
|
+
[-w, y - h],
|
|
575
|
+
[w, y - h],
|
|
576
|
+
[w, y + h],
|
|
577
|
+
[-w, y + h]
|
|
578
|
+
]);
|
|
579
|
+
} else {
|
|
580
|
+
d = `M${f2(-mw)} 0C${f2(-mw)} ${f2(mb * kb)} ${f2(mw)} ${f2(mb * kb)} ${f2(mw)} 0C${f2(mw)} ${f2(mt * kb)} ${f2(-mw)} ${f2(mt * kb)} ${f2(-mw)} 0Z`;
|
|
581
|
+
}
|
|
582
|
+
const mouth = n("path", "mouth", {
|
|
583
|
+
d,
|
|
584
|
+
transform: `translate(${f2(m.x + g("mx"))} ${f2(m.y + g("my"))}) rotate(${f2(g("mk"))})`,
|
|
585
|
+
fill: INK.ink
|
|
586
|
+
});
|
|
587
|
+
const hair = g("hair");
|
|
588
|
+
const s = seat(crown, Math.max(0, hair) * 8, 110 + Math.max(0, -hair) * 40);
|
|
589
|
+
const shape = who.trait === "square" ? n("rect", "trait.shape", { x: -21, y: -21, width: 42, height: 42 }) : who.trait === "dot" ? n("circle", "trait.shape", { cx: 0, cy: 0, r: 22 }) : who.trait === "ring" ? n("circle", "trait.shape", {
|
|
590
|
+
cx: 0,
|
|
591
|
+
cy: 0,
|
|
592
|
+
r: 17.5,
|
|
593
|
+
fill: "none",
|
|
594
|
+
stroke: strong,
|
|
595
|
+
"stroke-width": 13
|
|
596
|
+
}) : who.trait === "fin" ? n("path", "trait.shape", { d: "M-27 27V-27A54 54 0 0 1 27 27Z" }) : n("rect", "trait.shape", {
|
|
597
|
+
x: -16,
|
|
598
|
+
y: -30,
|
|
599
|
+
width: 32,
|
|
600
|
+
height: 60
|
|
601
|
+
});
|
|
602
|
+
const trait = n("g", "trait", {
|
|
603
|
+
transform: `translate(${f2(s.x)} ${f2(s.y + pose.lag)}) scale(${f2(up)})`,
|
|
604
|
+
fill: strong
|
|
605
|
+
}, [shape]);
|
|
606
|
+
return [
|
|
607
|
+
[block("body", strong), block("body.light", light, `url(#${id}-r)`), trait],
|
|
608
|
+
[...eyes, ...bars, mouth]
|
|
609
|
+
];
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/identity.ts
|
|
613
|
+
var STYLE = "peek";
|
|
614
|
+
var tidy = (s) => s.normalize("NFC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
615
|
+
function fnv1a(str) {
|
|
616
|
+
let h = 2166136261;
|
|
617
|
+
for (const b of new TextEncoder().encode(str)) {
|
|
618
|
+
h ^= b;
|
|
619
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
620
|
+
}
|
|
621
|
+
return h >>> 0;
|
|
622
|
+
}
|
|
623
|
+
function mulberry32(a) {
|
|
624
|
+
return () => {
|
|
625
|
+
a = a + 1831565813 | 0;
|
|
626
|
+
let t = Math.imul(a ^ a >>> 15, 1 | a);
|
|
627
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
628
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
var LISTS = {
|
|
632
|
+
face: Object.keys(FACES),
|
|
633
|
+
color: Object.keys(COLORS),
|
|
634
|
+
...PARTS,
|
|
635
|
+
...ACCESSORIES
|
|
636
|
+
};
|
|
637
|
+
var AXES = Object.keys(LISTS);
|
|
638
|
+
function seed(name, axis, version = LATEST) {
|
|
639
|
+
return fnv1a(`${STYLE}@${version}:${axis}:${tidy(name)}`);
|
|
640
|
+
}
|
|
641
|
+
function identify(name, { version = LATEST } = {}) {
|
|
642
|
+
const lengths = VERSIONS[version];
|
|
643
|
+
if (!lengths)
|
|
644
|
+
throw new Error(`peek@${version} does not exist`);
|
|
645
|
+
const pick = (axis) => LISTS[axis][seed(name, axis, version) % lengths[axis]];
|
|
646
|
+
const rnd = mulberry32(seed(name, "persona", version));
|
|
647
|
+
const r = (a, b) => Math.round((a + rnd() * (b - a)) * 100) / 100;
|
|
648
|
+
const persona = {
|
|
649
|
+
spread: r(-7, 7),
|
|
650
|
+
blink: r(0.75, 1.4),
|
|
651
|
+
add: {
|
|
652
|
+
browY: r(-4, 4),
|
|
653
|
+
browTilt: r(-5, 5),
|
|
654
|
+
browArch: r(-0.2, 0.3),
|
|
655
|
+
rot: r(-3, 3),
|
|
656
|
+
hair: r(-0.2, 0.35),
|
|
657
|
+
gx: r(-0.12, 0.12),
|
|
658
|
+
my: r(-2, 3)
|
|
659
|
+
},
|
|
660
|
+
mul: {
|
|
661
|
+
eyeS: r(0.92, 1.08),
|
|
662
|
+
pupil: r(0.9, 1.12),
|
|
663
|
+
browW: r(0.85, 1.2),
|
|
664
|
+
mw: r(0.85, 1.18)
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
const key = tidy(name);
|
|
668
|
+
return {
|
|
669
|
+
key,
|
|
670
|
+
hash: fnv1a(key),
|
|
671
|
+
version,
|
|
672
|
+
face: pick("face"),
|
|
673
|
+
color: pick("color"),
|
|
674
|
+
eyes: pick("eyes"),
|
|
675
|
+
brows: pick("brows"),
|
|
676
|
+
mouth: pick("mouth"),
|
|
677
|
+
cheeks: pick("cheeks"),
|
|
678
|
+
trait: pick("trait"),
|
|
679
|
+
eyewear: pick("eyewear"),
|
|
680
|
+
headwear: pick("headwear"),
|
|
681
|
+
neckwear: pick("neckwear"),
|
|
682
|
+
persona
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
350
686
|
// src/draw.ts
|
|
351
687
|
var VB = [-30, -30, 400, 400];
|
|
352
688
|
var FLOOR = 370;
|
|
@@ -358,8 +694,8 @@ var smooth = (a, b, v) => {
|
|
|
358
694
|
};
|
|
359
695
|
var f2 = (v) => String(Math.round(v * 100) / 100);
|
|
360
696
|
var f3 = (v) => String(Math.round(v * 1000) / 1000);
|
|
361
|
-
var
|
|
362
|
-
var
|
|
697
|
+
var strokeFor2 = (px) => px >= 96 ? 1 : px >= 56 ? 1.25 : px >= 40 ? 1.6 : px >= 30 ? 2 : 2.4;
|
|
698
|
+
var RAD2 = Math.PI / 180;
|
|
363
699
|
var STEM = "M0 0Q3 -19 0 -36";
|
|
364
700
|
var LEAF0 = "M0 -33C-24 -30 -38 -52 -25 -53C-12 -54 -2 -43 0 -33Z";
|
|
365
701
|
var LEAF1 = "M0 -33C5 -54 28 -61 27 -48C26 -36 11 -31 0 -33Z";
|
|
@@ -391,18 +727,18 @@ function seat(crown, d, u) {
|
|
|
391
727
|
const at = ([x, y], b2) => ({
|
|
392
728
|
x: x + R * Math.sin(b2),
|
|
393
729
|
y: y - R * Math.cos(b2),
|
|
394
|
-
a: b2 /
|
|
730
|
+
a: b2 / RAD2
|
|
395
731
|
});
|
|
396
732
|
const P = crown.poly;
|
|
397
733
|
if (P.length === 1)
|
|
398
734
|
return at(P[0], R ? u / R : 0);
|
|
399
|
-
const
|
|
735
|
+
const n2 = P.length;
|
|
400
736
|
const dir = u >= 0 ? 1 : -1;
|
|
401
737
|
let left = Math.abs(u);
|
|
402
738
|
let i = 0;
|
|
403
739
|
let b = 0;
|
|
404
|
-
for (let step = 0;step <
|
|
405
|
-
const j = (i + dir +
|
|
740
|
+
for (let step = 0;step < n2; step++) {
|
|
741
|
+
const j = (i + dir + n2) % n2;
|
|
406
742
|
const [x0, y0] = P[i];
|
|
407
743
|
const [x1, y1] = P[j];
|
|
408
744
|
const ex = x1 - x0;
|
|
@@ -422,7 +758,7 @@ function seat(crown, d, u) {
|
|
|
422
758
|
return {
|
|
423
759
|
x: x0 + ex / L * left + R * nx,
|
|
424
760
|
y: y0 + ey / L * left + R * ny,
|
|
425
|
-
a: be /
|
|
761
|
+
a: be / RAD2
|
|
426
762
|
};
|
|
427
763
|
left -= L;
|
|
428
764
|
i = j;
|
|
@@ -449,7 +785,7 @@ function depth(crown, x, y) {
|
|
|
449
785
|
}
|
|
450
786
|
return (out <= 0 ? out : near) - crown.r;
|
|
451
787
|
}
|
|
452
|
-
var RING_U = 158 * 35 *
|
|
788
|
+
var RING_U = 158 * 35 * RAD2;
|
|
453
789
|
function ringWalk(sh) {
|
|
454
790
|
const ex = sh.eyes[1][0] + sh.brow.hw + 7;
|
|
455
791
|
const top = sh.brow.y - 30;
|
|
@@ -483,14 +819,11 @@ function prune(node) {
|
|
|
483
819
|
}
|
|
484
820
|
function draw(who, pose, o) {
|
|
485
821
|
const sh = FACES[who.face];
|
|
486
|
-
const { body: fill, deep } = COLORS[who.color];
|
|
487
822
|
const P = who.persona;
|
|
488
823
|
const mul = P.mul;
|
|
489
824
|
const add = P.add;
|
|
490
825
|
const g = (c) => pose[c] * (mul[c] ?? 1) + (add[c] ?? 0);
|
|
491
|
-
const spread = P.spread;
|
|
492
826
|
const id = o.id;
|
|
493
|
-
const st = strokeFor(o.size);
|
|
494
827
|
const { baseY, R } = frameOf(sh);
|
|
495
828
|
const defs = [];
|
|
496
829
|
const VBr = { x: VB[0], y: VB[1], width: VB[2], height: VB[3] };
|
|
@@ -584,7 +917,165 @@ function draw(who, pose, o) {
|
|
|
584
917
|
const B = sh.bottom;
|
|
585
918
|
const ty = baseY - alt * R;
|
|
586
919
|
const sc = (v) => Math.round(v * 1e5) / 1e5;
|
|
587
|
-
const
|
|
920
|
+
const [front, back] = (o.variant === "bloc" ? blocParts : peekParts)({
|
|
921
|
+
who,
|
|
922
|
+
pose,
|
|
923
|
+
o,
|
|
924
|
+
defs,
|
|
925
|
+
g
|
|
926
|
+
});
|
|
927
|
+
const off = (dx, dy) => riso ? `translate(${f2(dx * k * upp)} ${f2(dy * k * upp)})` : undefined;
|
|
928
|
+
const av = n("g", "av", {
|
|
929
|
+
transform: `translate(${f2(x)} ${f2(ty)}) rotate(${f2(rot)} 170 ${B}) translate(170 ${B}) scale(${sc(sx)} ${sc(sy)}) translate(-170 ${-B})`,
|
|
930
|
+
filter: dim > 0.01 ? `url(#${id}-dim)` : undefined
|
|
931
|
+
}, [
|
|
932
|
+
n("g", "plateA", {
|
|
933
|
+
transform: off(-0.55, 0.45),
|
|
934
|
+
filter: riso ? `url(#${id}-pA)` : undefined
|
|
935
|
+
}, front),
|
|
936
|
+
n("g", "plateB", {
|
|
937
|
+
transform: off(0.6, -0.5),
|
|
938
|
+
filter: riso ? `url(#${id}-pB)` : undefined
|
|
939
|
+
}, back)
|
|
940
|
+
]);
|
|
941
|
+
const scene = [];
|
|
942
|
+
if (o.frame !== "none") {
|
|
943
|
+
const bg = o.frame === "ink" ? INK.ink : o.frame === "bone" ? INK.bone : INK.paper;
|
|
944
|
+
scene.push(n("rect", "bg", { ...VBr, fill: bg }));
|
|
945
|
+
const th = clamp(g("thing"), 0, 1);
|
|
946
|
+
const dots = [];
|
|
947
|
+
for (let j = 0;j < 3; j++)
|
|
948
|
+
for (let i = 0;i < 3; i++) {
|
|
949
|
+
const q = j * 3 + i;
|
|
950
|
+
const kk = smooth(q / 12, q / 12 + 0.35, th);
|
|
951
|
+
dots.push(n("circle", `lattice.${q}`, {
|
|
952
|
+
cx: 312 + i * 18,
|
|
953
|
+
cy: 2 + j * 18,
|
|
954
|
+
r: f2(1.2 + 2.2 * kk),
|
|
955
|
+
opacity: f3(kk * 0.55)
|
|
956
|
+
}));
|
|
957
|
+
}
|
|
958
|
+
scene.push(n("g", "lattice", { fill: o.frame === "ink" ? INK.bone : INK.ink }, dots));
|
|
959
|
+
}
|
|
960
|
+
scene.push(av);
|
|
961
|
+
if (grainy)
|
|
962
|
+
scene.push(n("rect", "grain", {
|
|
963
|
+
...VBr,
|
|
964
|
+
filter: `url(#${id}-grain)`,
|
|
965
|
+
opacity: o.frame === "ink" ? 0.3 : 0.16,
|
|
966
|
+
"pointer-events": "none"
|
|
967
|
+
}));
|
|
968
|
+
const root = n("svg", "root", {
|
|
969
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
970
|
+
viewBox: VB.join(" "),
|
|
971
|
+
width: o.size,
|
|
972
|
+
height: o.size,
|
|
973
|
+
role: o.title === false ? undefined : "img",
|
|
974
|
+
"aria-label": o.title === false ? undefined : o.title,
|
|
975
|
+
"aria-hidden": o.title === false ? "true" : undefined
|
|
976
|
+
}, [
|
|
977
|
+
n("defs", "defs", {}, defs),
|
|
978
|
+
n("g", "frame", { "clip-path": `url(#${id}-f)` }, scene)
|
|
979
|
+
]);
|
|
980
|
+
return o.live ? root : prune(root) ?? root;
|
|
981
|
+
}
|
|
982
|
+
var HAZE_LEVEL = {
|
|
983
|
+
medium: {
|
|
984
|
+
deep: [0.502, 0.224],
|
|
985
|
+
glow: [0.749, 0.337],
|
|
986
|
+
tint: [0.4, 0.5],
|
|
987
|
+
tintStops: [
|
|
988
|
+
[0, 0.878],
|
|
989
|
+
[0.15, 0.878],
|
|
990
|
+
[0.618, 0.396]
|
|
991
|
+
]
|
|
992
|
+
},
|
|
993
|
+
light: {
|
|
994
|
+
deep: [0.298, 0.133],
|
|
995
|
+
glow: [0.549, 0.247],
|
|
996
|
+
tint: [0.31, 0.387],
|
|
997
|
+
tintStops: [
|
|
998
|
+
[0, 0.549],
|
|
999
|
+
[0.55, 0.247]
|
|
1000
|
+
]
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
1003
|
+
function hazePaint(who, o) {
|
|
1004
|
+
const sh = FACES[who.face];
|
|
1005
|
+
const id = o.id;
|
|
1006
|
+
const L = HAZE_LEVEL[o.size < 32 ? "light" : "medium"];
|
|
1007
|
+
const xs = sh.crown.poly.map((p) => p[0]);
|
|
1008
|
+
const ys = sh.crown.poly.map((p) => p[1]);
|
|
1009
|
+
const x0 = Math.min(...xs) - sh.crown.r;
|
|
1010
|
+
const y0 = Math.min(...ys) - sh.crown.r;
|
|
1011
|
+
const W = Math.max(...xs) + sh.crown.r - x0;
|
|
1012
|
+
const H = sh.bottom - y0;
|
|
1013
|
+
const rnd = mulberry32(fnv1a(`haze:${who.key ?? ""}`));
|
|
1014
|
+
const warm = rnd() < 0.5;
|
|
1015
|
+
const left = rnd() < 0.5;
|
|
1016
|
+
const t = rnd();
|
|
1017
|
+
const tintX = 0.04 + 0.174 * t;
|
|
1018
|
+
const tintY = 0.649 + 0.202 * t;
|
|
1019
|
+
const glowX = 0.38 - 0.12 * rnd();
|
|
1020
|
+
const glowY = 0.12 + 0.099 * rnd();
|
|
1021
|
+
const deepX = 0.251 - 0.151 * rnd();
|
|
1022
|
+
const tintA = 90 - 180 * rnd();
|
|
1023
|
+
const at = (inset, onLeft) => x0 + W * (onLeft ? inset : 1 - inset);
|
|
1024
|
+
const i = WHEEL.indexOf(who.color);
|
|
1025
|
+
const near = WHEEL[(i + (warm ? WHEEL.length - 1 : 1)) % WHEEL.length];
|
|
1026
|
+
const { body, deep } = COLORS[who.color];
|
|
1027
|
+
const blob = (k, color, [cx, cy, a, rx, ry], stops) => n("radialGradient", `haze.${k}`, {
|
|
1028
|
+
id: `${id}-h${k[0]}`,
|
|
1029
|
+
gradientUnits: "userSpaceOnUse",
|
|
1030
|
+
cx: 0,
|
|
1031
|
+
cy: 0,
|
|
1032
|
+
r: 1,
|
|
1033
|
+
gradientTransform: `translate(${f2(cx)} ${f2(cy)}) rotate(${f2(a)}) scale(${f2(rx)} ${f2(ry)})`
|
|
1034
|
+
}, [...stops, [1, 0]].map(([at2, op], j) => n("stop", `haze.${k}.${j}`, {
|
|
1035
|
+
offset: at2,
|
|
1036
|
+
"stop-color": color,
|
|
1037
|
+
"stop-opacity": op
|
|
1038
|
+
})));
|
|
1039
|
+
const fade = ([a, b]) => [
|
|
1040
|
+
[0, a],
|
|
1041
|
+
[0.55, b]
|
|
1042
|
+
];
|
|
1043
|
+
const blobs = [
|
|
1044
|
+
blob("deep", deep, [at(deepX, !left), y0 + H * 0.95, 0, W * 0.5, W * 0.35], fade(L.deep)),
|
|
1045
|
+
blob("tint", HAZE[near].tint, [at(tintX, left), y0 + H * tintY, tintA, W * L.tint[0], W * L.tint[1]], L.tintStops),
|
|
1046
|
+
blob("glow", HAZE[who.color].glow, [at(glowX, !left), y0 + H * glowY, 0, W * 0.475, W * 0.356], fade(L.glow))
|
|
1047
|
+
];
|
|
1048
|
+
const shape = (key, paint) => ("d" in sh.body) ? n("path", key, {
|
|
1049
|
+
d: sh.body.d,
|
|
1050
|
+
fill: paint,
|
|
1051
|
+
stroke: sh.body.stroke ? paint : undefined,
|
|
1052
|
+
"stroke-width": sh.body.stroke,
|
|
1053
|
+
"stroke-linejoin": sh.body.stroke ? "round" : undefined
|
|
1054
|
+
}) : n("circle", key, {
|
|
1055
|
+
cx: sh.body.circle[0],
|
|
1056
|
+
cy: sh.body.circle[1],
|
|
1057
|
+
r: sh.body.circle[2],
|
|
1058
|
+
fill: paint
|
|
1059
|
+
});
|
|
1060
|
+
return [
|
|
1061
|
+
...blobs,
|
|
1062
|
+
n("g", "haze", { id: `${id}-hz` }, [
|
|
1063
|
+
shape("haze.body", body),
|
|
1064
|
+
...["deep", "tint", "glow"].map((k) => shape(`haze.${k}.fill`, `url(#${id}-h${k[0]})`))
|
|
1065
|
+
])
|
|
1066
|
+
];
|
|
1067
|
+
}
|
|
1068
|
+
function peekParts({ who, pose, o, defs, g }) {
|
|
1069
|
+
const sh = FACES[who.face];
|
|
1070
|
+
const { body: fill, deep } = COLORS[who.color];
|
|
1071
|
+
const P = who.persona;
|
|
1072
|
+
const spread = P.spread;
|
|
1073
|
+
const id = o.id;
|
|
1074
|
+
const st = strokeFor2(o.size);
|
|
1075
|
+
const haze = o.variant === "haze";
|
|
1076
|
+
if (haze)
|
|
1077
|
+
defs.push(...hazePaint(who, o));
|
|
1078
|
+
const bodyNode = haze ? n("use", "body", { href: `#${id}-hz` }) : ("d" in sh.body) ? n("path", "body", {
|
|
588
1079
|
d: sh.body.d,
|
|
589
1080
|
fill,
|
|
590
1081
|
stroke: sh.body.stroke ? fill : undefined,
|
|
@@ -672,25 +1163,36 @@ function draw(who, pose, o) {
|
|
|
672
1163
|
const lrx = rx * 1.55;
|
|
673
1164
|
const lry = ry * 1.15;
|
|
674
1165
|
const top = ry + 1.6 - lower * ry * 1.5;
|
|
1166
|
+
const [etx, ety] = bead ? [ex + side * spread + gx * 6, ey + gy * 6] : [ex + side * spread, ey];
|
|
1167
|
+
const lids = [
|
|
1168
|
+
n("rect", `${kk}.lid`, {
|
|
1169
|
+
x: f2(-rx * 2.2),
|
|
1170
|
+
y: f2(-ry * 3),
|
|
1171
|
+
width: f2(rx * 4.4),
|
|
1172
|
+
height: f2(Math.max(0, edge + ry * 3)),
|
|
1173
|
+
transform: `rotate(${f2(a)})`,
|
|
1174
|
+
fill
|
|
1175
|
+
}),
|
|
1176
|
+
n("ellipse", `${kk}.lower`, {
|
|
1177
|
+
cx: 0,
|
|
1178
|
+
cy: f2(top + lry),
|
|
1179
|
+
rx: f2(lrx),
|
|
1180
|
+
ry: f2(lry),
|
|
1181
|
+
fill
|
|
1182
|
+
})
|
|
1183
|
+
];
|
|
1184
|
+
if (haze)
|
|
1185
|
+
defs.push(n("clipPath", `${kk}.lidshape`, { id: `${id}-s${i}` }, lids));
|
|
675
1186
|
const parts = [
|
|
676
1187
|
n("g", `${kk}.inner`, { "clip-path": `url(#${id}-e${i})` }, inner),
|
|
677
|
-
n("g", `${kk}.lids`, { "clip-path": `url(#${id}-l${i})` }, [
|
|
678
|
-
n("
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}),
|
|
686
|
-
n("ellipse", `${kk}.lower`, {
|
|
687
|
-
cx: 0,
|
|
688
|
-
cy: f2(top + lry),
|
|
689
|
-
rx: f2(lrx),
|
|
690
|
-
ry: f2(lry),
|
|
691
|
-
fill
|
|
692
|
-
})
|
|
693
|
-
])
|
|
1188
|
+
n("g", `${kk}.lids`, { "clip-path": `url(#${id}-l${i})` }, haze ? [
|
|
1189
|
+
n("g", `${kk}.lidpaint`, { "clip-path": `url(#${id}-s${i})` }, [
|
|
1190
|
+
n("use", `${kk}.lidbody`, {
|
|
1191
|
+
href: `#${id}-hz`,
|
|
1192
|
+
transform: `translate(${f2(-etx)} ${f2(-ety)})`
|
|
1193
|
+
})
|
|
1194
|
+
])
|
|
1195
|
+
] : lids)
|
|
694
1196
|
];
|
|
695
1197
|
if (who.eyes === "ring")
|
|
696
1198
|
parts.push(n("g", `${kk}.edges`, {
|
|
@@ -724,9 +1226,7 @@ function draw(who, pose, o) {
|
|
|
724
1226
|
"stroke-width": f2(sw * 0.85),
|
|
725
1227
|
opacity: co > 0.01 ? f2(co) : 0
|
|
726
1228
|
}));
|
|
727
|
-
return n("g", kk, {
|
|
728
|
-
transform: bead ? `translate(${f2(ex + side * spread + gx * 6)} ${f2(ey + gy * 6)})` : `translate(${f2(ex + side * spread)} ${ey})`
|
|
729
|
-
}, parts);
|
|
1229
|
+
return n("g", kk, { transform: `translate(${f2(etx)} ${f2(ety)})` }, parts);
|
|
730
1230
|
});
|
|
731
1231
|
const browY = g("browY") - (eyeS - 1) * sh.ry * 0.9;
|
|
732
1232
|
const btilt = g("browTilt");
|
|
@@ -746,8 +1246,8 @@ function draw(who, pose, o) {
|
|
|
746
1246
|
const half = (t) => wedge ? hl + (hr - hl) * t : bw * k2 / 2;
|
|
747
1247
|
const bx = ex + side * spread;
|
|
748
1248
|
const by = sh.brow.y + browY + (i === 1 ? -basym : basym * 0.3);
|
|
749
|
-
const cos = Math.cos(side * btilt *
|
|
750
|
-
const sin = Math.sin(side * btilt *
|
|
1249
|
+
const cos = Math.cos(side * btilt * RAD2);
|
|
1250
|
+
const sin = Math.sin(side * btilt * RAD2);
|
|
751
1251
|
const inside = (dy) => {
|
|
752
1252
|
for (let t = 0;t <= 1; t += 0.25) {
|
|
753
1253
|
const lx = w2 * (2 * t - 1);
|
|
@@ -763,7 +1263,7 @@ function draw(who, pose, o) {
|
|
|
763
1263
|
let hi = 0;
|
|
764
1264
|
if (!inside(0)) {
|
|
765
1265
|
hi = 40;
|
|
766
|
-
for (let
|
|
1266
|
+
for (let k = 0;k < 12; k++) {
|
|
767
1267
|
const mid2 = (lo + hi) / 2;
|
|
768
1268
|
if (inside(mid2))
|
|
769
1269
|
hi = mid2;
|
|
@@ -866,7 +1366,7 @@ function draw(who, pose, o) {
|
|
|
866
1366
|
fill: deep
|
|
867
1367
|
});
|
|
868
1368
|
} else if (who.trait === "fin") {
|
|
869
|
-
const s = seat(sh.crown, -6, -164 * 22 *
|
|
1369
|
+
const s = seat(sh.crown, -6, -164 * 22 * RAD2);
|
|
870
1370
|
const r = s.a + (hair >= 0 ? hair * 20 : hair * 55) - lag * 0.8;
|
|
871
1371
|
traitT = `translate(${f2(s.x)} ${f2(s.y + lag * 0.25)}) rotate(${f2(r)})`;
|
|
872
1372
|
shape = n("path", "trait.shape", {
|
|
@@ -876,7 +1376,7 @@ function draw(who, pose, o) {
|
|
|
876
1376
|
} else if (who.trait === "ring") {
|
|
877
1377
|
const b = 35 - hair * 14 - (hair < 0 ? hair * -21 : 0) + lag * 0.9;
|
|
878
1378
|
const w2 = ringWalk(sh);
|
|
879
|
-
const s = seat(sh.crown, 8, Math.max(w2.min, w2.rest + 158 * (b - 35) *
|
|
1379
|
+
const s = seat(sh.crown, 8, Math.max(w2.min, w2.rest + 158 * (b - 35) * RAD2));
|
|
880
1380
|
traitT = `translate(${f2(s.x)} ${f2(s.y)}) scale(${f2(1 + Math.max(0, hair) * 0.1)})`;
|
|
881
1381
|
shape = n("circle", "trait.shape", {
|
|
882
1382
|
cx: 0,
|
|
@@ -888,7 +1388,7 @@ function draw(who, pose, o) {
|
|
|
888
1388
|
});
|
|
889
1389
|
} else if (who.trait === "dot") {
|
|
890
1390
|
const s = clamp(-hair, 0, 1.2);
|
|
891
|
-
const th = Math.min(1, s / 0.35) * 61.05 *
|
|
1391
|
+
const th = Math.min(1, s / 0.35) * 61.05 * RAD2;
|
|
892
1392
|
const travel = Math.max(0, s - 0.35) / 0.65 * 92;
|
|
893
1393
|
const p = seat(sh.crown, 12.5, 26.1 * th + travel);
|
|
894
1394
|
let cy = p.y;
|
|
@@ -1059,7 +1559,7 @@ function draw(who, pose, o) {
|
|
|
1059
1559
|
}, parts));
|
|
1060
1560
|
}
|
|
1061
1561
|
if (who.neckwear === "tie") {
|
|
1062
|
-
const skew = Math.abs(Math.sin(g("mk") *
|
|
1562
|
+
const skew = Math.abs(Math.sin(g("mk") * RAD2)) * mw;
|
|
1063
1563
|
const bottom = Math.max(0, mt * kb, mb * kb) + skew + m.sw * st;
|
|
1064
1564
|
wardrobe.push(n("g", "neckwear", {
|
|
1065
1565
|
transform: `translate(${m.x} ${f2(m.y + g("my") + bottom + 8)})`,
|
|
@@ -1073,133 +1573,56 @@ function draw(who, pose, o) {
|
|
|
1073
1573
|
})
|
|
1074
1574
|
]));
|
|
1075
1575
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}, [
|
|
1081
|
-
n("g", "plateA", {
|
|
1082
|
-
transform: off(-0.55, 0.45),
|
|
1083
|
-
filter: riso ? `url(#${id}-pA)` : undefined
|
|
1084
|
-
}, [bodyNode, ...cheeks, trait]),
|
|
1085
|
-
n("g", "plateB", {
|
|
1086
|
-
transform: off(0.6, -0.5),
|
|
1087
|
-
filter: riso ? `url(#${id}-pB)` : undefined
|
|
1088
|
-
}, [...eyes, ...brows, mouth, ...wardrobe])
|
|
1089
|
-
]);
|
|
1090
|
-
const scene = [];
|
|
1091
|
-
if (o.frame !== "none") {
|
|
1092
|
-
const bg = o.frame === "ink" ? INK.ink : o.frame === "bone" ? INK.bone : INK.paper;
|
|
1093
|
-
scene.push(n("rect", "bg", { ...VBr, fill: bg }));
|
|
1094
|
-
const th = clamp(g("thing"), 0, 1);
|
|
1095
|
-
const dots = [];
|
|
1096
|
-
for (let j = 0;j < 3; j++)
|
|
1097
|
-
for (let i = 0;i < 3; i++) {
|
|
1098
|
-
const q = j * 3 + i;
|
|
1099
|
-
const kk = smooth(q / 12, q / 12 + 0.35, th);
|
|
1100
|
-
dots.push(n("circle", `lattice.${q}`, {
|
|
1101
|
-
cx: 312 + i * 18,
|
|
1102
|
-
cy: 2 + j * 18,
|
|
1103
|
-
r: f2(1.2 + 2.2 * kk),
|
|
1104
|
-
opacity: f3(kk * 0.55)
|
|
1105
|
-
}));
|
|
1106
|
-
}
|
|
1107
|
-
scene.push(n("g", "lattice", { fill: o.frame === "ink" ? INK.bone : INK.ink }, dots));
|
|
1108
|
-
}
|
|
1109
|
-
scene.push(av);
|
|
1110
|
-
if (grainy)
|
|
1111
|
-
scene.push(n("rect", "grain", {
|
|
1112
|
-
...VBr,
|
|
1113
|
-
filter: `url(#${id}-grain)`,
|
|
1114
|
-
opacity: o.frame === "ink" ? 0.3 : 0.16,
|
|
1115
|
-
"pointer-events": "none"
|
|
1116
|
-
}));
|
|
1117
|
-
const root = n("svg", "root", {
|
|
1118
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1119
|
-
viewBox: VB.join(" "),
|
|
1120
|
-
width: o.size,
|
|
1121
|
-
height: o.size,
|
|
1122
|
-
role: o.title === false ? undefined : "img",
|
|
1123
|
-
"aria-label": o.title === false ? undefined : o.title,
|
|
1124
|
-
"aria-hidden": o.title === false ? "true" : undefined
|
|
1125
|
-
}, [
|
|
1126
|
-
n("defs", "defs", {}, defs),
|
|
1127
|
-
n("g", "frame", { "clip-path": `url(#${id}-f)` }, scene)
|
|
1128
|
-
]);
|
|
1129
|
-
return o.live ? root : prune(root) ?? root;
|
|
1130
|
-
}
|
|
1131
|
-
// src/identity.ts
|
|
1132
|
-
var STYLE = "peek";
|
|
1133
|
-
var tidy = (s) => s.normalize("NFC").trim().replace(/\s+/g, " ").toLowerCase();
|
|
1134
|
-
function fnv1a(str) {
|
|
1135
|
-
let h = 2166136261;
|
|
1136
|
-
for (const b of new TextEncoder().encode(str)) {
|
|
1137
|
-
h ^= b;
|
|
1138
|
-
h = Math.imul(h, 16777619) >>> 0;
|
|
1139
|
-
}
|
|
1140
|
-
return h >>> 0;
|
|
1576
|
+
return [
|
|
1577
|
+
[bodyNode, ...cheeks, trait],
|
|
1578
|
+
[...eyes, ...brows, mouth, ...wardrobe]
|
|
1579
|
+
];
|
|
1141
1580
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1581
|
+
// src/svg.ts
|
|
1582
|
+
var wear = (o, base, s) => ACCESSORIES[s].includes(o[s]) ? o[s] : base[s];
|
|
1583
|
+
function settle(name, o, live = false) {
|
|
1584
|
+
const base = identify(name, { version: o.version });
|
|
1585
|
+
const who = {
|
|
1586
|
+
...base,
|
|
1587
|
+
face: o.face ?? base.face,
|
|
1588
|
+
color: o.color ?? base.color,
|
|
1589
|
+
eyes: o.eyes ?? base.eyes,
|
|
1590
|
+
brows: o.brows ?? base.brows,
|
|
1591
|
+
mouth: o.mouth ?? base.mouth,
|
|
1592
|
+
cheeks: o.cheeks ?? base.cheeks,
|
|
1593
|
+
trait: o.trait ?? base.trait,
|
|
1594
|
+
eyewear: wear(o, base, "eyewear"),
|
|
1595
|
+
headwear: wear(o, base, "headwear"),
|
|
1596
|
+
neckwear: wear(o, base, "neckwear")
|
|
1597
|
+
};
|
|
1598
|
+
const pose = restPose(who, o.expression ?? "normal", o.gaze);
|
|
1599
|
+
const variant = VARIANTS.includes(o.variant) ? o.variant : "peek";
|
|
1600
|
+
const look = {
|
|
1601
|
+
size: o.size ?? 64,
|
|
1602
|
+
frame: o.frame ?? "ink",
|
|
1603
|
+
square: o.square ?? true,
|
|
1604
|
+
riso: o.riso ?? false,
|
|
1605
|
+
live,
|
|
1606
|
+
...variant !== "peek" && { variant }
|
|
1148
1607
|
};
|
|
1608
|
+
const { eyewear, headwear, neckwear, ...legacy } = who;
|
|
1609
|
+
const wardrobe = eyewear !== "none" || headwear !== "none" || neckwear !== "none";
|
|
1610
|
+
const id = o.id ?? `peek-${fnv1a(JSON.stringify([wardrobe ? who : legacy, pose, look])).toString(36)}`;
|
|
1611
|
+
return { who, pose, opts: { ...look, id, title: o.title ?? name } };
|
|
1149
1612
|
}
|
|
1150
|
-
var
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
return
|
|
1613
|
+
var ILLEGAL = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
1614
|
+
var esc = (s) => s.replace(ILLEGAL, "�").replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
1615
|
+
function serialize(node) {
|
|
1616
|
+
let a = "";
|
|
1617
|
+
for (const k in node.attrs)
|
|
1618
|
+
a += ` ${k}="${esc(node.attrs[k])}"`;
|
|
1619
|
+
if (!node.children.length)
|
|
1620
|
+
return `<${node.tag}${a}/>`;
|
|
1621
|
+
return `<${node.tag}${a}>${node.children.map(serialize).join("")}</${node.tag}>`;
|
|
1159
1622
|
}
|
|
1160
|
-
function
|
|
1161
|
-
const
|
|
1162
|
-
|
|
1163
|
-
throw new Error(`peek@${version} does not exist`);
|
|
1164
|
-
const pick = (axis) => LISTS[axis][seed(name, axis, version) % lengths[axis]];
|
|
1165
|
-
const rnd = mulberry32(seed(name, "persona", version));
|
|
1166
|
-
const r = (a, b) => Math.round((a + rnd() * (b - a)) * 100) / 100;
|
|
1167
|
-
const persona = {
|
|
1168
|
-
spread: r(-7, 7),
|
|
1169
|
-
blink: r(0.75, 1.4),
|
|
1170
|
-
add: {
|
|
1171
|
-
browY: r(-4, 4),
|
|
1172
|
-
browTilt: r(-5, 5),
|
|
1173
|
-
browArch: r(-0.2, 0.3),
|
|
1174
|
-
rot: r(-3, 3),
|
|
1175
|
-
hair: r(-0.2, 0.35),
|
|
1176
|
-
gx: r(-0.12, 0.12),
|
|
1177
|
-
my: r(-2, 3)
|
|
1178
|
-
},
|
|
1179
|
-
mul: {
|
|
1180
|
-
eyeS: r(0.92, 1.08),
|
|
1181
|
-
pupil: r(0.9, 1.12),
|
|
1182
|
-
browW: r(0.85, 1.2),
|
|
1183
|
-
mw: r(0.85, 1.18)
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
const key = tidy(name);
|
|
1187
|
-
return {
|
|
1188
|
-
key,
|
|
1189
|
-
hash: fnv1a(key),
|
|
1190
|
-
version,
|
|
1191
|
-
face: pick("face"),
|
|
1192
|
-
color: pick("color"),
|
|
1193
|
-
eyes: pick("eyes"),
|
|
1194
|
-
brows: pick("brows"),
|
|
1195
|
-
mouth: pick("mouth"),
|
|
1196
|
-
cheeks: pick("cheeks"),
|
|
1197
|
-
trait: pick("trait"),
|
|
1198
|
-
eyewear: pick("eyewear"),
|
|
1199
|
-
headwear: pick("headwear"),
|
|
1200
|
-
neckwear: pick("neckwear"),
|
|
1201
|
-
persona
|
|
1202
|
-
};
|
|
1623
|
+
function toSvg(name, props = {}) {
|
|
1624
|
+
const { who, pose, opts } = settle(name, props);
|
|
1625
|
+
return serialize(draw(who, pose, opts));
|
|
1203
1626
|
}
|
|
1204
1627
|
// src/peek.tsx
|
|
1205
1628
|
import {
|
|
@@ -1786,51 +2209,6 @@ class Live {
|
|
|
1786
2209
|
}
|
|
1787
2210
|
}
|
|
1788
2211
|
|
|
1789
|
-
// src/svg.ts
|
|
1790
|
-
var wear = (o, base, s) => ACCESSORIES[s].includes(o[s]) ? o[s] : base[s];
|
|
1791
|
-
function settle(name, o, live = false) {
|
|
1792
|
-
const base = identify(name, { version: o.version });
|
|
1793
|
-
const who = {
|
|
1794
|
-
...base,
|
|
1795
|
-
face: o.face ?? base.face,
|
|
1796
|
-
color: o.color ?? base.color,
|
|
1797
|
-
eyes: o.eyes ?? base.eyes,
|
|
1798
|
-
brows: o.brows ?? base.brows,
|
|
1799
|
-
mouth: o.mouth ?? base.mouth,
|
|
1800
|
-
cheeks: o.cheeks ?? base.cheeks,
|
|
1801
|
-
trait: o.trait ?? base.trait,
|
|
1802
|
-
eyewear: wear(o, base, "eyewear"),
|
|
1803
|
-
headwear: wear(o, base, "headwear"),
|
|
1804
|
-
neckwear: wear(o, base, "neckwear")
|
|
1805
|
-
};
|
|
1806
|
-
const pose = restPose(who, o.expression ?? "normal", o.gaze);
|
|
1807
|
-
const look = {
|
|
1808
|
-
size: o.size ?? 64,
|
|
1809
|
-
frame: o.frame ?? "ink",
|
|
1810
|
-
square: o.square ?? true,
|
|
1811
|
-
riso: o.riso ?? false,
|
|
1812
|
-
live
|
|
1813
|
-
};
|
|
1814
|
-
const { eyewear, headwear, neckwear, ...legacy } = who;
|
|
1815
|
-
const wardrobe = eyewear !== "none" || headwear !== "none" || neckwear !== "none";
|
|
1816
|
-
const id = o.id ?? `peek-${fnv1a(JSON.stringify([wardrobe ? who : legacy, pose, look])).toString(36)}`;
|
|
1817
|
-
return { who, pose, opts: { ...look, id, title: o.title ?? name } };
|
|
1818
|
-
}
|
|
1819
|
-
var ILLEGAL = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
1820
|
-
var esc = (s) => s.replace(ILLEGAL, "�").replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ })[c]);
|
|
1821
|
-
function serialize(node) {
|
|
1822
|
-
let a = "";
|
|
1823
|
-
for (const k in node.attrs)
|
|
1824
|
-
a += ` ${k}="${esc(node.attrs[k])}"`;
|
|
1825
|
-
if (!node.children.length)
|
|
1826
|
-
return `<${node.tag}${a}/>`;
|
|
1827
|
-
return `<${node.tag}${a}>${node.children.map(serialize).join("")}</${node.tag}>`;
|
|
1828
|
-
}
|
|
1829
|
-
function toSvg(name, props = {}) {
|
|
1830
|
-
const { who, pose, opts } = settle(name, props);
|
|
1831
|
-
return serialize(draw(who, pose, opts));
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
2212
|
// src/peek.tsx
|
|
1835
2213
|
var camel = (k) => k.startsWith("aria-") ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
1836
2214
|
function toReact(node, root) {
|
|
@@ -1878,15 +2256,19 @@ function Peek({
|
|
|
1878
2256
|
export {
|
|
1879
2257
|
ACCESSORIES,
|
|
1880
2258
|
AXES,
|
|
2259
|
+
BLOC,
|
|
1881
2260
|
COLORS,
|
|
1882
2261
|
EXPRESSIONS,
|
|
1883
2262
|
FACES,
|
|
1884
2263
|
GROUPS,
|
|
2264
|
+
HAZE,
|
|
1885
2265
|
LATEST,
|
|
1886
2266
|
LISTS,
|
|
1887
2267
|
PARTS,
|
|
1888
2268
|
Peek,
|
|
2269
|
+
VARIANTS,
|
|
1889
2270
|
VERSIONS,
|
|
2271
|
+
WHEEL,
|
|
1890
2272
|
draw,
|
|
1891
2273
|
identify,
|
|
1892
2274
|
settle,
|