@kevin5251984/guild 0.2.17 → 0.2.19

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,432 @@
1
+ /* 18×32 tavern buddy. Handle-seeded hair/skin/cloth + outline. Not a cast. */
2
+ (function (root) {
3
+ "use strict";
4
+ const W = 18;
5
+ const H = 32;
6
+ const OUT = [27, 21, 16];
7
+ const SHOE = [
8
+ [44, 36, 32],
9
+ [62, 44, 34],
10
+ ];
11
+ const PANTS = [
12
+ [42, 48, 62],
13
+ [58, 48, 40],
14
+ [46, 58, 48],
15
+ [72, 64, 58],
16
+ ];
17
+ const HAIR_RGB = [
18
+ [42, 28, 18],
19
+ [22, 18, 16],
20
+ [196, 163, 90],
21
+ [122, 52, 44],
22
+ [58, 72, 108],
23
+ [88, 56, 140],
24
+ [154, 86, 46],
25
+ [72, 44, 58],
26
+ ];
27
+ const SKIN = [
28
+ { hi: [255, 221, 189], base: [247, 201, 170], sh: [212, 158, 126], line: [168, 112, 82] },
29
+ { hi: [232, 182, 136], base: [214, 162, 116], sh: [176, 126, 86], line: [138, 92, 60] },
30
+ { hi: [196, 148, 108], base: [176, 128, 90], sh: [140, 98, 68], line: [104, 70, 48] },
31
+ { hi: [168, 118, 86], base: [146, 100, 70], sh: [112, 76, 52], line: [80, 54, 36] },
32
+ { hi: [130, 90, 64], base: [108, 74, 52], sh: [82, 56, 38], line: [56, 38, 26] },
33
+ ];
34
+ const L = 4;
35
+ const R = 13;
36
+
37
+ function clamp(v) {
38
+ return v < 0 ? 0 : v > 255 ? 255 : Math.round(v);
39
+ }
40
+ function shades(rgb, hi = 1.22, lo = 0.68) {
41
+ return [
42
+ [clamp(rgb[0] * hi), clamp(rgb[1] * hi), clamp(rgb[2] * hi)],
43
+ rgb,
44
+ [clamp(rgb[0] * lo), clamp(rgb[1] * lo), clamp(rgb[2] * lo)],
45
+ ];
46
+ }
47
+ function parseHex(hex) {
48
+ const h = String(hex || "#7c6af7").replace("#", "");
49
+ const full = h.length === 3 ? h[0] + h[0] + h[1] + h[1] + h[2] + h[2] : h;
50
+ return [
51
+ parseInt(full.slice(0, 2), 16) || 120,
52
+ parseInt(full.slice(2, 4), 16) || 100,
53
+ parseInt(full.slice(4, 6), 16) || 90,
54
+ ];
55
+ }
56
+ function set(buf, x, y, c, a = 255) {
57
+ if (x < 0 || x >= W || y < 0 || y >= H) return;
58
+ const i = (y * W + x) * 4;
59
+ buf[i] = c[0];
60
+ buf[i + 1] = c[1];
61
+ buf[i + 2] = c[2];
62
+ buf[i + 3] = a;
63
+ }
64
+ function alpha(buf, x, y) {
65
+ if (x < 0 || x >= W || y < 0 || y >= H) return 0;
66
+ return buf[(y * W + x) * 4 + 3];
67
+ }
68
+ function rect(buf, x0, y0, x1, y1, c) {
69
+ for (let y = y0; y <= y1; y++) for (let x = x0; x <= x1; x++) set(buf, x, y, c);
70
+ }
71
+ function dots(buf, pts, c) {
72
+ for (const [x, y] of pts) set(buf, x, y, c);
73
+ }
74
+
75
+ function drawHead(buf, s) {
76
+ for (let y = 4; y <= 16; y++) {
77
+ for (let x = L; x <= R; x++) {
78
+ if ((x === L || x === R) && (y === 4 || y === 16)) continue;
79
+ if ((x === L + 1 || x === R - 1) && y === 4) continue;
80
+ set(buf, x, y, s.base);
81
+ }
82
+ }
83
+ for (let y = 6; y <= 11; y++) set(buf, 5, y, s.hi);
84
+ set(buf, 6, 5, s.hi);
85
+ set(buf, 7, 5, s.hi);
86
+ for (let y = 6; y <= 15; y++) set(buf, 12, y, s.sh);
87
+ for (const x of [7, 8, 9, 10, 11]) set(buf, x, 16, s.sh);
88
+ set(buf, 3, 9, s.base);
89
+ set(buf, 3, 10, s.base);
90
+ set(buf, 3, 11, s.sh);
91
+ set(buf, 14, 9, s.base);
92
+ set(buf, 14, 10, s.base);
93
+ set(buf, 14, 11, s.sh);
94
+ rect(buf, 7, 17, 10, 18, s.sh);
95
+ rect(buf, 7, 17, 9, 17, s.base);
96
+ }
97
+
98
+ function drawFace(buf, s, brow, mouth, blush, lashes) {
99
+ const white = [250, 248, 244];
100
+ const pup = [46, 38, 42];
101
+ const glint = [252, 250, 248];
102
+ const lash = [54, 40, 48];
103
+ const lip = [158, 86, 80];
104
+ set(buf, 5, 9, white);
105
+ set(buf, 6, 9, pup);
106
+ set(buf, 10, 9, pup);
107
+ set(buf, 11, 9, white);
108
+ set(buf, 5, 9, glint);
109
+ if (lashes) {
110
+ for (const x of [5, 6, 10, 11]) set(buf, x, 8, lash);
111
+ set(buf, 4, 8, lash);
112
+ set(buf, 12, 8, lash);
113
+ set(buf, 10, 9, glint);
114
+ }
115
+ if (brow === 0) for (const x of [5, 6, 10, 11]) set(buf, x, 7, s.line);
116
+ else if (brow === 1) {
117
+ set(buf, 5, 8, s.line);
118
+ set(buf, 6, 7, s.line);
119
+ set(buf, 10, 7, s.line);
120
+ set(buf, 11, 8, s.line);
121
+ } else if (brow === 2) for (const x of [5, 6, 10, 11]) set(buf, x, 6, s.line);
122
+ else {
123
+ set(buf, 5, 7, s.line);
124
+ set(buf, 11, 7, s.line);
125
+ set(buf, 6, 7, s.sh);
126
+ set(buf, 10, 7, s.sh);
127
+ }
128
+ set(buf, 8, 11, s.sh);
129
+ set(buf, 8, 12, s.sh);
130
+ set(buf, 7, 12, s.sh);
131
+ const mouths = [
132
+ [[7, 14], [8, 14], [9, 14], [10, 14]],
133
+ [[7, 14], [8, 14], [9, 14], [10, 14], [6, 13], [11, 13]],
134
+ [[7, 15], [8, 15], [9, 15], [10, 15]],
135
+ [[6, 14], [7, 14], [8, 14], [9, 14], [10, 14], [11, 14], [6, 13], [11, 13]],
136
+ ];
137
+ dots(buf, mouths[mouth], lip);
138
+ if (blush) {
139
+ set(buf, 5, 12, [228, 140, 128]);
140
+ set(buf, 12, 12, [228, 140, 128]);
141
+ }
142
+ }
143
+
144
+ function hairShort(buf, hi, base, sh) {
145
+ rect(buf, L, 2, R, 4, base);
146
+ rect(buf, L - 1, 3, R + 1, 5, base);
147
+ for (let y = 6; y <= 8; y++) {
148
+ set(buf, L - 1, y, base);
149
+ set(buf, L, y, base);
150
+ set(buf, R, y, base);
151
+ set(buf, R + 1, y, base);
152
+ }
153
+ for (let x = L; x <= R; x++) set(buf, x, 5, base);
154
+ for (let y = 2; y <= 5; y++) set(buf, 8, y, sh);
155
+ for (let x = L; x <= 7; x++) if (alpha(buf, x, 2)) set(buf, x, 2, hi);
156
+ for (let x = L; x <= 7; x++) if (alpha(buf, x, 3)) set(buf, x, 3, hi);
157
+ }
158
+ function hairFringe(buf, hi, base, sh, skinBase) {
159
+ hairShort(buf, hi, base, sh);
160
+ rect(buf, 6, 6, 11, 6, base);
161
+ set(buf, 8, 6, skinBase);
162
+ set(buf, 9, 6, skinBase);
163
+ set(buf, 7, 6, hi);
164
+ set(buf, 10, 6, base);
165
+ }
166
+ function hairLong(buf, hi, base, sh, skinBase) {
167
+ hairShort(buf, hi, base, sh);
168
+ rect(buf, 6, 6, 11, 6, base);
169
+ set(buf, 8, 6, skinBase);
170
+ set(buf, 9, 6, skinBase);
171
+ for (let y = 9; y <= 18; y++) {
172
+ set(buf, L - 1, y, base);
173
+ set(buf, R + 1, y, sh);
174
+ }
175
+ set(buf, L - 1, 19, base);
176
+ set(buf, R + 1, 19, sh);
177
+ }
178
+ function hairBun(buf, hi, base, sh, skinBase) {
179
+ rect(buf, L, 3, R, 5, base);
180
+ rect(buf, L - 1, 4, R + 1, 5, base);
181
+ rect(buf, 7, 1, 10, 2, base);
182
+ set(buf, 8, 0, hi);
183
+ set(buf, 9, 0, base);
184
+ rect(buf, 6, 6, 11, 6, base);
185
+ set(buf, 8, 6, skinBase);
186
+ set(buf, 9, 6, skinBase);
187
+ for (let y = 6; y <= 8; y++) {
188
+ set(buf, L, y, base);
189
+ set(buf, R, y, sh);
190
+ }
191
+ for (let x = L; x <= R; x++) if (alpha(buf, x, 3)) set(buf, x, 3, hi);
192
+ }
193
+ function hairCurly(buf, hi, base, sh, skinBase) {
194
+ rect(buf, L, 3, R, 5, base);
195
+ const pts = [
196
+ [4, 2], [5, 1], [6, 2], [7, 1], [8, 2], [9, 1], [10, 2], [11, 1], [12, 2], [13, 2],
197
+ [3, 3], [3, 4], [3, 5], [3, 6], [14, 3], [14, 4], [14, 5], [14, 6], [4, 6], [13, 6],
198
+ ];
199
+ dots(buf, pts, base);
200
+ rect(buf, 6, 6, 11, 6, base);
201
+ set(buf, 8, 6, skinBase);
202
+ set(buf, 9, 6, skinBase);
203
+ dots(buf, [[5, 1], [7, 1], [9, 1], [11, 1]], hi);
204
+ set(buf, R + 1, 5, sh);
205
+ }
206
+ function hairSpiky(buf, hi, base, sh, skinBase) {
207
+ rect(buf, L, 3, R, 5, base);
208
+ rect(buf, L - 1, 4, R + 1, 5, base);
209
+ dots(buf, [[5, 2], [6, 1], [7, 2], [8, 1], [9, 2], [10, 1], [11, 2], [12, 1], [13, 2]], base);
210
+ dots(buf, [[6, 1], [8, 1], [10, 1], [12, 1]], hi);
211
+ rect(buf, 6, 6, 11, 6, base);
212
+ set(buf, 8, 6, skinBase);
213
+ set(buf, 9, 6, skinBase);
214
+ for (let y = 6; y <= 7; y++) {
215
+ set(buf, L, y, base);
216
+ set(buf, R, y, sh);
217
+ }
218
+ }
219
+ function hairBob(buf, hi, base, sh, skinBase) {
220
+ hairShort(buf, hi, base, sh);
221
+ rect(buf, 5, 6, 12, 6, base);
222
+ set(buf, 8, 6, skinBase);
223
+ set(buf, 9, 6, skinBase);
224
+ for (let y = 7; y <= 12; y++) {
225
+ set(buf, L - 1, y, base);
226
+ set(buf, R + 1, y, sh);
227
+ }
228
+ set(buf, L - 1, 13, base);
229
+ set(buf, R + 1, 13, sh);
230
+ }
231
+ function hairPony(buf, hi, base, sh) {
232
+ hairShort(buf, hi, base, sh);
233
+ rect(buf, 11, 0, 13, 2, base);
234
+ set(buf, 12, 0, hi);
235
+ set(buf, 13, 3, sh);
236
+ set(buf, 14, 1, base);
237
+ set(buf, 14, 2, sh);
238
+ }
239
+
240
+ const HAIR_FNS = [hairShort, hairFringe, hairLong, hairBun, hairCurly, hairSpiky, hairBob, hairPony];
241
+
242
+ function drawFacial(buf, kind, color) {
243
+ const [, base, sh] = shades(color);
244
+ if (kind === 1) {
245
+ for (const x of [6, 7, 8, 9, 10]) set(buf, x, 13, base);
246
+ set(buf, 6, 12, base);
247
+ set(buf, 10, 12, base);
248
+ } else if (kind === 2) {
249
+ dots(buf, [[5, 14], [6, 15], [7, 15], [8, 15], [9, 15], [10, 15], [11, 14], [12, 13], [4, 13]], sh);
250
+ } else if (kind === 3) {
251
+ rect(buf, 8, 14, 9, 15, base);
252
+ rect(buf, 7, 13, 10, 13, base);
253
+ }
254
+ }
255
+
256
+ function drawGlasses(buf) {
257
+ const frame = [60, 54, 62];
258
+ const glint = [236, 240, 246];
259
+ for (const x of [5, 6]) {
260
+ set(buf, x, 8, frame);
261
+ set(buf, x, 10, frame);
262
+ }
263
+ set(buf, 4, 9, frame);
264
+ set(buf, 7, 9, frame);
265
+ for (const x of [10, 11]) {
266
+ set(buf, x, 8, frame);
267
+ set(buf, x, 10, frame);
268
+ }
269
+ set(buf, 9, 9, frame);
270
+ set(buf, 12, 9, frame);
271
+ set(buf, 8, 8, frame);
272
+ set(buf, 3, 9, frame);
273
+ set(buf, 13, 9, frame);
274
+ set(buf, 4, 8, glint);
275
+ set(buf, 9, 8, glint);
276
+ }
277
+
278
+ function drawBody(buf, cloth, c1, c2, skin) {
279
+ const [hi, base, sh] = shades(c1);
280
+ rect(buf, 4, 18, 13, 18, base);
281
+ rect(buf, 3, 19, 14, 19, base);
282
+ rect(buf, 4, 20, 13, 24, base);
283
+ for (let y = 20; y <= 24; y++) {
284
+ set(buf, 3, y, sh);
285
+ set(buf, 14, y, sh);
286
+ set(buf, 13, y, sh);
287
+ }
288
+ set(buf, 3, 24, skin.sh);
289
+ set(buf, 14, 24, skin.sh);
290
+ if (cloth === 0) {
291
+ for (const [x, y] of [[6, 18], [7, 18], [10, 18], [11, 18]]) set(buf, x, y, sh);
292
+ rect(buf, 7, 18, 10, 19, skin.sh);
293
+ } else if (cloth === 1) {
294
+ const inner = c2 ? shades(c2)[1] : [235, 233, 226];
295
+ for (let y = 18; y <= 24; y++) {
296
+ set(buf, 8, y, inner);
297
+ set(buf, 9, y, inner);
298
+ }
299
+ for (const [x, y] of [[6, 18], [7, 18], [10, 18], [11, 18]]) set(buf, x, y, sh);
300
+ } else if (cloth === 2) {
301
+ for (const [x, y] of [[6, 18], [7, 18], [10, 18], [11, 18]]) set(buf, x, y, hi);
302
+ set(buf, 8, 19, sh);
303
+ set(buf, 8, 21, sh);
304
+ } else if (cloth === 3) {
305
+ for (const x of [6, 7, 8, 9, 10, 11]) set(buf, x, 18, sh);
306
+ } else if (cloth === 4) {
307
+ const inner = c2 ? shades(c2)[1] : [238, 236, 228];
308
+ rect(buf, 7, 18, 10, 19, inner);
309
+ for (const [x, y] of [[6, 18], [7, 19], [11, 18], [10, 19]]) set(buf, x, y, sh);
310
+ for (let y = 20; y <= 24; y += 2) set(buf, 8, y, sh);
311
+ } else {
312
+ const apron = [236, 224, 196];
313
+ rect(buf, 7, 20, 10, 24, apron);
314
+ set(buf, 8, 19, apron);
315
+ set(buf, 9, 19, apron);
316
+ for (const [x, y] of [[6, 18], [7, 18], [10, 18], [11, 18]]) set(buf, x, y, hi);
317
+ }
318
+ }
319
+
320
+ function drawLegs(buf, pants, shoe, short) {
321
+ const top = short ? 26 : 25;
322
+ const foot = short ? 30 : 31;
323
+ const [, base, sh] = shades(pants);
324
+ rect(buf, 5, top, 7, foot - 1, base);
325
+ rect(buf, 10, top, 12, foot - 1, base);
326
+ for (let y = top; y <= foot - 1; y++) {
327
+ set(buf, 7, y, sh);
328
+ set(buf, 12, y, sh);
329
+ }
330
+ rect(buf, 5, foot, 7, foot, shoe);
331
+ rect(buf, 10, foot, 12, foot, shoe);
332
+ }
333
+
334
+ function elfEars(buf, s) {
335
+ dots(buf, [[2, 8], [2, 7], [3, 7], [3, 8]], s.base);
336
+ set(buf, 2, 7, s.hi);
337
+ dots(buf, [[15, 8], [15, 7], [14, 7], [14, 8]], s.base);
338
+ set(buf, 15, 7, s.hi);
339
+ }
340
+
341
+ function demiEars(buf, s) {
342
+ set(buf, 3, 8, s.base);
343
+ set(buf, 2, 9, s.sh);
344
+ set(buf, 14, 8, s.base);
345
+ set(buf, 15, 9, s.sh);
346
+ }
347
+
348
+ function dwarfStout(buf, clothRgb, skin) {
349
+ const sh = shades(clothRgb)[2];
350
+ for (let y = 19; y <= 24; y++) {
351
+ set(buf, 2, y, sh);
352
+ set(buf, 15, y, sh);
353
+ }
354
+ for (const x of [5, 6, 10, 11]) set(buf, x, 7, skin.line);
355
+ }
356
+
357
+ function outlinePass(buf) {
358
+ const pts = [];
359
+ for (let y = 0; y < H; y++) {
360
+ for (let x = 0; x < W; x++) {
361
+ if (alpha(buf, x, y) !== 0) continue;
362
+ if (
363
+ alpha(buf, x + 1, y) === 255 ||
364
+ alpha(buf, x - 1, y) === 255 ||
365
+ alpha(buf, x, y + 1) === 255 ||
366
+ alpha(buf, x, y - 1) === 255
367
+ ) {
368
+ pts.push([x, y]);
369
+ }
370
+ }
371
+ }
372
+ for (const [x, y] of pts) set(buf, x, y, OUT);
373
+ }
374
+
375
+ function fnv(key) {
376
+ let n = 2166136261;
377
+ const s = String(key || "");
378
+ for (let i = 0; i < s.length; i++) {
379
+ n ^= s.charCodeAt(i);
380
+ n = Math.imul(n, 16777619);
381
+ }
382
+ return n >>> 0;
383
+ }
384
+
385
+ function buddyPixels(shirt, seed) {
386
+ const n = typeof seed === "string" ? fnv(seed) : seed >>> 0;
387
+ const buf = new Uint8ClampedArray(W * H * 4);
388
+ const race = (n >>> 20) % 4;
389
+ const skin = SKIN[n % SKIN.length];
390
+ const hairc = HAIR_RGB[(n * 3) % HAIR_RGB.length];
391
+ const [hi, base, sh] = shades(hairc);
392
+ const cloth = n % 6;
393
+ const pants = PANTS[(n * 5) % PANTS.length];
394
+ const shoe = SHOE[n % SHOE.length];
395
+ const shirtRgb = parseHex(shirt);
396
+ const accent = shades(shirtRgb)[2];
397
+ const brow = race === 1 ? 0 : (n * 7) % 4;
398
+ const mouth = [1, 3, 0, 1][n % 4];
399
+ const lashes = cloth === 1 || cloth === 5 || (n % 5 === 2);
400
+ const blush = lashes && n % 3 !== 0;
401
+ const glasses = n % 19 === 0;
402
+ const facial = 0;
403
+ drawBody(buf, cloth, shirtRgb, accent, skin);
404
+ drawLegs(buf, pants, shoe, race === 1);
405
+ drawHead(buf, skin);
406
+ drawFace(buf, skin, brow, mouth, blush, lashes);
407
+ if (facial) drawFacial(buf, facial, hairc);
408
+ HAIR_FNS[n % HAIR_FNS.length](buf, hi, base, sh, skin.base);
409
+ if (glasses) drawGlasses(buf);
410
+ if (race === 1) dwarfStout(buf, shirtRgb, skin);
411
+ if (race === 2) elfEars(buf, skin);
412
+ if (race === 3) demiEars(buf, skin);
413
+ outlinePass(buf);
414
+ return buf;
415
+ }
416
+
417
+ function drawBuddy(canvas, shirt, seed) {
418
+ const ctx = canvas.getContext("2d");
419
+ canvas.width = W;
420
+ canvas.height = H;
421
+ ctx.imageSmoothingEnabled = false;
422
+ const img = ctx.createImageData(W, H);
423
+ img.data.set(buddyPixels(shirt, seed));
424
+ ctx.putImageData(img, 0, 0);
425
+ }
426
+
427
+ root.BUDDY_W = W;
428
+ root.BUDDY_H = H;
429
+ root.buddyFnv = fnv;
430
+ root.buddyPixels = buddyPixels;
431
+ root.drawBuddy = drawBuddy;
432
+ })(typeof globalThis !== "undefined" ? globalThis : this);