@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.
- package/README.md +312 -3
- package/package.json +12 -3
- package/src/index.d.ts +5 -1
- package/src/index.mjs +20 -5
- package/src/runtime.mjs +6 -2
- package/vendor/README.md +7 -4
- package/vendor/keel-render/core-primitives.mjs +478 -0
- package/vendor/keel-render/effects-world.mjs +439 -0
- package/vendor/keel-render/indexed-render.mjs +516 -0
- package/vendor/keel-render/pixel-raster.mjs +512 -0
- package/vendor/keel-render/render-passes.mjs +530 -0
- package/vendor/keel-render/renderer-api.mjs +121 -0
- package/vendor/keel-render.mjs +1 -2268
- package/vendor/keel-theme/codec-runtime.mjs +549 -0
- package/vendor/keel-theme/collection-codecs.mjs +360 -0
- package/vendor/keel-theme/color-font.mjs +471 -0
- package/vendor/keel-theme/glyph-theme.mjs +529 -0
- package/vendor/keel-theme/icon-schema.mjs +540 -0
- package/vendor/keel-theme/scalar-codecs.mjs +535 -0
- package/vendor/keel-theme/schema-codec.mjs +515 -0
- package/vendor/keel-theme/schema-theme.mjs +533 -0
- package/vendor/keel-theme.mjs +1 -3571
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import './codec-runtime.mjs';
|
|
2
|
+
import {
|
|
3
|
+
SCREEN_IDS,
|
|
4
|
+
SERIFS,
|
|
5
|
+
SOFTS,
|
|
6
|
+
ZEROS,
|
|
7
|
+
toHex,
|
|
8
|
+
} from './color-font.mjs';
|
|
9
|
+
import {
|
|
10
|
+
CORNERS,
|
|
11
|
+
CULTURES,
|
|
12
|
+
FILLS,
|
|
13
|
+
FRAME_KINDS,
|
|
14
|
+
ICON_STYLES,
|
|
15
|
+
MOTIONS,
|
|
16
|
+
THEME_GENERATOR,
|
|
17
|
+
TONES,
|
|
18
|
+
themeOf,
|
|
19
|
+
} from './glyph-theme.mjs';
|
|
20
|
+
import {
|
|
21
|
+
ANCHORS,
|
|
22
|
+
DRIVING_KINDS,
|
|
23
|
+
DRIVING_VARIANTS,
|
|
24
|
+
SchemaError,
|
|
25
|
+
WIDGETS,
|
|
26
|
+
array,
|
|
27
|
+
bool,
|
|
28
|
+
bytes,
|
|
29
|
+
dyn,
|
|
30
|
+
enumOf,
|
|
31
|
+
fixed,
|
|
32
|
+
int,
|
|
33
|
+
num,
|
|
34
|
+
optional,
|
|
35
|
+
ref,
|
|
36
|
+
string,
|
|
37
|
+
struct,
|
|
38
|
+
uint,
|
|
39
|
+
varint,
|
|
40
|
+
varuint,
|
|
41
|
+
} from './icon-schema.mjs';
|
|
42
|
+
import {
|
|
43
|
+
alt,
|
|
44
|
+
extend,
|
|
45
|
+
named,
|
|
46
|
+
planes,
|
|
47
|
+
recursive,
|
|
48
|
+
seedText,
|
|
49
|
+
tuple,
|
|
50
|
+
union,
|
|
51
|
+
} from './schema-codec.mjs';
|
|
52
|
+
import {
|
|
53
|
+
K,
|
|
54
|
+
encodeRaw,
|
|
55
|
+
} from './codec-runtime.mjs';
|
|
56
|
+
|
|
57
|
+
function sha256(data) {
|
|
58
|
+
const h = new Uint32Array([1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]);
|
|
59
|
+
const len2 = data.length;
|
|
60
|
+
const padded = new Uint8Array(Math.ceil((len2 + 9) / 64) * 64);
|
|
61
|
+
padded.set(data);
|
|
62
|
+
padded[len2] = 128;
|
|
63
|
+
const view = new DataView(padded.buffer);
|
|
64
|
+
view.setUint32(padded.length - 8, Math.floor(len2 * 8 / 2 ** 32));
|
|
65
|
+
view.setUint32(padded.length - 4, len2 * 8 >>> 0);
|
|
66
|
+
const w = new Uint32Array(64);
|
|
67
|
+
for (let off = 0; off < padded.length; off += 64) {
|
|
68
|
+
for (let i = 0; i < 16; i += 1) w[i] = view.getUint32(off + i * 4);
|
|
69
|
+
for (let i = 16; i < 64; i += 1) {
|
|
70
|
+
const a2 = w[i - 15], b3 = w[i - 2];
|
|
71
|
+
const s0 = (a2 >>> 7 | a2 << 25) ^ (a2 >>> 18 | a2 << 14) ^ a2 >>> 3;
|
|
72
|
+
const s1 = (b3 >>> 17 | b3 << 15) ^ (b3 >>> 19 | b3 << 13) ^ b3 >>> 10;
|
|
73
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
|
|
74
|
+
}
|
|
75
|
+
let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4], f = h[5], g = h[6], hh = h[7];
|
|
76
|
+
for (let i = 0; i < 64; i += 1) {
|
|
77
|
+
const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
|
|
78
|
+
const ch = e & f ^ ~e & g;
|
|
79
|
+
const t1 = hh + S1 + ch + K[i] + w[i] >>> 0;
|
|
80
|
+
const S0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
|
|
81
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
82
|
+
const t2 = S0 + maj >>> 0;
|
|
83
|
+
hh = g;
|
|
84
|
+
g = f;
|
|
85
|
+
f = e;
|
|
86
|
+
e = d + t1 >>> 0;
|
|
87
|
+
d = c;
|
|
88
|
+
c = b;
|
|
89
|
+
b = a;
|
|
90
|
+
a = t1 + t2 >>> 0;
|
|
91
|
+
}
|
|
92
|
+
h[0] = h[0] + a >>> 0;
|
|
93
|
+
h[1] = h[1] + b >>> 0;
|
|
94
|
+
h[2] = h[2] + c >>> 0;
|
|
95
|
+
h[3] = h[3] + d >>> 0;
|
|
96
|
+
h[4] = h[4] + e >>> 0;
|
|
97
|
+
h[5] = h[5] + f >>> 0;
|
|
98
|
+
h[6] = h[6] + g >>> 0;
|
|
99
|
+
h[7] = h[7] + hh >>> 0;
|
|
100
|
+
}
|
|
101
|
+
const out = new Uint8Array(32);
|
|
102
|
+
const ov = new DataView(out.buffer);
|
|
103
|
+
for (let i = 0; i < 8; i += 1) ov.setUint32(i * 4, h[i]);
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
var toHex2 = (b) => {
|
|
107
|
+
let s = "";
|
|
108
|
+
for (let i = 0; i < b.length; i += 1) s += b[i].toString(16).padStart(2, "0");
|
|
109
|
+
return s;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// packages/codec/src/canonical.ts
|
|
113
|
+
var NAMES = "$names";
|
|
114
|
+
var field = (self) => struct({ name: ref(NAMES), type: self });
|
|
115
|
+
var SCHEMA_SCHEMA = named("keel/codec/schema", recursive((self) => union("kind", {
|
|
116
|
+
uint: struct({ bits: uint(6) }),
|
|
117
|
+
int: struct({ bits: uint(6) }),
|
|
118
|
+
bool: struct({}),
|
|
119
|
+
fixed: struct({ min: num(), max: num(), step: num(), off: enumOf(["round", "strict", "exact"]), k: int(7), delta: bool() }),
|
|
120
|
+
float: struct({ bits: enumOf([16, 32, 64]) }),
|
|
121
|
+
enum: struct({ values: array(alt([string(), num(), bool()])), capacity: varuint(), open: bool(), other: bool() }),
|
|
122
|
+
varuint: struct({ k: uint(5), group: uint(5) }),
|
|
123
|
+
varint: struct({ k: uint(5), group: uint(5) }),
|
|
124
|
+
string: struct({ max: varuint(), packHex: bool() }),
|
|
125
|
+
ref: struct({ table: ref(NAMES), packHex: bool() }),
|
|
126
|
+
bytes: struct({ length: varuint() }),
|
|
127
|
+
hex: struct({ bytes: varuint() }),
|
|
128
|
+
biguint: struct({ bits: uint(9) }),
|
|
129
|
+
array: struct({ of: self, length: varuint(), max: varuint() }),
|
|
130
|
+
optional: struct({ of: self }),
|
|
131
|
+
nullable: struct({ of: self }),
|
|
132
|
+
default: struct({ of: self, value: bytes() }),
|
|
133
|
+
struct: struct({ fields: array(field(self)), open: bool(), ext: array(array(field(self))) }),
|
|
134
|
+
tuple: struct({ items: array(self) }),
|
|
135
|
+
union: struct({ tag: ref(NAMES), variants: array(field(self)), capacity: varuint() }),
|
|
136
|
+
alt: struct({ of: array(self) }),
|
|
137
|
+
map: struct({ key: self, value: self, order: enumOf(["sorted", "kept"]) }),
|
|
138
|
+
delta: struct({ of: self, k: uint(5) }),
|
|
139
|
+
runs: struct({ of: self }),
|
|
140
|
+
planes: struct({ bits: uint(6) }),
|
|
141
|
+
dyn: struct({}),
|
|
142
|
+
num: struct({}),
|
|
143
|
+
const: struct({ value: dyn() }),
|
|
144
|
+
named: struct({ name: ref(NAMES), version: varuint(), doc: string(), of: self }),
|
|
145
|
+
rec: struct({ of: self }),
|
|
146
|
+
self: struct({ depth: varuint() }),
|
|
147
|
+
lz: struct({ of: self, min: uint(4) }),
|
|
148
|
+
grow: struct({ base: self, of: self })
|
|
149
|
+
}, { capacity: 64 })), { doc: "Every schema, as data: a document can carry its own." });
|
|
150
|
+
function toRecord(type, { docs = true } = {}) {
|
|
151
|
+
const walk = (n) => {
|
|
152
|
+
const fl = (fs) => fs.map((f) => ({ name: f.name, type: walk(f.type) }));
|
|
153
|
+
switch (n.kind) {
|
|
154
|
+
case "uint":
|
|
155
|
+
case "int":
|
|
156
|
+
case "biguint":
|
|
157
|
+
case "planes":
|
|
158
|
+
return { kind: n.kind, bits: n.bits };
|
|
159
|
+
case "bool":
|
|
160
|
+
case "dyn":
|
|
161
|
+
case "num":
|
|
162
|
+
return { kind: n.kind };
|
|
163
|
+
case "fixed":
|
|
164
|
+
return { kind: "fixed", min: n.min, max: n.max, step: n.step, off: n.off, k: n.k, delta: n.delta };
|
|
165
|
+
case "float":
|
|
166
|
+
return { kind: "float", bits: n.bits };
|
|
167
|
+
case "enum":
|
|
168
|
+
return { kind: "enum", values: [...n.values], capacity: n.capacity, open: n.open, other: n.other };
|
|
169
|
+
case "varuint":
|
|
170
|
+
case "varint":
|
|
171
|
+
return { kind: n.kind, k: n.k, group: n.group };
|
|
172
|
+
case "string":
|
|
173
|
+
return { kind: "string", max: n.max, packHex: n.packHex };
|
|
174
|
+
case "ref":
|
|
175
|
+
return { kind: "ref", table: n.table, packHex: n.packHex };
|
|
176
|
+
case "bytes":
|
|
177
|
+
return { kind: "bytes", length: n.length };
|
|
178
|
+
case "hex":
|
|
179
|
+
return { kind: "hex", bytes: n.bytes };
|
|
180
|
+
case "array":
|
|
181
|
+
return { kind: "array", of: walk(n.of), length: n.length, max: n.max };
|
|
182
|
+
case "optional":
|
|
183
|
+
case "nullable":
|
|
184
|
+
case "runs":
|
|
185
|
+
case "rec":
|
|
186
|
+
return { kind: n.kind, of: walk(n.of) };
|
|
187
|
+
case "default": {
|
|
188
|
+
let value;
|
|
189
|
+
try {
|
|
190
|
+
value = encodeRaw(n.of, n.value);
|
|
191
|
+
} catch (e) {
|
|
192
|
+
throw new SchemaError(`A default can't be written as data: ${e.message}`);
|
|
193
|
+
}
|
|
194
|
+
return { kind: "default", of: walk(n.of), value };
|
|
195
|
+
}
|
|
196
|
+
case "struct":
|
|
197
|
+
return { kind: "struct", fields: fl(n.fields), open: n.open, ext: n.ext.map((g) => fl(g)) };
|
|
198
|
+
case "tuple":
|
|
199
|
+
return { kind: "tuple", items: n.items.map((x) => walk(x)) };
|
|
200
|
+
case "union":
|
|
201
|
+
return { kind: "union", tag: n.tag, variants: fl(n.variants), capacity: n.capacity };
|
|
202
|
+
case "alt":
|
|
203
|
+
return { kind: "alt", of: n.of.map((x) => walk(x)) };
|
|
204
|
+
case "map":
|
|
205
|
+
return { kind: "map", key: walk(n.key), value: walk(n.value), order: n.order };
|
|
206
|
+
case "delta":
|
|
207
|
+
return { kind: "delta", of: walk(n.of), k: n.k };
|
|
208
|
+
case "const":
|
|
209
|
+
return { kind: "const", value: n.value };
|
|
210
|
+
case "named":
|
|
211
|
+
return { kind: "named", name: n.name, version: n.version, doc: docs ? n.doc : "", of: walk(n.of) };
|
|
212
|
+
case "self":
|
|
213
|
+
return { kind: "self", depth: n.depth };
|
|
214
|
+
case "lz":
|
|
215
|
+
return { kind: "lz", of: walk(n.of), min: n.min };
|
|
216
|
+
case "grow":
|
|
217
|
+
return { kind: "grow", base: walk(n.base), of: walk(n.of) };
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
return walk(type);
|
|
221
|
+
}
|
|
222
|
+
var encodeSchema = (type, opts = {}) => encodeRaw(SCHEMA_SCHEMA, toRecord(type, opts));
|
|
223
|
+
var IDS = /* @__PURE__ */ new WeakMap();
|
|
224
|
+
function schemaId(type) {
|
|
225
|
+
const have = IDS.get(type);
|
|
226
|
+
if (have) return have;
|
|
227
|
+
const id2 = toHex2(sha256(encodeSchema(type, { docs: false })));
|
|
228
|
+
IDS.set(type, id2);
|
|
229
|
+
return id2;
|
|
230
|
+
}
|
|
231
|
+
function schemaName(type) {
|
|
232
|
+
const n = type;
|
|
233
|
+
return n.kind === "named" ? { name: n.name, version: n.version, doc: n.doc } : null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// packages/codec/src/document.ts
|
|
237
|
+
function createRegistry() {
|
|
238
|
+
const byId = /* @__PURE__ */ new Map();
|
|
239
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
240
|
+
const reg = {
|
|
241
|
+
register(schema, alias) {
|
|
242
|
+
const id2 = schemaId(schema);
|
|
243
|
+
const named2 = schemaName(schema);
|
|
244
|
+
const have = byId.get(id2);
|
|
245
|
+
const aliases = new Set(have?.aliases ?? []);
|
|
246
|
+
if (alias) {
|
|
247
|
+
const other = byKey.get(alias);
|
|
248
|
+
if (other && other.id !== id2) throw new RangeError(`The name ${alias} is already schema ${other.short}.`);
|
|
249
|
+
aliases.add(alias);
|
|
250
|
+
}
|
|
251
|
+
const entry = { id: id2, short: id2.slice(0, 8), schema: have?.schema ?? schema, name: named2?.name ?? null, version: named2?.version ?? null, aliases: [...aliases] };
|
|
252
|
+
const clash = byKey.get(entry.short);
|
|
253
|
+
if (clash && clash.id !== id2) throw new RangeError(`Two schemas share the short id ${entry.short} (${clash.id} and ${id2}): a header can't tell them apart.`);
|
|
254
|
+
byId.set(id2, entry);
|
|
255
|
+
for (const k of [id2, entry.short, ...aliases, ...named2 ? [`${named2.name}@${named2.version}`] : []]) byKey.set(k, entry);
|
|
256
|
+
return id2;
|
|
257
|
+
},
|
|
258
|
+
get: (key) => byKey.get(key),
|
|
259
|
+
has: (key) => byKey.has(key),
|
|
260
|
+
list: () => [...byId.values()]
|
|
261
|
+
};
|
|
262
|
+
return reg;
|
|
263
|
+
}
|
|
264
|
+
var defaultRegistry = createRegistry();
|
|
265
|
+
function registerSchema(a, b) {
|
|
266
|
+
return typeof a === "string" ? defaultRegistry.register(b, a) : defaultRegistry.register(a);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// packages/ui/src/schemas.ts
|
|
270
|
+
var hue = fixed(0, 360, 0.01, { off: "exact" });
|
|
271
|
+
var share = fixed(0, 1, 0.01, { off: "exact" });
|
|
272
|
+
var FONT_PARAMS = struct({
|
|
273
|
+
width: share,
|
|
274
|
+
xHeight: share,
|
|
275
|
+
descender: share,
|
|
276
|
+
round: uint(2),
|
|
277
|
+
stroke: fixed(0, 0.5, 0.01, { off: "exact" }),
|
|
278
|
+
serif: enumOf(SERIFS, { capacity: 8 }),
|
|
279
|
+
slant: uint(1),
|
|
280
|
+
tracking: uint(2),
|
|
281
|
+
zero: enumOf(ZEROS, { capacity: 4 }),
|
|
282
|
+
ascend: uint(1),
|
|
283
|
+
soft: enumOf(SOFTS, { capacity: 4 }),
|
|
284
|
+
capWidth: uint(2)
|
|
285
|
+
});
|
|
286
|
+
var FONT_PINS = struct({
|
|
287
|
+
width: optional(share),
|
|
288
|
+
xHeight: optional(share),
|
|
289
|
+
descender: optional(share),
|
|
290
|
+
round: optional(uint(2)),
|
|
291
|
+
stroke: optional(fixed(0, 0.5, 0.01, { off: "exact" })),
|
|
292
|
+
serif: optional(enumOf(SERIFS, { capacity: 8 })),
|
|
293
|
+
slant: optional(uint(1)),
|
|
294
|
+
tracking: optional(uint(2)),
|
|
295
|
+
zero: optional(enumOf(ZEROS, { capacity: 4 })),
|
|
296
|
+
ascend: optional(uint(1)),
|
|
297
|
+
soft: optional(enumOf(SOFTS, { capacity: 4 })),
|
|
298
|
+
capWidth: optional(uint(2))
|
|
299
|
+
});
|
|
300
|
+
var THEME_PINS = struct({
|
|
301
|
+
tone: optional(enumOf(TONES, { capacity: 4 })),
|
|
302
|
+
hue: optional(hue),
|
|
303
|
+
accentHue: optional(hue),
|
|
304
|
+
chroma: optional(fixed(0, 0.5, 1e-3, { off: "exact" })),
|
|
305
|
+
corner: optional(enumOf(CORNERS, { capacity: 16 })),
|
|
306
|
+
radius: optional(uint(3)),
|
|
307
|
+
border: optional(uint(2)),
|
|
308
|
+
bevel: optional(uint(2)),
|
|
309
|
+
fill: optional(enumOf(FILLS, { capacity: 8 })),
|
|
310
|
+
screen: optional(enumOf(SCREEN_IDS, { capacity: 32 })),
|
|
311
|
+
shadow: optional(uint(2)),
|
|
312
|
+
glow: optional(uint(2)),
|
|
313
|
+
motion: optional(enumOf(MOTIONS, { capacity: 8 })),
|
|
314
|
+
body: optional(uint(5)),
|
|
315
|
+
caps: optional(bool()),
|
|
316
|
+
font: optional(FONT_PINS),
|
|
317
|
+
icon: optional(enumOf(ICON_STYLES, { capacity: 8 })),
|
|
318
|
+
unit: optional(uint(4)),
|
|
319
|
+
teams: optional(uint(5)),
|
|
320
|
+
teamHues: optional(array(hue, { max: 24 }))
|
|
321
|
+
}, { open: true });
|
|
322
|
+
var UI_THEME = named("keel/ui/theme", struct({
|
|
323
|
+
generator: ref("modules"),
|
|
324
|
+
seed: seedText,
|
|
325
|
+
culture: enumOf(CULTURES, { capacity: 16 }),
|
|
326
|
+
pins: THEME_PINS
|
|
327
|
+
}, { open: true }), { doc: "A UI theme as its recipe: generator@version, seed, culture and sparse pins." });
|
|
328
|
+
var GLYPH = struct({
|
|
329
|
+
code: fixed(0, 1114111, 1, { k: 2, delta: true }),
|
|
330
|
+
w: uint(6),
|
|
331
|
+
h: uint(6),
|
|
332
|
+
ox: varint(),
|
|
333
|
+
oy: varint(),
|
|
334
|
+
adv: uint(7),
|
|
335
|
+
bits: planes(1)
|
|
336
|
+
});
|
|
337
|
+
var UI_FONT = named("keel/ui/font", struct({
|
|
338
|
+
name: string(),
|
|
339
|
+
size: uint(6),
|
|
340
|
+
ascent: uint(7),
|
|
341
|
+
descent: uint(6),
|
|
342
|
+
lineHeight: uint(7),
|
|
343
|
+
source: enumOf(["generated", "ttf", "bmfont", "grid", "browser", "codec"], { capacity: 16 }),
|
|
344
|
+
glyphs: array(GLYPH),
|
|
345
|
+
kern: array(tuple([varuint({ k: 5 }), varuint({ k: 5 }), varint()]))
|
|
346
|
+
}, { open: true }), { doc: "A pixel font: metrics, 1-bit glyphs, kerning pairs." });
|
|
347
|
+
var UI_FONT_RECIPE = named("keel/ui/font-recipe", struct({
|
|
348
|
+
generator: ref("modules"),
|
|
349
|
+
params: FONT_PARAMS,
|
|
350
|
+
sizes: array(uint(6), { max: 31 })
|
|
351
|
+
}, { open: true }), { doc: "A generated pixel font as its recipe: the family's parameters and the sizes used." });
|
|
352
|
+
var size2 = alt([varint(), ref("sizes")]);
|
|
353
|
+
var u = () => optional(varuint());
|
|
354
|
+
function nodeSchema(driving) {
|
|
355
|
+
return recursive((self) => {
|
|
356
|
+
const legacy = extend(struct({
|
|
357
|
+
type: enumOf(driving ? WIDGETS : WIDGETS.slice(0, -1), { capacity: 64 }),
|
|
358
|
+
id: optional(ref("ids")),
|
|
359
|
+
anchor: optional(enumOf(ANCHORS, { capacity: 16 })),
|
|
360
|
+
x: optional(varint()),
|
|
361
|
+
y: optional(varint()),
|
|
362
|
+
w: optional(size2),
|
|
363
|
+
h: optional(size2),
|
|
364
|
+
minW: u(),
|
|
365
|
+
maxW: u(),
|
|
366
|
+
minH: u(),
|
|
367
|
+
maxH: u(),
|
|
368
|
+
dir: optional(enumOf(["free", "row", "col", "grid"], { capacity: 8 })),
|
|
369
|
+
gap: u(),
|
|
370
|
+
pad: u(),
|
|
371
|
+
align: optional(enumOf(["start", "center", "end", "stretch"], { capacity: 8 })),
|
|
372
|
+
justify: optional(enumOf(["start", "center", "end", "between"], { capacity: 8 })),
|
|
373
|
+
grow: u(),
|
|
374
|
+
cols: u(),
|
|
375
|
+
cellH: u(),
|
|
376
|
+
hidden: optional(bool()),
|
|
377
|
+
frame: optional(enumOf([...FRAME_KINDS, "none"], { capacity: 16 })),
|
|
378
|
+
mesh: optional(bool()),
|
|
379
|
+
tone: optional(ref("tones")),
|
|
380
|
+
font: optional(enumOf(["small", "body", "title", "display"], { capacity: 8 })),
|
|
381
|
+
textAlign: optional(enumOf(["left", "center", "right"], { capacity: 4 })),
|
|
382
|
+
wrap: optional(bool()),
|
|
383
|
+
maxLines: u(),
|
|
384
|
+
caps: optional(bool()),
|
|
385
|
+
shadow: optional(bool()),
|
|
386
|
+
text: optional(string()),
|
|
387
|
+
title: optional(string()),
|
|
388
|
+
icon: optional(ref("icons")),
|
|
389
|
+
iconSize: u(),
|
|
390
|
+
value: optional(num()),
|
|
391
|
+
max: optional(num()),
|
|
392
|
+
segments: u(),
|
|
393
|
+
trail: optional(num()),
|
|
394
|
+
hotkey: optional(ref("keys")),
|
|
395
|
+
cooldown: optional(fixed(0, 1, 1 / 64, { off: "exact" })),
|
|
396
|
+
count: u(),
|
|
397
|
+
disabled: optional(bool()),
|
|
398
|
+
active: optional(bool()),
|
|
399
|
+
primary: optional(bool()),
|
|
400
|
+
items: optional(array(string())),
|
|
401
|
+
selected: optional(varint()),
|
|
402
|
+
view: optional(tuple([fixed(0, 1, 1 / 1024, { off: "exact" }), fixed(0, 1, 1 / 1024, { off: "exact" }), fixed(0, 1, 1 / 1024, { off: "exact" }), fixed(0, 1, 1 / 1024, { off: "exact" })])),
|
|
403
|
+
tip: optional(string()),
|
|
404
|
+
focusable: optional(bool()),
|
|
405
|
+
action: optional(ref("actions")),
|
|
406
|
+
hole: optional(bool()),
|
|
407
|
+
children: optional(array(self))
|
|
408
|
+
}, { open: true }), {
|
|
409
|
+
// (Added later, as an extension group: old records read as before.)
|
|
410
|
+
tipDock: optional(bool()),
|
|
411
|
+
trim: optional(string()),
|
|
412
|
+
edge: optional(string()),
|
|
413
|
+
scrim: optional(enumOf(["solid", "dither"], { capacity: 4 })),
|
|
414
|
+
reflow: optional(bool()),
|
|
415
|
+
iconFill: optional(bool()),
|
|
416
|
+
hp: optional(num())
|
|
417
|
+
});
|
|
418
|
+
return driving ? extend(legacy, {
|
|
419
|
+
// A separate extension group keeps the original group's field bitmap unchanged.
|
|
420
|
+
drivingKind: optional(enumOf(DRIVING_KINDS, { capacity: 16 })),
|
|
421
|
+
drivingVariant: optional(enumOf(DRIVING_VARIANTS, { capacity: 4 })),
|
|
422
|
+
secondaryValue: optional(num()),
|
|
423
|
+
secondaryMax: optional(num()),
|
|
424
|
+
drivingRedline: optional(num())
|
|
425
|
+
}) : legacy;
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
var UI_NODE = nodeSchema(true);
|
|
429
|
+
var LEGACY_UI_NODE = nodeSchema(false);
|
|
430
|
+
var screenSchema = (root, version) => named("keel/ui/screen", struct({
|
|
431
|
+
screen: string(),
|
|
432
|
+
theme: optional(struct({ generator: ref("modules"), seed: seedText, culture: enumOf(CULTURES, { capacity: 16 }), pins: THEME_PINS }, { open: true })),
|
|
433
|
+
root
|
|
434
|
+
}, { open: true }), { version, doc: "A UI screen: its layout tree (and the theme recipe it was made with)." });
|
|
435
|
+
var UI_SCREEN_V1 = screenSchema(LEGACY_UI_NODE, 1);
|
|
436
|
+
var UI_SCREEN = screenSchema(UI_NODE, 2);
|
|
437
|
+
registerSchema(UI_SCREEN_V1);
|
|
438
|
+
registerSchema(UI_SCREEN);
|
|
439
|
+
|
|
440
|
+
// packages/ui/src/import/inflate.ts
|
|
441
|
+
function build(lengths, off, n) {
|
|
442
|
+
const counts = new Uint16Array(16);
|
|
443
|
+
const symbols = new Uint16Array(n);
|
|
444
|
+
for (let i = 0; i < n; i += 1) counts[lengths[off + i]] += 1;
|
|
445
|
+
counts[0] = 0;
|
|
446
|
+
const offs = new Uint16Array(16);
|
|
447
|
+
for (let i = 1; i < 16; i += 1) offs[i] = offs[i - 1] + counts[i - 1];
|
|
448
|
+
for (let i = 0; i < n; i += 1) {
|
|
449
|
+
const l = lengths[off + i];
|
|
450
|
+
if (l) symbols[offs[l]++] = i;
|
|
451
|
+
}
|
|
452
|
+
return { counts, symbols };
|
|
453
|
+
}
|
|
454
|
+
var FIXED = (() => {
|
|
455
|
+
const l = new Uint8Array(288);
|
|
456
|
+
l.fill(8, 0, 144);
|
|
457
|
+
l.fill(9, 144, 256);
|
|
458
|
+
l.fill(7, 256, 280);
|
|
459
|
+
l.fill(8, 280, 288);
|
|
460
|
+
const d = new Uint8Array(30).fill(5);
|
|
461
|
+
return { lit: build(l, 0, 288), dist: build(d, 0, 30) };
|
|
462
|
+
})();
|
|
463
|
+
|
|
464
|
+
// packages/ui/src/import/png.ts
|
|
465
|
+
var CRC = (() => {
|
|
466
|
+
const t = new Uint32Array(256);
|
|
467
|
+
for (let n = 0; n < 256; n += 1) {
|
|
468
|
+
let c = n;
|
|
469
|
+
for (let k = 0; k < 8; k += 1) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
470
|
+
t[n] = c >>> 0;
|
|
471
|
+
}
|
|
472
|
+
return t;
|
|
473
|
+
})();
|
|
474
|
+
|
|
475
|
+
// packages/ui/src/import/ttf.ts
|
|
476
|
+
var DEFAULT_CODES = [...Array.from({ length: 95 }, (_, i) => 32 + i), 8230, 8226, 215, 176, 8592, 8593, 8594, 8595];
|
|
477
|
+
|
|
478
|
+
// packages/react/src/design.ts
|
|
479
|
+
var DESIGN_LANGUAGE = Object.freeze({
|
|
480
|
+
id: "keel/react-design@1",
|
|
481
|
+
rules: ["Canonical KEEL generators and renderer own the scene.", "React binds state, lifecycle and accessible controls to the same world.", "Controls stay on their authored world surfaces; DOM counterparts retain their placement.", "Theme recipes provide semantic palette, spacing, type, frames and motion.", "Pixel scenes use integer scale and nearest-neighbour sampling.", "Project-owned fonts and assets retain provenance.", "Seed and frame clocks are explicit; captures export real source geometry and state."],
|
|
482
|
+
references: ["REDLINE: React host callbacks into the shared engine world.", "CRUCIBLE: React state controls a genuine KEEL pixel-rendered package room."],
|
|
483
|
+
limitations: ["DOM primitives expose semantic theme roles, not every pixel UI frame decoration.", "A CSS font must be supplied by the project; generated pixel glyphs are available through keel/ui.", "The React adapter is host tooling, not an onchain registered React runtime."]
|
|
484
|
+
});
|
|
485
|
+
function themeTokens(theme, scale2 = 2) {
|
|
486
|
+
if (!Number.isInteger(scale2) || scale2 < 1 || scale2 > 16) throw new RangeError("UI scale must be an integer from 1 to 16.");
|
|
487
|
+
const p = theme.palette, hex2 = (r, i) => toHex(r[i] ?? r[0] ?? 0);
|
|
488
|
+
const values = {
|
|
489
|
+
"--keel-surface": hex2(p.surface, 2),
|
|
490
|
+
"--keel-raised": hex2(p.surface, 3),
|
|
491
|
+
"--keel-ink": hex2(p.ink, 1),
|
|
492
|
+
"--keel-muted": hex2(p.ink, 0),
|
|
493
|
+
"--keel-accent": hex2(p.accent, 2),
|
|
494
|
+
"--keel-on-accent": toHex(p.onAccent),
|
|
495
|
+
"--keel-outline": toHex(p.outline),
|
|
496
|
+
"--keel-good": hex2(p.good, 2),
|
|
497
|
+
"--keel-warn": hex2(p.warn, 2),
|
|
498
|
+
"--keel-bad": hex2(p.bad, 2),
|
|
499
|
+
"--keel-px": `${scale2}px`,
|
|
500
|
+
"--keel-border": `${theme.frame.border * scale2}px`,
|
|
501
|
+
"--keel-pad": `${theme.space.pad * scale2}px`,
|
|
502
|
+
"--keel-gap": `${theme.space.gap * scale2}px`,
|
|
503
|
+
"--keel-body": `${theme.type.body * scale2}px`,
|
|
504
|
+
"--keel-motion": `${theme.motion.ms}ms`
|
|
505
|
+
};
|
|
506
|
+
for (const [name, ramp3] of Object.entries(p)) if (Array.isArray(ramp3) && typeof ramp3[0] === "number") ramp3.forEach((value, i) => {
|
|
507
|
+
values[`--keel-${name}-${i}`] = toHex(value);
|
|
508
|
+
});
|
|
509
|
+
return values;
|
|
510
|
+
}
|
|
511
|
+
function recipeTheme(input = {}) {
|
|
512
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) throw new TypeError("Theme recipe must be an object.");
|
|
513
|
+
const value = input;
|
|
514
|
+
for (const key of Object.keys(value)) if (!["seed", "culture", "pins"].includes(key)) throw new TypeError(`Unknown recipe field ${key}.`);
|
|
515
|
+
const seed = value.seed ?? "keel/react", culture = value.culture ?? "clean";
|
|
516
|
+
if (typeof seed !== "string" || seed.length > 256 || !CULTURES.includes(culture)) throw new TypeError("Invalid seed or culture.");
|
|
517
|
+
const pins = value.pins ?? {};
|
|
518
|
+
if (!pins || typeof pins !== "object" || Array.isArray(pins)) throw new TypeError("Pins must be an object.");
|
|
519
|
+
const allowed = { tone: ["dark", "light"], hue: [0, 360], accentHue: [0, 360], motion: ["snappy", "bouncy", "none"], corner: ["flat", "bevel", "inset", "notched", "rivets", "glow", "round"], body: [5, 16], unit: [1, 8], border: [1, 3], bevel: [0, 2], fill: ["solid", "dither", "gradient", "scan"], shadow: [0, 2], glow: [0, 2], caps: [true, false] };
|
|
520
|
+
for (const [key, pin] of Object.entries(pins)) {
|
|
521
|
+
const range = allowed[key];
|
|
522
|
+
if (!range) throw new TypeError(`Unsupported pin ${key}.`);
|
|
523
|
+
if (typeof range[0] === "number") {
|
|
524
|
+
if (typeof pin !== "number" || !Number.isFinite(pin) || pin < range[0] || pin > range[1] || !key.endsWith("Hue") && key !== "hue" && !Number.isInteger(pin)) throw new TypeError(`Invalid pin ${key}.`);
|
|
525
|
+
} else if (!range.includes(pin)) throw new TypeError(`Invalid pin ${key}.`);
|
|
526
|
+
}
|
|
527
|
+
return themeOf({ generator: THEME_GENERATOR, seed, culture, pins });
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export {
|
|
531
|
+
recipeTheme,
|
|
532
|
+
themeTokens,
|
|
533
|
+
};
|