@cj-tech-master/excelts 9.4.1 → 9.4.2

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.
Files changed (66) hide show
  1. package/dist/browser/modules/pdf/builder/document-builder.js +4 -23
  2. package/dist/browser/modules/pdf/core/pdf-stream.d.ts +15 -0
  3. package/dist/browser/modules/pdf/core/pdf-stream.js +47 -3
  4. package/dist/browser/modules/pdf/font/font-manager.d.ts +37 -6
  5. package/dist/browser/modules/pdf/font/font-manager.js +129 -17
  6. package/dist/browser/modules/pdf/font/system-fonts.d.ts +41 -0
  7. package/dist/browser/modules/pdf/font/system-fonts.js +188 -0
  8. package/dist/browser/modules/pdf/font/ttf-parser.js +29 -1
  9. package/dist/browser/modules/pdf/font/type3-font.d.ts +35 -0
  10. package/dist/browser/modules/pdf/font/type3-font.js +228 -0
  11. package/dist/browser/modules/pdf/font/type3-glyphs-extended.d.ts +33 -0
  12. package/dist/browser/modules/pdf/font/type3-glyphs-extended.js +4164 -0
  13. package/dist/browser/modules/pdf/font/type3-glyphs-extended2.d.ts +16 -0
  14. package/dist/browser/modules/pdf/font/type3-glyphs-extended2.js +9649 -0
  15. package/dist/browser/modules/pdf/font/type3-glyphs-fill.d.ts +17 -0
  16. package/dist/browser/modules/pdf/font/type3-glyphs-fill.js +5438 -0
  17. package/dist/browser/modules/pdf/font/type3-glyphs-quality.d.ts +28 -0
  18. package/dist/browser/modules/pdf/font/type3-glyphs-quality.js +5345 -0
  19. package/dist/browser/modules/pdf/font/type3-glyphs.d.ts +79 -0
  20. package/dist/browser/modules/pdf/font/type3-glyphs.js +2567 -0
  21. package/dist/browser/modules/pdf/render/layout-engine.js +36 -23
  22. package/dist/browser/modules/pdf/render/page-renderer.d.ts +9 -0
  23. package/dist/browser/modules/pdf/render/page-renderer.js +110 -78
  24. package/dist/browser/modules/pdf/render/pdf-exporter.js +73 -5
  25. package/dist/cjs/modules/pdf/builder/document-builder.js +3 -22
  26. package/dist/cjs/modules/pdf/core/pdf-stream.js +49 -3
  27. package/dist/cjs/modules/pdf/font/font-manager.js +129 -17
  28. package/dist/cjs/modules/pdf/font/system-fonts.js +194 -0
  29. package/dist/cjs/modules/pdf/font/ttf-parser.js +29 -1
  30. package/dist/cjs/modules/pdf/font/type3-font.js +231 -0
  31. package/dist/cjs/modules/pdf/font/type3-glyphs-extended.js +4167 -0
  32. package/dist/cjs/modules/pdf/font/type3-glyphs-extended2.js +9652 -0
  33. package/dist/cjs/modules/pdf/font/type3-glyphs-fill.js +5441 -0
  34. package/dist/cjs/modules/pdf/font/type3-glyphs-quality.js +5348 -0
  35. package/dist/cjs/modules/pdf/font/type3-glyphs.js +2573 -0
  36. package/dist/cjs/modules/pdf/render/layout-engine.js +36 -23
  37. package/dist/cjs/modules/pdf/render/page-renderer.js +111 -78
  38. package/dist/cjs/modules/pdf/render/pdf-exporter.js +71 -3
  39. package/dist/esm/modules/pdf/builder/document-builder.js +4 -23
  40. package/dist/esm/modules/pdf/core/pdf-stream.js +47 -3
  41. package/dist/esm/modules/pdf/font/font-manager.js +129 -17
  42. package/dist/esm/modules/pdf/font/system-fonts.js +188 -0
  43. package/dist/esm/modules/pdf/font/ttf-parser.js +29 -1
  44. package/dist/esm/modules/pdf/font/type3-font.js +228 -0
  45. package/dist/esm/modules/pdf/font/type3-glyphs-extended.js +4164 -0
  46. package/dist/esm/modules/pdf/font/type3-glyphs-extended2.js +9649 -0
  47. package/dist/esm/modules/pdf/font/type3-glyphs-fill.js +5438 -0
  48. package/dist/esm/modules/pdf/font/type3-glyphs-quality.js +5345 -0
  49. package/dist/esm/modules/pdf/font/type3-glyphs.js +2567 -0
  50. package/dist/esm/modules/pdf/render/layout-engine.js +36 -23
  51. package/dist/esm/modules/pdf/render/page-renderer.js +110 -78
  52. package/dist/esm/modules/pdf/render/pdf-exporter.js +73 -5
  53. package/dist/iife/excelts.iife.js +25445 -344
  54. package/dist/iife/excelts.iife.js.map +1 -1
  55. package/dist/iife/excelts.iife.min.js +48 -46
  56. package/dist/types/modules/pdf/core/pdf-stream.d.ts +15 -0
  57. package/dist/types/modules/pdf/font/font-manager.d.ts +37 -6
  58. package/dist/types/modules/pdf/font/system-fonts.d.ts +41 -0
  59. package/dist/types/modules/pdf/font/type3-font.d.ts +35 -0
  60. package/dist/types/modules/pdf/font/type3-glyphs-extended.d.ts +33 -0
  61. package/dist/types/modules/pdf/font/type3-glyphs-extended2.d.ts +16 -0
  62. package/dist/types/modules/pdf/font/type3-glyphs-fill.d.ts +17 -0
  63. package/dist/types/modules/pdf/font/type3-glyphs-quality.d.ts +28 -0
  64. package/dist/types/modules/pdf/font/type3-glyphs.d.ts +79 -0
  65. package/dist/types/modules/pdf/render/page-renderer.d.ts +9 -0
  66. package/package.json +1 -1
