@weft-js/plugin-surface-keel 0.1.1 → 0.1.3

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,529 @@
1
+ import './color-font.mjs';
2
+ import {
3
+ DEFAULT_FONT_RANGES,
4
+ SCREEN_IDS,
5
+ contrast,
6
+ createRoll,
7
+ deriveSeed,
8
+ ellipse,
9
+ fontParamsOf,
10
+ fromOklch,
11
+ stream,
12
+ } from './color-font.mjs';
13
+
14
+ var GLYPHS = [
15
+ // Capitals.
16
+ [65, "n", "M0,b L0,c~ L1,c~ L1,b M0,h L1,h"],
17
+ // (B, D, O, S and I are at least 5 wide -- wider than the figures in a narrow family's small sizes -- so none of
18
+ // them is ever an 8, a 0, a 5 or a 1.)
19
+ [66, "o", "M0,b L0,c L1,c^ L1,h^ L0,h M0,h L1,h^ L1,b^ L0,b"],
20
+ [67, "n", "M1,c L0,c~ L0,b~ L1,b"],
21
+ [68, "o", "M0,b L0,c L1,c^ L1,b^ L0,b"],
22
+ [69, "n", "M1,c L0,c L0,b L1,b M0,h L1-1,h"],
23
+ [70, "n", "M1,c L0,c L0,b M0,h L1-1,h"],
24
+ // (G: open at the top-right -- its top stops short of the corner and never turns down -- the right side rises from
25
+ // the baseline to the middle, and a bar comes in from it; never reaching the left side, so no B-like join. At least
26
+ // 5 px wide, room for the gap between that bar and the left stem.)
27
+ [71, "o", "M1-2,c L0,c^ L0,b^ L1,b^ L1,h L.5+1,h"],
28
+ [72, "n", "M0,b L0,c M1,b L1,c M0,h L1,h"],
29
+ [73, "I", "M0,c L1,c M.5,c L.5,b M0,b L1,b"],
30
+ [74, "n", "M1,c L1,b~ L0,b~ L0,.25"],
31
+ [75, "n", "M0,b L0,c M1,c L0+1,h L1,b"],
32
+ [76, "n", "M0,c L0,b L1,b"],
33
+ [77, "w", "M0,b L0,c L.5,.45 L1,c L1,b"],
34
+ [78, "n", "M0,b L0,c L1,b L1,c"],
35
+ [79, "o", "M0,b~ L0,c~ L1,c~ L1,b~ Z"],
36
+ [80, "n", "M0,b L0,c L1,c~ L1,h~ L0,h"],
37
+ [81, "n", "M0,b~ L0,c~ L1,c~ L1,b~ Z M.5,.3 L1,b-1"],
38
+ [82, "n", "M0,b L0,c L1,c~ L1,h^ L0,h M0+1,h L1,b"],
39
+ [83, "o", "M1,c L0,c^ L0,h^ L1,h^ L1,b^ L0,b"],
40
+ [84, "n", "M0,c L1,c M.5,c L.5,b"],
41
+ [85, "n", "M0,c L0,b~ L1,b~ L1,c"],
42
+ [86, "n", "M0,c L0,.3 L.5,b L1,.3 L1,c"],
43
+ [87, "w", "M0,c L0,b L.5,.55 L1,b L1,c"],
44
+ [88, "n", "M0,c L0,.75 L1,.25 L1,b M1,c L1,.75 L0,.25 L0,b"],
45
+ [89, "n", "M0,c L0,.75 L.5,h L1,.75 L1,c M.5,h L.5,b"],
46
+ [90, "n", "M0,c L1,c L1,.8 L0,.2 L0,b L1,b"],
47
+ // Lower case.
48
+ [97, "n", "M0+1,x L1,x~ L1,b M1,k L0,k~ L0,b~ L1,b"],
49
+ [98, "n", "M0,a L0,b L1,b~ L1,x~ L0,x"],
50
+ [99, "n", "M1,x L0,x~ L0,b~ L1,b"],
51
+ [100, "n", "M1,a L1,b L0,b~ L0,x~ L1,x"],
52
+ [101, "n", "M0,k L1,k L1,x~ L0,x~ L0,b~ L1-1,b"],
53
+ [102, "s", "M1,a L.5,a~ L.5,b M0,x L1-1,x"],
54
+ [103, "n", "M1,b L0,b~ L0,x~ L1,x L1,d~ L0,d"],
55
+ [104, "n", "M0,a L0,b M0,x L1,x~ L1,b"],
56
+ [105, "i", "M0,b L0,s M0,c"],
57
+ [106, "t", "M1,s L1,d~ L0,d M1,c"],
58
+ [107, "n", "M0,a L0,b M1,x L0+1,k L1,b"],
59
+ [108, "i", "M0,a L0,b"],
60
+ [109, "w", "M0,b L0,x L1,x~ L1,b M.5,x L.5,b"],
61
+ [110, "n", "M0,b L0,x L1,x~ L1,b"],
62
+ [111, "n", "M0,b~ L0,x~ L1,x~ L1,b~ Z"],
63
+ [112, "n", "M0,d L0,x L1,x~ L1,b~ L0,b"],
64
+ [113, "n", "M1,d L1,x L0,x~ L0,b~ L1,b"],
65
+ [114, "t", "M0,b L0,x L1,x"],
66
+ [115, "n", "M1,x L0,x~ L0,.6x L1,.4x L1,b~ L0,b"],
67
+ // (t: a crossbar through the stem at the x-height, both sides; the stem only a little above it -- well under l's
68
+ // ascender -- and a foot turned right, always cut, square fonts too: never an l.)
69
+ [116, "s", "M.5,t L.5,b^ L1,b M0,x L1,x"],
70
+ [117, "n", "M0,x L0,b~ L1,b L1,x"],
71
+ [118, "n", "M0,x L0,.4x L.5,b L1,.4x L1,x"],
72
+ [119, "w", "M0,x L0,b L.5,k L1,b L1,x"],
73
+ [120, "n", "M0,x L1,b M1,x L0,b"],
74
+ [121, "n", "M0,x L0,b~ L1,b M1,x L1,d~ L0,d"],
75
+ [122, "n", "M0,x L1,x L0,b L1,b"],
76
+ // Figures (tabular: all one width).
77
+ // (Figures: 0 narrower than its cell where there's room -- an oval, never an O; 8 two stacked loops, the upper one
78
+ // narrower, pinched at the waist -- never a flat-sided B; 1 a long flag and a foot; 5 a flat top over a bowl.)
79
+ [48, "d", "M0+i,b^ L0+i,c^ L1-i,c^ L1-i,b^ Z"],
80
+ [49, "d", "M0,c-2 L0,c-1 L.5,c L.5,b M0,b L1,b"],
81
+ [50, "d", "M0,c L1,c~ L1,h~ L0,h~ L0,b L1,b"],
82
+ [51, "d", "M0,c L1,c^ L1,h^ L.5,h M.5,h L1,h^ L1,b^ L0,b"],
83
+ [52, "d", "M0,c L0,h L1,h M1,c L1,b"],
84
+ [53, "d", "M1,c L0,c L0,.7 L1,.7~ L1,b~ L0,b"],
85
+ [54, "d", "M1,c L0,c~ L0,b~ L1,b~ L1,h~ L0,h"],
86
+ [55, "d", "M0,c L1,c L1,.75 L.5,.35 L.5,b"],
87
+ [56, "d", "M0+i,h L0+i,c^ L1-i,c^ L1-i,h Z M0+i,h L0,h-1 L0,b^ L1,b^ L1,h-1 L1-i,h"],
88
+ [57, "d", "M.5,b L1,b~ L1,c~ L0,c~ L0,h~ L1,h"],
89
+ // Punctuation and symbols.
90
+ [33, "i", "M0,c L0,b+2 M0,b"],
91
+ [34, "s", "M0,c L0,c-1 M1,c L1,c-1"],
92
+ [35, "w", "M.25,c L.25,b M.75,c L.75,b M0,.7 L1,.7 M0,.3 L1,.3"],
93
+ [36, "n", "M1,c-1 L0,c-1~ L0,h~ L1,h~ L1,b+1~ L0,b+1 M.5,c L.5,b"],
94
+ [37, "n", "M0,c M1,c L0,b M1,b"],
95
+ [38, "n", "M1,b L0,.55 L0,c~ L1-1,c~ L1-1,.7 L0,.3 L0,b~ L1-1,b L1,.3"],
96
+ [39, "i", "M0,c L0,c-1"],
97
+ [40, "t", "M1,c L0,c-1 L0,b+1 L1,b"],
98
+ [41, "t", "M0,c L1,c-1 L1,b+1 L0,b"],
99
+ [42, "n", "M0,.75 L1,.25 M1,.75 L0,.25 M.5,.85 L.5,.15"],
100
+ // (+: at least 5 wide, its arms as long as the room allows each way -- a cross, never a t without its foot.)
101
+ [43, "o", "M0,h L1,h M.5,h+r L.5,h-r"],
102
+ [44, "t", "M1,b L0,b-1"],
103
+ [45, "s", "M0,h L1,h"],
104
+ [46, "i", "M0,b"],
105
+ [47, "n", "M1,c L0,b"],
106
+ [58, "i", "M0,b M0,.75x"],
107
+ [59, "t", "M1,.75x M1,b L0,b-1"],
108
+ [60, "s", "M1,c-1 L0,h L1,b+1"],
109
+ [61, "s", "M0,.65 L1,.65 M0,.35 L1,.35"],
110
+ [62, "s", "M0,c-1 L1,h L0,b+1"],
111
+ [63, "n", "M0,c L1,c~ L1,h~ L.5,h L.5,b+2 M.5,b"],
112
+ [64, "w", "M1,.3 L1,c~ L0,c~ L0,b~ L1,b M.75,.3 L.35,.3 L.35,.7 L.75,.7 L.75,.3"],
113
+ [91, "t", "M1,c L0,c L0,b L1,b"],
114
+ [92, "n", "M0,c L1,b"],
115
+ [93, "t", "M0,c L1,c L1,b L0,b"],
116
+ [94, "s", "M0,.7 L.5,c L1,.7"],
117
+ [95, "n", "M0,b-1 L1,b-1"],
118
+ [96, "t", "M0,c L1,c-1"],
119
+ [123, "s", "M1,c L.5,c~ L.5,h+1 L0,h L.5,h-1 L.5,b~ L1,b"],
120
+ [124, "i", "M0,c L0,b-1"],
121
+ [125, "s", "M0,c L.5,c~ L.5,h+1 L1,h L.5,h-1 L.5,b~ L0,b"],
122
+ [126, "w", "M0,h L.25,h+1 L.5,h L.75,h-1 L1,h"],
123
+ // The UI's own: ellipsis, bullet, multiply, divide, degree, arrows, triangles, squares, tick, heart, star.
124
+ [8230, "w", "M0,b M.5,b M1,b"],
125
+ [8226, "s", "FM0,h-1 L1,h-1 L1,h+1 L0,h+1 Z"],
126
+ [215, "s", "M0,.7 L1,.3 M0,.3 L1,.7"],
127
+ [247, "s", "M0,h L1,h M.5,h+2 M.5,h-2"],
128
+ [176, "t", "M0,c L1,c L1,c-1 L0,c-1 Z"],
129
+ [8592, "w", "M0,h L1,h M0+2,h+2 L0,h L0+2,h-2"],
130
+ [8594, "w", "M0,h L1,h M1-2,h+2 L1,h L1-2,h-2"],
131
+ [8593, "n", "M.5,c L.5,b M0,c-1 L.5,c L1,c-1"],
132
+ [8595, "n", "M.5,c L.5,b M0,b+1 L.5,b L1,b+1"],
133
+ [9650, "n", "FM0,.15 L.5,.85 L1,.15 Z"],
134
+ [9660, "n", "FM0,.85 L.5,.15 L1,.85 Z"],
135
+ [9664, "n", "FM1,.9 L0,h L1,.1 Z"],
136
+ [9654, "n", "FM0,.9 L1,h L0,.1 Z"],
137
+ [9632, "n", "FM0,.8 L1,.8 L1,.2 L0,.2 Z"],
138
+ [9633, "n", "M0,.8 L1,.8 L1,.2 L0,.2 Z"],
139
+ [10003, "n", "M0,h L.4,b+1 L1,c-1"],
140
+ [9829, "n", "FM.5,.05 L0,.55 L0,.78 L.25,.95 L.5,.78 L.75,.95 L1,.78 L1,.55 Z"],
141
+ [9733, "w", "FM.5,1 L.62,.62 L1,.62 L.69,.38 L.81,0 L.5,.24 L.19,0 L.31,.38 L0,.62 L.38,.62 Z"]
142
+ ];
143
+ var GENERATED_CODES = [32, ...GLYPHS.map(([c]) => c)].sort((a, b) => a - b);
144
+
145
+ // packages/ui/src/theme.ts
146
+ var THEME_GENERATOR = "keel/ui/theme@1";
147
+ var CULTURES = ["industrial", "organic", "crystalline", "arcane", "brutal", "clean"];
148
+ var CORNERS = ["flat", "bevel", "inset", "notched", "rivets", "glow", "round"];
149
+ var FILLS = ["solid", "dither", "gradient", "scan"];
150
+ var MOTIONS = ["snappy", "bouncy", "none"];
151
+ var ICON_STYLES = ["solid", "outline", "duotone"];
152
+ var TONES = ["dark", "light"];
153
+ var F = DEFAULT_FONT_RANGES;
154
+ var CULTURE_SPECS = {
155
+ industrial: {
156
+ surfaceHue: [[[200, 245], 4], [[30, 60], 1]],
157
+ surfaceChroma: [0.012, 0.035],
158
+ surfaceL: [0.27, 0.35],
159
+ accentHue: [[[55, 88], 4], [[25, 45], 2]],
160
+ accentChroma: [0.13, 0.18],
161
+ shift: 8,
162
+ light: 0,
163
+ corners: [["rivets", 4], ["bevel", 3], ["notched", 1]],
164
+ border: [2, 2, 3],
165
+ bevel: [1, 1, 2],
166
+ inner: 0.5,
167
+ fills: [["dither", 3], ["scan", 2], ["gradient", 2], ["solid", 1]],
168
+ screens: ["diagonal", "lines", "bayer4", "hatch"],
169
+ shadow: [1, 1, 2],
170
+ font: { ...F, width: [0.62, 0.85], xHeight: [0.66, 0.78], round: [0, 0, 1], stroke: [0.1, 0.2], serif: [["none", 5], ["slab", 1]], slant: 0 },
171
+ caps: 0.75,
172
+ body: [7, 7, 8],
173
+ ratio: [1.25, 1.5],
174
+ unit: [2, 3],
175
+ motion: [["snappy", 5], ["none", 1]],
176
+ icon: [["solid", 3], ["duotone", 2]],
177
+ iconStroke: [1, 2]
178
+ },
179
+ organic: {
180
+ surfaceHue: [[[95, 155], 4], [[35, 70], 2]],
181
+ surfaceChroma: [0.03, 0.065],
182
+ surfaceL: [0.25, 0.33],
183
+ accentHue: [[[65, 105], 3], [[130, 170], 2], [[330, 360], 1]],
184
+ accentChroma: [0.12, 0.17],
185
+ shift: 14,
186
+ light: 0.05,
187
+ corners: [["round", 6], ["glow", 1], ["inset", 1]],
188
+ border: [1, 2],
189
+ bevel: [0, 1],
190
+ inner: 0.3,
191
+ fills: [["dither", 3], ["gradient", 2], ["solid", 1]],
192
+ screens: ["stipple", "halftone", "weave", "coarseDot"],
193
+ shadow: [0, 1, 1],
194
+ font: { ...F, width: [0.7, 0.86], round: [2, 2, 3], stroke: [0.08, 0.15], serif: [["none", 3], ["foot", 2]], slant: 0.05, tracking: [1] },
195
+ caps: 0.2,
196
+ body: [8, 8, 9],
197
+ ratio: [1.3, 1.5],
198
+ unit: [3, 4],
199
+ motion: [["bouncy", 5], ["snappy", 2]],
200
+ icon: [["duotone", 3], ["solid", 2]],
201
+ iconStroke: [1]
202
+ },
203
+ crystalline: {
204
+ surfaceHue: [[[190, 235], 3], [[260, 305], 2]],
205
+ surfaceChroma: [0.035, 0.075],
206
+ surfaceL: [0.2, 0.28],
207
+ accentHue: [[[165, 205], 3], [[290, 330], 2]],
208
+ accentChroma: [0.13, 0.19],
209
+ shift: -12,
210
+ light: 0.05,
211
+ corners: [["notched", 6], ["glow", 2], ["bevel", 1]],
212
+ border: [1, 1, 2],
213
+ bevel: [1],
214
+ inner: 0.6,
215
+ fills: [["gradient", 3], ["dither", 2], ["solid", 1]],
216
+ screens: ["bayer4", "bayer8", "checker", "diagonal"],
217
+ shadow: [0, 1],
218
+ font: { ...F, width: [0.5, 0.66], round: [0], stroke: [0.08, 0.14], serif: [["none", 1]], slant: 0.35 },
219
+ caps: 0.6,
220
+ body: [7, 8],
221
+ ratio: [1.3, 1.6],
222
+ unit: [2, 3],
223
+ motion: [["snappy", 5], ["bouncy", 1]],
224
+ icon: [["outline", 3], ["duotone", 2]],
225
+ iconStroke: [1]
226
+ },
227
+ arcane: {
228
+ surfaceHue: [[[270, 325], 4], [[230, 265], 2]],
229
+ surfaceChroma: [0.045, 0.085],
230
+ surfaceL: [0.2, 0.28],
231
+ accentHue: [[[70, 98], 4], [[160, 195], 2]],
232
+ accentChroma: [0.12, 0.17],
233
+ shift: 16,
234
+ light: 0,
235
+ corners: [["glow", 4], ["round", 2], ["notched", 1], ["inset", 1]],
236
+ border: [1, 2],
237
+ bevel: [0, 1],
238
+ inner: 0.7,
239
+ fills: [["dither", 3], ["gradient", 2]],
240
+ screens: ["halftone", "weave", "hatch", "coarseDot"],
241
+ shadow: [1],
242
+ font: { ...F, round: [1, 2], serif: [["slab", 4], ["foot", 2], ["none", 1]], slant: 0.2 },
243
+ caps: 0.5,
244
+ body: [7, 8],
245
+ ratio: [1.35, 1.6],
246
+ unit: [3, 4],
247
+ motion: [["bouncy", 4], ["snappy", 2]],
248
+ icon: [["duotone", 4], ["outline", 1]],
249
+ iconStroke: [1]
250
+ },
251
+ brutal: {
252
+ surfaceHue: [[[0, 35], 3], [[340, 360], 2], [[90, 120], 1]],
253
+ surfaceChroma: [8e-3, 0.04],
254
+ surfaceL: [0.16, 0.24],
255
+ accentHue: [[[20, 40], 4], [[92, 112], 2]],
256
+ accentChroma: [0.16, 0.22],
257
+ shift: 4,
258
+ light: 0,
259
+ corners: [["flat", 6], ["inset", 2], ["notched", 1]],
260
+ border: [2, 3, 3],
261
+ bevel: [0],
262
+ inner: 0.2,
263
+ fills: [["solid", 3], ["scan", 2], ["dither", 1]],
264
+ screens: ["chunky", "hatch", "lines"],
265
+ shadow: [2, 2, 1],
266
+ font: { ...F, width: [0.7, 0.9], stroke: [0.16, 0.25], round: [0], serif: [["none", 5], ["slab", 2]], slant: 0.1, tracking: [1] },
267
+ caps: 0.9,
268
+ body: [7, 8, 9],
269
+ ratio: [1.3, 1.7],
270
+ unit: [2, 3],
271
+ motion: [["none", 3], ["snappy", 3]],
272
+ icon: [["solid", 5]],
273
+ iconStroke: [2]
274
+ },
275
+ clean: {
276
+ surfaceHue: [[[215, 262], 3], [[175, 215], 2], [[0, 360], 1]],
277
+ surfaceChroma: [8e-3, 0.03],
278
+ surfaceL: [0.27, 0.36],
279
+ accentHue: [[[200, 262], 3], [[140, 180], 2], [[15, 45], 1]],
280
+ accentChroma: [0.11, 0.16],
281
+ shift: 3,
282
+ light: 0.2,
283
+ corners: [["round", 4], ["flat", 3], ["bevel", 1]],
284
+ border: [1],
285
+ bevel: [0, 1],
286
+ inner: 0.1,
287
+ fills: [["solid", 5], ["gradient", 2]],
288
+ screens: ["bayer4", "ign", "bayer8"],
289
+ shadow: [0, 1],
290
+ font: { ...F, width: [0.55, 0.7], round: [1], stroke: [0.08, 0.13], serif: [["none", 1]], slant: 0 },
291
+ caps: 0.15,
292
+ body: [7, 7, 8],
293
+ ratio: [1.25, 1.45],
294
+ unit: [3, 4],
295
+ motion: [["snappy", 5], ["bouncy", 1]],
296
+ icon: [["outline", 3], ["solid", 2]],
297
+ iconStroke: [1]
298
+ }
299
+ };
300
+ var wrapHue = (h) => (h % 360 + 360) % 360;
301
+ var r3 = (v) => Math.round(v * 1e3) / 1e3;
302
+ var pickRange = (S, ranges) => {
303
+ const [a, b] = S.weighted(ranges);
304
+ return S.between(a, b);
305
+ };
306
+ function ramp2(n, hue2, chroma, lo, hi, shift) {
307
+ const out = [];
308
+ for (let i = 0; i < n; i += 1) {
309
+ const t = n === 1 ? 0.5 : i / (n - 1);
310
+ const L = lo + (hi - lo) * t;
311
+ const C = chroma * (1 - 0.45 * Math.abs(t - 0.5) * 2 * (t > 0.5 ? 1 : 0.5));
312
+ out.push(fromOklch(L, C, wrapHue(hue2 + shift * (t - 0.5) * 2)));
313
+ }
314
+ return out;
315
+ }
316
+ function readable(L, chroma, hue2, on, min, dir) {
317
+ let c = fromOklch(L, chroma, hue2);
318
+ for (let step = 0; step < 60 && on.some((s) => contrast(c, s) < min); step += 1) {
319
+ L = Math.max(0, Math.min(1, L + dir * 0.012));
320
+ c = fromOklch(L, chroma * (step > 30 ? 0.5 : 1), hue2);
321
+ }
322
+ return c;
323
+ }
324
+ function recipeKey(r) {
325
+ const text = JSON.stringify([r.generator, r.seed, r.culture, sortPins(r.pins)]);
326
+ let h = 2166136261;
327
+ for (let i = 0; i < text.length; i += 1) h = Math.imul(h ^ text.charCodeAt(i), 16777619) >>> 0;
328
+ return `theme:${h.toString(16).padStart(8, "0")}`;
329
+ }
330
+ function sortPins(p) {
331
+ const o = {};
332
+ for (const k of Object.keys(p).sort()) {
333
+ const v = p[k];
334
+ if (v === void 0) continue;
335
+ o[k] = v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a < b ? -1 : 1)) : v;
336
+ }
337
+ return o;
338
+ }
339
+ function themeResult(recipe, tone, surface, ink, accent, semantic, team, outline, accentText, hue2, accentHue, frame, type, unit2, P, drawnIcon, iconStroke, kind, overshoot) {
340
+ return {
341
+ recipe,
342
+ culture: recipe.culture,
343
+ palette: {
344
+ tone,
345
+ surface,
346
+ ink,
347
+ accent,
348
+ good: semantic(145, 0.15),
349
+ warn: semantic(82, 0.15),
350
+ bad: semantic(27, 0.18),
351
+ team,
352
+ outline,
353
+ onAccent: accentText,
354
+ hues: { surface: r3(hue2), accent: r3(accentHue) }
355
+ },
356
+ frame,
357
+ type,
358
+ space: { unit: unit2, pad: unit2 + frame.border + (frame.bevel ? 1 : 0), gap: unit2 },
359
+ icon: { style: P.icon ?? drawnIcon, stroke: iconStroke },
360
+ motion: { kind, press: kind === "none" ? 0 : 1, ms: kind === "snappy" ? 90 : kind === "bouncy" ? 180 : 0, overshoot: kind === "bouncy" ? overshoot : 0 },
361
+ key: recipeKey(recipe)
362
+ };
363
+ }
364
+
365
+ function themeOf(recipe) {
366
+ if (recipe.generator !== THEME_GENERATOR) throw new RangeError(`This is ${THEME_GENERATOR}; the recipe names ${recipe.generator}.`);
367
+ const spec = CULTURE_SPECS[recipe.culture];
368
+ if (!spec) throw new RangeError(`"${recipe.culture}" isn't a culture (${CULTURES.join(", ")}).`);
369
+ const P = recipe.pins;
370
+ const S = (name) => stream(createRoll(deriveSeed(`${recipe.seed}/${recipe.culture}`, `ui/theme/${name}`)), 0);
371
+ const sp = S("palette");
372
+ const drawnTone = sp.chance(spec.light) ? "light" : "dark";
373
+ const drawnHue = pickRange(sp, spec.surfaceHue);
374
+ const drawnChroma = sp.between(spec.surfaceChroma[0], spec.surfaceChroma[1]);
375
+ const drawnL = sp.between(spec.surfaceL[0], spec.surfaceL[1]);
376
+ const drawnAccent = pickRange(sp, spec.accentHue);
377
+ const accentChroma = sp.between(spec.accentChroma[0], spec.accentChroma[1]);
378
+ const semanticNudge = sp.between(-8, 8);
379
+ const teamStart = sp.between(0, 360);
380
+ const tone = P.tone ?? drawnTone;
381
+ const hue2 = wrapHue(P.hue ?? drawnHue);
382
+ const chroma = P.chroma ?? drawnChroma;
383
+ const accentHue = wrapHue(P.accentHue ?? drawnAccent);
384
+ const shift = spec.shift;
385
+ const dark = tone === "dark";
386
+ const base = dark ? drawnL : 0.9 - (drawnL - 0.25) * 0.4;
387
+ const surface = dark ? ramp2(6, hue2, chroma, Math.max(0.06, base - 0.15), Math.min(0.72, base + 0.27), shift).map((c, i) => i === 2 ? fromOklch(base, chroma, hue2) : c) : ramp2(6, hue2, chroma * 0.8, 0.58, 0.99, shift).map((c, i) => i === 2 ? fromOklch(base, chroma * 0.6, hue2) : c);
388
+ const panels = [surface[1], surface[2], surface[3]];
389
+ const ink = dark ? [readable(0.74, 0.025, hue2, panels, 4.6, 1), readable(0.9, 0.02, hue2, panels, 5.5, 1), readable(0.97, 0.015, hue2, panels, 7, 1)] : [readable(0.46, 0.03, hue2, panels, 4.6, -1), readable(0.28, 0.03, hue2, panels, 6, -1), readable(0.16, 0.03, hue2, panels, 8, -1)];
390
+ const accent = ramp2(5, accentHue, accentChroma, 0.36, 0.9, shift * 0.6);
391
+ const semantic = (h, c) => ramp2(5, h + semanticNudge, c, 0.36, 0.9, shift * 0.4);
392
+ const teams = Math.max(1, Math.min(24, P.teams ?? 8));
393
+ const team = [];
394
+ for (let i = 0; i < teams; i += 1) {
395
+ const th = P.teamHues?.[i] ?? wrapHue(teamStart + i * 137.508);
396
+ const lift = teams > 12 && i % 2 ? 0.08 : 0;
397
+ team.push(ramp2(5, th, 0.16, 0.38 + lift, 0.9, 6));
398
+ }
399
+ const labels = [ink[2], surface[0], fromOklch(0.99, 0.01, accentHue), fromOklch(0.14, 0.02, accentHue)];
400
+ const accentText = labels.reduce((b, c) => contrast(c, accent[1]) > contrast(b, accent[1]) ? c : b);
401
+ const fr = S("frame");
402
+ const drawn = {
403
+ corner: fr.weighted(spec.corners),
404
+ border: fr.pick(spec.border),
405
+ bevel: fr.pick(spec.bevel),
406
+ inner: fr.chance(spec.inner),
407
+ fill: fr.weighted(spec.fills),
408
+ screen: fr.pick(spec.screens),
409
+ shadow: fr.pick(spec.shadow),
410
+ radius: fr.int(2, 4),
411
+ rivets: fr.pick([0, 12, 16, 24])
412
+ };
413
+ const corner = P.corner ?? drawn.corner;
414
+ const frame = {
415
+ corner,
416
+ radius: P.radius ?? (corner === "notched" ? Math.min(drawn.radius, 3) : drawn.radius),
417
+ border: Math.max(1, Math.min(3, P.border ?? drawn.border)),
418
+ bevel: P.bevel ?? (corner === "bevel" || corner === "rivets" ? Math.max(1, drawn.bevel) : drawn.bevel),
419
+ inner: drawn.inner,
420
+ shadow: P.shadow ?? drawn.shadow,
421
+ glow: P.glow ?? (corner === "glow" ? 2 : 0),
422
+ fill: P.fill ?? drawn.fill,
423
+ screen: P.screen && SCREEN_IDS.includes(P.screen) ? P.screen : drawn.screen,
424
+ rivets: corner === "rivets" ? drawn.rivets || 16 : 0
425
+ };
426
+ const outline = corner === "glow" ? accent[0] : dark ? surface[0] : fromOklch(0.3, chroma, hue2);
427
+ const ty = S("type");
428
+ const font = fontParamsOf(ty, spec.font, P.font);
429
+ const drawnBody = ty.pick(spec.body);
430
+ const ratio = ty.between(spec.ratio[0], spec.ratio[1]);
431
+ const drawnCaps = ty.chance(spec.caps);
432
+ const body = Math.max(5, Math.min(12, P.body ?? drawnBody));
433
+ const title = Math.min(16, Math.max(body + 2, Math.round(body * ratio)));
434
+ const type = { small: Math.max(5, body - 2), body, title, display: Math.min(16, Math.max(title + 2, Math.round(title * ratio))), font, caps: P.caps ?? drawnCaps };
435
+ const mo = S("motion");
436
+ const drawnUnit = mo.pick(spec.unit);
437
+ const drawnMotion = mo.weighted(spec.motion);
438
+ const drawnIcon = mo.weighted(spec.icon);
439
+ const iconStroke = mo.pick(spec.iconStroke);
440
+ const overshoot = r3(mo.between(0.15, 0.35));
441
+ const unit2 = P.unit ?? drawnUnit;
442
+ const kind = P.motion ?? drawnMotion;
443
+ return themeResult(recipe, tone, surface, ink, accent, semantic, team, outline, accentText, hue2, accentHue, frame, type, unit2, P, drawnIcon, iconStroke, kind, overshoot);
444
+ }
445
+
446
+ // packages/ui/src/frames.ts
447
+ var FRAME_KINDS = ["panel", "button", "inset", "tooltip", "badge", "tab", "header"];
448
+
449
+ // packages/ui/src/icons.ts
450
+ var poly = (...pts) => pts.flatMap(([x, y]) => [x, y]);
451
+ var rect = (x0, y0, x1, y1) => poly([x0, y0], [x1, y0], [x1, y1], [x0, y1]);
452
+ var disc = (cx, cy, r, ry = r) => ellipse(cx, cy, r, ry, 40);
453
+ function seg(x0, y0, x1, y1, w) {
454
+ const dx = x1 - x0, dy = y1 - y0, l = Math.hypot(dx, dy) || 1;
455
+ const nx = -dy / l * (w / 2), ny = dx / l * (w / 2);
456
+ return poly([x0 + nx, y0 + ny], [x1 + nx, y1 + ny], [x1 - nx, y1 - ny], [x0 - nx, y0 - ny]);
457
+ }
458
+ var strokes = (pts, w, closed = false) => {
459
+ const out = [];
460
+ const n = pts.length;
461
+ for (let i = 0; i < (closed ? n : n - 1); i += 1) {
462
+ const a = pts[i], b = pts[(i + 1) % n];
463
+ out.push(seg(a[0], a[1], b[0], b[1], w));
464
+ }
465
+ for (const p of pts) out.push(disc(p[0], p[1], w / 2));
466
+ return out;
467
+ };
468
+ function star(cx, cy, r0, r1, n, rot = -Math.PI / 2) {
469
+ const pts = [];
470
+ for (let i = 0; i < n * 2; i += 1) {
471
+ const a = rot + i * Math.PI / n;
472
+ const r = i % 2 ? r1 : r0;
473
+ pts.push([cx + Math.cos(a) * r, cy + Math.sin(a) * r]);
474
+ }
475
+ return poly(...pts);
476
+ }
477
+ function gear(cx, cy, r, teeth, depth) {
478
+ const pts = [];
479
+ const steps = teeth * 4;
480
+ for (let i = 0; i < steps; i += 1) {
481
+ const a = i / steps * Math.PI * 2;
482
+ const rr = i % 4 < 2 ? r : r - depth;
483
+ pts.push([cx + Math.cos(a) * rr, cy + Math.sin(a) * rr]);
484
+ }
485
+ return poly(...pts);
486
+ }
487
+ var arrowHead = (tipX, tipY, dirX, dirY, size3) => {
488
+ const l = Math.hypot(dirX, dirY) || 1, ux = dirX / l, uy = dirY / l;
489
+ return poly([tipX, tipY], [tipX - ux * size3 - uy * size3 * 0.8, tipY - uy * size3 + ux * size3 * 0.8], [tipX - ux * size3 + uy * size3 * 0.8, tipY - uy * size3 - ux * size3 * 0.8]);
490
+ };
491
+ var add2 = (...shape) => ({ shape });
492
+ var cut = (...shape) => ({ cut: true, shape });
493
+ var mirror = (ops) => ops.map((o) => ({ ...o, shape: o.shape.map((c) => c.map((v, i) => i % 2 ? v : 1 - v)) }));
494
+ function sword(S, w, flip) {
495
+ const len2 = S.between(0.62, 0.78);
496
+ const bw = w * S.between(1.2, 1.6);
497
+ const tip = [0.86, 0.14];
498
+ const hilt = [tip[0] - len2 * 0.7071, tip[1] + len2 * 0.7071];
499
+ const guard = S.between(0.14, 0.22);
500
+ const ops = [
501
+ add2(seg(hilt[0], hilt[1], tip[0] - 0.03, tip[1] + 0.03, bw), poly([tip[0], tip[1]], [tip[0] - 0.12, tip[1] + 0.03], [tip[0] - 0.03, tip[1] + 0.12])),
502
+ add2(seg(hilt[0] - guard * 0.7071, hilt[1] - guard * 0.7071, hilt[0] + guard * 0.7071, hilt[1] + guard * 0.7071, w * 1.3)),
503
+ add2(seg(hilt[0], hilt[1], hilt[0] - 0.16, hilt[1] + 0.16, w * 1.1), disc(hilt[0] - 0.18, hilt[1] + 0.18, w * 0.9))
504
+ ];
505
+ return flip ? mirror(ops) : ops;
506
+ }
507
+
508
+ export {
509
+ CORNERS,
510
+ CULTURES,
511
+ FILLS,
512
+ FRAME_KINDS,
513
+ ICON_STYLES,
514
+ MOTIONS,
515
+ THEME_GENERATOR,
516
+ TONES,
517
+ add2,
518
+ arrowHead,
519
+ cut,
520
+ disc,
521
+ gear,
522
+ poly,
523
+ rect,
524
+ seg,
525
+ star,
526
+ strokes,
527
+ sword,
528
+ themeOf,
529
+ };