@shopify/klint 0.2.0 → 0.3.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,2489 @@
1
+ import "../chunk-3RG5ZIWI.js";
2
+
3
+ // src/plugins/FontParser.tsx
4
+ var BinaryReader = class {
5
+ constructor() {
6
+ const ab = new ArrayBuffer(8);
7
+ this.t = {
8
+ buff: ab,
9
+ int8: new Int8Array(ab),
10
+ uint8: new Uint8Array(ab),
11
+ int16: new Int16Array(ab),
12
+ uint16: new Uint16Array(ab),
13
+ int32: new Int32Array(ab),
14
+ uint32: new Uint32Array(ab)
15
+ };
16
+ }
17
+ readFixed(data, o) {
18
+ return (data[o] << 8 | data[o + 1]) + (data[o + 2] << 8 | data[o + 3]) / (256 * 256 + 4);
19
+ }
20
+ readF2dot14(data, o) {
21
+ const num = this.readShort(data, o);
22
+ return num / 16384;
23
+ }
24
+ readInt(buff, p) {
25
+ const a = this.t.uint8;
26
+ a[0] = buff[p + 3];
27
+ a[1] = buff[p + 2];
28
+ a[2] = buff[p + 1];
29
+ a[3] = buff[p];
30
+ return this.t.int32[0];
31
+ }
32
+ readInt8(buff, p) {
33
+ const a = this.t.uint8;
34
+ a[0] = buff[p];
35
+ return this.t.int8[0];
36
+ }
37
+ readShort(buff, p) {
38
+ const a = this.t.uint16;
39
+ a[0] = buff[p] << 8 | buff[p + 1];
40
+ return this.t.int16[0];
41
+ }
42
+ readUshort(buff, p) {
43
+ return buff[p] << 8 | buff[p + 1];
44
+ }
45
+ readUshorts(buff, p, len) {
46
+ const arr = [];
47
+ for (let i = 0; i < len; i++) {
48
+ arr.push(this.readUshort(buff, p + i * 2));
49
+ }
50
+ return arr;
51
+ }
52
+ readUint(buff, p) {
53
+ const a = this.t.uint8;
54
+ a[3] = buff[p];
55
+ a[2] = buff[p + 1];
56
+ a[1] = buff[p + 2];
57
+ a[0] = buff[p + 3];
58
+ return this.t.uint32[0];
59
+ }
60
+ readUint64(buff, p) {
61
+ return this.readUint(buff, p) * (4294967295 + 1) + this.readUint(buff, p + 4);
62
+ }
63
+ readASCII(buff, p, l) {
64
+ let s = "";
65
+ for (let i = 0; i < l; i++) s += String.fromCharCode(buff[p + i]);
66
+ return s;
67
+ }
68
+ readBytes(buff, p, l) {
69
+ const arr = [];
70
+ for (let i = 0; i < l; i++) arr.push(buff[p + i]);
71
+ return arr;
72
+ }
73
+ };
74
+ var bin = new BinaryReader();
75
+ function findTable(data, tab, foff = 0) {
76
+ const numTables = bin.readUshort(data, foff + 4);
77
+ let offset = foff + 12;
78
+ for (let i = 0; i < numTables; i++) {
79
+ const tag = bin.readASCII(data, offset, 4);
80
+ const checkSum = bin.readUint(data, offset + 4);
81
+ const toffset = bin.readUint(data, offset + 8);
82
+ const length = bin.readUint(data, offset + 12);
83
+ if (tag === tab) return [toffset, length];
84
+ offset += 16;
85
+ }
86
+ return null;
87
+ }
88
+ var Tables = {
89
+ head: {
90
+ parseTab(data, offset, length) {
91
+ const obj = {};
92
+ const tableVersion = bin.readFixed(data, offset);
93
+ offset += 4;
94
+ obj.fontRevision = bin.readFixed(data, offset);
95
+ offset += 4;
96
+ const checkSumAdjustment = bin.readUint(data, offset);
97
+ offset += 4;
98
+ const magicNumber = bin.readUint(data, offset);
99
+ offset += 4;
100
+ obj.flags = bin.readUshort(data, offset);
101
+ offset += 2;
102
+ obj.unitsPerEm = bin.readUshort(data, offset);
103
+ offset += 2;
104
+ obj.created = bin.readUint64(data, offset);
105
+ offset += 8;
106
+ obj.modified = bin.readUint64(data, offset);
107
+ offset += 8;
108
+ obj.xMin = bin.readShort(data, offset);
109
+ offset += 2;
110
+ obj.yMin = bin.readShort(data, offset);
111
+ offset += 2;
112
+ obj.xMax = bin.readShort(data, offset);
113
+ offset += 2;
114
+ obj.yMax = bin.readShort(data, offset);
115
+ offset += 2;
116
+ obj.macStyle = bin.readUshort(data, offset);
117
+ offset += 2;
118
+ obj.lowestRecPPEM = bin.readUshort(data, offset);
119
+ offset += 2;
120
+ obj.fontDirectionHint = bin.readShort(data, offset);
121
+ offset += 2;
122
+ obj.indexToLocFormat = bin.readShort(data, offset);
123
+ offset += 2;
124
+ obj.glyphDataFormat = bin.readShort(data, offset);
125
+ offset += 2;
126
+ return obj;
127
+ }
128
+ },
129
+ maxp: {
130
+ parseTab(data, offset, length) {
131
+ const obj = {};
132
+ const ver = bin.readUint(data, offset);
133
+ offset += 4;
134
+ obj.numGlyphs = bin.readUshort(data, offset);
135
+ offset += 2;
136
+ return obj;
137
+ }
138
+ },
139
+ hhea: {
140
+ parseTab(data, offset, length) {
141
+ const obj = {};
142
+ const tableVersion = bin.readFixed(data, offset);
143
+ offset += 4;
144
+ const keys = [
145
+ "ascender",
146
+ "descender",
147
+ "lineGap",
148
+ "advanceWidthMax",
149
+ "minLeftSideBearing",
150
+ "minRightSideBearing",
151
+ "xMaxExtent",
152
+ "caretSlopeRise",
153
+ "caretSlopeRun",
154
+ "caretOffset",
155
+ "res0",
156
+ "res1",
157
+ "res2",
158
+ "res3",
159
+ "metricDataFormat",
160
+ "numberOfHMetrics"
161
+ ];
162
+ for (let i = 0; i < keys.length; i++) {
163
+ const key = keys[i];
164
+ const func = key === "advanceWidthMax" || key === "numberOfHMetrics" ? bin.readUshort : bin.readShort;
165
+ obj[key] = func.call(bin, data, offset + i * 2);
166
+ }
167
+ return obj;
168
+ }
169
+ },
170
+ hmtx: {
171
+ parseTab(data, offset, length, font) {
172
+ const aWidth = [];
173
+ const lsBearing = [];
174
+ const nG = font.maxp.numGlyphs;
175
+ const nH = font.hhea.numberOfHMetrics;
176
+ let aw = 0, lsb = 0, i = 0;
177
+ while (i < nH) {
178
+ aw = bin.readUshort(data, offset + (i << 2));
179
+ lsb = bin.readShort(data, offset + (i << 2) + 2);
180
+ aWidth.push(aw);
181
+ lsBearing.push(lsb);
182
+ i++;
183
+ }
184
+ while (i < nG) {
185
+ aWidth.push(aw);
186
+ lsBearing.push(lsb);
187
+ i++;
188
+ }
189
+ return { aWidth, lsBearing };
190
+ }
191
+ },
192
+ loca: {
193
+ parseTab(data, offset, length, font) {
194
+ const obj = [];
195
+ const ver = font.head.indexToLocFormat;
196
+ const len = font.maxp.numGlyphs + 1;
197
+ if (ver === 0) {
198
+ for (let i = 0; i < len; i++) {
199
+ obj.push(bin.readUshort(data, offset + (i << 1)) << 1);
200
+ }
201
+ }
202
+ if (ver === 1) {
203
+ for (let i = 0; i < len; i++) {
204
+ obj.push(bin.readUint(data, offset + (i << 2)));
205
+ }
206
+ }
207
+ return obj;
208
+ }
209
+ },
210
+ kern: {
211
+ parseTab(data, offset, length, font) {
212
+ const version = bin.readUshort(data, offset);
213
+ if (version === 1) return this.parseV1(data, offset, length, font);
214
+ const nTables = bin.readUshort(data, offset + 2);
215
+ offset += 4;
216
+ const map = { glyph1: [], rval: [] };
217
+ for (let i = 0; i < nTables; i++) {
218
+ offset += 2;
219
+ const length2 = bin.readUshort(data, offset);
220
+ offset += 2;
221
+ const coverage = bin.readUshort(data, offset);
222
+ offset += 2;
223
+ let format = coverage >>> 8;
224
+ format &= 15;
225
+ if (format === 0) offset = this.readFormat0(data, offset, map);
226
+ }
227
+ return map;
228
+ },
229
+ parseV1(data, offset, length, font) {
230
+ const version = bin.readFixed(data, offset);
231
+ const nTables = bin.readUint(data, offset + 4);
232
+ offset += 8;
233
+ const map = { glyph1: [], rval: [] };
234
+ for (let i = 0; i < nTables; i++) {
235
+ const length2 = bin.readUint(data, offset);
236
+ offset += 4;
237
+ const coverage = bin.readUshort(data, offset);
238
+ offset += 2;
239
+ const tupleIndex = bin.readUshort(data, offset);
240
+ offset += 2;
241
+ const format = coverage & 255;
242
+ if (format === 0) offset = this.readFormat0(data, offset, map);
243
+ }
244
+ return map;
245
+ },
246
+ readFormat0(data, offset, map) {
247
+ let pleft = -1;
248
+ const nPairs = bin.readUshort(data, offset);
249
+ const searchRange = bin.readUshort(data, offset + 2);
250
+ const entrySelector = bin.readUshort(data, offset + 4);
251
+ const rangeShift = bin.readUshort(data, offset + 6);
252
+ offset += 8;
253
+ for (let j = 0; j < nPairs; j++) {
254
+ const left = bin.readUshort(data, offset);
255
+ offset += 2;
256
+ const right = bin.readUshort(data, offset);
257
+ offset += 2;
258
+ const value = bin.readShort(data, offset);
259
+ offset += 2;
260
+ if (left !== pleft) {
261
+ map.glyph1.push(left);
262
+ map.rval.push({ glyph2: [], vals: [] });
263
+ }
264
+ const rval = map.rval[map.rval.length - 1];
265
+ rval.glyph2.push(right);
266
+ rval.vals.push(value);
267
+ pleft = left;
268
+ }
269
+ return offset;
270
+ }
271
+ }
272
+ };
273
+ var cmap = {
274
+ parseTab(data, offset, length) {
275
+ const obj = { tables: [], ids: {}, off: offset };
276
+ data = new Uint8Array(data.buffer, offset, length);
277
+ offset = 0;
278
+ const version = bin.readUshort(data, offset);
279
+ offset += 2;
280
+ const numTables = bin.readUshort(data, offset);
281
+ offset += 2;
282
+ const offs = [];
283
+ for (let i = 0; i < numTables; i++) {
284
+ const platformID = bin.readUshort(data, offset);
285
+ offset += 2;
286
+ const encodingID = bin.readUshort(data, offset);
287
+ offset += 2;
288
+ const noffset = bin.readUint(data, offset);
289
+ offset += 4;
290
+ const id = "p" + platformID + "e" + encodingID;
291
+ let tind = offs.indexOf(noffset);
292
+ if (tind === -1) {
293
+ tind = obj.tables.length;
294
+ let subt = {};
295
+ offs.push(noffset);
296
+ const format = subt.format = bin.readUshort(data, noffset);
297
+ if (format === 0) subt = this.parse0(data, noffset, subt);
298
+ else if (format === 4) subt = this.parse4(data, noffset, subt);
299
+ else if (format === 6) subt = this.parse6(data, noffset, subt);
300
+ else if (format === 12) subt = this.parse12(data, noffset, subt);
301
+ obj.tables.push(subt);
302
+ }
303
+ obj.ids[id] = tind;
304
+ }
305
+ return obj;
306
+ },
307
+ parse0(data, offset, obj) {
308
+ const startOffset = offset;
309
+ const format = bin.readUshort(data, offset);
310
+ offset += 2;
311
+ const length = bin.readUshort(data, offset);
312
+ offset += 2;
313
+ const language = bin.readUshort(data, offset);
314
+ offset += 2;
315
+ obj.map = [];
316
+ for (let i = 0; i < 256; i++) obj.map.push(data[offset + i]);
317
+ return obj;
318
+ },
319
+ parse4(data, offset, obj) {
320
+ const startOffset = offset;
321
+ const format = bin.readUshort(data, offset);
322
+ offset += 2;
323
+ const length = bin.readUshort(data, offset);
324
+ offset += 2;
325
+ const language = bin.readUshort(data, offset);
326
+ offset += 2;
327
+ const segCountX2 = bin.readUshort(data, offset);
328
+ offset += 2;
329
+ const segCount = segCountX2 >>> 1;
330
+ obj.searchRange = bin.readUshort(data, offset);
331
+ offset += 2;
332
+ obj.entrySelector = bin.readUshort(data, offset);
333
+ offset += 2;
334
+ obj.rangeShift = bin.readUshort(data, offset);
335
+ offset += 2;
336
+ obj.endCount = bin.readUshorts(data, offset, segCount);
337
+ offset += segCount * 2;
338
+ offset += 2;
339
+ obj.startCount = bin.readUshorts(data, offset, segCount);
340
+ offset += segCount * 2;
341
+ obj.idDelta = [];
342
+ for (let i = 0; i < segCount; i++) {
343
+ obj.idDelta.push(bin.readShort(data, offset));
344
+ offset += 2;
345
+ }
346
+ obj.idRangeOffset = bin.readUshorts(data, offset, segCount);
347
+ offset += segCount * 2;
348
+ obj.glyphIdArray = bin.readUshorts(
349
+ data,
350
+ offset,
351
+ startOffset + length - offset >> 1
352
+ );
353
+ return obj;
354
+ },
355
+ parse6(data, offset, obj) {
356
+ const startOffset = offset;
357
+ const format = bin.readUshort(data, offset);
358
+ offset += 2;
359
+ const length = bin.readUshort(data, offset);
360
+ offset += 2;
361
+ const language = bin.readUshort(data, offset);
362
+ offset += 2;
363
+ obj.firstCode = bin.readUshort(data, offset);
364
+ offset += 2;
365
+ obj.entryCount = bin.readUshort(data, offset);
366
+ offset += 2;
367
+ obj.glyphIdArray = bin.readUshorts(data, offset, obj.entryCount);
368
+ return obj;
369
+ },
370
+ parse12(data, offset, obj) {
371
+ const startOffset = offset;
372
+ offset += 4;
373
+ const length = bin.readUint(data, offset);
374
+ offset += 4;
375
+ const language = bin.readUint(data, offset);
376
+ offset += 4;
377
+ const nGroups = bin.readUint(data, offset) * 3;
378
+ offset += 4;
379
+ obj.groups = new Uint32Array(nGroups);
380
+ for (let i = 0; i < nGroups; i += 3) {
381
+ obj.groups[i] = bin.readUint(data, offset + (i << 2));
382
+ obj.groups[i + 1] = bin.readUint(data, offset + (i << 2) + 4);
383
+ obj.groups[i + 2] = bin.readUint(data, offset + (i << 2) + 8);
384
+ }
385
+ return obj;
386
+ }
387
+ };
388
+ var glyf = {
389
+ parseTab(data, offset, length, font) {
390
+ const obj = [];
391
+ const ng = font.maxp.numGlyphs;
392
+ for (let g = 0; g < ng; g++) obj.push(null);
393
+ return obj;
394
+ },
395
+ parseGlyf(font, g) {
396
+ const data = font._data;
397
+ const loca = font.loca;
398
+ if (loca[g] === loca[g + 1]) return null;
399
+ const offset = findTable(data, "glyf", font._offset)[0] + loca[g];
400
+ const gl = {};
401
+ gl.noc = bin.readShort(data, offset);
402
+ let off = offset + 2;
403
+ gl.xMin = bin.readShort(data, off);
404
+ off += 2;
405
+ gl.yMin = bin.readShort(data, off);
406
+ off += 2;
407
+ gl.xMax = bin.readShort(data, off);
408
+ off += 2;
409
+ gl.yMax = bin.readShort(data, off);
410
+ off += 2;
411
+ if (gl.xMin >= gl.xMax || gl.yMin >= gl.yMax) return null;
412
+ if (gl.noc > 0) {
413
+ gl.endPts = [];
414
+ for (let i = 0; i < gl.noc; i++) {
415
+ gl.endPts.push(bin.readUshort(data, off));
416
+ off += 2;
417
+ }
418
+ const instructionLength = bin.readUshort(data, off);
419
+ off += 2;
420
+ if (data.length - off < instructionLength) return null;
421
+ gl.instructions = bin.readBytes(data, off, instructionLength);
422
+ off += instructionLength;
423
+ const crdnum = gl.endPts[gl.noc - 1] + 1;
424
+ gl.flags = [];
425
+ for (let i = 0; i < crdnum; i++) {
426
+ const flag = data[off];
427
+ off++;
428
+ gl.flags.push(flag);
429
+ if ((flag & 8) !== 0) {
430
+ const rep = data[off];
431
+ off++;
432
+ for (let j = 0; j < rep; j++) {
433
+ gl.flags.push(flag);
434
+ i++;
435
+ }
436
+ }
437
+ }
438
+ gl.xs = [];
439
+ for (let i = 0; i < crdnum; i++) {
440
+ const i8 = (gl.flags[i] & 2) !== 0;
441
+ const same = (gl.flags[i] & 16) !== 0;
442
+ if (i8) {
443
+ gl.xs.push(same ? data[off] : -data[off]);
444
+ off++;
445
+ } else {
446
+ if (same) gl.xs.push(0);
447
+ else {
448
+ gl.xs.push(bin.readShort(data, off));
449
+ off += 2;
450
+ }
451
+ }
452
+ }
453
+ gl.ys = [];
454
+ for (let i = 0; i < crdnum; i++) {
455
+ const i8 = (gl.flags[i] & 4) !== 0;
456
+ const same = (gl.flags[i] & 32) !== 0;
457
+ if (i8) {
458
+ gl.ys.push(same ? data[off] : -data[off]);
459
+ off++;
460
+ } else {
461
+ if (same) gl.ys.push(0);
462
+ else {
463
+ gl.ys.push(bin.readShort(data, off));
464
+ off += 2;
465
+ }
466
+ }
467
+ }
468
+ let x = 0, y = 0;
469
+ for (let i = 0; i < crdnum; i++) {
470
+ x += gl.xs[i];
471
+ y += gl.ys[i];
472
+ gl.xs[i] = x;
473
+ gl.ys[i] = y;
474
+ }
475
+ } else {
476
+ const ARG_1_AND_2_ARE_WORDS = 1;
477
+ const ARGS_ARE_XY_VALUES = 2;
478
+ const WE_HAVE_A_SCALE = 8;
479
+ const MORE_COMPONENTS = 32;
480
+ const WE_HAVE_AN_X_AND_Y_SCALE = 64;
481
+ const WE_HAVE_A_TWO_BY_TWO = 128;
482
+ const WE_HAVE_INSTRUCTIONS = 256;
483
+ gl.parts = [];
484
+ let flags;
485
+ do {
486
+ flags = bin.readUshort(data, off);
487
+ off += 2;
488
+ const part = {
489
+ m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 },
490
+ p1: -1,
491
+ p2: -1
492
+ };
493
+ gl.parts.push(part);
494
+ part.glyphIndex = bin.readUshort(data, off);
495
+ off += 2;
496
+ let arg1, arg2;
497
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
498
+ arg1 = bin.readShort(data, off);
499
+ off += 2;
500
+ arg2 = bin.readShort(data, off);
501
+ off += 2;
502
+ } else {
503
+ arg1 = bin.readInt8(data, off);
504
+ off++;
505
+ arg2 = bin.readInt8(data, off);
506
+ off++;
507
+ }
508
+ if (flags & ARGS_ARE_XY_VALUES) {
509
+ part.m.tx = arg1;
510
+ part.m.ty = arg2;
511
+ } else {
512
+ part.p1 = arg1;
513
+ part.p2 = arg2;
514
+ }
515
+ if (flags & WE_HAVE_A_SCALE) {
516
+ part.m.a = part.m.d = bin.readF2dot14(data, off);
517
+ off += 2;
518
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
519
+ part.m.a = bin.readF2dot14(data, off);
520
+ off += 2;
521
+ part.m.d = bin.readF2dot14(data, off);
522
+ off += 2;
523
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
524
+ part.m.a = bin.readF2dot14(data, off);
525
+ off += 2;
526
+ part.m.b = bin.readF2dot14(data, off);
527
+ off += 2;
528
+ part.m.c = bin.readF2dot14(data, off);
529
+ off += 2;
530
+ part.m.d = bin.readF2dot14(data, off);
531
+ off += 2;
532
+ }
533
+ } while (flags & MORE_COMPONENTS);
534
+ if (flags & WE_HAVE_INSTRUCTIONS) {
535
+ const numInstr = bin.readUshort(data, off);
536
+ off += 2;
537
+ gl.instr = [];
538
+ for (let i = 0; i < numInstr; i++) {
539
+ gl.instr.push(data[off]);
540
+ off++;
541
+ }
542
+ }
543
+ }
544
+ return gl;
545
+ }
546
+ };
547
+ var VariableTables = {
548
+ fvar: {
549
+ parseTab(data, offset, length, obj) {
550
+ const name = obj.name;
551
+ let off = offset;
552
+ const axes = [];
553
+ const inst = [];
554
+ off += 8;
555
+ const acnt = bin.readUshort(data, off);
556
+ off += 2;
557
+ off += 2;
558
+ const icnt = bin.readUshort(data, off);
559
+ off += 2;
560
+ const isiz = bin.readUshort(data, off);
561
+ off += 2;
562
+ for (let i = 0; i < acnt; i++) {
563
+ const tag = bin.readASCII(data, off, 4);
564
+ const min = bin.readFixed(data, off + 4);
565
+ const def = bin.readFixed(data, off + 8);
566
+ const max = bin.readFixed(data, off + 12);
567
+ const flg = bin.readUshort(data, off + 16);
568
+ const nid = bin.readUshort(data, off + 18);
569
+ axes.push([tag, min, def, max, flg, name ? name["_" + nid] : null]);
570
+ off += 20;
571
+ }
572
+ for (let i = 0; i < icnt; i++) {
573
+ const snid = bin.readUshort(data, off);
574
+ let pnid = null;
575
+ const flg = bin.readUshort(data, off + 2);
576
+ const crd = [];
577
+ for (let j = 0; j < acnt; j++) {
578
+ crd.push(bin.readFixed(data, off + 4 + j * 4));
579
+ }
580
+ off += 4 + acnt * 4;
581
+ if ((isiz & 3) === 2) {
582
+ pnid = bin.readUshort(data, off);
583
+ off += 2;
584
+ }
585
+ inst.push([name ? name["_" + snid] : null, flg, crd, pnid]);
586
+ }
587
+ return [axes, inst];
588
+ }
589
+ },
590
+ avar: {
591
+ parseTab(data, offset, length, obj) {
592
+ let off = offset;
593
+ const out = [];
594
+ off += 6;
595
+ const acnt = bin.readUshort(data, off);
596
+ off += 2;
597
+ for (let ai = 0; ai < acnt; ai++) {
598
+ const cnt = bin.readUshort(data, off);
599
+ off += 2;
600
+ const poly = [];
601
+ out.push(poly);
602
+ for (let i = 0; i < cnt; i++) {
603
+ const x = bin.readF2dot14(data, off);
604
+ const y = bin.readF2dot14(data, off + 2);
605
+ off += 4;
606
+ poly.push(x, y);
607
+ }
608
+ }
609
+ return out;
610
+ }
611
+ },
612
+ gvar: {
613
+ parseTab(data, offset, length, obj) {
614
+ const EMBEDDED_PEAK_TUPLE = 32768;
615
+ const INTERMEDIATE_REGION = 16384;
616
+ const PRIVATE_POINT_NUMBERS = 8192;
617
+ const DELTAS_ARE_ZERO = 128;
618
+ const DELTAS_ARE_WORDS = 64;
619
+ const POINTS_ARE_WORDS = 128;
620
+ const SHARED_POINT_NUMBERS = 32768;
621
+ function readTuple(data2, o, acnt2) {
622
+ const tup = [];
623
+ for (let j = 0; j < acnt2; j++)
624
+ tup.push(bin.readF2dot14(data2, o + j * 2));
625
+ return tup;
626
+ }
627
+ function readTupleVarHeader(data2, off2, vcnt, acnt2, eoff) {
628
+ const out = [];
629
+ for (let j = 0; j < vcnt; j++) {
630
+ const dsiz = bin.readUshort(data2, off2);
631
+ off2 += 2;
632
+ const tind = bin.readUshort(data2, off2);
633
+ const flag = tind & 61440;
634
+ const tupleIndex = tind & 4095;
635
+ off2 += 2;
636
+ let peak = null, start = null, end = null;
637
+ if (flag & EMBEDDED_PEAK_TUPLE) {
638
+ peak = readTuple(data2, off2, acnt2);
639
+ off2 += acnt2 * 2;
640
+ }
641
+ if (flag & INTERMEDIATE_REGION) {
642
+ start = readTuple(data2, off2, acnt2);
643
+ off2 += acnt2 * 2;
644
+ }
645
+ if (flag & INTERMEDIATE_REGION) {
646
+ end = readTuple(data2, off2, acnt2);
647
+ off2 += acnt2 * 2;
648
+ }
649
+ out.push([dsiz, tupleIndex, flag, start, peak, end]);
650
+ }
651
+ return out;
652
+ }
653
+ function readPointNumbers(data2, off2, gid) {
654
+ let cnt = data2[off2];
655
+ off2++;
656
+ if (cnt === 0) return [[], off2];
657
+ if (127 < cnt) {
658
+ cnt = (cnt & 127) << 8 | data2[off2++];
659
+ }
660
+ const pts = [];
661
+ let last = 0;
662
+ while (pts.length < cnt) {
663
+ const v = data2[off2];
664
+ off2++;
665
+ const wds = (v & POINTS_ARE_WORDS) !== 0;
666
+ const runLength = (v & 127) + 1;
667
+ for (let i = 0; i < runLength; i++) {
668
+ let dif = 0;
669
+ if (wds) {
670
+ dif = bin.readUshort(data2, off2);
671
+ off2 += 2;
672
+ } else {
673
+ dif = data2[off2];
674
+ off2++;
675
+ }
676
+ last += dif;
677
+ pts.push(last);
678
+ }
679
+ }
680
+ return [pts, off2];
681
+ }
682
+ let off = offset + 4;
683
+ const acnt = bin.readUshort(data, off);
684
+ off += 2;
685
+ const tcnt = bin.readUshort(data, off);
686
+ off += 2;
687
+ const toff = bin.readUint(data, off);
688
+ off += 4;
689
+ const gcnt = bin.readUshort(data, off);
690
+ off += 2;
691
+ const flgs = bin.readUshort(data, off);
692
+ off += 2;
693
+ const goff = bin.readUint(data, off);
694
+ off += 4;
695
+ const offs = [];
696
+ for (let i = 0; i < gcnt + 1; i++) {
697
+ offs.push(bin.readUint(data, off + i * 4));
698
+ }
699
+ const tups = [], mins = [], maxs = [];
700
+ off = offset + toff;
701
+ for (let i = 0; i < tcnt; i++) {
702
+ const peak = readTuple(data, off + i * acnt * 2, acnt);
703
+ const imin = [], imax = [];
704
+ tups.push(peak);
705
+ mins.push(imin);
706
+ maxs.push(imax);
707
+ for (let k = 0; k < acnt; k++) {
708
+ imin[k] = Math.min(peak[k], 0);
709
+ imax[k] = Math.max(peak[k], 0);
710
+ }
711
+ }
712
+ const i8 = new Int8Array(data.buffer);
713
+ const tabs = [];
714
+ for (let i = 0; i < gcnt; i++) {
715
+ off = offset + goff + offs[i];
716
+ let vcnt = bin.readUshort(data, off);
717
+ off += 2;
718
+ const snum = vcnt & SHARED_POINT_NUMBERS;
719
+ vcnt &= 4095;
720
+ const soff = bin.readUshort(data, off);
721
+ off += 2;
722
+ const hdr = readTupleVarHeader(
723
+ data,
724
+ off,
725
+ vcnt,
726
+ acnt,
727
+ offset + goff + offs[i + 1]
728
+ );
729
+ const tab = [];
730
+ tabs.push(tab);
731
+ off = offset + goff + offs[i] + soff;
732
+ let sind = [];
733
+ if (snum) {
734
+ const oo = readPointNumbers(data, off, i);
735
+ sind = oo[0];
736
+ off = oo[1];
737
+ }
738
+ for (let j = 0; j < vcnt; j++) {
739
+ const vr = hdr[j];
740
+ const end = off + vr[0];
741
+ let ind = sind;
742
+ if (vr[2] & PRIVATE_POINT_NUMBERS) {
743
+ const oo = readPointNumbers(data, off, i);
744
+ ind = oo[0];
745
+ off = oo[1];
746
+ }
747
+ const ds = [];
748
+ while (off < end) {
749
+ const cb = data[off++];
750
+ const cnt = (cb & 63) + 1;
751
+ if (cb & DELTAS_ARE_ZERO) {
752
+ for (let k = 0; k < cnt; k++) ds.push(0);
753
+ } else if (cb & DELTAS_ARE_WORDS) {
754
+ for (let k = 0; k < cnt; k++) {
755
+ ds.push(bin.readShort(data, off + k * 2));
756
+ }
757
+ off += cnt * 2;
758
+ } else {
759
+ for (let k = 0; k < cnt; k++) ds.push(i8[off + k]);
760
+ off += cnt;
761
+ }
762
+ }
763
+ const ti = vr[1];
764
+ tab.push([
765
+ [
766
+ vr[3] ? vr[3] : mins[ti],
767
+ vr[4] ? vr[4] : tups[ti],
768
+ vr[5] ? vr[5] : maxs[ti]
769
+ ],
770
+ ds,
771
+ ind.length == 0 ? null : ind
772
+ ]);
773
+ if (ind.length != 0 && ind.length * 2 != ds.length) throw "e";
774
+ }
775
+ }
776
+ return tabs;
777
+ }
778
+ },
779
+ HVAR: {
780
+ parseTab(data, offset, length, obj) {
781
+ let off = offset;
782
+ const oo = offset;
783
+ off += 4;
784
+ const varO = bin.readUint(data, off);
785
+ off += 4;
786
+ const advO = bin.readUint(data, off);
787
+ off += 4;
788
+ const lsbO = bin.readUint(data, off);
789
+ off += 4;
790
+ const rsbO = bin.readUint(data, off);
791
+ off += 4;
792
+ if (lsbO !== 0 || rsbO !== 0) throw lsbO;
793
+ off = oo + varO;
794
+ const ioff = off;
795
+ const fmt = bin.readUshort(data, off);
796
+ off += 2;
797
+ if (fmt !== 1) throw "e";
798
+ const vregO = bin.readUint(data, off);
799
+ off += 4;
800
+ const vcnt = bin.readUshort(data, off);
801
+ off += 2;
802
+ const offs = [];
803
+ for (let i = 0; i < vcnt; i++) offs.push(bin.readUint(data, off + i * 4));
804
+ off += vcnt * 4;
805
+ off = ioff + vregO;
806
+ const acnt = bin.readUshort(data, off);
807
+ off += 2;
808
+ const rcnt = bin.readUshort(data, off);
809
+ off += 2;
810
+ const regs = [];
811
+ for (let i = 0; i < rcnt; i++) {
812
+ const crd = [[], [], []];
813
+ regs.push(crd);
814
+ for (let j = 0; j < acnt; j++) {
815
+ crd[0].push(bin.readF2dot14(data, off + 0));
816
+ crd[1].push(bin.readF2dot14(data, off + 2));
817
+ crd[2].push(bin.readF2dot14(data, off + 4));
818
+ off += 6;
819
+ }
820
+ }
821
+ const i8 = new Int8Array(data.buffer);
822
+ const varStore = [];
823
+ for (let i = 0; i < offs.length; i++) {
824
+ off = oo + varO + offs[i];
825
+ const vdata = [];
826
+ varStore.push(vdata);
827
+ const icnt = bin.readUshort(data, off);
828
+ off += 2;
829
+ const dcnt = bin.readUshort(data, off);
830
+ off += 2;
831
+ if (dcnt & 32768) throw "e";
832
+ const rcnt2 = bin.readUshort(data, off);
833
+ off += 2;
834
+ const ixs = [];
835
+ for (let j = 0; j < rcnt2; j++) {
836
+ ixs.push(bin.readUshort(data, off + j * 2));
837
+ }
838
+ off += rcnt2 * 2;
839
+ for (let k = 0; k < icnt; k++) {
840
+ const deltaData = [];
841
+ for (let ri = 0; ri < rcnt2; ri++) {
842
+ deltaData.push(ri < dcnt ? bin.readShort(data, off) : i8[off]);
843
+ off += ri < dcnt ? 2 : 1;
844
+ }
845
+ const dd = new Array(regs.length);
846
+ dd.fill(0);
847
+ vdata.push(dd);
848
+ for (let j = 0; j < ixs.length; j++) dd[ixs[j]] = deltaData[j];
849
+ }
850
+ }
851
+ off = oo + advO;
852
+ const fmt2 = data[off++];
853
+ if (fmt2 !== 0) throw "e";
854
+ const entryFormat = data[off++];
855
+ const mapCount = bin.readUshort(data, off);
856
+ off += 2;
857
+ const INNER_INDEX_BIT_COUNT_MASK = 15;
858
+ const MAP_ENTRY_SIZE_MASK = 48;
859
+ const entrySize = ((entryFormat & MAP_ENTRY_SIZE_MASK) >> 4) + 1;
860
+ const dfs = [];
861
+ for (let i = 0; i < mapCount; i++) {
862
+ let entry = 0;
863
+ if (entrySize === 1) entry = data[off++];
864
+ else {
865
+ entry = bin.readUshort(data, off);
866
+ off += 2;
867
+ }
868
+ const outerIndex = entry >> (entryFormat & INNER_INDEX_BIT_COUNT_MASK) + 1;
869
+ const innerIndex = entry & (1 << (entryFormat & INNER_INDEX_BIT_COUNT_MASK) + 1) - 1;
870
+ dfs.push(varStore[outerIndex][innerIndex]);
871
+ }
872
+ return [regs, dfs];
873
+ }
874
+ }
875
+ };
876
+ var PathBuilder = {
877
+ MoveTo(p, x, y) {
878
+ p.cmds.push("M");
879
+ p.crds.push(x, y);
880
+ },
881
+ LineTo(p, x, y) {
882
+ p.cmds.push("L");
883
+ p.crds.push(x, y);
884
+ },
885
+ qCurveTo(p, a, b, c, d) {
886
+ p.cmds.push("Q");
887
+ p.crds.push(a, b, c, d);
888
+ },
889
+ ClosePath(p) {
890
+ p.cmds.push("Z");
891
+ }
892
+ };
893
+ function codeToGlyph(font, code) {
894
+ if (font._ctab == null) {
895
+ const cmap2 = font.cmap;
896
+ let tind = -1;
897
+ const pps = [
898
+ "p3e10",
899
+ "p0e4",
900
+ "p3e1",
901
+ "p1e0",
902
+ "p0e3",
903
+ "p0e1",
904
+ "p3e0",
905
+ "p3e5"
906
+ ];
907
+ for (let i = 0; i < pps.length; i++) {
908
+ if (cmap2.ids[pps[i]] != null) {
909
+ tind = cmap2.ids[pps[i]];
910
+ break;
911
+ }
912
+ }
913
+ if (tind === -1) throw "no familiar platform and encoding!";
914
+ font._ctab = cmap2.tables[tind];
915
+ }
916
+ const tab = font._ctab;
917
+ const fmt = tab.format;
918
+ let gid = -1;
919
+ if (fmt === 0) {
920
+ if (code >= tab.map.length) gid = 0;
921
+ else gid = tab.map[code];
922
+ } else if (fmt === 4) {
923
+ const ec = tab.endCount;
924
+ gid = 0;
925
+ if (code <= ec[ec.length - 1]) {
926
+ let sind = arrSearch(ec, 1, code);
927
+ if (ec[sind] < code) sind++;
928
+ if (code >= tab.startCount[sind]) {
929
+ let gli = 0;
930
+ if (tab.idRangeOffset[sind] !== 0) {
931
+ gli = tab.glyphIdArray[code - tab.startCount[sind] + (tab.idRangeOffset[sind] >> 1) - (tab.idRangeOffset.length - sind)];
932
+ } else {
933
+ gli = code + tab.idDelta[sind];
934
+ }
935
+ gid = gli & 65535;
936
+ }
937
+ }
938
+ } else if (fmt === 6) {
939
+ const off = code - tab.firstCode;
940
+ const arr = tab.glyphIdArray;
941
+ if (off < 0 || off >= arr.length) gid = 0;
942
+ else gid = arr[off];
943
+ } else if (fmt === 12) {
944
+ const grp = tab.groups;
945
+ gid = 0;
946
+ if (code <= grp[grp.length - 2]) {
947
+ const i = arrSearch(grp, 3, code);
948
+ if (grp[i] <= code && code <= grp[i + 1]) {
949
+ gid = grp[i + 2] + (code - grp[i]);
950
+ }
951
+ }
952
+ } else {
953
+ throw "unknown cmap table format " + tab.format;
954
+ }
955
+ return gid;
956
+ }
957
+ function arrSearch(arr, k, v) {
958
+ let l = 0;
959
+ let r = Math.floor(arr.length / k);
960
+ while (l + 1 !== r) {
961
+ const mid = l + (r - l >>> 1);
962
+ if (arr[mid * k] <= v) l = mid;
963
+ else r = mid;
964
+ }
965
+ return l * k;
966
+ }
967
+ function getGlyphPosition(font, gls, i1) {
968
+ const g1 = gls[i1];
969
+ const g2 = gls[i1 + 1];
970
+ const kern = font.kern;
971
+ if (kern) {
972
+ const ind1 = kern.glyph1.indexOf(g1);
973
+ if (ind1 !== -1) {
974
+ const ind2 = kern.rval[ind1].glyph2.indexOf(g2);
975
+ if (ind2 !== -1) return [0, 0, kern.rval[ind1].vals[ind2], 0];
976
+ }
977
+ }
978
+ return [0, 0, 0, 0];
979
+ }
980
+ function normalizeAxis(font, vv) {
981
+ const fvar = font.fvar;
982
+ const avar = font.avar;
983
+ const fv = fvar ? fvar[0] : null;
984
+ const nv = [];
985
+ for (let i = 0; i < fv.length; i++) {
986
+ const min = fv[i][1];
987
+ const def = fv[i][2];
988
+ const max = fv[i][3];
989
+ const v = Math.max(min, Math.min(max, vv[i]));
990
+ if (v < def) nv[i] = (def - v) / (min - def);
991
+ else if (v > def) nv[i] = (v - def) / (max - def);
992
+ else nv[i] = 0;
993
+ if (avar && nv[i] !== -1) {
994
+ const av = avar[i];
995
+ let j = 0;
996
+ for (; j < av.length; j += 2) if (av[j] >= nv[i]) break;
997
+ const f = (nv[i] - av[j - 2]) / (av[j] - av[j - 2]);
998
+ nv[i] = f * av[j + 1] + (1 - f) * av[j - 1];
999
+ }
1000
+ }
1001
+ return nv;
1002
+ }
1003
+ function shape(font, str, prm = {}) {
1004
+ let axs = prm.axs;
1005
+ if (font.fvar && axs == null) axs = font.fvar[1][font._index || 0][2];
1006
+ const HVAR = font.HVAR;
1007
+ if (axs && HVAR) {
1008
+ axs = normalizeAxis(font, axs);
1009
+ }
1010
+ const gls = [];
1011
+ for (let i = 0; i < str.length; i++) {
1012
+ const cc = str.codePointAt(i);
1013
+ if (cc > 65535) i++;
1014
+ gls.push(codeToGlyph(font, cc));
1015
+ }
1016
+ const shape2 = [];
1017
+ let x = 0, y = 0;
1018
+ for (let i = 0; i < gls.length; i++) {
1019
+ const padj = getGlyphPosition(font, gls, i);
1020
+ const gid = gls[i];
1021
+ let ax = font.hmtx.aWidth[gid] + padj[2];
1022
+ if (HVAR && HVAR[1][gid]) {
1023
+ const difs = HVAR[1][gid];
1024
+ for (let j = 0; j < HVAR[0].length; j++) {
1025
+ ax += _interpolate(HVAR[0][j], axs) * difs[j];
1026
+ }
1027
+ }
1028
+ shape2.push({ g: gid, cl: i, dx: 0, dy: 0, ax, ay: 0 });
1029
+ x += ax;
1030
+ }
1031
+ return shape2;
1032
+ }
1033
+ function glyphToPath(font, gid, noColor, axs) {
1034
+ const path = { cmds: [], crds: [] };
1035
+ if (font.fvar) {
1036
+ if (axs == null) axs = font.fvar[1][font._index || 0][2];
1037
+ axs = normalizeAxis(font, axs);
1038
+ }
1039
+ if (font.glyf) {
1040
+ drawGlyf(gid, font, path, axs);
1041
+ }
1042
+ return { cmds: path.cmds, crds: path.crds };
1043
+ }
1044
+ function drawGlyf(gid, font, path, axs) {
1045
+ let gl = font.glyf[gid];
1046
+ if (gl == null) {
1047
+ gl = font.glyf[gid] = glyf.parseGlyf(font, gid);
1048
+ }
1049
+ if (gl != null) {
1050
+ if (gl.noc > -1) simpleGlyph(gl, font, gid, path, axs);
1051
+ else compoGlyph(gl, font, gid, path, axs);
1052
+ }
1053
+ }
1054
+ function simpleGlyph(gl, font, gid, p, axs) {
1055
+ let xs = gl.xs;
1056
+ let ys = gl.ys;
1057
+ if (font.fvar && axs) {
1058
+ xs = xs.slice(0);
1059
+ ys = ys.slice(0);
1060
+ const gvar = font.gvar;
1061
+ const gv = gvar ? gvar[gid] : null;
1062
+ if (gv) {
1063
+ for (let vi = 0; vi < gv.length; vi++) {
1064
+ const axv = gv[vi][0];
1065
+ const S = _interpolate(axv, axs);
1066
+ if (S < 1e-9) continue;
1067
+ let dfs = gv[vi][1];
1068
+ const ind = gv[vi][2];
1069
+ if (ind) {
1070
+ dfs = gv[vi][1] = interpolateDeltas(dfs, ind, xs, ys, gl.endPts);
1071
+ gv[vi][2] = null;
1072
+ }
1073
+ if (dfs.length === xs.length * 2 + 8) {
1074
+ for (let i = 0; i < xs.length; i++) {
1075
+ xs[i] += S * dfs[i];
1076
+ ys[i] += S * dfs[i + xs.length + 4];
1077
+ }
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ for (let c = 0; c < gl.noc; c++) {
1083
+ const i0 = c === 0 ? 0 : gl.endPts[c - 1] + 1;
1084
+ const il = gl.endPts[c];
1085
+ for (let i = i0; i <= il; i++) {
1086
+ const pr = i === i0 ? il : i - 1;
1087
+ const nx = i === il ? i0 : i + 1;
1088
+ const onCurve = gl.flags[i] & 1;
1089
+ const prOnCurve = gl.flags[pr] & 1;
1090
+ const nxOnCurve = gl.flags[nx] & 1;
1091
+ const x = xs[i], y = ys[i];
1092
+ if (i === i0) {
1093
+ if (onCurve) {
1094
+ if (prOnCurve) PathBuilder.MoveTo(p, xs[pr], ys[pr]);
1095
+ else {
1096
+ PathBuilder.MoveTo(p, x, y);
1097
+ continue;
1098
+ }
1099
+ } else {
1100
+ if (prOnCurve) PathBuilder.MoveTo(p, xs[pr], ys[pr]);
1101
+ else
1102
+ PathBuilder.MoveTo(
1103
+ p,
1104
+ Math.floor((xs[pr] + x) * 0.5),
1105
+ Math.floor((ys[pr] + y) * 0.5)
1106
+ );
1107
+ }
1108
+ }
1109
+ if (onCurve) {
1110
+ if (prOnCurve) PathBuilder.LineTo(p, x, y);
1111
+ } else {
1112
+ if (nxOnCurve) PathBuilder.qCurveTo(p, x, y, xs[nx], ys[nx]);
1113
+ else
1114
+ PathBuilder.qCurveTo(
1115
+ p,
1116
+ x,
1117
+ y,
1118
+ Math.floor((x + xs[nx]) * 0.5),
1119
+ Math.floor((y + ys[nx]) * 0.5)
1120
+ );
1121
+ }
1122
+ }
1123
+ PathBuilder.ClosePath(p);
1124
+ }
1125
+ }
1126
+ function compoGlyph(gl, font, gid, p, axs) {
1127
+ const dx = [0, 0, 0, 0, 0, 0];
1128
+ const dy = [0, 0, 0, 0, 0, 0];
1129
+ const ccnt = gl.parts.length;
1130
+ if (font.fvar && axs) {
1131
+ const gvar = font.gvar;
1132
+ const gv = gvar ? gvar[gid] : null;
1133
+ if (gv) {
1134
+ for (let vi = 0; vi < gv.length; vi++) {
1135
+ const axv = gv[vi][0];
1136
+ const S = _interpolate(axv, axs);
1137
+ if (S < 1e-6) continue;
1138
+ const dfs = gv[vi][1];
1139
+ const ind = gv[vi][2];
1140
+ if (ind == null) {
1141
+ for (let i = 0; i < ccnt; i++) {
1142
+ dx[i] += S * dfs[i];
1143
+ dy[i] += S * dfs[i + ccnt + 4];
1144
+ }
1145
+ } else {
1146
+ for (let j = 0; j < ind.length; j++) {
1147
+ const i = ind[j];
1148
+ dx[i] += S * dfs[0];
1149
+ dy[i] += S * dfs[0 + ccnt];
1150
+ }
1151
+ }
1152
+ }
1153
+ }
1154
+ }
1155
+ for (let j = 0; j < ccnt; j++) {
1156
+ const path = { cmds: [], crds: [] };
1157
+ const prt = gl.parts[j];
1158
+ drawGlyf(prt.glyphIndex, font, path, axs);
1159
+ const m = prt.m;
1160
+ const tx = m.tx + dx[j];
1161
+ const ty = m.ty + dy[j];
1162
+ for (let i = 0; i < path.crds.length; i += 2) {
1163
+ const x = path.crds[i];
1164
+ const y = path.crds[i + 1];
1165
+ p.crds.push(x * m.a + y * m.c + tx);
1166
+ p.crds.push(x * m.b + y * m.d + ty);
1167
+ }
1168
+ for (let i = 0; i < path.cmds.length; i++) p.cmds.push(path.cmds[i]);
1169
+ }
1170
+ }
1171
+ function _interpolate(axs, v) {
1172
+ var acnt = v.length, S = 1;
1173
+ var s = axs[0];
1174
+ var p = axs[1];
1175
+ var e = axs[2];
1176
+ for (var i = 0; i < v.length; i++) {
1177
+ var AS = 1;
1178
+ if (s[i] > p[i] || p[i] > e[i]) AS = 1;
1179
+ else if (s[i] < 0 && e[i] > 0 && p[i] != 0) AS = 1;
1180
+ else if (p[i] == 0) AS = 1;
1181
+ else if (v[i] < s[i] || v[i] > e[i]) AS = 0;
1182
+ else {
1183
+ if (v[i] == p[i]) AS = 1;
1184
+ else if (v[i] < p[i]) AS = (v[i] - s[i]) / (p[i] - s[i]);
1185
+ else AS = (e[i] - v[i]) / (e[i] - p[i]);
1186
+ }
1187
+ S = S * AS;
1188
+ }
1189
+ return S;
1190
+ }
1191
+ function interpolateDeltas(dfs, ind, xs, ys, endPts) {
1192
+ const N = xs.length;
1193
+ const ndfs = new Array(N * 2 + 8);
1194
+ ndfs.fill(0);
1195
+ for (let i = 0; i < N; i++) {
1196
+ let dx = 0, dy = 0;
1197
+ const ii = ind.indexOf(i);
1198
+ if (ii !== -1) {
1199
+ dx = dfs[ii];
1200
+ dy = dfs[ind.length + ii];
1201
+ } else {
1202
+ let cmp = 0;
1203
+ while (endPts[cmp] < i) cmp++;
1204
+ const cmp0 = cmp === 0 ? 0 : endPts[cmp - 1] + 1;
1205
+ const cmp1 = endPts[cmp];
1206
+ let i0 = -1, i1 = -1;
1207
+ for (let j = 0; j < ind.length; j++) {
1208
+ const v = ind[j];
1209
+ if (v < cmp0 || v > cmp1 || v >= N) continue;
1210
+ i0 = j;
1211
+ if (i1 === -1) i1 = j;
1212
+ }
1213
+ for (let j = 0; j < ind.length; j++) {
1214
+ const v = ind[j];
1215
+ if (v < cmp0 || v > cmp1 || v >= N) continue;
1216
+ if (v < i) i0 = j;
1217
+ if (i < v) {
1218
+ i1 = j;
1219
+ break;
1220
+ }
1221
+ }
1222
+ for (let ax = 0; ax < 2; ax++) {
1223
+ const crd = ax === 0 ? xs : ys;
1224
+ const ofs = ax * ind.length;
1225
+ let dlt = 0;
1226
+ const c0 = crd[ind[i0]];
1227
+ const c1 = crd[ind[i1]];
1228
+ const cC = crd[i];
1229
+ const d0 = dfs[ofs + i0];
1230
+ const d1 = dfs[ofs + i1];
1231
+ if (c0 === c1) {
1232
+ if (d0 === d1) dlt = d0;
1233
+ else dlt = 0;
1234
+ } else {
1235
+ if (cC <= Math.min(c0, c1)) {
1236
+ if (c0 < c1) dlt = d0;
1237
+ else dlt = d1;
1238
+ } else if (Math.max(c0, c1) <= cC) {
1239
+ if (c0 < c1) dlt = d1;
1240
+ else dlt = d0;
1241
+ } else {
1242
+ const prop = (cC - c0) / (c1 - c0);
1243
+ dlt = prop * d1 + (1 - prop) * d0;
1244
+ }
1245
+ }
1246
+ if (ax === 0) dx = dlt;
1247
+ else dy = dlt;
1248
+ }
1249
+ }
1250
+ ndfs[i] = dx;
1251
+ ndfs[N + 4 + i] = dy;
1252
+ }
1253
+ return ndfs;
1254
+ }
1255
+ function shapeToPath(font, shape2, prm = {}) {
1256
+ const tpath = { cmds: [], crds: [] };
1257
+ let x = 0, y = 0;
1258
+ const axs = prm.axs;
1259
+ for (let i = 0; i < shape2.length; i++) {
1260
+ const it = shape2[i];
1261
+ const path = glyphToPath(font, it.g, false, axs);
1262
+ const crds = path.crds;
1263
+ for (let j = 0; j < crds.length; j += 2) {
1264
+ tpath.crds.push(crds[j] + x + it.dx);
1265
+ tpath.crds.push(crds[j + 1] + y + it.dy);
1266
+ }
1267
+ for (let j = 0; j < path.cmds.length; j++) {
1268
+ tpath.cmds.push(path.cmds[j]);
1269
+ }
1270
+ x += it.ax;
1271
+ y += it.ay;
1272
+ }
1273
+ return { cmds: tpath.cmds, crds: tpath.crds };
1274
+ }
1275
+ var FontUtils = class {
1276
+ static parse(buff) {
1277
+ const data = new Uint8Array(buff);
1278
+ const tmap = {};
1279
+ const font = readFont(data, 0, 0, tmap);
1280
+ const fvar = font.fvar;
1281
+ if (fvar) {
1282
+ const out = [font];
1283
+ for (let i = 0; i < fvar[1].length; i++) {
1284
+ const fv = fvar[1][i];
1285
+ const obj = {};
1286
+ out.push(obj);
1287
+ for (const p in font) obj[p] = font[p];
1288
+ obj._index = i;
1289
+ const name = obj.name = JSON.parse(
1290
+ JSON.stringify(obj.name || {})
1291
+ );
1292
+ name.fontSubfamily = fv[0];
1293
+ if (fv[3] == null) {
1294
+ fv[3] = ((name.fontFamily || "Font") + "-" + (name.fontSubfamily || "Regular")).replace(/ /g, "");
1295
+ }
1296
+ name.postScriptName = fv[3];
1297
+ }
1298
+ return out;
1299
+ }
1300
+ return [font];
1301
+ }
1302
+ };
1303
+ FontUtils.U = {
1304
+ shape,
1305
+ shapeToPath,
1306
+ glyphToPath,
1307
+ codeToGlyph
1308
+ };
1309
+ function readFont(data, idx, offset, tmap) {
1310
+ const parsers = {
1311
+ cmap,
1312
+ head: Tables.head,
1313
+ hhea: Tables.hhea,
1314
+ maxp: Tables.maxp,
1315
+ hmtx: Tables.hmtx,
1316
+ loca: Tables.loca,
1317
+ kern: Tables.kern,
1318
+ glyf,
1319
+ fvar: VariableTables.fvar,
1320
+ gvar: VariableTables.gvar,
1321
+ avar: VariableTables.avar,
1322
+ HVAR: VariableTables.HVAR
1323
+ };
1324
+ const obj = { _data: data, _index: idx, _offset: offset };
1325
+ for (const t in parsers) {
1326
+ const tab = findTable(data, t, offset);
1327
+ if (tab) {
1328
+ const off = tab[0];
1329
+ let tobj = tmap[off];
1330
+ if (tobj == null) {
1331
+ tobj = parsers[t].parseTab(data, off, tab[1], obj);
1332
+ }
1333
+ obj[t] = tmap[off] = tobj;
1334
+ }
1335
+ }
1336
+ if (!obj.name) {
1337
+ obj.name = { fontFamily: "Unknown", postScriptName: "Unknown" };
1338
+ }
1339
+ return obj;
1340
+ }
1341
+ var FontParser = class {
1342
+ constructor() {
1343
+ this.fonts = /* @__PURE__ */ new Map();
1344
+ }
1345
+ async load(url) {
1346
+ const ext = url.split(".").pop()?.toLowerCase();
1347
+ if (ext === "otf") {
1348
+ console.warn("OTF not supported. Convert: http://convertio.co/otf-ttf/");
1349
+ throw new Error("OTF not supported");
1350
+ }
1351
+ if (ext === "woff") {
1352
+ console.warn(
1353
+ "WOFF not supported. Convert: http://convertio.co/woff-ttf/"
1354
+ );
1355
+ throw new Error("WOFF not supported");
1356
+ }
1357
+ if (ext === "woff2") {
1358
+ console.warn(
1359
+ "WOFF2 not supported. Convert: http://convertio.co/woff2-ttf/"
1360
+ );
1361
+ throw new Error("WOFF2 not supported");
1362
+ }
1363
+ const response = await fetch(url);
1364
+ if (!response.ok) throw new Error("Failed to load font");
1365
+ const buffer = await response.arrayBuffer();
1366
+ return this.loadFromBuffer(buffer);
1367
+ }
1368
+ loadFromBuffer(buffer) {
1369
+ const fonts = FontUtils.parse(buffer);
1370
+ return this.createAPI(fonts[0]);
1371
+ }
1372
+ createAPI(font) {
1373
+ return {
1374
+ // For compatibility with the test - expose the font directly
1375
+ ...font,
1376
+ // Real API implementation
1377
+ toPaths(text, size = 100, options = {}) {
1378
+ const layout = this.layoutText(font, text, size, options);
1379
+ const letters = [];
1380
+ const scale = size / font.head.unitsPerEm;
1381
+ const axisValues = options.axisValues || (font.fvar ? font.fvar[1][font._index || 0][2] : null);
1382
+ for (const letter of layout.letters) {
1383
+ const path2D = new Path2D();
1384
+ const glyphPath = FontUtils.U.glyphToPath(
1385
+ font,
1386
+ letter.glyph.g,
1387
+ false,
1388
+ axisValues
1389
+ );
1390
+ let cmdIndex = 0;
1391
+ for (let i = 0; i < glyphPath.cmds.length; i++) {
1392
+ const cmd = glyphPath.cmds[i];
1393
+ if (cmd === "M") {
1394
+ path2D.moveTo(
1395
+ glyphPath.crds[cmdIndex] * scale,
1396
+ -glyphPath.crds[cmdIndex + 1] * scale
1397
+ );
1398
+ cmdIndex += 2;
1399
+ } else if (cmd === "L") {
1400
+ path2D.lineTo(
1401
+ glyphPath.crds[cmdIndex] * scale,
1402
+ -glyphPath.crds[cmdIndex + 1] * scale
1403
+ );
1404
+ cmdIndex += 2;
1405
+ } else if (cmd === "Q") {
1406
+ path2D.quadraticCurveTo(
1407
+ glyphPath.crds[cmdIndex] * scale,
1408
+ -glyphPath.crds[cmdIndex + 1] * scale,
1409
+ glyphPath.crds[cmdIndex + 2] * scale,
1410
+ -glyphPath.crds[cmdIndex + 3] * scale
1411
+ );
1412
+ cmdIndex += 4;
1413
+ } else if (cmd === "Z") {
1414
+ path2D.closePath();
1415
+ }
1416
+ }
1417
+ letters.push({
1418
+ path: path2D,
1419
+ letterIndex: letter.letterIndex,
1420
+ wordIndex: letter.wordIndex,
1421
+ lineIndex: letter.lineIndex,
1422
+ width: letter.width,
1423
+ height: letter.height,
1424
+ center: { x: letter.x, y: letter.y }
1425
+ });
1426
+ }
1427
+ return { letters, block: layout.block };
1428
+ },
1429
+ toPoints(text, size = 100, options = {}) {
1430
+ const layout = this.layoutText(font, text, size, options);
1431
+ const letters = [];
1432
+ const sampling = options.sampling || 0.25;
1433
+ const scale = size / font.head.unitsPerEm;
1434
+ const axisValues = options.axisValues || (font.fvar ? font.fvar[1][font._index || 0][2] : null);
1435
+ for (const letter of layout.letters) {
1436
+ const glyphPath = FontUtils.U.glyphToPath(
1437
+ font,
1438
+ letter.glyph.g,
1439
+ false,
1440
+ axisValues
1441
+ );
1442
+ const rawPoints = this.samplePathPoints(glyphPath, sampling);
1443
+ const points = rawPoints.map((point) => ({
1444
+ x: point.x * scale,
1445
+ y: -point.y * scale,
1446
+ contour: point.contour
1447
+ // Preserve contour information!
1448
+ }));
1449
+ letters.push({
1450
+ shape: points,
1451
+ center: { x: letter.x, y: letter.y },
1452
+ letterIndex: letter.letterIndex,
1453
+ wordIndex: letter.wordIndex,
1454
+ lineIndex: letter.lineIndex,
1455
+ width: letter.width,
1456
+ height: letter.height
1457
+ });
1458
+ }
1459
+ return { letters, block: layout.block };
1460
+ },
1461
+ // Helper methods
1462
+ layoutText(font2, text, size, options = {}) {
1463
+ const lines = text.split(/\r?\n/);
1464
+ const scale = size / font2.head.unitsPerEm;
1465
+ const letters = [];
1466
+ const letterSpacing = options.letterSpacing || 0;
1467
+ const wordSpacing = options.wordSpacing || 0;
1468
+ const lineSpacing = options.lineSpacing || 0;
1469
+ const axisValues = options.axisValues || (font2.fvar ? font2.fvar[1][font2._index || 0][2] : null);
1470
+ const ascender = font2.hhea.ascender * scale;
1471
+ const descender = font2.hhea.descender * scale;
1472
+ const lineGap = (font2.hhea.lineGap || 0) * scale;
1473
+ const lineHeight = size * 1.2 + lineSpacing;
1474
+ let letterIndex = 0;
1475
+ let wordIndex = 0;
1476
+ const shapeOptions = { ltr: true };
1477
+ if (axisValues) {
1478
+ shapeOptions.axs = axisValues;
1479
+ }
1480
+ const lineWidths = lines.map((line) => {
1481
+ const shaped = FontUtils.U.shape(font2, line, shapeOptions);
1482
+ let width = 0;
1483
+ for (let i = 0; i < shaped.length; i++) {
1484
+ const glyph = shaped[i];
1485
+ const char = line.charAt(i);
1486
+ width += (glyph.ax || 0) * scale;
1487
+ if (char === " ") {
1488
+ width += wordSpacing;
1489
+ } else if (i < shaped.length - 1) {
1490
+ width += letterSpacing;
1491
+ }
1492
+ }
1493
+ return width;
1494
+ });
1495
+ const blockWidth = Math.max(...lineWidths, 0);
1496
+ const blockHeight = lineHeight * lines.length;
1497
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
1498
+ const line = lines[lineIndex];
1499
+ const shaped = FontUtils.U.shape(font2, line, shapeOptions);
1500
+ const lineWidth = lineWidths[lineIndex];
1501
+ let x = 0;
1502
+ if (options.align === "center") {
1503
+ x = (blockWidth - lineWidth) / 2;
1504
+ } else if (options.align === "right") {
1505
+ x = blockWidth - lineWidth;
1506
+ }
1507
+ if (options.anchor === "center" && options.align === "center") {
1508
+ x = -lineWidth / 2;
1509
+ }
1510
+ let y;
1511
+ if (options.baseline === "center") {
1512
+ if (lines.length === 1) {
1513
+ y = 0;
1514
+ } else {
1515
+ y = -blockHeight / 2 + lineHeight / 2 + lineIndex * lineHeight;
1516
+ }
1517
+ } else if (options.baseline === "top") {
1518
+ y = -lineHeight / 2 + lineIndex * lineHeight;
1519
+ } else {
1520
+ y = -lineHeight / 2 + lineIndex * lineHeight;
1521
+ }
1522
+ const middleToBaseline = (ascender + descender) / 2;
1523
+ y += middleToBaseline;
1524
+ for (let i = 0; i < shaped.length; i++) {
1525
+ const glyph = shaped[i];
1526
+ const char = line.charAt(i);
1527
+ const advanceWidth = (glyph.ax || 0) * scale;
1528
+ letters.push({
1529
+ glyph,
1530
+ char,
1531
+ x,
1532
+ y,
1533
+ letterIndex: letterIndex++,
1534
+ wordIndex,
1535
+ lineIndex,
1536
+ width: advanceWidth,
1537
+ height: size
1538
+ });
1539
+ x += advanceWidth;
1540
+ if (char === " ") {
1541
+ x += wordSpacing;
1542
+ wordIndex++;
1543
+ } else if (i < shaped.length - 1) {
1544
+ x += letterSpacing;
1545
+ }
1546
+ }
1547
+ if (line.includes(" ")) wordIndex++;
1548
+ }
1549
+ let offsetX = 0, offsetY = 0;
1550
+ if (options.anchor === "center") {
1551
+ if (options.align !== "center") {
1552
+ offsetX = -blockWidth / 2;
1553
+ }
1554
+ if (options.baseline !== "center") {
1555
+ offsetY = -blockHeight / 2;
1556
+ }
1557
+ }
1558
+ letters.forEach((letter) => {
1559
+ letter.x += offsetX;
1560
+ letter.y += offsetY;
1561
+ });
1562
+ return { letters, block: { width: blockWidth, height: blockHeight } };
1563
+ },
1564
+ samplePathPoints(glyphPath, sampling) {
1565
+ const rawContours = this.parseContours(glyphPath);
1566
+ const contoursWithLength = rawContours.map(
1567
+ (contour, index) => ({
1568
+ contour,
1569
+ originalIndex: index,
1570
+ length: this.calculateContourLength(contour)
1571
+ })
1572
+ );
1573
+ contoursWithLength.sort((a, b) => b.length - a.length);
1574
+ const allPoints = [];
1575
+ for (let i = 0; i < contoursWithLength.length; i++) {
1576
+ const { contour } = contoursWithLength[i];
1577
+ const contourPoints = this.sampleContour(contour, sampling, i);
1578
+ allPoints.push(...contourPoints);
1579
+ }
1580
+ return allPoints;
1581
+ },
1582
+ // Calculate total length of a contour
1583
+ calculateContourLength(contour) {
1584
+ let totalLength = 0;
1585
+ let currentX = contour.startX;
1586
+ let currentY = contour.startY;
1587
+ for (const seg of contour.segments) {
1588
+ if (seg.cmd === "L") {
1589
+ const endX = seg.coords[0];
1590
+ const endY = seg.coords[1];
1591
+ totalLength += Math.sqrt(
1592
+ (endX - currentX) ** 2 + (endY - currentY) ** 2
1593
+ );
1594
+ currentX = endX;
1595
+ currentY = endY;
1596
+ } else if (seg.cmd === "Q") {
1597
+ const controlX = seg.coords[0];
1598
+ const controlY = seg.coords[1];
1599
+ const endX = seg.coords[2];
1600
+ const endY = seg.coords[3];
1601
+ totalLength += this.approximateQuadraticLength(
1602
+ currentX,
1603
+ currentY,
1604
+ controlX,
1605
+ controlY,
1606
+ endX,
1607
+ endY
1608
+ );
1609
+ currentX = endX;
1610
+ currentY = endY;
1611
+ }
1612
+ }
1613
+ return totalLength;
1614
+ },
1615
+ // Parse glyph path into separate contours
1616
+ parseContours(glyphPath) {
1617
+ const contours = [];
1618
+ let currentContour = null;
1619
+ let cmdIndex = 0;
1620
+ for (let i = 0; i < glyphPath.cmds.length; i++) {
1621
+ const cmd = glyphPath.cmds[i];
1622
+ if (cmd === "M") {
1623
+ if (currentContour) {
1624
+ contours.push(currentContour);
1625
+ }
1626
+ currentContour = {
1627
+ startX: glyphPath.crds[cmdIndex],
1628
+ startY: glyphPath.crds[cmdIndex + 1],
1629
+ segments: []
1630
+ };
1631
+ cmdIndex += 2;
1632
+ } else if (cmd === "L" || cmd === "Q") {
1633
+ if (currentContour) {
1634
+ currentContour.segments.push({
1635
+ cmd,
1636
+ coords: glyphPath.crds.slice(
1637
+ cmdIndex,
1638
+ cmdIndex + (cmd === "L" ? 2 : 4)
1639
+ )
1640
+ });
1641
+ }
1642
+ cmdIndex += cmd === "L" ? 2 : 4;
1643
+ } else if (cmd === "Z") {
1644
+ if (currentContour) {
1645
+ contours.push(currentContour);
1646
+ currentContour = null;
1647
+ }
1648
+ }
1649
+ }
1650
+ if (currentContour) {
1651
+ contours.push(currentContour);
1652
+ }
1653
+ return contours;
1654
+ },
1655
+ // Sample a single contour uniformly
1656
+ sampleContour(contour, sampling, contourIndex) {
1657
+ const segments = [];
1658
+ let currentX = contour.startX;
1659
+ let currentY = contour.startY;
1660
+ let totalLength = 0;
1661
+ for (const seg of contour.segments) {
1662
+ if (seg.cmd === "L") {
1663
+ const endX = seg.coords[0];
1664
+ const endY = seg.coords[1];
1665
+ const length = Math.sqrt(
1666
+ (endX - currentX) ** 2 + (endY - currentY) ** 2
1667
+ );
1668
+ segments.push({
1669
+ type: "L",
1670
+ startX: currentX,
1671
+ startY: currentY,
1672
+ endX,
1673
+ endY,
1674
+ length,
1675
+ startLength: totalLength
1676
+ });
1677
+ totalLength += length;
1678
+ currentX = endX;
1679
+ currentY = endY;
1680
+ } else if (seg.cmd === "Q") {
1681
+ const controlX = seg.coords[0];
1682
+ const controlY = seg.coords[1];
1683
+ const endX = seg.coords[2];
1684
+ const endY = seg.coords[3];
1685
+ const length = this.approximateQuadraticLength(
1686
+ currentX,
1687
+ currentY,
1688
+ controlX,
1689
+ controlY,
1690
+ endX,
1691
+ endY
1692
+ );
1693
+ segments.push({
1694
+ type: "Q",
1695
+ startX: currentX,
1696
+ startY: currentY,
1697
+ controlX,
1698
+ controlY,
1699
+ endX,
1700
+ endY,
1701
+ length,
1702
+ startLength: totalLength
1703
+ });
1704
+ totalLength += length;
1705
+ currentX = endX;
1706
+ currentY = endY;
1707
+ }
1708
+ }
1709
+ const points = [];
1710
+ const targetPoints = Math.max(
1711
+ 5,
1712
+ Math.floor(totalLength * sampling * 0.1)
1713
+ );
1714
+ for (let i = 0; i <= targetPoints; i++) {
1715
+ const targetLength = i / targetPoints * totalLength;
1716
+ const pointData = this.getPointAtLengthInContour(
1717
+ segments,
1718
+ targetLength
1719
+ );
1720
+ if (pointData) {
1721
+ points.push({
1722
+ x: pointData.x,
1723
+ y: pointData.y,
1724
+ contour: contourIndex
1725
+ });
1726
+ }
1727
+ }
1728
+ return points;
1729
+ },
1730
+ // Get point at length within a single contour
1731
+ getPointAtLengthInContour(segments, targetLength) {
1732
+ for (const segment of segments) {
1733
+ if (targetLength >= segment.startLength && targetLength <= segment.startLength + segment.length) {
1734
+ const localT = (targetLength - segment.startLength) / segment.length;
1735
+ if (segment.type === "L") {
1736
+ return {
1737
+ x: segment.startX + (segment.endX - segment.startX) * localT,
1738
+ y: segment.startY + (segment.endY - segment.startY) * localT
1739
+ };
1740
+ } else if (segment.type === "Q") {
1741
+ const t = localT;
1742
+ return {
1743
+ x: (1 - t) * (1 - t) * segment.startX + 2 * (1 - t) * t * segment.controlX + t * t * segment.endX,
1744
+ y: (1 - t) * (1 - t) * segment.startY + 2 * (1 - t) * t * segment.controlY + t * t * segment.endY
1745
+ };
1746
+ }
1747
+ }
1748
+ }
1749
+ return null;
1750
+ },
1751
+ // Helper function to approximate quadratic curve length
1752
+ approximateQuadraticLength(x0, y0, x1, y1, x2, y2) {
1753
+ const chordLength = Math.sqrt((x2 - x0) ** 2 + (y2 - y0) ** 2);
1754
+ const controlLength = Math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) + Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
1755
+ return (chordLength + controlLength) / 2;
1756
+ }
1757
+ };
1758
+ }
1759
+ };
1760
+
1761
+ // src/plugins/Delaunay.tsx
1762
+ var Delaunay = class {
1763
+ /**
1764
+ * Perform Delaunay triangulation on a set of points
1765
+ */
1766
+ static triangulate(points) {
1767
+ if (points.length < 3) {
1768
+ return [];
1769
+ }
1770
+ const triangles = [];
1771
+ for (let i = 0; i < points.length - 2; i++) {
1772
+ triangles.push({
1773
+ p1: points[i],
1774
+ p2: points[i + 1],
1775
+ p3: points[i + 2]
1776
+ });
1777
+ }
1778
+ return triangles;
1779
+ }
1780
+ /**
1781
+ * Draw triangles to the canvas
1782
+ */
1783
+ static drawTriangles(ctx, triangles, options) {
1784
+ const { fill = true, stroke = true } = options || {};
1785
+ triangles.forEach((triangle) => {
1786
+ ctx.beginPath();
1787
+ ctx.moveTo(triangle.p1.x, triangle.p1.y);
1788
+ ctx.lineTo(triangle.p2.x, triangle.p2.y);
1789
+ ctx.lineTo(triangle.p3.x, triangle.p3.y);
1790
+ ctx.closePath();
1791
+ if (fill) {
1792
+ if (options?.fillStyle) {
1793
+ const prevFill = ctx.fillStyle;
1794
+ ctx.fillStyle = options.fillStyle;
1795
+ ctx.fill();
1796
+ ctx.fillStyle = prevFill;
1797
+ } else {
1798
+ ctx.fill();
1799
+ }
1800
+ }
1801
+ if (stroke) {
1802
+ if (options?.strokeStyle) {
1803
+ const prevStroke = ctx.strokeStyle;
1804
+ ctx.strokeStyle = options.strokeStyle;
1805
+ ctx.stroke();
1806
+ ctx.strokeStyle = prevStroke;
1807
+ } else {
1808
+ ctx.stroke();
1809
+ }
1810
+ }
1811
+ });
1812
+ }
1813
+ /**
1814
+ * Calculate circumcenter of a triangle
1815
+ */
1816
+ static circumcenter(triangle) {
1817
+ const { p1, p2, p3 } = triangle;
1818
+ const ax = p1.x, ay = p1.y;
1819
+ const bx = p2.x, by = p2.y;
1820
+ const cx = p3.x, cy = p3.y;
1821
+ const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
1822
+ if (Math.abs(d) < 1e-6) {
1823
+ return { x: (ax + bx + cx) / 3, y: (ay + by + cy) / 3 };
1824
+ }
1825
+ const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
1826
+ const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
1827
+ return { x: ux, y: uy };
1828
+ }
1829
+ /**
1830
+ * Check if a point is inside a triangle's circumcircle
1831
+ */
1832
+ static inCircumcircle(point, triangle) {
1833
+ const center = this.circumcenter(triangle);
1834
+ const radius = Math.sqrt(
1835
+ Math.pow(triangle.p1.x - center.x, 2) + Math.pow(triangle.p1.y - center.y, 2)
1836
+ );
1837
+ const distance = Math.sqrt(
1838
+ Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2)
1839
+ );
1840
+ return distance < radius;
1841
+ }
1842
+ };
1843
+
1844
+ // src/plugins/Catmull.tsx
1845
+ var CatmullRom = class {
1846
+ /**
1847
+ * Interpolate points using Catmull-Rom spline
1848
+ */
1849
+ static interpolate(points, tension = 0.5, segments = 20) {
1850
+ if (points.length < 2) return points;
1851
+ const result = [];
1852
+ const extendedPoints = [points[0], ...points, points[points.length - 1]];
1853
+ for (let i = 1; i < extendedPoints.length - 2; i++) {
1854
+ const p0 = extendedPoints[i - 1];
1855
+ const p1 = extendedPoints[i];
1856
+ const p2 = extendedPoints[i + 1];
1857
+ const p3 = extendedPoints[i + 2];
1858
+ for (let t = 0; t < 1; t += 1 / segments) {
1859
+ const t2 = t * t;
1860
+ const t3 = t2 * t;
1861
+ const v0 = tension * (p2.x - p0.x);
1862
+ const v1 = tension * (p3.x - p1.x);
1863
+ const x = p1.x + v0 * t + (3 * (p2.x - p1.x) - 2 * v0 - v1) * t2 + (2 * (p1.x - p2.x) + v0 + v1) * t3;
1864
+ const v0y = tension * (p2.y - p0.y);
1865
+ const v1y = tension * (p3.y - p1.y);
1866
+ const y = p1.y + v0y * t + (3 * (p2.y - p1.y) - 2 * v0y - v1y) * t2 + (2 * (p1.y - p2.y) + v0y + v1y) * t3;
1867
+ result.push({ x, y });
1868
+ }
1869
+ }
1870
+ result.push(points[points.length - 1]);
1871
+ return result;
1872
+ }
1873
+ /**
1874
+ * Draw interpolated curve to canvas
1875
+ */
1876
+ static draw(ctx, points, options) {
1877
+ const { tension = 0.5, segments = 20, closed = false } = options || {};
1878
+ const interpolated = this.interpolate(
1879
+ closed ? [...points, points[0]] : points,
1880
+ tension,
1881
+ segments
1882
+ );
1883
+ ctx.save();
1884
+ if (options?.strokeStyle) {
1885
+ ctx.strokeStyle = options.strokeStyle;
1886
+ }
1887
+ if (options?.lineWidth) {
1888
+ ctx.lineWidth = options.lineWidth;
1889
+ }
1890
+ ctx.beginPath();
1891
+ ctx.moveTo(interpolated[0].x, interpolated[0].y);
1892
+ for (let i = 1; i < interpolated.length; i++) {
1893
+ ctx.lineTo(interpolated[i].x, interpolated[i].y);
1894
+ }
1895
+ if (closed) {
1896
+ ctx.closePath();
1897
+ }
1898
+ ctx.stroke();
1899
+ ctx.restore();
1900
+ }
1901
+ /**
1902
+ * Get path as a Path2D object
1903
+ */
1904
+ static toPath2D(points, options) {
1905
+ const { tension = 0.5, segments = 20, closed = false } = options || {};
1906
+ const interpolated = this.interpolate(
1907
+ closed ? [...points, points[0]] : points,
1908
+ tension,
1909
+ segments
1910
+ );
1911
+ const path = new Path2D();
1912
+ path.moveTo(interpolated[0].x, interpolated[0].y);
1913
+ for (let i = 1; i < interpolated.length; i++) {
1914
+ path.lineTo(interpolated[i].x, interpolated[i].y);
1915
+ }
1916
+ if (closed) {
1917
+ path.closePath();
1918
+ }
1919
+ return path;
1920
+ }
1921
+ };
1922
+
1923
+ // src/plugins/Things.tsx
1924
+ var Things = class {
1925
+ /**
1926
+ * Configure the plugin
1927
+ */
1928
+ static configure(config) {
1929
+ this.config = { ...this.config, ...config };
1930
+ }
1931
+ /**
1932
+ * Create a new thing
1933
+ */
1934
+ static create(options = {}) {
1935
+ if (this.things.size >= (this.config.maxThings || 1e3)) {
1936
+ throw new Error(
1937
+ `Maximum number of things (${this.config.maxThings}) reached`
1938
+ );
1939
+ }
1940
+ const thing = {
1941
+ id: options.id || `thing_${this.idCounter++}`,
1942
+ x: options.x || 0,
1943
+ y: options.y || 0,
1944
+ width: options.width || this.config.defaultSize || 50,
1945
+ height: options.height || this.config.defaultSize || 50,
1946
+ rotation: options.rotation || 0,
1947
+ scale: options.scale || 1,
1948
+ color: options.color || this.config.defaultColor || "#ffffff",
1949
+ data: options.data || {}
1950
+ };
1951
+ this.things.set(thing.id, thing);
1952
+ return thing;
1953
+ }
1954
+ /**
1955
+ * Get a thing by ID
1956
+ */
1957
+ static get(id) {
1958
+ return this.things.get(id);
1959
+ }
1960
+ /**
1961
+ * Get all things
1962
+ */
1963
+ static getAll() {
1964
+ return Array.from(this.things.values());
1965
+ }
1966
+ /**
1967
+ * Update a thing's properties
1968
+ */
1969
+ static update(id, updates) {
1970
+ const thing = this.things.get(id);
1971
+ if (thing) {
1972
+ Object.assign(thing, updates);
1973
+ }
1974
+ }
1975
+ /**
1976
+ * Remove a thing
1977
+ */
1978
+ static remove(id) {
1979
+ return this.things.delete(id);
1980
+ }
1981
+ /**
1982
+ * Clear all things
1983
+ */
1984
+ static clear() {
1985
+ this.things.clear();
1986
+ this.idCounter = 0;
1987
+ }
1988
+ /**
1989
+ * Move a thing
1990
+ */
1991
+ static move(id, dx, dy) {
1992
+ const thing = this.things.get(id);
1993
+ if (thing) {
1994
+ thing.x += dx;
1995
+ thing.y += dy;
1996
+ }
1997
+ }
1998
+ /**
1999
+ * Rotate a thing
2000
+ */
2001
+ static rotate(id, angle) {
2002
+ const thing = this.things.get(id);
2003
+ if (thing) {
2004
+ thing.rotation += angle;
2005
+ }
2006
+ }
2007
+ /**
2008
+ * Scale a thing
2009
+ */
2010
+ static scale(id, factor) {
2011
+ const thing = this.things.get(id);
2012
+ if (thing) {
2013
+ thing.scale *= factor;
2014
+ }
2015
+ }
2016
+ /**
2017
+ * Find things within a radius
2018
+ */
2019
+ static findNear(x, y, radius) {
2020
+ const near = [];
2021
+ const radiusSq = radius * radius;
2022
+ this.things.forEach((thing) => {
2023
+ const dx = thing.x - x;
2024
+ const dy = thing.y - y;
2025
+ if (dx * dx + dy * dy <= radiusSq) {
2026
+ near.push(thing);
2027
+ }
2028
+ });
2029
+ return near;
2030
+ }
2031
+ /**
2032
+ * Find things that overlap with a rectangle
2033
+ */
2034
+ static findInRect(x, y, width, height) {
2035
+ const found = [];
2036
+ this.things.forEach((thing) => {
2037
+ const halfW = thing.width * thing.scale / 2;
2038
+ const halfH = thing.height * thing.scale / 2;
2039
+ if (thing.x + halfW >= x && thing.x - halfW <= x + width && thing.y + halfH >= y && thing.y - halfH <= y + height) {
2040
+ found.push(thing);
2041
+ }
2042
+ });
2043
+ return found;
2044
+ }
2045
+ /**
2046
+ * Apply a function to all things
2047
+ */
2048
+ static forEach(fn) {
2049
+ this.things.forEach(fn);
2050
+ }
2051
+ /**
2052
+ * Map things to a new array
2053
+ */
2054
+ static map(fn) {
2055
+ return Array.from(this.things.values()).map(fn);
2056
+ }
2057
+ /**
2058
+ * Filter things
2059
+ */
2060
+ static filter(fn) {
2061
+ return Array.from(this.things.values()).filter(fn);
2062
+ }
2063
+ /**
2064
+ * Sort things by a property or function
2065
+ */
2066
+ static sort(fn) {
2067
+ return Array.from(this.things.values()).sort(fn);
2068
+ }
2069
+ /**
2070
+ * Draw all things
2071
+ */
2072
+ static draw(ctx, options) {
2073
+ const thingsToDraw = options?.filter ? this.filter(options.filter) : this.getAll();
2074
+ thingsToDraw.forEach((thing) => {
2075
+ if (options?.customDraw) {
2076
+ options.customDraw(ctx, thing);
2077
+ } else {
2078
+ this.drawThing(ctx, thing);
2079
+ }
2080
+ });
2081
+ }
2082
+ /**
2083
+ * Default drawing method for a thing
2084
+ */
2085
+ static drawThing(ctx, thing) {
2086
+ ctx.save();
2087
+ ctx.translate(thing.x, thing.y);
2088
+ ctx.rotate(thing.rotation);
2089
+ ctx.scale(thing.scale, thing.scale);
2090
+ ctx.fillStyle = thing.color;
2091
+ ctx.fillRect(
2092
+ -thing.width / 2,
2093
+ -thing.height / 2,
2094
+ thing.width,
2095
+ thing.height
2096
+ );
2097
+ ctx.restore();
2098
+ }
2099
+ /**
2100
+ * Animate things with a simple physics update
2101
+ */
2102
+ static animatePhysics(deltaTime, options) {
2103
+ const gravity = options?.gravity || 0;
2104
+ const friction = options?.friction || 0.99;
2105
+ const bounds = options?.bounds;
2106
+ this.things.forEach((thing) => {
2107
+ if (!thing.data.vx) thing.data.vx = 0;
2108
+ if (!thing.data.vy) thing.data.vy = 0;
2109
+ thing.data.vy += gravity;
2110
+ thing.data.vx *= friction;
2111
+ thing.data.vy *= friction;
2112
+ thing.x += thing.data.vx;
2113
+ thing.y += thing.data.vy;
2114
+ if (bounds) {
2115
+ const halfW = thing.width * thing.scale / 2;
2116
+ const halfH = thing.height * thing.scale / 2;
2117
+ if (thing.x - halfW < bounds.x) {
2118
+ thing.x = bounds.x + halfW;
2119
+ thing.data.vx *= -0.8;
2120
+ }
2121
+ if (thing.x + halfW > bounds.x + bounds.width) {
2122
+ thing.x = bounds.x + bounds.width - halfW;
2123
+ thing.data.vx *= -0.8;
2124
+ }
2125
+ if (thing.y - halfH < bounds.y) {
2126
+ thing.y = bounds.y + halfH;
2127
+ thing.data.vy *= -0.8;
2128
+ }
2129
+ if (thing.y + halfH > bounds.y + bounds.height) {
2130
+ thing.y = bounds.y + bounds.height - halfH;
2131
+ thing.data.vy *= -0.8;
2132
+ }
2133
+ }
2134
+ });
2135
+ }
2136
+ /**
2137
+ * Get the count of things
2138
+ */
2139
+ static count() {
2140
+ return this.things.size;
2141
+ }
2142
+ /**
2143
+ * Check if a thing exists
2144
+ */
2145
+ static has(id) {
2146
+ return this.things.has(id);
2147
+ }
2148
+ /**
2149
+ * Utility: Get distance between two things
2150
+ */
2151
+ static distance(id1, id2) {
2152
+ const thing1 = this.things.get(id1);
2153
+ const thing2 = this.things.get(id2);
2154
+ if (!thing1 || !thing2) return Infinity;
2155
+ const dx = thing2.x - thing1.x;
2156
+ const dy = thing2.y - thing1.y;
2157
+ return Math.sqrt(dx * dx + dy * dy);
2158
+ }
2159
+ /**
2160
+ * Utility: Check collision between two things
2161
+ */
2162
+ static collides(id1, id2) {
2163
+ const thing1 = this.things.get(id1);
2164
+ const thing2 = this.things.get(id2);
2165
+ if (!thing1 || !thing2) return false;
2166
+ const halfW1 = thing1.width * thing1.scale / 2;
2167
+ const halfH1 = thing1.height * thing1.scale / 2;
2168
+ const halfW2 = thing2.width * thing2.scale / 2;
2169
+ const halfH2 = thing2.height * thing2.scale / 2;
2170
+ return Math.abs(thing1.x - thing2.x) < halfW1 + halfW2 && Math.abs(thing1.y - thing2.y) < halfH1 + halfH2;
2171
+ }
2172
+ };
2173
+ Things.things = /* @__PURE__ */ new Map();
2174
+ Things.config = {
2175
+ maxThings: 1e3,
2176
+ defaultSize: 50,
2177
+ defaultColor: "#ffffff"
2178
+ };
2179
+ Things.idCounter = 0;
2180
+
2181
+ // src/plugins/Sprites.tsx
2182
+ var Sprites = class {
2183
+ /**
2184
+ * Load one or more spritesheets
2185
+ * @param configs - Sprite configuration(s) to load
2186
+ * @returns Promise that resolves when all sprites are loaded
2187
+ */
2188
+ static async load(...configs) {
2189
+ const promises = configs.map((config) => this.loadSingle(config));
2190
+ await Promise.all(promises);
2191
+ }
2192
+ /**
2193
+ * Load a single spritesheet
2194
+ * @param config - Sprite configuration
2195
+ * @returns Promise that resolves when sprite is loaded
2196
+ */
2197
+ static async loadSingle(config) {
2198
+ const { name, url, spriteWidth, spriteHeight, gap = 0 } = config;
2199
+ if (this.loadingPromises.has(name)) {
2200
+ return this.loadingPromises.get(name);
2201
+ }
2202
+ if (this.spritesheets.has(name)) {
2203
+ return Promise.resolve();
2204
+ }
2205
+ const loadPromise = new Promise((resolve, reject) => {
2206
+ const img = new Image();
2207
+ img.onload = () => {
2208
+ const cols = Math.floor((img.width + gap) / (spriteWidth + gap));
2209
+ const rows = Math.floor((img.height + gap) / (spriteHeight + gap));
2210
+ const numSprites = cols * rows;
2211
+ const spritesheet = {
2212
+ image: img,
2213
+ srcNaturalWidth: img.width,
2214
+ srcNaturalHeight: img.height,
2215
+ numSprites,
2216
+ spriteWidth,
2217
+ spriteHeight,
2218
+ gap,
2219
+ cols,
2220
+ rows
2221
+ };
2222
+ this.spritesheets.set(name, spritesheet);
2223
+ this.loadingPromises.delete(name);
2224
+ resolve();
2225
+ };
2226
+ img.onerror = () => {
2227
+ this.loadingPromises.delete(name);
2228
+ reject(new Error(`Failed to load sprite: ${url}`));
2229
+ };
2230
+ img.crossOrigin = "anonymous";
2231
+ img.src = url;
2232
+ });
2233
+ this.loadingPromises.set(name, loadPromise);
2234
+ return loadPromise;
2235
+ }
2236
+ /**
2237
+ * Get spritesheet information
2238
+ * @param name - Name of the spritesheet
2239
+ * @returns Spritesheet data or undefined if not loaded
2240
+ */
2241
+ static sheet(name) {
2242
+ return this.spritesheets.get(name);
2243
+ }
2244
+ /**
2245
+ * Draw a sprite from a spritesheet
2246
+ * @param ctx - Klint context
2247
+ * @param sheetName - Name of the spritesheet
2248
+ * @param sprite - Sprite index to draw
2249
+ * @param x - X position to draw at
2250
+ * @param y - Y position to draw at
2251
+ * @param options - Drawing options
2252
+ */
2253
+ static draw(ctx, sheetName, sprite, x, y, options) {
2254
+ const sheet = this.spritesheets.get(sheetName);
2255
+ if (!sheet) {
2256
+ console.warn(`Spritesheet '${sheetName}' not loaded`);
2257
+ return;
2258
+ }
2259
+ const spriteIndex = Math.floor(sprite) % sheet.numSprites;
2260
+ const col = spriteIndex % sheet.cols;
2261
+ const row = Math.floor(spriteIndex / sheet.cols);
2262
+ const sx = col * (sheet.spriteWidth + sheet.gap);
2263
+ const sy = row * (sheet.spriteHeight + sheet.gap);
2264
+ const drawWidth = options?.width || sheet.spriteWidth;
2265
+ const drawHeight = options?.height || sheet.spriteHeight;
2266
+ const scale = options?.scale || 1;
2267
+ const rotation = options?.rotation || 0;
2268
+ const flipX = options?.flipX || false;
2269
+ const flipY = options?.flipY || false;
2270
+ const alpha = options?.alpha !== void 0 ? options.alpha : 1;
2271
+ ctx.save();
2272
+ ctx.translate(x, y);
2273
+ if (rotation !== 0) {
2274
+ ctx.rotate(rotation);
2275
+ }
2276
+ if (flipX || flipY) {
2277
+ ctx.scale(flipX ? -1 : 1, flipY ? -1 : 1);
2278
+ }
2279
+ if (scale !== 1) {
2280
+ ctx.scale(scale, scale);
2281
+ }
2282
+ if (alpha !== 1) {
2283
+ ctx.globalAlpha = alpha;
2284
+ }
2285
+ ctx.drawImage(
2286
+ sheet.image,
2287
+ sx,
2288
+ sy,
2289
+ sheet.spriteWidth,
2290
+ sheet.spriteHeight,
2291
+ -drawWidth / 2,
2292
+ -drawHeight / 2,
2293
+ drawWidth,
2294
+ drawHeight
2295
+ );
2296
+ ctx.restore();
2297
+ }
2298
+ /**
2299
+ * Draw a sprite at its actual position without centering
2300
+ * @param ctx - Klint context
2301
+ * @param sheetName - Name of the spritesheet
2302
+ * @param sprite - Sprite index to draw
2303
+ * @param x - X position to draw at
2304
+ * @param y - Y position to draw at
2305
+ * @param width - Width to draw (optional)
2306
+ * @param height - Height to draw (optional)
2307
+ */
2308
+ static drawCorner(ctx, sheetName, sprite, x, y, width, height) {
2309
+ const sheet = this.spritesheets.get(sheetName);
2310
+ if (!sheet) {
2311
+ console.warn(`Spritesheet '${sheetName}' not loaded`);
2312
+ return;
2313
+ }
2314
+ const spriteIndex = Math.floor(sprite) % sheet.numSprites;
2315
+ const col = spriteIndex % sheet.cols;
2316
+ const row = Math.floor(spriteIndex / sheet.cols);
2317
+ const sx = col * (sheet.spriteWidth + sheet.gap);
2318
+ const sy = row * (sheet.spriteHeight + sheet.gap);
2319
+ const drawWidth = width || sheet.spriteWidth;
2320
+ const drawHeight = height || sheet.spriteHeight;
2321
+ ctx.drawImage(
2322
+ sheet.image,
2323
+ sx,
2324
+ sy,
2325
+ sheet.spriteWidth,
2326
+ sheet.spriteHeight,
2327
+ x,
2328
+ y,
2329
+ drawWidth,
2330
+ drawHeight
2331
+ );
2332
+ }
2333
+ /**
2334
+ * Create an animation from a range of sprites
2335
+ * @param sheetName - Name of the spritesheet
2336
+ * @param startSprite - Starting sprite index
2337
+ * @param endSprite - Ending sprite index
2338
+ * @param frameDuration - Duration of each frame in milliseconds
2339
+ * @returns Animation object
2340
+ */
2341
+ static animation(sheetName, startSprite, endSprite, frameDuration = 100) {
2342
+ return new SpriteAnimation(
2343
+ sheetName,
2344
+ startSprite,
2345
+ endSprite,
2346
+ frameDuration
2347
+ );
2348
+ }
2349
+ /**
2350
+ * Check if a spritesheet is loaded
2351
+ * @param name - Name of the spritesheet
2352
+ * @returns True if loaded, false otherwise
2353
+ */
2354
+ static hasSheet(name) {
2355
+ return this.spritesheets.has(name);
2356
+ }
2357
+ /**
2358
+ * Unload a spritesheet
2359
+ * @param name - Name of the spritesheet to unload
2360
+ */
2361
+ static unload(name) {
2362
+ this.spritesheets.delete(name);
2363
+ this.loadingPromises.delete(name);
2364
+ }
2365
+ /**
2366
+ * Unload all spritesheets
2367
+ */
2368
+ static clear() {
2369
+ this.spritesheets.clear();
2370
+ this.loadingPromises.clear();
2371
+ }
2372
+ /**
2373
+ * Get the number of loaded spritesheets
2374
+ * @returns Number of loaded spritesheets
2375
+ */
2376
+ static count() {
2377
+ return this.spritesheets.size;
2378
+ }
2379
+ /**
2380
+ * Get all loaded spritesheet names
2381
+ * @returns Array of spritesheet names
2382
+ */
2383
+ static getSheetNames() {
2384
+ return Array.from(this.spritesheets.keys());
2385
+ }
2386
+ };
2387
+ Sprites.spritesheets = /* @__PURE__ */ new Map();
2388
+ Sprites.loadingPromises = /* @__PURE__ */ new Map();
2389
+ var SpriteAnimation = class {
2390
+ constructor(sheetName, startSprite, endSprite, frameDuration) {
2391
+ this.currentFrame = 0;
2392
+ this.lastFrameTime = 0;
2393
+ this.playing = true;
2394
+ this.loop = true;
2395
+ this.sheetName = sheetName;
2396
+ this.startSprite = startSprite;
2397
+ this.endSprite = endSprite;
2398
+ this.frameDuration = frameDuration;
2399
+ this.currentFrame = startSprite;
2400
+ }
2401
+ /**
2402
+ * Update animation frame
2403
+ * @param deltaTime - Time since last update in milliseconds
2404
+ */
2405
+ update(deltaTime) {
2406
+ if (!this.playing) return;
2407
+ this.lastFrameTime += deltaTime;
2408
+ if (this.lastFrameTime >= this.frameDuration) {
2409
+ this.lastFrameTime = 0;
2410
+ this.currentFrame++;
2411
+ if (this.currentFrame > this.endSprite) {
2412
+ if (this.loop) {
2413
+ this.currentFrame = this.startSprite;
2414
+ } else {
2415
+ this.currentFrame = this.endSprite;
2416
+ this.playing = false;
2417
+ }
2418
+ }
2419
+ }
2420
+ }
2421
+ /**
2422
+ * Draw the current animation frame
2423
+ * @param ctx - Klint context
2424
+ * @param x - X position
2425
+ * @param y - Y position
2426
+ * @param options - Drawing options
2427
+ */
2428
+ draw(ctx, x, y, options) {
2429
+ Sprites.draw(ctx, this.sheetName, this.currentFrame, x, y, options);
2430
+ }
2431
+ /**
2432
+ * Play the animation
2433
+ */
2434
+ play() {
2435
+ this.playing = true;
2436
+ }
2437
+ /**
2438
+ * Pause the animation
2439
+ */
2440
+ pause() {
2441
+ this.playing = false;
2442
+ }
2443
+ /**
2444
+ * Stop the animation and reset to start
2445
+ */
2446
+ stop() {
2447
+ this.playing = false;
2448
+ this.currentFrame = this.startSprite;
2449
+ this.lastFrameTime = 0;
2450
+ }
2451
+ /**
2452
+ * Set whether the animation should loop
2453
+ * @param loop - True to loop, false to play once
2454
+ */
2455
+ setLoop(loop) {
2456
+ this.loop = loop;
2457
+ }
2458
+ /**
2459
+ * Get the current frame
2460
+ * @returns Current frame index
2461
+ */
2462
+ getCurrentFrame() {
2463
+ return this.currentFrame;
2464
+ }
2465
+ /**
2466
+ * Set the current frame
2467
+ * @param frame - Frame index to set
2468
+ */
2469
+ setFrame(frame) {
2470
+ this.currentFrame = Math.max(
2471
+ this.startSprite,
2472
+ Math.min(this.endSprite, frame)
2473
+ );
2474
+ }
2475
+ /**
2476
+ * Check if animation is playing
2477
+ * @returns True if playing, false otherwise
2478
+ */
2479
+ isPlaying() {
2480
+ return this.playing;
2481
+ }
2482
+ };
2483
+ export {
2484
+ CatmullRom,
2485
+ Delaunay,
2486
+ FontParser,
2487
+ Sprites,
2488
+ Things
2489
+ };