@@ -0,0 +1,2573 @@
1
+ "use strict";
2
+ /**
3
+ * Type3 fallback glyph definitions.
4
+ *
5
+ * Each glyph is a function that writes PDF content-stream operators into
6
+ * a 1000×1000 unit glyph coordinate system (matching a FontMatrix of
7
+ * [0.001 0 0 0.001 0 0]).
8
+ *
9
+ * The drawing callbacks receive a simple `GlyphPen` API so they don't
10
+ * depend on `PdfContentStream` directly — this keeps the module
11
+ * self-contained and easy to test.
12
+ *
13
+ * Coverage strategy:
14
+ * 1. Geometric Shapes (U+25A0–U+25FF)
15
+ * 2. Miscellaneous Symbols (U+2600–U+26FF)
16
+ * 3. Dingbats / checkmarks (U+2700–U+27BF)
17
+ * 4. Arrows (U+2190–U+21FF)
18
+ * 5. Mathematical Operators (U+2200–U+22FF)
19
+ * 6. Box Drawing (U+2500–U+257F)
20
+ * 7. Block Elements (U+2580–U+259F)
21
+ * 8. Misc Technical (U+2300–U+23FF)
22
+ * 9. Enclosed Alphanumerics (U+2460–U+24FF)
23
+ * 10. Misc Symbols & Arrows (U+2B00–U+2BFF)
24
+ * 11. Ballot / checkbox symbols (U+2610–U+2612)
25
+ * 12. Supplemental Arrows (U+27F0–U+27FF)
26
+ * 13. Braille Patterns (U+2800–U+28FF)
27
+ * 14. Squared symbols etc. (U+29C0–U+29FF)
28
+ *
29
+ * Characters not in this table get a generic .notdef glyph (open rectangle).
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.NOTDEF_GLYPH = void 0;
33
+ exports.lookupGlyph = lookupGlyph;
34
+ exports.hasGlyph = hasGlyph;
35
+ exports.glyphCount = glyphCount;
36
+ // =============================================================================
37
+ // Helpers
38
+ // =============================================================================
39
+ /** Standard advance width for a "normal-width" symbol. */
40
+ const W = 600;
41
+ /** A filled square glyph (generic, reusable). */
42
+ function filledRect(x, y, w, h) {
43
+ return {
44
+ width: W,
45
+ draw: p => {
46
+ p.rect(x, y, w, h);
47
+ p.fill();
48
+ }
49
+ };
50
+ }
51
+ function strokedRect(x, y, w, h, lw = 50) {
52
+ return {
53
+ width: W,
54
+ draw: p => {
55
+ p.lineWidth(lw);
56
+ p.rect(x, y, w, h);
57
+ p.stroke();
58
+ }
59
+ };
60
+ }
61
+ function filledCircle(cx, cy, r) {
62
+ return {
63
+ width: W,
64
+ draw: p => {
65
+ p.circle(cx, cy, r);
66
+ p.fill();
67
+ }
68
+ };
69
+ }
70
+ function strokedCircle(cx, cy, r, lw = 50) {
71
+ return {
72
+ width: W,
73
+ draw: p => {
74
+ p.lineWidth(lw);
75
+ p.circle(cx, cy, r);
76
+ p.stroke();
77
+ }
78
+ };
79
+ }
80
+ /** .notdef: open rectangle — drawn for any character we don't have. */
81
+ exports.NOTDEF_GLYPH = strokedRect(80, 0, 440, 700, 40);
82
+ // =============================================================================
83
+ // Geometric Shapes (U+25A0 – U+25FF)
84
+ // =============================================================================
85
+ const GEO = {
86
+ // ■ BLACK SQUARE
87
+ [0x25a0]: filledRect(100, 50, 400, 400),
88
+ // □ WHITE SQUARE
89
+ [0x25a1]: strokedRect(100, 50, 400, 400),
90
+ // ▢ WHITE SQUARE WITH ROUNDED CORNERS
91
+ [0x25a2]: {
92
+ width: W,
93
+ draw: p => {
94
+ p.lineWidth(50);
95
+ p.M(150, 50);
96
+ p.L(450, 50);
97
+ p.C(480, 50, 500, 70, 500, 100);
98
+ p.L(500, 400);
99
+ p.C(500, 430, 480, 450, 450, 450);
100
+ p.L(150, 450);
101
+ p.C(120, 450, 100, 430, 100, 400);
102
+ p.L(100, 100);
103
+ p.C(100, 70, 120, 50, 150, 50);
104
+ p.Z();
105
+ p.stroke();
106
+ }
107
+ },
108
+ // ▣ WHITE SQUARE CONTAINING BLACK SMALL SQUARE
109
+ [0x25a3]: {
110
+ width: W,
111
+ draw: p => {
112
+ p.lineWidth(40);
113
+ p.rect(100, 50, 400, 400);
114
+ p.stroke();
115
+ p.rect(200, 150, 200, 200);
116
+ p.fill();
117
+ }
118
+ },
119
+ // ▤ SQUARE WITH HORIZONTAL FILL
120
+ [0x25a4]: {
121
+ width: W,
122
+ draw: p => {
123
+ p.lineWidth(40);
124
+ p.rect(100, 50, 400, 400);
125
+ p.stroke();
126
+ p.lineWidth(30);
127
+ for (let y = 100; y <= 400; y += 80) {
128
+ p.M(100, y);
129
+ p.L(500, y);
130
+ }
131
+ p.stroke();
132
+ }
133
+ },
134
+ // ▥ SQUARE WITH VERTICAL FILL
135
+ [0x25a5]: {
136
+ width: W,
137
+ draw: p => {
138
+ p.lineWidth(40);
139
+ p.rect(100, 50, 400, 400);
140
+ p.stroke();
141
+ p.lineWidth(30);
142
+ for (let x = 150; x <= 450; x += 80) {
143
+ p.M(x, 50);
144
+ p.L(x, 450);
145
+ }
146
+ p.stroke();
147
+ }
148
+ },
149
+ // ▦ SQUARE WITH ORTHOGONAL CROSSHATCH
150
+ [0x25a6]: {
151
+ width: W,
152
+ draw: p => {
153
+ p.lineWidth(40);
154
+ p.rect(100, 50, 400, 400);
155
+ p.stroke();
156
+ p.lineWidth(20);
157
+ for (let y = 100; y <= 400; y += 80) {
158
+ p.M(100, y);
159
+ p.L(500, y);
160
+ }
161
+ for (let x = 150; x <= 450; x += 80) {
162
+ p.M(x, 50);
163
+ p.L(x, 450);
164
+ }
165
+ p.stroke();
166
+ }
167
+ },
168
+ // ▨ SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL — simplified as rect
169
+ [0x25a8]: {
170
+ width: W,
171
+ draw: p => {
172
+ p.lineWidth(40);
173
+ p.rect(100, 50, 400, 400);
174
+ p.stroke();
175
+ p.lineWidth(20);
176
+ for (let i = -400; i <= 400; i += 80) {
177
+ p.M(Math.max(100, 100 + i), Math.min(450, 450 + i));
178
+ p.L(Math.min(500, 500 + i), Math.max(50, 50 + i));
179
+ }
180
+ p.stroke();
181
+ }
182
+ },
183
+ // ▪ BLACK SMALL SQUARE
184
+ [0x25aa]: filledRect(175, 125, 250, 250),
185
+ // ▫ WHITE SMALL SQUARE
186
+ [0x25ab]: strokedRect(175, 125, 250, 250, 40),
187
+ // ▬ BLACK RECTANGLE
188
+ [0x25ac]: filledRect(80, 150, 440, 200),
189
+ // ▭ WHITE RECTANGLE
190
+ [0x25ad]: strokedRect(80, 150, 440, 200),
191
+ // ▮ BLACK VERTICAL RECTANGLE
192
+ [0x25ae]: filledRect(175, 0, 250, 500),
193
+ // ▯ WHITE VERTICAL RECTANGLE
194
+ [0x25af]: strokedRect(175, 0, 250, 500),
195
+ // ▰ BLACK PARALLELOGRAM
196
+ [0x25b0]: {
197
+ width: W,
198
+ draw: p => {
199
+ p.M(150, 100);
200
+ p.L(520, 100);
201
+ p.L(450, 400);
202
+ p.L(80, 400);
203
+ p.Z();
204
+ p.fill();
205
+ }
206
+ },
207
+ // ▲ BLACK UP-POINTING TRIANGLE
208
+ [0x25b2]: {
209
+ width: W,
210
+ draw: p => {
211
+ p.M(300, 500);
212
+ p.L(500, 50);
213
+ p.L(100, 50);
214
+ p.Z();
215
+ p.fill();
216
+ }
217
+ },
218
+ // △ WHITE UP-POINTING TRIANGLE
219
+ [0x25b3]: {
220
+ width: W,
221
+ draw: p => {
222
+ p.lineWidth(40);
223
+ p.M(300, 500);
224
+ p.L(500, 50);
225
+ p.L(100, 50);
226
+ p.Z();
227
+ p.stroke();
228
+ }
229
+ },
230
+ // ▴ BLACK UP-POINTING SMALL TRIANGLE
231
+ [0x25b4]: {
232
+ width: W,
233
+ draw: p => {
234
+ p.M(300, 450);
235
+ p.L(450, 100);
236
+ p.L(150, 100);
237
+ p.Z();
238
+ p.fill();
239
+ }
240
+ },
241
+ // ▵ WHITE UP-POINTING SMALL TRIANGLE
242
+ [0x25b5]: {
243
+ width: W,
244
+ draw: p => {
245
+ p.lineWidth(35);
246
+ p.M(300, 450);
247
+ p.L(450, 100);
248
+ p.L(150, 100);
249
+ p.Z();
250
+ p.stroke();
251
+ }
252
+ },
253
+ // ▶ BLACK RIGHT-POINTING TRIANGLE
254
+ [0x25b6]: {
255
+ width: W,
256
+ draw: p => {
257
+ p.M(100, 500);
258
+ p.L(500, 250);
259
+ p.L(100, 0);
260
+ p.Z();
261
+ p.fill();
262
+ }
263
+ },
264
+ // ▷ WHITE RIGHT-POINTING TRIANGLE
265
+ [0x25b7]: {
266
+ width: W,
267
+ draw: p => {
268
+ p.lineWidth(40);
269
+ p.M(100, 500);
270
+ p.L(500, 250);
271
+ p.L(100, 0);
272
+ p.Z();
273
+ p.stroke();
274
+ }
275
+ },
276
+ // ▸ BLACK RIGHT-POINTING SMALL TRIANGLE
277
+ [0x25b8]: {
278
+ width: W,
279
+ draw: p => {
280
+ p.M(150, 450);
281
+ p.L(450, 250);
282
+ p.L(150, 50);
283
+ p.Z();
284
+ p.fill();
285
+ }
286
+ },
287
+ // ▼ BLACK DOWN-POINTING TRIANGLE
288
+ [0x25bc]: {
289
+ width: W,
290
+ draw: p => {
291
+ p.M(100, 500);
292
+ p.L(500, 500);
293
+ p.L(300, 50);
294
+ p.Z();
295
+ p.fill();
296
+ }
297
+ },
298
+ // ▽ WHITE DOWN-POINTING TRIANGLE
299
+ [0x25bd]: {
300
+ width: W,
301
+ draw: p => {
302
+ p.lineWidth(40);
303
+ p.M(100, 500);
304
+ p.L(500, 500);
305
+ p.L(300, 50);
306
+ p.Z();
307
+ p.stroke();
308
+ }
309
+ },
310
+ // ▾ BLACK DOWN-POINTING SMALL TRIANGLE
311
+ [0x25be]: {
312
+ width: W,
313
+ draw: p => {
314
+ p.M(150, 400);
315
+ p.L(450, 400);
316
+ p.L(300, 100);
317
+ p.Z();
318
+ p.fill();
319
+ }
320
+ },
321
+ // ◀ BLACK LEFT-POINTING TRIANGLE
322
+ [0x25c0]: {
323
+ width: W,
324
+ draw: p => {
325
+ p.M(500, 500);
326
+ p.L(100, 250);
327
+ p.L(500, 0);
328
+ p.Z();
329
+ p.fill();
330
+ }
331
+ },
332
+ // ◁ WHITE LEFT-POINTING TRIANGLE
333
+ [0x25c1]: {
334
+ width: W,
335
+ draw: p => {
336
+ p.lineWidth(40);
337
+ p.M(500, 500);
338
+ p.L(100, 250);
339
+ p.L(500, 0);
340
+ p.Z();
341
+ p.stroke();
342
+ }
343
+ },
344
+ // ◂ BLACK LEFT-POINTING SMALL TRIANGLE
345
+ [0x25c2]: {
346
+ width: W,
347
+ draw: p => {
348
+ p.M(450, 450);
349
+ p.L(150, 250);
350
+ p.L(450, 50);
351
+ p.Z();
352
+ p.fill();
353
+ }
354
+ },
355
+ // ◆ BLACK DIAMOND
356
+ [0x25c6]: {
357
+ width: W,
358
+ draw: p => {
359
+ p.M(300, 500);
360
+ p.L(530, 250);
361
+ p.L(300, 0);
362
+ p.L(70, 250);
363
+ p.Z();
364
+ p.fill();
365
+ }
366
+ },
367
+ // ◇ WHITE DIAMOND
368
+ [0x25c7]: {
369
+ width: W,
370
+ draw: p => {
371
+ p.lineWidth(40);
372
+ p.M(300, 500);
373
+ p.L(530, 250);
374
+ p.L(300, 0);
375
+ p.L(70, 250);
376
+ p.Z();
377
+ p.stroke();
378
+ }
379
+ },
380
+ // ◈ WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND
381
+ [0x25c8]: {
382
+ width: W,
383
+ draw: p => {
384
+ p.lineWidth(40);
385
+ p.M(300, 500);
386
+ p.L(530, 250);
387
+ p.L(300, 0);
388
+ p.L(70, 250);
389
+ p.Z();
390
+ p.stroke();
391
+ p.M(300, 380);
392
+ p.L(410, 250);
393
+ p.L(300, 120);
394
+ p.L(190, 250);
395
+ p.Z();
396
+ p.fill();
397
+ }
398
+ },
399
+ // ◉ FISHEYE (big circle with smaller filled circle)
400
+ [0x25c9]: {
401
+ width: W,
402
+ draw: p => {
403
+ p.lineWidth(40);
404
+ p.circle(300, 250, 220);
405
+ p.stroke();
406
+ p.circle(300, 250, 120);
407
+ p.fill();
408
+ }
409
+ },
410
+ // ◊ LOZENGE
411
+ [0x25ca]: {
412
+ width: W,
413
+ draw: p => {
414
+ p.lineWidth(40);
415
+ p.M(300, 550);
416
+ p.L(500, 250);
417
+ p.L(300, -50);
418
+ p.L(100, 250);
419
+ p.Z();
420
+ p.stroke();
421
+ }
422
+ },
423
+ // ○ WHITE CIRCLE
424
+ [0x25cb]: strokedCircle(300, 250, 220),
425
+ // ◌ DOTTED CIRCLE — simplified as dashed circle
426
+ [0x25cc]: strokedCircle(300, 250, 220, 30),
427
+ // ◍ CIRCLE WITH UPPER HALF BLACK
428
+ [0x25cd]: {
429
+ width: W,
430
+ draw: p => {
431
+ p.lineWidth(40);
432
+ p.circle(300, 250, 220);
433
+ p.stroke();
434
+ /* upper half */ p.M(80, 250);
435
+ p.C(80, 371, 179, 470, 300, 470);
436
+ p.C(421, 470, 520, 371, 520, 250);
437
+ p.Z();
438
+ p.fill();
439
+ }
440
+ },
441
+ // ◎ BULLSEYE
442
+ [0x25ce]: {
443
+ width: W,
444
+ draw: p => {
445
+ p.lineWidth(35);
446
+ p.circle(300, 250, 220);
447
+ p.stroke();
448
+ p.circle(300, 250, 140);
449
+ p.stroke();
450
+ }
451
+ },
452
+ // ● BLACK CIRCLE
453
+ [0x25cf]: filledCircle(300, 250, 220),
454
+ // ◐ CIRCLE WITH LEFT HALF BLACK
455
+ [0x25d0]: {
456
+ width: W,
457
+ draw: p => {
458
+ p.lineWidth(40);
459
+ p.circle(300, 250, 220);
460
+ p.stroke();
461
+ /* left half */ p.M(300, 30);
462
+ p.C(179, 30, 80, 129, 80, 250);
463
+ p.C(80, 371, 179, 470, 300, 470);
464
+ p.Z();
465
+ p.fill();
466
+ }
467
+ },
468
+ // ◑ CIRCLE WITH RIGHT HALF BLACK
469
+ [0x25d1]: {
470
+ width: W,
471
+ draw: p => {
472
+ p.lineWidth(40);
473
+ p.circle(300, 250, 220);
474
+ p.stroke();
475
+ p.M(300, 470);
476
+ p.C(421, 470, 520, 371, 520, 250);
477
+ p.C(520, 129, 421, 30, 300, 30);
478
+ p.Z();
479
+ p.fill();
480
+ }
481
+ },
482
+ // ◒ CIRCLE WITH LOWER HALF BLACK
483
+ [0x25d2]: {
484
+ width: W,
485
+ draw: p => {
486
+ p.lineWidth(40);
487
+ p.circle(300, 250, 220);
488
+ p.stroke();
489
+ p.M(520, 250);
490
+ p.C(520, 129, 421, 30, 300, 30);
491
+ p.C(179, 30, 80, 129, 80, 250);
492
+ p.Z();
493
+ p.fill();
494
+ }
495
+ },
496
+ // ◓ CIRCLE WITH UPPER HALF BLACK
497
+ [0x25d3]: {
498
+ width: W,
499
+ draw: p => {
500
+ p.lineWidth(40);
501
+ p.circle(300, 250, 220);
502
+ p.stroke();
503
+ p.M(80, 250);
504
+ p.C(80, 371, 179, 470, 300, 470);
505
+ p.C(421, 470, 520, 371, 520, 250);
506
+ p.Z();
507
+ p.fill();
508
+ }
509
+ },
510
+ // ◔ CIRCLE WITH UPPER RIGHT QUADRANT BLACK
511
+ [0x25d4]: {
512
+ width: W,
513
+ draw: p => {
514
+ p.lineWidth(40);
515
+ p.circle(300, 250, 220);
516
+ p.stroke();
517
+ p.M(300, 250);
518
+ p.L(300, 470);
519
+ p.C(421, 470, 520, 371, 520, 250);
520
+ p.Z();
521
+ p.fill();
522
+ }
523
+ },
524
+ // ◕ CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK
525
+ [0x25d5]: {
526
+ width: W,
527
+ draw: p => {
528
+ p.lineWidth(40);
529
+ p.circle(300, 250, 220);
530
+ p.stroke();
531
+ p.M(300, 250);
532
+ p.L(300, 470);
533
+ p.C(179, 470, 80, 371, 80, 250);
534
+ p.Z();
535
+ p.fill();
536
+ p.M(300, 250);
537
+ p.L(520, 250);
538
+ p.C(520, 129, 421, 30, 300, 30);
539
+ p.C(179, 30, 80, 129, 80, 250);
540
+ p.Z();
541
+ p.fill();
542
+ }
543
+ },
544
+ // ◖ LEFT HALF BLACK CIRCLE
545
+ [0x25d6]: {
546
+ width: W,
547
+ draw: p => {
548
+ p.M(300, 30);
549
+ p.C(179, 30, 80, 129, 80, 250);
550
+ p.C(80, 371, 179, 470, 300, 470);
551
+ p.Z();
552
+ p.fill();
553
+ }
554
+ },
555
+ // ◗ RIGHT HALF BLACK CIRCLE
556
+ [0x25d7]: {
557
+ width: W,
558
+ draw: p => {
559
+ p.M(300, 470);
560
+ p.C(421, 470, 520, 371, 520, 250);
561
+ p.C(520, 129, 421, 30, 300, 30);
562
+ p.Z();
563
+ p.fill();
564
+ }
565
+ },
566
+ // ◘ INVERSE BULLET (filled square, white circle inside)
567
+ [0x25d8]: {
568
+ width: W,
569
+ draw: p => {
570
+ p.rect(80, 30, 440, 440);
571
+ p.fill();
572
+ }
573
+ },
574
+ // ◙ INVERSE WHITE CIRCLE (filled circle w/ white square)
575
+ [0x25d9]: {
576
+ width: W,
577
+ draw: p => {
578
+ p.circle(300, 250, 240);
579
+ p.fill();
580
+ }
581
+ },
582
+ // ◜◝◞◟ UPPER LEFT / UPPER RIGHT / LOWER RIGHT / LOWER LEFT QUADRANT CIRCULAR ARC
583
+ [0x25dc]: {
584
+ width: W,
585
+ draw: p => {
586
+ p.lineWidth(50);
587
+ p.M(300, 470);
588
+ p.C(179, 470, 80, 371, 80, 250);
589
+ p.stroke();
590
+ }
591
+ },
592
+ [0x25dd]: {
593
+ width: W,
594
+ draw: p => {
595
+ p.lineWidth(50);
596
+ p.M(520, 250);
597
+ p.C(520, 371, 421, 470, 300, 470);
598
+ p.stroke();
599
+ }
600
+ },
601
+ [0x25de]: {
602
+ width: W,
603
+ draw: p => {
604
+ p.lineWidth(50);
605
+ p.M(300, 30);
606
+ p.C(421, 30, 520, 129, 520, 250);
607
+ p.stroke();
608
+ }
609
+ },
610
+ [0x25df]: {
611
+ width: W,
612
+ draw: p => {
613
+ p.lineWidth(50);
614
+ p.M(80, 250);
615
+ p.C(80, 129, 179, 30, 300, 30);
616
+ p.stroke();
617
+ }
618
+ },
619
+ // ◠ UPPER HALF CIRCLE
620
+ [0x25e0]: {
621
+ width: W,
622
+ draw: p => {
623
+ p.lineWidth(50);
624
+ p.M(80, 250);
625
+ p.C(80, 371, 179, 470, 300, 470);
626
+ p.C(421, 470, 520, 371, 520, 250);
627
+ p.stroke();
628
+ }
629
+ },
630
+ // ◡ LOWER HALF CIRCLE
631
+ [0x25e1]: {
632
+ width: W,
633
+ draw: p => {
634
+ p.lineWidth(50);
635
+ p.M(520, 250);
636
+ p.C(520, 129, 421, 30, 300, 30);
637
+ p.C(179, 30, 80, 129, 80, 250);
638
+ p.stroke();
639
+ }
640
+ },
641
+ // ◦ WHITE BULLET
642
+ [0x25e6]: strokedCircle(300, 250, 100, 40),
643
+ // ◯ LARGE CIRCLE
644
+ [0x25ef]: strokedCircle(300, 250, 280, 40)
645
+ };
646
+ // =============================================================================
647
+ // Arrows (U+2190 – U+21FF)
648
+ // =============================================================================
649
+ const ARR = {
650
+ // ← LEFTWARDS ARROW
651
+ [0x2190]: {
652
+ width: W,
653
+ draw: p => {
654
+ p.lineWidth(50);
655
+ p.M(500, 250);
656
+ p.L(100, 250);
657
+ p.stroke();
658
+ p.M(100, 250);
659
+ p.L(250, 380);
660
+ p.L(250, 120);
661
+ p.Z();
662
+ p.fill();
663
+ }
664
+ },
665
+ // ↑ UPWARDS ARROW
666
+ [0x2191]: {
667
+ width: W,
668
+ draw: p => {
669
+ p.lineWidth(50);
670
+ p.M(300, 50);
671
+ p.L(300, 450);
672
+ p.stroke();
673
+ p.M(300, 450);
674
+ p.L(170, 300);
675
+ p.L(430, 300);
676
+ p.Z();
677
+ p.fill();
678
+ }
679
+ },
680
+ // → RIGHTWARDS ARROW
681
+ [0x2192]: {
682
+ width: W,
683
+ draw: p => {
684
+ p.lineWidth(50);
685
+ p.M(100, 250);
686
+ p.L(500, 250);
687
+ p.stroke();
688
+ p.M(500, 250);
689
+ p.L(350, 380);
690
+ p.L(350, 120);
691
+ p.Z();
692
+ p.fill();
693
+ }
694
+ },
695
+ // ↓ DOWNWARDS ARROW
696
+ [0x2193]: {
697
+ width: W,
698
+ draw: p => {
699
+ p.lineWidth(50);
700
+ p.M(300, 450);
701
+ p.L(300, 50);
702
+ p.stroke();
703
+ p.M(300, 50);
704
+ p.L(170, 200);
705
+ p.L(430, 200);
706
+ p.Z();
707
+ p.fill();
708
+ }
709
+ },
710
+ // ↔ LEFT RIGHT ARROW
711
+ [0x2194]: {
712
+ width: W,
713
+ draw: p => {
714
+ p.lineWidth(40);
715
+ p.M(150, 250);
716
+ p.L(450, 250);
717
+ p.stroke();
718
+ p.M(100, 250);
719
+ p.L(220, 360);
720
+ p.L(220, 140);
721
+ p.Z();
722
+ p.fill();
723
+ p.M(500, 250);
724
+ p.L(380, 360);
725
+ p.L(380, 140);
726
+ p.Z();
727
+ p.fill();
728
+ }
729
+ },
730
+ // ↕ UP DOWN ARROW
731
+ [0x2195]: {
732
+ width: W,
733
+ draw: p => {
734
+ p.lineWidth(40);
735
+ p.M(300, 100);
736
+ p.L(300, 400);
737
+ p.stroke();
738
+ p.M(300, 450);
739
+ p.L(190, 330);
740
+ p.L(410, 330);
741
+ p.Z();
742
+ p.fill();
743
+ p.M(300, 50);
744
+ p.L(190, 170);
745
+ p.L(410, 170);
746
+ p.Z();
747
+ p.fill();
748
+ }
749
+ },
750
+ // ↖ NORTH WEST ARROW
751
+ [0x2196]: {
752
+ width: W,
753
+ draw: p => {
754
+ p.lineWidth(50);
755
+ p.M(480, 50);
756
+ p.L(120, 410);
757
+ p.stroke();
758
+ p.M(120, 450);
759
+ p.L(120, 320);
760
+ p.L(250, 450);
761
+ p.Z();
762
+ p.fill();
763
+ }
764
+ },
765
+ // ↗ NORTH EAST ARROW
766
+ [0x2197]: {
767
+ width: W,
768
+ draw: p => {
769
+ p.lineWidth(50);
770
+ p.M(120, 50);
771
+ p.L(480, 410);
772
+ p.stroke();
773
+ p.M(480, 450);
774
+ p.L(350, 450);
775
+ p.L(480, 320);
776
+ p.Z();
777
+ p.fill();
778
+ }
779
+ },
780
+ // ↘ SOUTH EAST ARROW
781
+ [0x2198]: {
782
+ width: W,
783
+ draw: p => {
784
+ p.lineWidth(50);
785
+ p.M(120, 450);
786
+ p.L(480, 90);
787
+ p.stroke();
788
+ p.M(480, 50);
789
+ p.L(480, 180);
790
+ p.L(350, 50);
791
+ p.Z();
792
+ p.fill();
793
+ }
794
+ },
795
+ // ↙ SOUTH WEST ARROW
796
+ [0x2199]: {
797
+ width: W,
798
+ draw: p => {
799
+ p.lineWidth(50);
800
+ p.M(480, 450);
801
+ p.L(120, 90);
802
+ p.stroke();
803
+ p.M(120, 50);
804
+ p.L(250, 50);
805
+ p.L(120, 180);
806
+ p.Z();
807
+ p.fill();
808
+ }
809
+ },
810
+ // ↩ LEFTWARDS ARROW WITH HOOK
811
+ [0x21a9]: {
812
+ width: W,
813
+ draw: p => {
814
+ p.lineWidth(50);
815
+ p.M(500, 350);
816
+ p.L(200, 350);
817
+ p.C(120, 350, 80, 300, 80, 250);
818
+ p.C(80, 200, 120, 150, 200, 150);
819
+ p.L(350, 150);
820
+ p.stroke();
821
+ p.M(100, 350);
822
+ p.L(230, 430);
823
+ p.L(230, 270);
824
+ p.Z();
825
+ p.fill();
826
+ }
827
+ },
828
+ // ↪ RIGHTWARDS ARROW WITH HOOK
829
+ [0x21aa]: {
830
+ width: W,
831
+ draw: p => {
832
+ p.lineWidth(50);
833
+ p.M(100, 350);
834
+ p.L(400, 350);
835
+ p.C(480, 350, 520, 300, 520, 250);
836
+ p.C(520, 200, 480, 150, 400, 150);
837
+ p.L(250, 150);
838
+ p.stroke();
839
+ p.M(500, 350);
840
+ p.L(370, 430);
841
+ p.L(370, 270);
842
+ p.Z();
843
+ p.fill();
844
+ }
845
+ },
846
+ // ⇐ LEFTWARDS DOUBLE ARROW
847
+ [0x21d0]: {
848
+ width: W,
849
+ draw: p => {
850
+ p.M(100, 250);
851
+ p.L(280, 420);
852
+ p.L(280, 300);
853
+ p.L(500, 300);
854
+ p.L(500, 200);
855
+ p.L(280, 200);
856
+ p.L(280, 80);
857
+ p.Z();
858
+ p.fill();
859
+ }
860
+ },
861
+ // ⇑ UPWARDS DOUBLE ARROW
862
+ [0x21d1]: {
863
+ width: W,
864
+ draw: p => {
865
+ p.M(300, 480);
866
+ p.L(480, 280);
867
+ p.L(370, 280);
868
+ p.L(370, 30);
869
+ p.L(230, 30);
870
+ p.L(230, 280);
871
+ p.L(120, 280);
872
+ p.Z();
873
+ p.fill();
874
+ }
875
+ },
876
+ // ⇒ RIGHTWARDS DOUBLE ARROW
877
+ [0x21d2]: {
878
+ width: W,
879
+ draw: p => {
880
+ p.M(500, 250);
881
+ p.L(320, 420);
882
+ p.L(320, 300);
883
+ p.L(100, 300);
884
+ p.L(100, 200);
885
+ p.L(320, 200);
886
+ p.L(320, 80);
887
+ p.Z();
888
+ p.fill();
889
+ }
890
+ },
891
+ // ⇓ DOWNWARDS DOUBLE ARROW
892
+ [0x21d3]: {
893
+ width: W,
894
+ draw: p => {
895
+ p.M(300, 20);
896
+ p.L(120, 220);
897
+ p.L(230, 220);
898
+ p.L(230, 470);
899
+ p.L(370, 470);
900
+ p.L(370, 220);
901
+ p.L(480, 220);
902
+ p.Z();
903
+ p.fill();
904
+ }
905
+ },
906
+ // ⇔ LEFT RIGHT DOUBLE ARROW
907
+ [0x21d4]: {
908
+ width: W,
909
+ draw: p => {
910
+ p.M(80, 250);
911
+ p.L(220, 400);
912
+ p.L(220, 300);
913
+ p.L(380, 300);
914
+ p.L(380, 400);
915
+ p.L(520, 250);
916
+ p.L(380, 100);
917
+ p.L(380, 200);
918
+ p.L(220, 200);
919
+ p.L(220, 100);
920
+ p.Z();
921
+ p.fill();
922
+ }
923
+ }
924
+ };
925
+ // =============================================================================
926
+ // Mathematical Operators (U+2200 – U+22FF)
927
+ // =============================================================================
928
+ const MATH = {
929
+ // ∀ FOR ALL
930
+ [0x2200]: {
931
+ width: W,
932
+ draw: p => {
933
+ p.lineWidth(50);
934
+ p.M(100, 500);
935
+ p.L(300, 0);
936
+ p.L(500, 500);
937
+ p.stroke();
938
+ p.M(170, 200);
939
+ p.L(430, 200);
940
+ p.stroke();
941
+ }
942
+ },
943
+ // ∂ PARTIAL DIFFERENTIAL
944
+ [0x2202]: {
945
+ width: W,
946
+ draw: p => {
947
+ p.lineWidth(50);
948
+ p.circle(300, 200, 150);
949
+ p.stroke();
950
+ p.M(450, 200);
951
+ p.L(450, 450);
952
+ p.C(450, 500, 400, 520, 350, 500);
953
+ p.stroke();
954
+ }
955
+ },
956
+ // ∃ THERE EXISTS
957
+ [0x2203]: {
958
+ width: W,
959
+ draw: p => {
960
+ p.lineWidth(50);
961
+ p.M(450, 500);
962
+ p.L(150, 500);
963
+ p.L(150, 0);
964
+ p.L(450, 0);
965
+ p.stroke();
966
+ p.M(150, 250);
967
+ p.L(400, 250);
968
+ p.stroke();
969
+ }
970
+ },
971
+ // ∅ EMPTY SET
972
+ [0x2205]: {
973
+ width: W,
974
+ draw: p => {
975
+ p.lineWidth(50);
976
+ p.ellipse(300, 250, 180, 220);
977
+ p.stroke();
978
+ p.M(150, 50);
979
+ p.L(450, 450);
980
+ p.stroke();
981
+ }
982
+ },
983
+ // ∆ INCREMENT (triangle)
984
+ [0x2206]: {
985
+ width: W,
986
+ draw: p => {
987
+ p.lineWidth(50);
988
+ p.M(300, 500);
989
+ p.L(100, 0);
990
+ p.L(500, 0);
991
+ p.Z();
992
+ p.stroke();
993
+ }
994
+ },
995
+ // ∇ NABLA
996
+ [0x2207]: {
997
+ width: W,
998
+ draw: p => {
999
+ p.lineWidth(50);
1000
+ p.M(100, 500);
1001
+ p.L(500, 500);
1002
+ p.L(300, 0);
1003
+ p.Z();
1004
+ p.stroke();
1005
+ }
1006
+ },
1007
+ // ∈ ELEMENT OF
1008
+ [0x2208]: {
1009
+ width: W,
1010
+ draw: p => {
1011
+ p.lineWidth(50);
1012
+ p.M(480, 450);
1013
+ p.C(250, 450, 120, 380, 120, 250);
1014
+ p.C(120, 120, 250, 50, 480, 50);
1015
+ p.stroke();
1016
+ p.M(120, 250);
1017
+ p.L(430, 250);
1018
+ p.stroke();
1019
+ }
1020
+ },
1021
+ // ∉ NOT AN ELEMENT OF
1022
+ [0x2209]: {
1023
+ width: W,
1024
+ draw: p => {
1025
+ p.lineWidth(50);
1026
+ p.M(480, 450);
1027
+ p.C(250, 450, 120, 380, 120, 250);
1028
+ p.C(120, 120, 250, 50, 480, 50);
1029
+ p.stroke();
1030
+ p.M(120, 250);
1031
+ p.L(430, 250);
1032
+ p.stroke();
1033
+ p.M(160, 50);
1034
+ p.L(440, 450);
1035
+ p.stroke();
1036
+ }
1037
+ },
1038
+ // ∋ CONTAINS AS MEMBER
1039
+ [0x220b]: {
1040
+ width: W,
1041
+ draw: p => {
1042
+ p.lineWidth(50);
1043
+ p.M(120, 450);
1044
+ p.C(350, 450, 480, 380, 480, 250);
1045
+ p.C(480, 120, 350, 50, 120, 50);
1046
+ p.stroke();
1047
+ p.M(170, 250);
1048
+ p.L(480, 250);
1049
+ p.stroke();
1050
+ }
1051
+ },
1052
+ // ∎ END OF PROOF
1053
+ [0x220e]: filledRect(150, 50, 300, 400),
1054
+ // ∏ N-ARY PRODUCT
1055
+ [0x220f]: {
1056
+ width: W,
1057
+ draw: p => {
1058
+ p.lineWidth(50);
1059
+ p.M(120, 500);
1060
+ p.L(480, 500);
1061
+ p.stroke();
1062
+ p.M(170, 500);
1063
+ p.L(170, 0);
1064
+ p.stroke();
1065
+ p.M(430, 500);
1066
+ p.L(430, 0);
1067
+ p.stroke();
1068
+ }
1069
+ },
1070
+ // ∑ N-ARY SUMMATION
1071
+ [0x2211]: {
1072
+ width: W,
1073
+ draw: p => {
1074
+ p.lineWidth(50);
1075
+ p.M(480, 500);
1076
+ p.L(120, 500);
1077
+ p.L(300, 250);
1078
+ p.L(120, 0);
1079
+ p.L(480, 0);
1080
+ p.stroke();
1081
+ }
1082
+ },
1083
+ // − MINUS SIGN
1084
+ [0x2212]: {
1085
+ width: W,
1086
+ draw: p => {
1087
+ p.lineWidth(60);
1088
+ p.M(120, 250);
1089
+ p.L(480, 250);
1090
+ p.stroke();
1091
+ }
1092
+ },
1093
+ // ∓ MINUS-OR-PLUS SIGN
1094
+ [0x2213]: {
1095
+ width: W,
1096
+ draw: p => {
1097
+ p.lineWidth(50);
1098
+ p.M(120, 350);
1099
+ p.L(480, 350);
1100
+ p.stroke();
1101
+ p.M(300, 200);
1102
+ p.L(300, 0);
1103
+ p.stroke();
1104
+ p.M(120, 100);
1105
+ p.L(480, 100);
1106
+ p.stroke();
1107
+ }
1108
+ },
1109
+ // ∗ ASTERISK OPERATOR
1110
+ [0x2217]: {
1111
+ width: W,
1112
+ draw: p => {
1113
+ p.lineWidth(50);
1114
+ p.M(300, 400);
1115
+ p.L(300, 100);
1116
+ p.stroke();
1117
+ p.M(140, 350);
1118
+ p.L(460, 150);
1119
+ p.stroke();
1120
+ p.M(140, 150);
1121
+ p.L(460, 350);
1122
+ p.stroke();
1123
+ }
1124
+ },
1125
+ // √ SQUARE ROOT
1126
+ [0x221a]: {
1127
+ width: W,
1128
+ draw: p => {
1129
+ p.lineWidth(50);
1130
+ p.M(60, 250);
1131
+ p.L(150, 200);
1132
+ p.L(250, 0);
1133
+ p.L(540, 500);
1134
+ p.stroke();
1135
+ }
1136
+ },
1137
+ // ∞ INFINITY
1138
+ [0x221e]: {
1139
+ width: 700,
1140
+ draw: p => {
1141
+ p.lineWidth(50);
1142
+ p.M(350, 250);
1143
+ p.C(350, 400, 500, 450, 550, 350);
1144
+ p.C(600, 250, 550, 100, 500, 100);
1145
+ p.C(450, 100, 350, 250, 350, 250);
1146
+ p.C(350, 250, 250, 400, 200, 400);
1147
+ p.C(150, 400, 100, 250, 150, 150);
1148
+ p.C(200, 50, 350, 100, 350, 250);
1149
+ p.stroke();
1150
+ }
1151
+ },
1152
+ // ∠ ANGLE
1153
+ [0x2220]: {
1154
+ width: W,
1155
+ draw: p => {
1156
+ p.lineWidth(50);
1157
+ p.M(480, 50);
1158
+ p.L(120, 50);
1159
+ p.L(380, 450);
1160
+ p.stroke();
1161
+ }
1162
+ },
1163
+ // ∧ LOGICAL AND
1164
+ [0x2227]: {
1165
+ width: W,
1166
+ draw: p => {
1167
+ p.lineWidth(50);
1168
+ p.M(100, 50);
1169
+ p.L(300, 450);
1170
+ p.L(500, 50);
1171
+ p.stroke();
1172
+ }
1173
+ },
1174
+ // ∨ LOGICAL OR
1175
+ [0x2228]: {
1176
+ width: W,
1177
+ draw: p => {
1178
+ p.lineWidth(50);
1179
+ p.M(100, 450);
1180
+ p.L(300, 50);
1181
+ p.L(500, 450);
1182
+ p.stroke();
1183
+ }
1184
+ },
1185
+ // ∩ INTERSECTION
1186
+ [0x2229]: {
1187
+ width: W,
1188
+ draw: p => {
1189
+ p.lineWidth(50);
1190
+ p.M(120, 50);
1191
+ p.L(120, 300);
1192
+ p.C(120, 470, 250, 500, 300, 500);
1193
+ p.C(350, 500, 480, 470, 480, 300);
1194
+ p.L(480, 50);
1195
+ p.stroke();
1196
+ }
1197
+ },
1198
+ // ∪ UNION
1199
+ [0x222a]: {
1200
+ width: W,
1201
+ draw: p => {
1202
+ p.lineWidth(50);
1203
+ p.M(120, 450);
1204
+ p.L(120, 200);
1205
+ p.C(120, 30, 250, 0, 300, 0);
1206
+ p.C(350, 0, 480, 30, 480, 200);
1207
+ p.L(480, 450);
1208
+ p.stroke();
1209
+ }
1210
+ },
1211
+ // ∫ INTEGRAL
1212
+ [0x222b]: {
1213
+ width: W,
1214
+ draw: p => {
1215
+ p.lineWidth(50);
1216
+ p.M(380, 530);
1217
+ p.C(350, 530, 300, 500, 300, 450);
1218
+ p.L(300, 50);
1219
+ p.C(300, 0, 250, -30, 220, -30);
1220
+ p.stroke();
1221
+ }
1222
+ },
1223
+ // ≈ ALMOST EQUAL TO
1224
+ [0x2248]: {
1225
+ width: W,
1226
+ draw: p => {
1227
+ p.lineWidth(50);
1228
+ p.M(120, 350);
1229
+ p.C(200, 430, 350, 430, 480, 350);
1230
+ p.stroke();
1231
+ p.M(120, 200);
1232
+ p.C(200, 280, 350, 280, 480, 200);
1233
+ p.stroke();
1234
+ }
1235
+ },
1236
+ // ≠ NOT EQUAL TO
1237
+ [0x2260]: {
1238
+ width: W,
1239
+ draw: p => {
1240
+ p.lineWidth(50);
1241
+ p.M(120, 330);
1242
+ p.L(480, 330);
1243
+ p.stroke();
1244
+ p.M(120, 170);
1245
+ p.L(480, 170);
1246
+ p.stroke();
1247
+ p.M(380, 450);
1248
+ p.L(220, 50);
1249
+ p.stroke();
1250
+ }
1251
+ },
1252
+ // ≡ IDENTICAL TO
1253
+ [0x2261]: {
1254
+ width: W,
1255
+ draw: p => {
1256
+ p.lineWidth(50);
1257
+ p.M(120, 380);
1258
+ p.L(480, 380);
1259
+ p.stroke();
1260
+ p.M(120, 250);
1261
+ p.L(480, 250);
1262
+ p.stroke();
1263
+ p.M(120, 120);
1264
+ p.L(480, 120);
1265
+ p.stroke();
1266
+ }
1267
+ },
1268
+ // ≤ LESS-THAN OR EQUAL TO
1269
+ [0x2264]: {
1270
+ width: W,
1271
+ draw: p => {
1272
+ p.lineWidth(50);
1273
+ p.M(480, 420);
1274
+ p.L(120, 250);
1275
+ p.L(480, 80);
1276
+ p.stroke();
1277
+ p.M(120, 30);
1278
+ p.L(480, 30);
1279
+ p.stroke();
1280
+ }
1281
+ },
1282
+ // ≥ GREATER-THAN OR EQUAL TO
1283
+ [0x2265]: {
1284
+ width: W,
1285
+ draw: p => {
1286
+ p.lineWidth(50);
1287
+ p.M(120, 420);
1288
+ p.L(480, 250);
1289
+ p.L(120, 80);
1290
+ p.stroke();
1291
+ p.M(120, 30);
1292
+ p.L(480, 30);
1293
+ p.stroke();
1294
+ }
1295
+ },
1296
+ // ⊂ SUBSET OF
1297
+ [0x2282]: {
1298
+ width: W,
1299
+ draw: p => {
1300
+ p.lineWidth(50);
1301
+ p.M(470, 450);
1302
+ p.C(200, 450, 130, 350, 130, 250);
1303
+ p.C(130, 150, 200, 50, 470, 50);
1304
+ p.stroke();
1305
+ }
1306
+ },
1307
+ // ⊃ SUPERSET OF
1308
+ [0x2283]: {
1309
+ width: W,
1310
+ draw: p => {
1311
+ p.lineWidth(50);
1312
+ p.M(130, 450);
1313
+ p.C(400, 450, 470, 350, 470, 250);
1314
+ p.C(470, 150, 400, 50, 130, 50);
1315
+ p.stroke();
1316
+ }
1317
+ },
1318
+ // ⊕ CIRCLED PLUS
1319
+ [0x2295]: {
1320
+ width: W,
1321
+ draw: p => {
1322
+ p.lineWidth(45);
1323
+ p.circle(300, 250, 200);
1324
+ p.stroke();
1325
+ p.M(100, 250);
1326
+ p.L(500, 250);
1327
+ p.stroke();
1328
+ p.M(300, 50);
1329
+ p.L(300, 450);
1330
+ p.stroke();
1331
+ }
1332
+ },
1333
+ // ⊖ CIRCLED MINUS
1334
+ [0x2296]: {
1335
+ width: W,
1336
+ draw: p => {
1337
+ p.lineWidth(45);
1338
+ p.circle(300, 250, 200);
1339
+ p.stroke();
1340
+ p.M(100, 250);
1341
+ p.L(500, 250);
1342
+ p.stroke();
1343
+ }
1344
+ },
1345
+ // ⊗ CIRCLED TIMES
1346
+ [0x2297]: {
1347
+ width: W,
1348
+ draw: p => {
1349
+ p.lineWidth(45);
1350
+ p.circle(300, 250, 200);
1351
+ p.stroke();
1352
+ p.M(160, 110);
1353
+ p.L(440, 390);
1354
+ p.stroke();
1355
+ p.M(160, 390);
1356
+ p.L(440, 110);
1357
+ p.stroke();
1358
+ }
1359
+ },
1360
+ // ⊘ CIRCLED DIVISION SLASH
1361
+ [0x2298]: {
1362
+ width: W,
1363
+ draw: p => {
1364
+ p.lineWidth(45);
1365
+ p.circle(300, 250, 200);
1366
+ p.stroke();
1367
+ p.M(160, 100);
1368
+ p.L(440, 400);
1369
+ p.stroke();
1370
+ }
1371
+ },
1372
+ // ⊙ CIRCLED DOT OPERATOR
1373
+ [0x2299]: {
1374
+ width: W,
1375
+ draw: p => {
1376
+ p.lineWidth(45);
1377
+ p.circle(300, 250, 200);
1378
+ p.stroke();
1379
+ p.circle(300, 250, 40);
1380
+ p.fill();
1381
+ }
1382
+ }
1383
+ };
1384
+ // =============================================================================
1385
+ // Dingbats / Checkmarks / Misc Symbols (U+2600–U+27BF)
1386
+ // =============================================================================
1387
+ const DING = {
1388
+ // ☀ BLACK SUN WITH RAYS — simplified as circle with lines
1389
+ [0x2600]: {
1390
+ width: W,
1391
+ draw: p => {
1392
+ p.circle(300, 250, 130);
1393
+ p.fill();
1394
+ p.lineWidth(40);
1395
+ for (let a = 0; a < 360; a += 45) {
1396
+ const r1 = 160;
1397
+ const r2 = 240;
1398
+ const rad = (a * Math.PI) / 180;
1399
+ p.M(300 + r1 * Math.cos(rad), 250 + r1 * Math.sin(rad));
1400
+ p.L(300 + r2 * Math.cos(rad), 250 + r2 * Math.sin(rad));
1401
+ }
1402
+ p.stroke();
1403
+ }
1404
+ },
1405
+ // ★ BLACK STAR
1406
+ [0x2605]: {
1407
+ width: W,
1408
+ draw: p => {
1409
+ const cx = 300;
1410
+ const cy = 260;
1411
+ const R = 230;
1412
+ const r = 90;
1413
+ for (let i = 0; i < 5; i++) {
1414
+ const a1 = ((i * 72 - 90) * Math.PI) / 180;
1415
+ const a2 = ((i * 72 + 36 - 90) * Math.PI) / 180;
1416
+ if (i === 0) {
1417
+ p.M(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
1418
+ }
1419
+ else {
1420
+ p.L(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
1421
+ }
1422
+ p.L(cx + r * Math.cos(a2), cy + r * Math.sin(a2));
1423
+ }
1424
+ p.Z();
1425
+ p.fill();
1426
+ }
1427
+ },
1428
+ // ☆ WHITE STAR
1429
+ [0x2606]: {
1430
+ width: W,
1431
+ draw: p => {
1432
+ p.lineWidth(35);
1433
+ const cx = 300;
1434
+ const cy = 260;
1435
+ const R = 230;
1436
+ const r = 90;
1437
+ for (let i = 0; i < 5; i++) {
1438
+ const a1 = ((i * 72 - 90) * Math.PI) / 180;
1439
+ const a2 = ((i * 72 + 36 - 90) * Math.PI) / 180;
1440
+ if (i === 0) {
1441
+ p.M(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
1442
+ }
1443
+ else {
1444
+ p.L(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
1445
+ }
1446
+ p.L(cx + r * Math.cos(a2), cy + r * Math.sin(a2));
1447
+ }
1448
+ p.Z();
1449
+ p.stroke();
1450
+ }
1451
+ },
1452
+ // ☐ BALLOT BOX
1453
+ [0x2610]: strokedRect(100, 30, 400, 400, 45),
1454
+ // ☑ BALLOT BOX WITH CHECK
1455
+ [0x2611]: {
1456
+ width: W,
1457
+ draw: p => {
1458
+ p.lineWidth(45);
1459
+ p.rect(100, 30, 400, 400);
1460
+ p.stroke();
1461
+ p.lineWidth(55);
1462
+ p.M(180, 230);
1463
+ p.L(280, 130);
1464
+ p.L(430, 350);
1465
+ p.stroke();
1466
+ }
1467
+ },
1468
+ // ☒ BALLOT BOX WITH X
1469
+ [0x2612]: {
1470
+ width: W,
1471
+ draw: p => {
1472
+ p.lineWidth(45);
1473
+ p.rect(100, 30, 400, 400);
1474
+ p.stroke();
1475
+ p.lineWidth(50);
1476
+ p.M(170, 100);
1477
+ p.L(430, 360);
1478
+ p.stroke();
1479
+ p.M(170, 360);
1480
+ p.L(430, 100);
1481
+ p.stroke();
1482
+ }
1483
+ },
1484
+ // ☓ SALTIRE (X)
1485
+ [0x2613]: {
1486
+ width: W,
1487
+ draw: p => {
1488
+ p.lineWidth(55);
1489
+ p.M(120, 50);
1490
+ p.L(480, 450);
1491
+ p.stroke();
1492
+ p.M(120, 450);
1493
+ p.L(480, 50);
1494
+ p.stroke();
1495
+ }
1496
+ },
1497
+ // ☛ BLACK RIGHT POINTING INDEX — simplified arrow
1498
+ [0x261b]: {
1499
+ width: W,
1500
+ draw: p => {
1501
+ p.M(500, 250);
1502
+ p.L(300, 400);
1503
+ p.L(300, 300);
1504
+ p.L(100, 300);
1505
+ p.L(100, 200);
1506
+ p.L(300, 200);
1507
+ p.L(300, 100);
1508
+ p.Z();
1509
+ p.fill();
1510
+ }
1511
+ },
1512
+ // ☞ WHITE RIGHT POINTING INDEX
1513
+ [0x261e]: {
1514
+ width: W,
1515
+ draw: p => {
1516
+ p.lineWidth(40);
1517
+ p.M(500, 250);
1518
+ p.L(300, 400);
1519
+ p.L(300, 300);
1520
+ p.L(100, 300);
1521
+ p.L(100, 200);
1522
+ p.L(300, 200);
1523
+ p.L(300, 100);
1524
+ p.Z();
1525
+ p.stroke();
1526
+ }
1527
+ },
1528
+ // ♀ FEMALE SIGN
1529
+ [0x2640]: {
1530
+ width: W,
1531
+ draw: p => {
1532
+ p.lineWidth(50);
1533
+ p.circle(300, 330, 150);
1534
+ p.stroke();
1535
+ p.M(300, 180);
1536
+ p.L(300, 0);
1537
+ p.stroke();
1538
+ p.M(220, 90);
1539
+ p.L(380, 90);
1540
+ p.stroke();
1541
+ }
1542
+ },
1543
+ // ♂ MALE SIGN
1544
+ [0x2642]: {
1545
+ width: W,
1546
+ draw: p => {
1547
+ p.lineWidth(50);
1548
+ p.circle(250, 220, 150);
1549
+ p.stroke();
1550
+ p.M(360, 330);
1551
+ p.L(500, 470);
1552
+ p.stroke();
1553
+ p.M(400, 470);
1554
+ p.L(500, 470);
1555
+ p.L(500, 370);
1556
+ p.stroke();
1557
+ }
1558
+ },
1559
+ // ♠ BLACK SPADE SUIT
1560
+ [0x2660]: {
1561
+ width: W,
1562
+ draw: p => {
1563
+ p.M(300, 500);
1564
+ p.C(300, 500, 80, 350, 80, 200);
1565
+ p.C(80, 100, 200, 50, 300, 180);
1566
+ p.C(400, 50, 520, 100, 520, 200);
1567
+ p.C(520, 350, 300, 500, 300, 500);
1568
+ p.Z();
1569
+ p.fill();
1570
+ p.M(250, 0);
1571
+ p.L(350, 0);
1572
+ p.L(320, 150);
1573
+ p.L(280, 150);
1574
+ p.Z();
1575
+ p.fill();
1576
+ }
1577
+ },
1578
+ // ♣ BLACK CLUB SUIT
1579
+ [0x2663]: {
1580
+ width: W,
1581
+ draw: p => {
1582
+ p.circle(300, 370, 110);
1583
+ p.fill();
1584
+ p.circle(190, 230, 100);
1585
+ p.fill();
1586
+ p.circle(410, 230, 100);
1587
+ p.fill();
1588
+ p.rect(270, 0, 60, 200);
1589
+ p.fill();
1590
+ }
1591
+ },
1592
+ // ♥ BLACK HEART SUIT
1593
+ [0x2665]: {
1594
+ width: W,
1595
+ draw: p => {
1596
+ p.M(300, 80);
1597
+ p.C(300, 80, 80, 200, 80, 340);
1598
+ p.C(80, 440, 180, 490, 300, 490);
1599
+ p.C(420, 490, 520, 440, 520, 340);
1600
+ p.C(520, 200, 300, 80, 300, 80);
1601
+ p.Z();
1602
+ p.fill();
1603
+ }
1604
+ },
1605
+ // ♦ BLACK DIAMOND SUIT
1606
+ [0x2666]: {
1607
+ width: W,
1608
+ draw: p => {
1609
+ p.M(300, 500);
1610
+ p.L(500, 250);
1611
+ p.L(300, 0);
1612
+ p.L(100, 250);
1613
+ p.Z();
1614
+ p.fill();
1615
+ }
1616
+ },
1617
+ // ♩ QUARTER NOTE
1618
+ [0x2669]: {
1619
+ width: W,
1620
+ draw: p => {
1621
+ p.ellipse(230, 80, 100, 70);
1622
+ p.fill();
1623
+ p.lineWidth(40);
1624
+ p.M(330, 80);
1625
+ p.L(330, 480);
1626
+ p.stroke();
1627
+ }
1628
+ },
1629
+ // ♪ EIGHTH NOTE
1630
+ [0x266a]: {
1631
+ width: W,
1632
+ draw: p => {
1633
+ p.ellipse(200, 80, 100, 70);
1634
+ p.fill();
1635
+ p.lineWidth(35);
1636
+ p.M(300, 80);
1637
+ p.L(300, 480);
1638
+ p.stroke();
1639
+ p.M(300, 480);
1640
+ p.C(350, 450, 430, 400, 430, 350);
1641
+ p.stroke();
1642
+ }
1643
+ },
1644
+ // ♭ MUSIC FLAT SIGN
1645
+ [0x266d]: {
1646
+ width: W,
1647
+ draw: p => {
1648
+ p.lineWidth(40);
1649
+ p.M(200, 0);
1650
+ p.L(200, 500);
1651
+ p.stroke();
1652
+ p.M(200, 200);
1653
+ p.C(350, 200, 400, 100, 200, 0);
1654
+ p.stroke();
1655
+ }
1656
+ },
1657
+ // ♯ MUSIC SHARP SIGN
1658
+ [0x266f]: {
1659
+ width: W,
1660
+ draw: p => {
1661
+ p.lineWidth(40);
1662
+ p.M(220, 0);
1663
+ p.L(220, 500);
1664
+ p.stroke();
1665
+ p.M(380, 0);
1666
+ p.L(380, 500);
1667
+ p.stroke();
1668
+ p.lineWidth(50);
1669
+ p.M(140, 180);
1670
+ p.L(460, 240);
1671
+ p.stroke();
1672
+ p.M(140, 310);
1673
+ p.L(460, 370);
1674
+ p.stroke();
1675
+ }
1676
+ },
1677
+ // ✓ CHECK MARK
1678
+ [0x2713]: {
1679
+ width: W,
1680
+ draw: p => {
1681
+ p.lineWidth(65);
1682
+ p.M(100, 250);
1683
+ p.L(240, 80);
1684
+ p.L(500, 450);
1685
+ p.stroke();
1686
+ }
1687
+ },
1688
+ // ✔ HEAVY CHECK MARK
1689
+ [0x2714]: {
1690
+ width: W,
1691
+ draw: p => {
1692
+ p.lineWidth(85);
1693
+ p.M(100, 250);
1694
+ p.L(240, 80);
1695
+ p.L(500, 450);
1696
+ p.stroke();
1697
+ }
1698
+ },
1699
+ // ✕ MULTIPLICATION X
1700
+ [0x2715]: {
1701
+ width: W,
1702
+ draw: p => {
1703
+ p.lineWidth(55);
1704
+ p.M(140, 70);
1705
+ p.L(460, 430);
1706
+ p.stroke();
1707
+ p.M(140, 430);
1708
+ p.L(460, 70);
1709
+ p.stroke();
1710
+ }
1711
+ },
1712
+ // ✖ HEAVY MULTIPLICATION X
1713
+ [0x2716]: {
1714
+ width: W,
1715
+ draw: p => {
1716
+ p.lineWidth(75);
1717
+ p.M(140, 70);
1718
+ p.L(460, 430);
1719
+ p.stroke();
1720
+ p.M(140, 430);
1721
+ p.L(460, 70);
1722
+ p.stroke();
1723
+ }
1724
+ },
1725
+ // ✗ BALLOT X
1726
+ [0x2717]: {
1727
+ width: W,
1728
+ draw: p => {
1729
+ p.lineWidth(60);
1730
+ p.M(130, 60);
1731
+ p.L(470, 440);
1732
+ p.stroke();
1733
+ p.M(130, 440);
1734
+ p.L(470, 60);
1735
+ p.stroke();
1736
+ }
1737
+ },
1738
+ // ✘ HEAVY BALLOT X
1739
+ [0x2718]: {
1740
+ width: W,
1741
+ draw: p => {
1742
+ p.lineWidth(80);
1743
+ p.M(130, 60);
1744
+ p.L(470, 440);
1745
+ p.stroke();
1746
+ p.M(130, 440);
1747
+ p.L(470, 60);
1748
+ p.stroke();
1749
+ }
1750
+ },
1751
+ // ✚ HEAVY GREEK CROSS
1752
+ [0x271a]: {
1753
+ width: W,
1754
+ draw: p => {
1755
+ p.rect(210, 30, 180, 440);
1756
+ p.fill();
1757
+ p.rect(90, 160, 420, 180);
1758
+ p.fill();
1759
+ }
1760
+ },
1761
+ // ✜ HEAVY OPEN CENTRE CROSS — simplified
1762
+ [0x271c]: {
1763
+ width: W,
1764
+ draw: p => {
1765
+ p.lineWidth(60);
1766
+ p.M(300, 30);
1767
+ p.L(300, 470);
1768
+ p.stroke();
1769
+ p.M(90, 250);
1770
+ p.L(510, 250);
1771
+ p.stroke();
1772
+ }
1773
+ },
1774
+ // ✠ MALTESE CROSS — simplified
1775
+ [0x2720]: {
1776
+ width: W,
1777
+ draw: p => {
1778
+ p.M(300, 480);
1779
+ p.L(250, 320);
1780
+ p.L(100, 350);
1781
+ p.L(200, 250);
1782
+ p.L(100, 150);
1783
+ p.L(250, 180);
1784
+ p.L(300, 20);
1785
+ p.L(350, 180);
1786
+ p.L(500, 150);
1787
+ p.L(400, 250);
1788
+ p.L(500, 350);
1789
+ p.L(350, 320);
1790
+ p.Z();
1791
+ p.fill();
1792
+ }
1793
+ },
1794
+ // ❤ HEAVY BLACK HEART
1795
+ [0x2764]: {
1796
+ width: W,
1797
+ draw: p => {
1798
+ p.M(300, 80);
1799
+ p.C(300, 80, 60, 220, 60, 350);
1800
+ p.C(60, 470, 180, 500, 300, 500);
1801
+ p.C(420, 500, 540, 470, 540, 350);
1802
+ p.C(540, 220, 300, 80, 300, 80);
1803
+ p.Z();
1804
+ p.fill();
1805
+ }
1806
+ },
1807
+ // ❶–❿ DINGBAT NEGATIVE CIRCLED (1–10)
1808
+ ...(() => {
1809
+ const r = {};
1810
+ for (let i = 0; i < 10; i++) {
1811
+ const cp = 0x2776 + i;
1812
+ r[cp] = {
1813
+ width: W,
1814
+ draw: p => {
1815
+ p.circle(300, 250, 240);
1816
+ p.fill(); /* digit rendered as glyph outline – too complex for paths; filled circle is best approximation */
1817
+ }
1818
+ };
1819
+ }
1820
+ return r;
1821
+ })(),
1822
+ // ①–⑩ CIRCLED DIGIT (U+2460–U+2469)
1823
+ ...(() => {
1824
+ const r = {};
1825
+ for (let i = 0; i < 10; i++) {
1826
+ r[0x2460 + i] = {
1827
+ width: W,
1828
+ draw: p => {
1829
+ p.lineWidth(40);
1830
+ p.circle(300, 250, 220);
1831
+ p.stroke();
1832
+ }
1833
+ };
1834
+ }
1835
+ return r;
1836
+ })()
1837
+ };
1838
+ // =============================================================================
1839
+ // Miscellaneous Technical (U+2300 – U+23FF)
1840
+ // =============================================================================
1841
+ const TECH = {
1842
+ // ⌀ DIAMETER SIGN
1843
+ [0x2300]: {
1844
+ width: W,
1845
+ draw: p => {
1846
+ p.lineWidth(45);
1847
+ p.circle(300, 250, 200);
1848
+ p.stroke();
1849
+ p.M(140, 90);
1850
+ p.L(460, 410);
1851
+ p.stroke();
1852
+ }
1853
+ },
1854
+ // ⌂ HOUSE
1855
+ [0x2302]: {
1856
+ width: W,
1857
+ draw: p => {
1858
+ p.lineWidth(45);
1859
+ p.M(300, 480);
1860
+ p.L(520, 250);
1861
+ p.L(520, 30);
1862
+ p.L(80, 30);
1863
+ p.L(80, 250);
1864
+ p.Z();
1865
+ p.stroke();
1866
+ }
1867
+ },
1868
+ // ⌘ PLACE OF INTEREST SIGN (command key) — simplified as looped square
1869
+ [0x2318]: {
1870
+ width: W,
1871
+ draw: p => {
1872
+ p.lineWidth(45);
1873
+ p.rect(180, 130, 240, 240);
1874
+ p.stroke();
1875
+ p.circle(180, 370, 70);
1876
+ p.stroke();
1877
+ p.circle(420, 370, 70);
1878
+ p.stroke();
1879
+ p.circle(180, 130, 70);
1880
+ p.stroke();
1881
+ p.circle(420, 130, 70);
1882
+ p.stroke();
1883
+ }
1884
+ },
1885
+ // ⌛ HOURGLASS
1886
+ [0x231b]: {
1887
+ width: W,
1888
+ draw: p => {
1889
+ p.lineWidth(45);
1890
+ p.M(120, 480);
1891
+ p.L(480, 480);
1892
+ p.stroke();
1893
+ p.M(120, 20);
1894
+ p.L(480, 20);
1895
+ p.stroke();
1896
+ p.M(150, 480);
1897
+ p.L(300, 250);
1898
+ p.L(450, 480);
1899
+ p.stroke();
1900
+ p.M(150, 20);
1901
+ p.L(300, 250);
1902
+ p.L(450, 20);
1903
+ p.stroke();
1904
+ }
1905
+ },
1906
+ // ⏎ RETURN SYMBOL
1907
+ [0x23ce]: {
1908
+ width: W,
1909
+ draw: p => {
1910
+ p.lineWidth(45);
1911
+ p.M(480, 420);
1912
+ p.L(480, 200);
1913
+ p.L(150, 200);
1914
+ p.stroke();
1915
+ p.M(150, 200);
1916
+ p.L(280, 310);
1917
+ p.L(280, 90);
1918
+ p.Z();
1919
+ p.fill();
1920
+ }
1921
+ }
1922
+ };
1923
+ // =============================================================================
1924
+ // Box Drawing (U+2500 – U+257F)
1925
+ // =============================================================================
1926
+ const BOX = {
1927
+ // ─ BOX DRAWINGS LIGHT HORIZONTAL
1928
+ [0x2500]: {
1929
+ width: W,
1930
+ draw: p => {
1931
+ p.lineWidth(40);
1932
+ p.M(0, 250);
1933
+ p.L(600, 250);
1934
+ p.stroke();
1935
+ }
1936
+ },
1937
+ // ━ BOX DRAWINGS HEAVY HORIZONTAL
1938
+ [0x2501]: {
1939
+ width: W,
1940
+ draw: p => {
1941
+ p.lineWidth(80);
1942
+ p.M(0, 250);
1943
+ p.L(600, 250);
1944
+ p.stroke();
1945
+ }
1946
+ },
1947
+ // │ BOX DRAWINGS LIGHT VERTICAL
1948
+ [0x2502]: {
1949
+ width: W,
1950
+ draw: p => {
1951
+ p.lineWidth(40);
1952
+ p.M(300, 0);
1953
+ p.L(300, 500);
1954
+ p.stroke();
1955
+ }
1956
+ },
1957
+ // ┃ BOX DRAWINGS HEAVY VERTICAL
1958
+ [0x2503]: {
1959
+ width: W,
1960
+ draw: p => {
1961
+ p.lineWidth(80);
1962
+ p.M(300, 0);
1963
+ p.L(300, 500);
1964
+ p.stroke();
1965
+ }
1966
+ },
1967
+ // ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT
1968
+ [0x250c]: {
1969
+ width: W,
1970
+ draw: p => {
1971
+ p.lineWidth(40);
1972
+ p.M(300, 0);
1973
+ p.L(300, 250);
1974
+ p.L(600, 250);
1975
+ p.stroke();
1976
+ }
1977
+ },
1978
+ // ┐ BOX DRAWINGS LIGHT DOWN AND LEFT
1979
+ [0x2510]: {
1980
+ width: W,
1981
+ draw: p => {
1982
+ p.lineWidth(40);
1983
+ p.M(300, 0);
1984
+ p.L(300, 250);
1985
+ p.L(0, 250);
1986
+ p.stroke();
1987
+ }
1988
+ },
1989
+ // └ BOX DRAWINGS LIGHT UP AND RIGHT
1990
+ [0x2514]: {
1991
+ width: W,
1992
+ draw: p => {
1993
+ p.lineWidth(40);
1994
+ p.M(300, 500);
1995
+ p.L(300, 250);
1996
+ p.L(600, 250);
1997
+ p.stroke();
1998
+ }
1999
+ },
2000
+ // ┘ BOX DRAWINGS LIGHT UP AND LEFT
2001
+ [0x2518]: {
2002
+ width: W,
2003
+ draw: p => {
2004
+ p.lineWidth(40);
2005
+ p.M(300, 500);
2006
+ p.L(300, 250);
2007
+ p.L(0, 250);
2008
+ p.stroke();
2009
+ }
2010
+ },
2011
+ // ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT
2012
+ [0x251c]: {
2013
+ width: W,
2014
+ draw: p => {
2015
+ p.lineWidth(40);
2016
+ p.M(300, 0);
2017
+ p.L(300, 500);
2018
+ p.stroke();
2019
+ p.M(300, 250);
2020
+ p.L(600, 250);
2021
+ p.stroke();
2022
+ }
2023
+ },
2024
+ // ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT
2025
+ [0x2524]: {
2026
+ width: W,
2027
+ draw: p => {
2028
+ p.lineWidth(40);
2029
+ p.M(300, 0);
2030
+ p.L(300, 500);
2031
+ p.stroke();
2032
+ p.M(300, 250);
2033
+ p.L(0, 250);
2034
+ p.stroke();
2035
+ }
2036
+ },
2037
+ // ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
2038
+ [0x252c]: {
2039
+ width: W,
2040
+ draw: p => {
2041
+ p.lineWidth(40);
2042
+ p.M(0, 250);
2043
+ p.L(600, 250);
2044
+ p.stroke();
2045
+ p.M(300, 250);
2046
+ p.L(300, 0);
2047
+ p.stroke();
2048
+ }
2049
+ },
2050
+ // ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL
2051
+ [0x2534]: {
2052
+ width: W,
2053
+ draw: p => {
2054
+ p.lineWidth(40);
2055
+ p.M(0, 250);
2056
+ p.L(600, 250);
2057
+ p.stroke();
2058
+ p.M(300, 250);
2059
+ p.L(300, 500);
2060
+ p.stroke();
2061
+ }
2062
+ },
2063
+ // ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
2064
+ [0x253c]: {
2065
+ width: W,
2066
+ draw: p => {
2067
+ p.lineWidth(40);
2068
+ p.M(0, 250);
2069
+ p.L(600, 250);
2070
+ p.stroke();
2071
+ p.M(300, 0);
2072
+ p.L(300, 500);
2073
+ p.stroke();
2074
+ }
2075
+ },
2076
+ // ╔ BOX DRAWINGS DOUBLE DOWN AND RIGHT
2077
+ [0x2554]: {
2078
+ width: W,
2079
+ draw: p => {
2080
+ p.lineWidth(30);
2081
+ p.M(270, 0);
2082
+ p.L(270, 270);
2083
+ p.L(600, 270);
2084
+ p.stroke();
2085
+ p.M(330, 0);
2086
+ p.L(330, 230);
2087
+ p.L(600, 230);
2088
+ p.stroke();
2089
+ }
2090
+ },
2091
+ // ╗ BOX DRAWINGS DOUBLE DOWN AND LEFT
2092
+ [0x2557]: {
2093
+ width: W,
2094
+ draw: p => {
2095
+ p.lineWidth(30);
2096
+ p.M(330, 0);
2097
+ p.L(330, 270);
2098
+ p.L(0, 270);
2099
+ p.stroke();
2100
+ p.M(270, 0);
2101
+ p.L(270, 230);
2102
+ p.L(0, 230);
2103
+ p.stroke();
2104
+ }
2105
+ },
2106
+ // ╚ BOX DRAWINGS DOUBLE UP AND RIGHT
2107
+ [0x255a]: {
2108
+ width: W,
2109
+ draw: p => {
2110
+ p.lineWidth(30);
2111
+ p.M(270, 500);
2112
+ p.L(270, 230);
2113
+ p.L(600, 230);
2114
+ p.stroke();
2115
+ p.M(330, 500);
2116
+ p.L(330, 270);
2117
+ p.L(600, 270);
2118
+ p.stroke();
2119
+ }
2120
+ },
2121
+ // ╝ BOX DRAWINGS DOUBLE UP AND LEFT
2122
+ [0x255d]: {
2123
+ width: W,
2124
+ draw: p => {
2125
+ p.lineWidth(30);
2126
+ p.M(330, 500);
2127
+ p.L(330, 230);
2128
+ p.L(0, 230);
2129
+ p.stroke();
2130
+ p.M(270, 500);
2131
+ p.L(270, 270);
2132
+ p.L(0, 270);
2133
+ p.stroke();
2134
+ }
2135
+ },
2136
+ // ═ BOX DRAWINGS DOUBLE HORIZONTAL
2137
+ [0x2550]: {
2138
+ width: W,
2139
+ draw: p => {
2140
+ p.lineWidth(30);
2141
+ p.M(0, 270);
2142
+ p.L(600, 270);
2143
+ p.stroke();
2144
+ p.M(0, 230);
2145
+ p.L(600, 230);
2146
+ p.stroke();
2147
+ }
2148
+ },
2149
+ // ║ BOX DRAWINGS DOUBLE VERTICAL
2150
+ [0x2551]: {
2151
+ width: W,
2152
+ draw: p => {
2153
+ p.lineWidth(30);
2154
+ p.M(270, 0);
2155
+ p.L(270, 500);
2156
+ p.stroke();
2157
+ p.M(330, 0);
2158
+ p.L(330, 500);
2159
+ p.stroke();
2160
+ }
2161
+ }
2162
+ };
2163
+ // =============================================================================
2164
+ // Block Elements (U+2580 – U+259F)
2165
+ // =============================================================================
2166
+ const BLOCK = {
2167
+ // ▀ UPPER HALF BLOCK
2168
+ [0x2580]: filledRect(0, 250, 600, 250),
2169
+ // ▄ LOWER HALF BLOCK
2170
+ [0x2584]: filledRect(0, 0, 600, 250),
2171
+ // █ FULL BLOCK
2172
+ [0x2588]: filledRect(0, 0, 600, 500),
2173
+ // ▌ LEFT HALF BLOCK
2174
+ [0x258c]: filledRect(0, 0, 300, 500),
2175
+ // ▐ RIGHT HALF BLOCK
2176
+ [0x2590]: filledRect(300, 0, 300, 500),
2177
+ // ░ LIGHT SHADE — simplified as rect with lines
2178
+ [0x2591]: {
2179
+ width: W,
2180
+ draw: p => {
2181
+ p.lineWidth(15);
2182
+ p.rect(0, 0, 600, 500);
2183
+ p.stroke();
2184
+ for (let y = 0; y <= 500; y += 60) {
2185
+ p.M(0, y);
2186
+ p.L(600, y);
2187
+ }
2188
+ p.stroke();
2189
+ }
2190
+ },
2191
+ // ▒ MEDIUM SHADE
2192
+ [0x2592]: {
2193
+ width: W,
2194
+ draw: p => {
2195
+ p.lineWidth(25);
2196
+ p.rect(0, 0, 600, 500);
2197
+ p.stroke();
2198
+ for (let y = 0; y <= 500; y += 50) {
2199
+ p.M(0, y);
2200
+ p.L(600, y);
2201
+ }
2202
+ for (let x = 0; x <= 600; x += 60) {
2203
+ p.M(x, 0);
2204
+ p.L(x, 500);
2205
+ }
2206
+ p.stroke();
2207
+ }
2208
+ },
2209
+ // ▓ DARK SHADE
2210
+ [0x2593]: {
2211
+ width: W,
2212
+ draw: p => {
2213
+ p.lineWidth(35);
2214
+ p.rect(0, 0, 600, 500);
2215
+ p.fill();
2216
+ }
2217
+ }
2218
+ };
2219
+ // =============================================================================
2220
+ // Misc Symbols & Arrows (U+2B00 – U+2BFF)
2221
+ // =============================================================================
2222
+ const MISC_ARROWS = {
2223
+ // ⬆ UPWARDS BLACK ARROW
2224
+ [0x2b06]: {
2225
+ width: W,
2226
+ draw: p => {
2227
+ p.M(300, 500);
2228
+ p.L(100, 280);
2229
+ p.L(230, 280);
2230
+ p.L(230, 0);
2231
+ p.L(370, 0);
2232
+ p.L(370, 280);
2233
+ p.L(500, 280);
2234
+ p.Z();
2235
+ p.fill();
2236
+ }
2237
+ },
2238
+ // ⬇ DOWNWARDS BLACK ARROW
2239
+ [0x2b07]: {
2240
+ width: W,
2241
+ draw: p => {
2242
+ p.M(300, 0);
2243
+ p.L(100, 220);
2244
+ p.L(230, 220);
2245
+ p.L(230, 500);
2246
+ p.L(370, 500);
2247
+ p.L(370, 220);
2248
+ p.L(500, 220);
2249
+ p.Z();
2250
+ p.fill();
2251
+ }
2252
+ },
2253
+ // ⬅ LEFTWARDS BLACK ARROW
2254
+ [0x2b05]: {
2255
+ width: W,
2256
+ draw: p => {
2257
+ p.M(0, 250);
2258
+ p.L(220, 430);
2259
+ p.L(220, 320);
2260
+ p.L(550, 320);
2261
+ p.L(550, 180);
2262
+ p.L(220, 180);
2263
+ p.L(220, 70);
2264
+ p.Z();
2265
+ p.fill();
2266
+ }
2267
+ },
2268
+ // ➡ BLACK RIGHTWARDS ARROW (U+27A1 not here, but mapped)
2269
+ // ⬛ BLACK LARGE SQUARE
2270
+ [0x2b1b]: filledRect(60, 10, 480, 480),
2271
+ // ⬜ WHITE LARGE SQUARE
2272
+ [0x2b1c]: strokedRect(60, 10, 480, 480, 45),
2273
+ // ⭐ WHITE MEDIUM STAR — same as ☆
2274
+ [0x2b50]: {
2275
+ width: W,
2276
+ draw: p => {
2277
+ p.lineWidth(35);
2278
+ const cx = 300;
2279
+ const cy = 260;
2280
+ const R = 230;
2281
+ const r = 90;
2282
+ for (let i = 0; i < 5; i++) {
2283
+ const a1 = ((i * 72 - 90) * Math.PI) / 180;
2284
+ const a2 = ((i * 72 + 36 - 90) * Math.PI) / 180;
2285
+ if (i === 0) {
2286
+ p.M(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
2287
+ }
2288
+ else {
2289
+ p.L(cx + R * Math.cos(a1), cy + R * Math.sin(a1));
2290
+ }
2291
+ p.L(cx + r * Math.cos(a2), cy + r * Math.sin(a2));
2292
+ }
2293
+ p.Z();
2294
+ p.stroke();
2295
+ }
2296
+ }
2297
+ };
2298
+ // =============================================================================
2299
+ // Squared / circled symbols from Misc Math Symbols-B (U+29C0–U+29FF)
2300
+ // =============================================================================
2301
+ const SQUARED = {
2302
+ // ⧀ CIRCLED LESS-THAN
2303
+ [0x29c0]: {
2304
+ width: W,
2305
+ draw: p => {
2306
+ p.lineWidth(40);
2307
+ p.circle(300, 250, 220);
2308
+ p.stroke();
2309
+ p.lineWidth(45);
2310
+ p.M(400, 380);
2311
+ p.L(200, 250);
2312
+ p.L(400, 120);
2313
+ p.stroke();
2314
+ }
2315
+ },
2316
+ // ⧁ CIRCLED GREATER-THAN
2317
+ [0x29c1]: {
2318
+ width: W,
2319
+ draw: p => {
2320
+ p.lineWidth(40);
2321
+ p.circle(300, 250, 220);
2322
+ p.stroke();
2323
+ p.lineWidth(45);
2324
+ p.M(200, 380);
2325
+ p.L(400, 250);
2326
+ p.L(200, 120);
2327
+ p.stroke();
2328
+ }
2329
+ },
2330
+ // ⧇ SQUARED SMALL CIRCLE (key character from the issue!)
2331
+ [0x29c7]: {
2332
+ width: W,
2333
+ draw: p => {
2334
+ p.lineWidth(40);
2335
+ p.rect(80, 30, 440, 440);
2336
+ p.stroke();
2337
+ p.circle(300, 250, 130);
2338
+ p.stroke();
2339
+ }
2340
+ },
2341
+ // ⧈ SQUARED SQUARE
2342
+ [0x29c8]: {
2343
+ width: W,
2344
+ draw: p => {
2345
+ p.lineWidth(40);
2346
+ p.rect(80, 30, 440, 440);
2347
+ p.stroke();
2348
+ p.rect(190, 140, 220, 220);
2349
+ p.stroke();
2350
+ }
2351
+ },
2352
+ // ⧉ TWO JOINED SQUARES
2353
+ [0x29c9]: {
2354
+ width: W,
2355
+ draw: p => {
2356
+ p.lineWidth(35);
2357
+ p.rect(80, 80, 300, 300);
2358
+ p.stroke();
2359
+ p.rect(220, 120, 300, 300);
2360
+ p.stroke();
2361
+ }
2362
+ }
2363
+ };
2364
+ // =============================================================================
2365
+ // Currency Symbols (U+20A0 – U+20CF)
2366
+ // =============================================================================
2367
+ const CURRENCY = {
2368
+ // ₹ INDIAN RUPEE SIGN
2369
+ [0x20b9]: {
2370
+ width: W,
2371
+ draw: p => {
2372
+ p.lineWidth(50);
2373
+ p.M(130, 480);
2374
+ p.L(470, 480);
2375
+ p.stroke();
2376
+ p.M(130, 380);
2377
+ p.L(470, 380);
2378
+ p.stroke();
2379
+ p.M(230, 480);
2380
+ p.C(350, 480, 420, 400, 420, 350);
2381
+ p.C(420, 280, 350, 200, 230, 200);
2382
+ p.stroke();
2383
+ p.M(200, 380);
2384
+ p.L(400, 0);
2385
+ p.stroke();
2386
+ }
2387
+ },
2388
+ // ₺ TURKISH LIRA SIGN
2389
+ [0x20ba]: {
2390
+ width: W,
2391
+ draw: p => {
2392
+ p.lineWidth(50);
2393
+ p.M(350, 480);
2394
+ p.L(350, 50);
2395
+ p.C(350, 0, 200, 0, 150, 50);
2396
+ p.stroke();
2397
+ p.M(150, 330);
2398
+ p.L(450, 250);
2399
+ p.stroke();
2400
+ p.M(150, 230);
2401
+ p.L(450, 150);
2402
+ p.stroke();
2403
+ }
2404
+ },
2405
+ // ₽ RUBLE SIGN
2406
+ [0x20bd]: {
2407
+ width: W,
2408
+ draw: p => {
2409
+ p.lineWidth(50);
2410
+ p.M(180, 0);
2411
+ p.L(180, 500);
2412
+ p.stroke();
2413
+ p.M(180, 500);
2414
+ p.L(350, 500);
2415
+ p.C(480, 500, 480, 350, 350, 300);
2416
+ p.L(180, 300);
2417
+ p.stroke();
2418
+ p.M(120, 200);
2419
+ p.L(400, 200);
2420
+ p.stroke();
2421
+ }
2422
+ }
2423
+ };
2424
+ // =============================================================================
2425
+ // General Punctuation & Misc (assorted useful ones)
2426
+ // =============================================================================
2427
+ const PUNCT = {
2428
+ // • BULLET (U+2022)
2429
+ [0x2022]: filledCircle(300, 250, 100),
2430
+ // … HORIZONTAL ELLIPSIS (U+2026)
2431
+ [0x2026]: {
2432
+ width: W,
2433
+ draw: p => {
2434
+ p.circle(120, 100, 40);
2435
+ p.fill();
2436
+ p.circle(300, 100, 40);
2437
+ p.fill();
2438
+ p.circle(480, 100, 40);
2439
+ p.fill();
2440
+ }
2441
+ },
2442
+ // ‣ TRIANGULAR BULLET (U+2023)
2443
+ [0x2023]: {
2444
+ width: W,
2445
+ draw: p => {
2446
+ p.M(150, 400);
2447
+ p.L(450, 250);
2448
+ p.L(150, 100);
2449
+ p.Z();
2450
+ p.fill();
2451
+ }
2452
+ },
2453
+ // ⁃ HYPHEN BULLET (U+2043)
2454
+ [0x2043]: {
2455
+ width: W,
2456
+ draw: p => {
2457
+ p.lineWidth(60);
2458
+ p.M(150, 250);
2459
+ p.L(450, 250);
2460
+ p.stroke();
2461
+ }
2462
+ },
2463
+ // ⁄ FRACTION SLASH (U+2044)
2464
+ [0x2044]: {
2465
+ width: W,
2466
+ draw: p => {
2467
+ p.lineWidth(40);
2468
+ p.M(450, 500);
2469
+ p.L(150, 0);
2470
+ p.stroke();
2471
+ }
2472
+ }
2473
+ };
2474
+ // =============================================================================
2475
+ // Master lookup table
2476
+ // =============================================================================
2477
+ const type3_glyphs_extended_1 = require("./type3-glyphs-extended");
2478
+ const type3_glyphs_extended2_1 = require("./type3-glyphs-extended2");
2479
+ const type3_glyphs_fill_1 = require("./type3-glyphs-fill");
2480
+ const type3_glyphs_quality_1 = require("./type3-glyphs-quality");
2481
+ const ALL_TABLES = [
2482
+ GEO,
2483
+ ARR,
2484
+ MATH,
2485
+ DING,
2486
+ TECH,
2487
+ BOX,
2488
+ BLOCK,
2489
+ MISC_ARROWS,
2490
+ SQUARED,
2491
+ CURRENCY,
2492
+ PUNCT,
2493
+ // Extended tables
2494
+ type3_glyphs_extended_1.BOX_FULL,
2495
+ type3_glyphs_extended_1.BLOCK_FULL,
2496
+ type3_glyphs_extended_1.BRAILLE,
2497
+ type3_glyphs_extended_1.LETTERLIKE,
2498
+ type3_glyphs_extended_1.NUMBER_FORMS,
2499
+ type3_glyphs_extended_1.ENCLOSED,
2500
+ type3_glyphs_extended_1.PUNCT_EXT,
2501
+ type3_glyphs_extended_1.ARROWS_EXT,
2502
+ type3_glyphs_extended_1.MATH_EXT,
2503
+ type3_glyphs_extended_1.MISC_EXT,
2504
+ type3_glyphs_extended_1.DING_EXT,
2505
+ type3_glyphs_extended_1.TECH_EXT,
2506
+ type3_glyphs_extended_1.CURRENCY_EXT,
2507
+ type3_glyphs_extended_1.MATH_SYM_A,
2508
+ type3_glyphs_extended_1.SUP_ARROWS_A,
2509
+ type3_glyphs_extended_1.GEOMETRIC_EXT,
2510
+ type3_glyphs_extended_1.ROMAN_NUMERALS,
2511
+ type3_glyphs_extended_1.ENCLOSED_EXT,
2512
+ // Extended2 tables
2513
+ type3_glyphs_extended2_1.ARROWS_HARPOONS,
2514
+ type3_glyphs_extended2_1.DINGBATS_FULL,
2515
+ type3_glyphs_extended2_1.MISC_SYMBOLS_FULL,
2516
+ type3_glyphs_extended2_1.MISC_TECHNICAL_EXT,
2517
+ type3_glyphs_extended2_1.SUP_ARROWS_B,
2518
+ type3_glyphs_extended2_1.MISC_MATH_A_EXT,
2519
+ type3_glyphs_extended2_1.MISC_SYM_ARROWS_EXT,
2520
+ // Fill tables (gap coverage)
2521
+ type3_glyphs_fill_1.DINGBATS_FILL,
2522
+ type3_glyphs_fill_1.MISC_SYM_FILL,
2523
+ type3_glyphs_fill_1.MISC_SYM_ARR_FILL,
2524
+ type3_glyphs_fill_1.SUP_ARROWS_FILL,
2525
+ type3_glyphs_fill_1.GEN_PUNCT_FILL,
2526
+ type3_glyphs_fill_1.NUM_FORMS_FILL,
2527
+ type3_glyphs_fill_1.FINAL_FILL,
2528
+ // Quality overrides + new coverage (must be LAST to override earlier entries)
2529
+ type3_glyphs_quality_1.SPACES,
2530
+ type3_glyphs_quality_1.SUPP_MATH_OP,
2531
+ type3_glyphs_quality_1.MISC_MATH_B,
2532
+ type3_glyphs_quality_1.MATH_OP_FULL,
2533
+ type3_glyphs_quality_1.LETTERLIKE_FULL,
2534
+ type3_glyphs_quality_1.CURRENCY_REMAINING,
2535
+ type3_glyphs_quality_1.ARROWS_REMAINING,
2536
+ type3_glyphs_quality_1.CIRCLED_DIGITS,
2537
+ type3_glyphs_quality_1.CIRCLED_LETTERS,
2538
+ type3_glyphs_quality_1.CIRCLED_SMALL_LETTERS,
2539
+ type3_glyphs_quality_1.NEG_CIRCLED_DIGITS,
2540
+ type3_glyphs_quality_1.REFINED_SYMBOLS
2541
+ ];
2542
+ /** Merged lookup table (built once on first access). */
2543
+ let _merged = null;
2544
+ function getMerged() {
2545
+ if (!_merged) {
2546
+ _merged = new Map();
2547
+ for (const table of ALL_TABLES) {
2548
+ for (const [cp, def] of Object.entries(table)) {
2549
+ _merged.set(Number(cp), def);
2550
+ }
2551
+ }
2552
+ }
2553
+ return _merged;
2554
+ }
2555
+ /**
2556
+ * Look up a glyph definition for a Unicode code point.
2557
+ * Returns the glyph def, or `undefined` if no specific drawing is available.
2558
+ */
2559
+ function lookupGlyph(codePoint) {
2560
+ return getMerged().get(codePoint);
2561
+ }
2562
+ /**
2563
+ * Check whether a specific code point has a dedicated vector glyph.
2564
+ */
2565
+ function hasGlyph(codePoint) {
2566
+ return getMerged().has(codePoint);
2567
+ }
2568
+ /**
2569
+ * Return the total number of defined glyphs (for diagnostics / testing).
2570
+ */
2571
+ function glyphCount() {
2572
+ return getMerged().size;
2573
+ }