@logomarks/core 0.1.9 → 0.2.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.
Files changed (133) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +10 -1
  3. package/package.json +59 -4
  4. package/src/batch/args.d.ts +18 -0
  5. package/src/batch/args.js +44 -0
  6. package/src/batch/index.d.ts +7 -0
  7. package/src/batch/index.js +10 -0
  8. package/src/batch/run.d.ts +53 -0
  9. package/src/batch/run.js +92 -0
  10. package/src/batch/slug.d.ts +2 -0
  11. package/src/batch/slug.js +12 -0
  12. package/src/batch/source.d.ts +12 -0
  13. package/src/batch/source.js +23 -0
  14. package/src/fit/index.d.ts +4 -0
  15. package/src/fit/index.js +29 -5
  16. package/src/font/glyphs.d.ts +31 -0
  17. package/src/font/glyphs.js +228 -0
  18. package/src/font/index.d.ts +10 -0
  19. package/src/font/index.js +10 -0
  20. package/src/font/measure.d.ts +16 -0
  21. package/src/font/measure.js +201 -0
  22. package/src/font/moves.d.ts +42 -0
  23. package/src/font/moves.js +263 -0
  24. package/src/forms/discs.d.ts +20 -0
  25. package/src/forms/discs.js +114 -0
  26. package/src/forms/emblems.d.ts +22 -0
  27. package/src/forms/emblems.js +109 -0
  28. package/src/forms/flow.d.ts +21 -0
  29. package/src/forms/flow.js +80 -0
  30. package/src/forms/folds.d.ts +18 -0
  31. package/src/forms/folds.js +147 -0
  32. package/src/forms/geo.d.ts +46 -0
  33. package/src/forms/geo.js +233 -0
  34. package/src/forms/hooks.d.ts +40 -0
  35. package/src/forms/hooks.js +204 -0
  36. package/src/forms/index.d.ts +22 -0
  37. package/src/forms/index.js +24 -0
  38. package/src/forms/jog.d.ts +33 -0
  39. package/src/forms/jog.js +162 -0
  40. package/src/forms/lines.d.ts +32 -0
  41. package/src/forms/lines.js +233 -0
  42. package/src/forms/ref.d.ts +41 -0
  43. package/src/forms/ref.js +246 -0
  44. package/src/forms/shatter.d.ts +40 -0
  45. package/src/forms/shatter.js +341 -0
  46. package/src/forms/slats.d.ts +35 -0
  47. package/src/forms/slats.js +78 -0
  48. package/src/forms/swash.d.ts +23 -0
  49. package/src/forms/swash.js +74 -0
  50. package/src/forms/tech.d.ts +40 -0
  51. package/src/forms/tech.js +293 -0
  52. package/src/forms/tracks.d.ts +36 -0
  53. package/src/forms/tracks.js +121 -0
  54. package/src/geometry/index.d.ts +1 -0
  55. package/src/geometry/index.js +1 -0
  56. package/src/geometry/mitre.d.ts +8 -0
  57. package/src/geometry/mitre.js +64 -0
  58. package/src/geometry/modular.d.ts +1 -1
  59. package/src/index.js +2 -1
  60. package/src/iso/index.d.ts +5 -0
  61. package/src/iso/index.js +13 -0
  62. package/src/iso/objects.d.ts +168 -0
  63. package/src/iso/objects.js +1042 -0
  64. package/src/iso/planes.d.ts +27 -0
  65. package/src/iso/planes.js +138 -0
  66. package/src/iso/voxels.d.ts +43 -0
  67. package/src/iso/voxels.js +255 -0
  68. package/src/letters/blackletter.d.ts +31 -0
  69. package/src/letters/blackletter.js +199 -0
  70. package/src/letters/dotstroke.d.ts +16 -0
  71. package/src/letters/dotstroke.js +77 -0
  72. package/src/letters/echo.d.ts +42 -0
  73. package/src/letters/echo.js +246 -0
  74. package/src/letters/frame.d.ts +6 -0
  75. package/src/letters/frame.js +14 -0
  76. package/src/letters/index.d.ts +16 -0
  77. package/src/letters/index.js +18 -0
  78. package/src/letters/inktrap.d.ts +66 -0
  79. package/src/letters/inktrap.js +244 -0
  80. package/src/letters/mono.d.ts +145 -0
  81. package/src/letters/mono.js +684 -0
  82. package/src/letters/pillar.d.ts +31 -0
  83. package/src/letters/pillar.js +257 -0
  84. package/src/letters/serif.d.ts +109 -0
  85. package/src/letters/serif.js +666 -0
  86. package/src/letters/stair.d.ts +8 -0
  87. package/src/letters/stair.js +43 -0
  88. package/src/letters/stem.d.ts +29 -0
  89. package/src/letters/stem.js +205 -0
  90. package/src/objects/animals.d.ts +105 -0
  91. package/src/objects/animals.js +469 -0
  92. package/src/objects/bio.d.ts +14 -0
  93. package/src/objects/bio.js +76 -0
  94. package/src/objects/devglyphs.d.ts +34 -0
  95. package/src/objects/devglyphs.js +226 -0
  96. package/src/objects/devices.d.ts +31 -0
  97. package/src/objects/devices.js +114 -0
  98. package/src/objects/faces.d.ts +94 -0
  99. package/src/objects/faces.js +344 -0
  100. package/src/objects/food.d.ts +12 -0
  101. package/src/objects/food.js +74 -0
  102. package/src/objects/index.d.ts +13 -0
  103. package/src/objects/index.js +18 -0
  104. package/src/objects/rosettes.d.ts +14 -0
  105. package/src/objects/rosettes.js +64 -0
  106. package/src/objects/sport.d.ts +8 -0
  107. package/src/objects/sport.js +37 -0
  108. package/src/objects/weapons.d.ts +31 -0
  109. package/src/objects/weapons.js +179 -0
  110. package/src/parts/index.d.ts +2 -0
  111. package/src/parts/index.js +2 -0
  112. package/src/parts/pixels.d.ts +11 -0
  113. package/src/parts/pixels.js +74 -0
  114. package/src/parts/run.js +4 -2
  115. package/src/parts/span.d.ts +13 -0
  116. package/src/parts/span.js +100 -0
  117. package/src/pixels/dither.d.ts +78 -0
  118. package/src/pixels/dither.js +399 -0
  119. package/src/pixels/emote.d.ts +6 -0
  120. package/src/pixels/emote.js +76 -0
  121. package/src/pixels/index.d.ts +7 -0
  122. package/src/pixels/index.js +8 -0
  123. package/src/sdf/fields.js +135 -0
  124. package/src/sdf/gap.js +42 -0
  125. package/src/sdf/index.d.ts +58 -0
  126. package/src/sdf/index.js +14 -0
  127. package/src/sdf/ops.js +102 -0
  128. package/src/sdf/trace.js +90 -0
  129. package/src/sdf/y2k.d.ts +12 -0
  130. package/src/sdf/y2k.js +80 -0
  131. package/src/skill/bundle.js +1 -1
  132. package/src/util/vec.d.ts +14 -0
  133. package/src/util/vec.js +61 -0
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Dev glyphs: the code symbols knocked out of a terminal window or a monitor (devices.js), each built from bars and
3
+ * polygons, never typeset. Every glyph is drawn about its centre (cx, cy), y down, at scale k (k = 1 is about 160–200
4
+ * tall, sized for devWindow()'s body), with strokes t thick: keep t at 40 or more so the glyph survives at 32 px.
5
+ * From the Logomarks tools (devglyphs.mjs, batches 175, 199).
6
+ */
7
+ import { U, D, I, poly, rect, rr, bar, stroke, fillet, sample } from '../geometry/index.js';
8
+
9
+ /** Maps points drawn about the origin to (cx, cy) at scale k. */
10
+ const at = (cx, cy, k) => (pts) => pts.map(([x, y]) => [cx + x * k, cy + y * k]);
11
+ /** A rectangle drawn about the origin, mapped like at(). */
12
+ const box = (cx, cy, k, x, y, w, h) => rect(cx + x * k, cy + y * k, w * k, h * k);
13
+ /** A chevron pointing right (dir 1) or left (dir −1): its arms `w` across and `h` tall, mitred at the tip. */
14
+ const chev = (P, x, y, w, h, t, dir = 1) => stroke(P([[x - (dir * w) / 2, y - h / 2], [x + (dir * w) / 2, y], [x - (dir * w) / 2, y + h / 2]]), t, { chunk: 8 });
15
+
16
+ /**
17
+ * The prompt >_ (a terminal window's).
18
+ *
19
+ * @param {number} cx The glyph's centre, x.
20
+ * @param {number} cy The glyph's centre, y.
21
+ * @param {number} [k=1] The scale.
22
+ * @param {number} [t=44] The stroke.
23
+ * @returns {import('../geometry/types.js').Shape} The glyph.
24
+ */
25
+ export const prompt = (cx, cy, k = 1, t = 44) => {
26
+ const P = at(cx, cy, k);
27
+ return U(stroke(P([[-115, -70], [-45, -10], [-115, 50]]), t, { chunk: 8 }), box(cx, cy, k, -5, 30, 120, 40));
28
+ };
29
+
30
+ /**
31
+ * The tag </> (a code screen's).
32
+ *
33
+ * @param {number} cx The glyph's centre, x.
34
+ * @param {number} cy The glyph's centre, y.
35
+ * @param {number} [k=1] The scale.
36
+ * @param {number} [t=42] The stroke.
37
+ * @returns {import('../geometry/types.js').Shape} The glyph.
38
+ */
39
+ export const code = (cx, cy, k = 1, t = 42) => {
40
+ const P = at(cx, cy, k);
41
+ return U(stroke(P([[-70, -55], [-140, 0], [-70, 55]]), t, { chunk: 8 }), stroke(P([[70, -55], [140, 0], [70, 55]]), t, { chunk: 8 }), bar(...P([[28, -72], [-28, 72]]), t - 6));
42
+ };
43
+
44
+ /** One curly brace's outline, the stem 40 thick with its point out to the left (−x) and its arms to the right: the point's
45
+ * inner notch is set so the slanted run keeps the stem's thickness. */
46
+ const BRACE = [[56, -98], [-20, -98], [-20, -40], [-56, 0], [-20, 40], [-20, 98], [56, 98], [56, 58], [20, 58], [20, 24.4], [-2, 0], [20, -24.4], [20, -58], [56, -58]];
47
+
48
+ /**
49
+ * Curly braces { }: angular, each with a point at its middle, their stems `apart` either side of the middle.
50
+ *
51
+ * @param {number} cx The glyph's centre, x.
52
+ * @param {number} cy The glyph's centre, y.
53
+ * @param {number} [k=1] The scale.
54
+ * @param {number} [apart=90] How far each stem sits from the middle.
55
+ * @returns {import('../geometry/types.js').Shape} The glyph.
56
+ */
57
+ export const braces = (cx, cy, k = 1, apart = 90) => {
58
+ const P = at(cx, cy, k);
59
+ return U(poly(P(BRACE.map(([x, y]) => [x - apart, y]))), poly(P(BRACE.map(([x, y]) => [apart - x, y]).reverse())));
60
+ };
61
+
62
+ /**
63
+ * The hash #, its uprights leaning a little.
64
+ *
65
+ * @param {number} cx The glyph's centre, x.
66
+ * @param {number} cy The glyph's centre, y.
67
+ * @param {number} [k=1] The scale.
68
+ * @param {number} [t=40] The stroke.
69
+ * @returns {import('../geometry/types.js').Shape} The glyph.
70
+ */
71
+ export const hash = (cx, cy, k = 1, t = 40) => {
72
+ const P = at(cx, cy, k);
73
+ return U(bar(...P([[-26, -92], [-54, 92]]), t), bar(...P([[54, -92], [26, 92]]), t), ...[-38, 38].map((y) => box(cx, cy, k, -100, y - t / 2 / k, 200, t / k)));
74
+ };
75
+
76
+ /**
77
+ * The dollar $: an angular S (three bars joined at alternate ends) with the stem through it standing proud top and bottom.
78
+ *
79
+ * @param {number} cx The glyph's centre, x.
80
+ * @param {number} cy The glyph's centre, y.
81
+ * @param {number} [k=1] The scale.
82
+ * @param {number} [t=36] The stroke.
83
+ * @returns {import('../geometry/types.js').Shape} The glyph.
84
+ */
85
+ export const dollar = (cx, cy, k = 1, t = 36) => {
86
+ const P = at(cx, cy, k), s = 70;
87
+ return U(stroke(P(fillet([[58, -s], [-52, -s], [-52, 0], [52, 0], [52, s], [-58, s]], [0, 16, 16, 16, 16, 0])), t, { chunk: 12 }), box(cx, cy, k, -17, -s - 34, 34, 2 * s + 68));
88
+ };
89
+
90
+ /**
91
+ * The underscore cursor _, w long.
92
+ *
93
+ * @param {number} cx The glyph's centre, x.
94
+ * @param {number} cy The glyph's centre, y.
95
+ * @param {number} [k=1] The scale.
96
+ * @param {number} [w=120] Its length.
97
+ * @param {number} [t=40] The stroke.
98
+ * @returns {import('../geometry/types.js').Polygon} The glyph.
99
+ */
100
+ export const under = (cx, cy, k = 1, w = 120, t = 40) => box(cx, cy, k, -w / 2, -t / 2 / k, w, t / k);
101
+
102
+ /**
103
+ * The tilde ~ as one wave, w across.
104
+ *
105
+ * @param {number} cx The glyph's centre, x.
106
+ * @param {number} cy The glyph's centre, y.
107
+ * @param {number} [k=1] The scale.
108
+ * @param {number} [t=40] The stroke.
109
+ * @param {number} [w=130] Its width.
110
+ * @param {number} [a=22] The wave's amplitude.
111
+ * @returns {import('../geometry/types.js').Shape} The glyph.
112
+ */
113
+ export const tilde = (cx, cy, k = 1, t = 40, w = 130, a = 22) => stroke(at(cx, cy, k)(sample((u) => [-w / 2 + w * u, -a * Math.sin(2 * Math.PI * u)], 0, 1, 40)), t, { chunk: 8 });
114
+
115
+ /**
116
+ * A slash / from bottom left to top right, h tall and leaning `lean` across.
117
+ *
118
+ * @param {number} cx The glyph's centre, x.
119
+ * @param {number} cy The glyph's centre, y.
120
+ * @param {number} [k=1] The scale.
121
+ * @param {number} [t=40] The stroke.
122
+ * @param {number} [h=180] Its height.
123
+ * @param {number} [lean=70] How far it leans across.
124
+ * @returns {import('../geometry/types.js').Polygon} The glyph.
125
+ */
126
+ export const slash = (cx, cy, k = 1, t = 40, h = 180, lean = 70) => bar(...at(cx, cy, k)([[lean / 2, -h / 2], [-lean / 2, h / 2]]), t);
127
+
128
+ /**
129
+ * The fat arrow =>: two bars and a chevron.
130
+ *
131
+ * @param {number} cx The glyph's centre, x.
132
+ * @param {number} cy The glyph's centre, y.
133
+ * @param {number} [k=1] The scale.
134
+ * @param {number} [t=36] The stroke.
135
+ * @returns {import('../geometry/types.js').Shape} The glyph.
136
+ */
137
+ export const fatArrow = (cx, cy, k = 1, t = 36) => {
138
+ const P = at(cx, cy, k);
139
+ return U(box(cx, cy, k, -120, -36 - t / 2 / k, 120, t / k), box(cx, cy, k, -120, 36 - t / 2 / k, 120, t / k), chev(P, 70, 0, 70, 160, t + 6));
140
+ };
141
+
142
+ /**
143
+ * Not equal !=: a bang (a bar over a square dot) and an equals sign.
144
+ *
145
+ * @param {number} cx The glyph's centre, x.
146
+ * @param {number} cy The glyph's centre, y.
147
+ * @param {number} [k=1] The scale.
148
+ * @param {number} [t=40] The stroke.
149
+ * @returns {import('../geometry/types.js').Shape} The glyph.
150
+ */
151
+ export const notEqual = (cx, cy, k = 1, t = 40) => U(box(cx, cy, k, -110, -84, t / k, 110), box(cx, cy, k, -110, 50, t / k, t / k),
152
+ ...[-30, 30].map((y) => box(cx, cy, k, -30, y - t / 2 / k, 140, t / k)));
153
+
154
+ /**
155
+ * Binary 01: a zero as a rounded ring and a one as a stem with its flag.
156
+ *
157
+ * @param {number} cx The glyph's centre, x.
158
+ * @param {number} cy The glyph's centre, y.
159
+ * @param {number} [k=1] The scale.
160
+ * @param {number} [t=40] The stroke.
161
+ * @returns {import('../geometry/types.js').Shape} The glyph.
162
+ */
163
+ export const binary = (cx, cy, k = 1, t = 40) => {
164
+ const x0 = cx - 140 * k, y0 = cy - 100 * k, w = 120 * k, h = 200 * k;
165
+ return U(D(rr(x0, y0, w, h, 54 * k), rr(x0 + t, y0 + t, w - 2 * t, h - 2 * t, Math.max(8, 54 * k - t))), box(cx, cy, k, 60, -100, 40, 200),
166
+ glyphPoly(cx, cy, k, [[60, -100], [60, -56], [24, -32], [24, -76]]));
167
+ };
168
+
169
+ /**
170
+ * Lambda λ: the long stroke from a flag at the top left down to the right, the short leg off its middle to the bottom
171
+ * left; the ends cut level.
172
+ *
173
+ * @param {number} cx The glyph's centre, x.
174
+ * @param {number} cy The glyph's centre, y.
175
+ * @param {number} [k=1] The scale.
176
+ * @param {number} [t=42] The stroke.
177
+ * @returns {import('../geometry/types.js').Shape} The glyph.
178
+ */
179
+ export const lambda = (cx, cy, k = 1, t = 42) => {
180
+ const P = at(cx, cy, k);
181
+ return I(U(stroke(P([[-78, -90], [-40, -90], [62, 120]]), t, { chunk: 8 }), bar(...P([[14, 8], [-66, 120]]), t)), box(cx, cy, k, -200, -120, 400, 210));
182
+ };
183
+
184
+ /**
185
+ * A diff + −.
186
+ *
187
+ * @param {number} cx The glyph's centre, x.
188
+ * @param {number} cy The glyph's centre, y.
189
+ * @param {number} [k=1] The scale.
190
+ * @param {number} [t=40] The stroke.
191
+ * @returns {import('../geometry/types.js').Shape} The glyph.
192
+ */
193
+ export const diff = (cx, cy, k = 1, t = 40) => U(box(cx, cy, k, -150, -t / 2 / k, 130, t / k), box(cx, cy, k, -85 - t / 2 / k, -65, t / k, 130), box(cx, cy, k, 30, -t / 2 / k, 120, t / k));
194
+
195
+ /**
196
+ * A tick ✓.
197
+ *
198
+ * @param {number} cx The glyph's centre, x.
199
+ * @param {number} cy The glyph's centre, y.
200
+ * @param {number} [k=1] The scale.
201
+ * @param {number} [t=44] The stroke.
202
+ * @returns {import('../geometry/types.js').Shape} The glyph.
203
+ */
204
+ export const tick = (cx, cy, k = 1, t = 44) => stroke(at(cx, cy, k)([[-80, 0], [-30, 50], [70, -60]]), t, { chunk: 8 });
205
+
206
+ /**
207
+ * Two slashes //, a comment.
208
+ *
209
+ * @param {number} cx The glyph's centre, x.
210
+ * @param {number} cy The glyph's centre, y.
211
+ * @param {number} [k=1] The scale.
212
+ * @param {number} [t=40] The stroke.
213
+ * @returns {import('../geometry/types.js').Shape} The glyph.
214
+ */
215
+ export const comment = (cx, cy, k = 1, t = 40) => U(slash(cx - 45 * k, cy, k, t), slash(cx + 45 * k, cy, k, t));
216
+
217
+ /**
218
+ * A polygon in glyph units mapped like the other glyphs (for a one-off).
219
+ *
220
+ * @param {number} cx The glyph's centre, x.
221
+ * @param {number} cy The glyph's centre, y.
222
+ * @param {number} k The scale.
223
+ * @param {readonly (readonly number[])[]} pts The points, about the origin.
224
+ * @returns {import('../geometry/types.js').Polygon} The polygon.
225
+ */
226
+ export const glyphPoly = (cx, cy, k, pts) => poly(at(cx, cy, k)(pts));
@@ -0,0 +1,31 @@
1
+ import type { Polygon, Shape } from '../geometry/types.js';
2
+
3
+ /** A device's size: W × H, corners r. */
4
+ export interface DeviceSize {
5
+ W: number;
6
+ H: number;
7
+ r: number;
8
+ }
9
+
10
+ /** The house phone: 244 × 448, corners 52. */
11
+ export const PHONE: DeviceSize;
12
+ /** A device's body: a rounded slab centred on the origin. */
13
+ export function slab(o?: DeviceSize): Polygon;
14
+ /** The screen inside a slab, inset at the sides and ends. */
15
+ export function screen(o?: DeviceSize, side?: number, top?: number, bot?: number): Polygon;
16
+ /** A slab with its screen parted off by the gap. */
17
+ export function windowed(g: number, o?: DeviceSize, side?: number, top?: number, bot?: number): Shape;
18
+ /** A terminal window: [title strip, body], parted by the gap. */
19
+ export function devWindow(g: number, W?: number, H?: number, bar?: number, r?: number): Polygon[];
20
+ /** The middle of devWindow()'s body (y). */
21
+ export function bodyMid(g: number, H?: number, bar?: number): number;
22
+ /** A monitor's stand under y = 0: [neck, foot]. */
23
+ export function standParts(g: number): Polygon[];
24
+ /** A laptop's deck: a shallow trapezoid at y under a lid W wide. */
25
+ export function laptopDeck(W: number, y: number, deck?: number, dh?: number): Polygon;
26
+ /** A VR headset's strap seen front on. */
27
+ export function strapBand(): Shape;
28
+ /** A VR headset's visor with its nose notch. */
29
+ export function visorSlab(): Shape;
30
+ /** A VR headset: the visor over its strap, parted by the gap. */
31
+ export function headset(g: number): Shape;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Devices: a phone's slab and its screen parted off by the gap, terminal windows, a monitor's stand, a laptop's deck and a
3
+ * VR headset. Every part is drawn about the origin (y down); a part that parts anything takes the gap g, so exact() keeps
4
+ * it 22 once fitted. From the Logomarks tools (deviceparts.mjs, batches 174–175, 188).
5
+ */
6
+ import { U, D, poly, ellipse, rr, rect, roundPoly, grown, over } from '../geometry/index.js';
7
+
8
+ /**
9
+ * The house phone: a slab W × H about the origin, corners r. Taller and slimmer than a card, rounder than a door.
10
+ *
11
+ * @type {{ W: number, H: number, r: number }}
12
+ */
13
+ export const PHONE = { W: 244, H: 448, r: 52 };
14
+
15
+ /**
16
+ * A device's body: a rounded slab W × H centred on the origin, corners r.
17
+ *
18
+ * @param {{ W: number, H: number, r: number }} [o=PHONE] Its size and corner radius.
19
+ * @returns {import('../geometry/types.js').Polygon} The slab.
20
+ */
21
+ export const slab = ({ W, H, r } = PHONE) => rr(-W / 2, -H / 2, W, H, r);
22
+
23
+ /**
24
+ * The screen inside a slab: inset `side` at the sides and `top` / `bot` at the ends, its corners following the body's.
25
+ *
26
+ * @param {{ W: number, H: number, r: number }} [o=PHONE] The slab.
27
+ * @param {number} [side=30] The inset at the sides.
28
+ * @param {number} [top=52] The inset at the top.
29
+ * @param {number} [bot=52] The inset at the bottom.
30
+ * @returns {import('../geometry/types.js').Polygon} The screen.
31
+ */
32
+ export const screen = ({ W, H, r } = PHONE, side = 30, top = 52, bot = 52) => rr(-W / 2 + side, -H / 2 + top, W - 2 * side, H - top - bot, Math.max(8, r - side + 6));
33
+
34
+ /**
35
+ * A slab with its screen parted off by the gap: the body a frame (`side` thick at the sides, `top` / `bot` at the ends;
36
+ * keep every side 26 or more so the frame never thins to a hairline at 32 px), the screen a solid panel floating in it.
37
+ *
38
+ * @param {number} g The gap.
39
+ * @param {{ W: number, H: number, r: number }} [o=PHONE] The slab.
40
+ * @param {number} [side=28] The frame at the sides.
41
+ * @param {number} [top=34] The frame at the top.
42
+ * @param {number} [bot=34] The frame at the bottom.
43
+ * @returns {import('../geometry/types.js').Shape} The frame and the screen.
44
+ */
45
+ export const windowed = (g, o = PHONE, side = 28, top = 34, bot = 34) => { const s = screen(o, side + g, top + g, bot + g); return U(D(slab(o), grown(s, g)), s); };
46
+
47
+ /**
48
+ * A terminal window W × H about the origin, corners r: the title strip `bar` tall parted off the body by the gap, no
49
+ * dots. Knock a dev glyph out of the body (its middle is bodyMid()).
50
+ *
51
+ * @param {number} g The gap.
52
+ * @param {number} [W=448] The width.
53
+ * @param {number} [H=340] The height.
54
+ * @param {number} [bar=60] The title strip's height.
55
+ * @param {number} [r=30] The corner radius.
56
+ * @returns {import('../geometry/types.js').Polygon[]} [title, body].
57
+ */
58
+ export const devWindow = (g, W = 448, H = 340, bar = 60, r = 30) => {
59
+ const y0 = -H / 2;
60
+ return [rr(-W / 2, y0, W, bar, [r, r, 0, 0]), rr(-W / 2, y0 + bar + g, W, H - bar - g, [0, 0, r, r])];
61
+ };
62
+
63
+ /**
64
+ * The middle of devWindow()'s body, for placing its glyph.
65
+ *
66
+ * @param {number} g The gap.
67
+ * @param {number} [H=340] The window's height.
68
+ * @param {number} [bar=60] Its title strip's height.
69
+ * @returns {number} The body's middle, y.
70
+ */
71
+ export const bodyMid = (g, H = 340, bar = 60) => -H / 2 + bar + g + (H - bar - g) / 2;
72
+
73
+ /**
74
+ * A monitor's stand under a screen whose foot edge is y = 0: the neck parted off below it by the gap and the foot parted
75
+ * off the neck. Union them with the screen.
76
+ *
77
+ * @param {number} g The gap.
78
+ * @returns {import('../geometry/types.js').Polygon[]} [neck, foot].
79
+ */
80
+ export const standParts = (g) => [rect(-36, g, 72, 64), rr(-130, 64 + 2 * g, 260, 40, 14)];
81
+
82
+ /**
83
+ * A laptop's deck: a shallow trapezoid at y, under a lid W wide, `deck` wide at its foot and `dh` deep.
84
+ *
85
+ * @param {number} W The lid's width.
86
+ * @param {number} y The deck's top.
87
+ * @param {number} [deck=448] Its width at the foot.
88
+ * @param {number} [dh=46] Its depth.
89
+ * @returns {import('../geometry/types.js').Polygon} The deck.
90
+ */
91
+ export const laptopDeck = (W, y, deck = 448, dh = 46) => roundPoly([[-W / 2 - 6, y], [W / 2 + 6, y], [deck / 2, y + dh], [-deck / 2, y + dh]], [6, 6, 14, 14]);
92
+
93
+ /**
94
+ * A VR headset's strap seen front on: an elliptical band round the origin (outer 224 × 150, 40 wide at the sides), its
95
+ * middle 10 above the origin.
96
+ *
97
+ * @returns {import('../geometry/types.js').Shape} The band.
98
+ */
99
+ export const strapBand = () => D(ellipse(0, -10, 224, 150), ellipse(0, -10, 184, 112));
100
+
101
+ /**
102
+ * A VR headset's visor: a rounded slab 380 × 190 (corners 70) about the origin, the nose notch cut up into its lower edge.
103
+ *
104
+ * @returns {import('../geometry/types.js').Shape} The visor.
105
+ */
106
+ export const visorSlab = () => D(rr(-190, -90, 380, 190, 70), poly([[-50, 100], [50, 100], [30, 50], [-30, 50]]));
107
+
108
+ /**
109
+ * A VR headset front on: the visor laid over its strap and parted from it by the gap.
110
+ *
111
+ * @param {number} g The gap.
112
+ * @returns {import('../geometry/types.js').Shape} The headset.
113
+ */
114
+ export const headset = (g) => over(strapBand(), visorSlab(), g);
@@ -0,0 +1,94 @@
1
+ import type { Geom, Polygon, Shape } from '../geometry/types.js';
2
+
3
+ /** A face's frame (frame()): eye radius, mouth and shut-eye strokes, and where the eyes sit. */
4
+ export interface FaceFrame {
5
+ /** The eye radius. */
6
+ e: number;
7
+ /** The mouth stroke. */
8
+ w: number;
9
+ /** The shut eyes' stroke. */
10
+ aw: number;
11
+ /** The eyes' height. */
12
+ ey: number;
13
+ /** The left and right eye centres, x. */
14
+ x1: number;
15
+ x2: number;
16
+ /** The eyes' middle, x. */
17
+ cx: number;
18
+ }
19
+
20
+ /** Headphones' options for headphones(). */
21
+ export interface HeadphoneOptions {
22
+ rx: number;
23
+ ry?: number;
24
+ cx?: number;
25
+ cy?: number;
26
+ bw?: number;
27
+ cw?: number;
28
+ ch?: number;
29
+ top?: number;
30
+ foot?: number;
31
+ a0?: number;
32
+ a1?: number;
33
+ }
34
+
35
+ /** An open arc as a round-capped stroke (degrees, 0 = right, 90 = down). */
36
+ export function arc(cx: number, cy: number, r: number, a0: number, a1: number, w: number): Shape;
37
+ /** A round-capped stroke along a smooth curve through pts. */
38
+ export function limb(pts: readonly (readonly number[])[], w: number): Shape;
39
+ /** A half-disc hole, flat side up at y (a grin). */
40
+ export function grinHole(x: number, y: number, r: number): Shape;
41
+ /** A face's frame for radius R, its features snapped to the gap. */
42
+ export function frame(R: number, g: number): FaceFrame;
43
+ /** The comma smile under the right eye. */
44
+ export function hook(R: number, g: number, f: FaceFrame): Shape;
45
+ /** Where shut eyes' centres sit, x. */
46
+ export function arcXs(f: FaceFrame, g: number): number[];
47
+ /** ^ : a closed, happy eye. */
48
+ export function happyEye(x: number, y: number, f: FaceFrame): Shape;
49
+ /** ∪ : a closed, sleeping eye. */
50
+ export function shutEye(x: number, y: number, f: FaceFrame): Shape;
51
+ /** Glance: two dots and the comma smile. */
52
+ export function glance(R: number, g: number): Geom[];
53
+ /** Laugh: both eyes shut happy over the wide mouth. */
54
+ export function laugh(R: number, g: number): Shape[];
55
+ /** A five-point star, point up. */
56
+ export function star(x: number, y: number, r: number, k?: number): Polygon;
57
+ /** Kiss: shut happy eyes over a puckered 3. */
58
+ export function kiss(R: number, g: number): Shape[];
59
+ /** Starstruck: two stars for eyes over the wide mouth. */
60
+ export function starstruck(R: number, g: number): Geom[];
61
+ /** Hmm: a raised brow and a short flat mouth. */
62
+ export function hmm(R: number, g: number): Geom[];
63
+ /** Zipped: two dots over a zip. */
64
+ export function zipped(R: number, g: number): Polygon[];
65
+ /** Dizzy: spiral eyes and a wavy mouth. */
66
+ export function dizzy(R: number, g: number): Shape[];
67
+ /** A mascot's stick limbs (30). */
68
+ export const LIMB: number;
69
+ /** Two dot eyes parted by the gap. */
70
+ export function eyes(g: number, x: number, y: number, e?: number): Polygon[];
71
+ /** Two stick legs under a body. */
72
+ export function legs(x: number, y: number, d?: number, L?: number): Shape[];
73
+ /** A waving arm and a hanging arm from shoulders at (±x, y). */
74
+ export function arms(x: number, y: number): Shape[];
75
+ /** A body with two dot eyes knocked out. */
76
+ export function eyed(body: Geom, g: number, x: number, y: number, e?: number): Shape;
77
+ /** A waving arm from the shoulder, out to side s. */
78
+ export function waveArm(x: number, y: number, s?: number): Shape;
79
+ /** A hanging arm from the shoulder, out to side s. */
80
+ export function hang(x: number, y: number, s?: number): Shape;
81
+ /** A pointed leaf from its base at deg, L long and W wide. */
82
+ export function leaf(x: number, y: number, deg: number, L: number, W: number): Shape;
83
+ /** Headphones: a band over an ellipse and two cups. */
84
+ export function headphones(o: HeadphoneOptions): Shape;
85
+ /** ∪ : a shut, blissful eye. */
86
+ export function lid(x: number, y: number, e: number, w: number): Shape;
87
+ /** A focused eye, its top cut away on a slant. */
88
+ export function focusEye(x: number, y: number, e: number, s: number, deg?: number): Shape;
89
+ /** A nose: a rounded triangle point down. */
90
+ export function nose(x: number, y: number, w: number, h: number, r?: number): Polygon;
91
+ /** A mic boom ending in a capsule mic. */
92
+ export function micBoom(pts: readonly (readonly number[])[], w: number, m?: number, mw?: number): Shape;
93
+ /** A head wearing headphones, `front` standing in front of the band. */
94
+ export function wearFront(head: Geom, P: Geom, g: number, front?: Geom): Shape;