@ideare/kit 0.0.0-stage → 0.1.0-next.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -2
  3. package/THIRD_PARTY.md +52 -0
  4. package/dist/brand/schema.d.ts +265 -0
  5. package/dist/brand/schema.js +271 -0
  6. package/dist/check/copy.d.ts +27 -0
  7. package/dist/check/copy.js +139 -0
  8. package/dist/check/index.d.ts +54 -0
  9. package/dist/check/index.js +492 -0
  10. package/dist/color/contrast.d.ts +41 -0
  11. package/dist/color/contrast.js +84 -0
  12. package/dist/color/palette.d.ts +27 -0
  13. package/dist/color/palette.js +114 -0
  14. package/dist/color/wcag.d.ts +22 -0
  15. package/dist/color/wcag.js +50 -0
  16. package/dist/draft/draft.d.ts +61 -0
  17. package/dist/draft/draft.js +383 -0
  18. package/dist/editor/history.d.ts +78 -0
  19. package/dist/editor/history.js +221 -0
  20. package/dist/editor/operations.d.ts +112 -0
  21. package/dist/editor/operations.js +621 -0
  22. package/dist/files/docs.d.ts +49 -0
  23. package/dist/files/docs.js +392 -0
  24. package/dist/files/generate.d.ts +47 -0
  25. package/dist/files/generate.js +254 -0
  26. package/dist/files/png.d.ts +40 -0
  27. package/dist/files/png.js +168 -0
  28. package/dist/files/raster.d.ts +14 -0
  29. package/dist/files/raster.js +0 -0
  30. package/dist/files/templates.d.ts +162 -0
  31. package/dist/files/templates.js +390 -0
  32. package/dist/files/tokens.d.ts +22 -0
  33. package/dist/files/tokens.js +204 -0
  34. package/dist/fonts/catalog.d.ts +3 -0
  35. package/dist/fonts/catalog.js +345 -0
  36. package/dist/fonts/ofl.d.ts +5 -0
  37. package/dist/fonts/ofl.js +5 -0
  38. package/dist/fonts/pick.d.ts +33 -0
  39. package/dist/fonts/pick.js +73 -0
  40. package/dist/imports/folder.d.ts +80 -0
  41. package/dist/imports/folder.js +124 -0
  42. package/dist/imports/unzip.d.ts +32 -0
  43. package/dist/imports/unzip.js +128 -0
  44. package/dist/index.d.ts +59 -0
  45. package/dist/index.js +34 -0
  46. package/dist/marks/draw.d.ts +48 -0
  47. package/dist/marks/draw.js +149 -0
  48. package/dist/marks/icons.data.d.ts +5 -0
  49. package/dist/marks/icons.data.js +600 -0
  50. package/dist/marks/svg.d.ts +46 -0
  51. package/dist/marks/svg.js +341 -0
  52. package/dist/node/index.d.ts +13 -0
  53. package/dist/node/index.js +41 -0
  54. package/dist/posts/pix.d.ts +19 -0
  55. package/dist/posts/pix.js +49 -0
  56. package/dist/posts/templates.d.ts +45 -0
  57. package/dist/posts/templates.js +868 -0
  58. package/dist/resvg/index.d.ts +2 -0
  59. package/dist/resvg/index.js +22 -0
  60. package/dist/scene/brand-art.d.ts +49 -0
  61. package/dist/scene/brand-art.js +154 -0
  62. package/dist/scene/frame.d.ts +89 -0
  63. package/dist/scene/frame.js +213 -0
  64. package/dist/scene/grain.d.ts +7 -0
  65. package/dist/scene/grain.js +7 -0
  66. package/dist/scene/qr.d.ts +10 -0
  67. package/dist/scene/qr.js +359 -0
  68. package/dist/scene/render.d.ts +76 -0
  69. package/dist/scene/render.js +557 -0
  70. package/dist/scene/schema.d.ts +271 -0
  71. package/dist/scene/schema.js +257 -0
  72. package/dist/sign.d.ts +47 -0
  73. package/dist/sign.js +88 -0
  74. package/dist/text/engine.d.ts +128 -0
  75. package/dist/text/engine.js +245 -0
  76. package/dist/text/fonts.d.ts +56 -0
  77. package/dist/text/fonts.js +65 -0
  78. package/dist/version.d.ts +2 -0
  79. package/dist/version.js +2 -0
  80. package/dist/wasm/index.d.ts +15 -0
  81. package/dist/wasm/index.js +46 -0
  82. package/package.json +78 -5
  83. package/schema/brand.v1.json +442 -0
@@ -0,0 +1,7 @@
1
+ /**
2
+ * A seeded 128 px noise tile (RGBA PNG, 26247 bytes) from the S1b render spike. Pages tile it with
3
+ * a userSpaceOnUse <pattern> for grain: 0% difference between resvg and Chrome, where
4
+ * feTurbulence differed on 10.8% of pixels (docs/spikes/render.md, rule 8).
5
+ */
6
+ export const GRAIN_TILE_SIZE = 128;
7
+ export const GRAIN_TILE_PNG_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAgAElEQVR4nE3dCdim5fzG8bsQM6hkC/nHWFJxo0xUShnLZELWUvasCZVQMVT2XSjGviWZJoQhS7ZEhhbbhEQ0hbIXivI/Ptcx347e43jnfeZ57vu6fst5nr/fdT/3Mq1YsWI+5JBD5p///OfzypUr53vc4x7za1/72vkhD3nI/KEPfWj+1a9+NR922GHzbrvtNl944YXzaaedNj/iEY+Yt9tuu/nII4+cP/3pT8/vf//75w022GBs97Of/Wy+6U1vOr/73e+eb3SjG80PetCD5k033XS+5z3vOX/ve9+bX/e61803vOEN57vf/e7z2rVr55e//OXzWWedNT/qUY+aX/SiF80LFy4c+7/1rW+d3/Oe98wPeMAD5uOPP35evHjx/PCHP3z+6le/Ov/yl7+cjz766Pk+97nPvHTp0nnZsmXzzW9+8/mTn/zkfPLJJ8+f/exn5z/96U/zrW51q/lvf/vb/IIXvGD+61//Ot/pTneat9hii/n617/+/MQnPnF+2cteNmxft27dfItb3GL+4he/OP/5z3+eH/rQh86f//znZz+vec1r5h/96EfzlltuOV9zzTXz29/+9vmPf/zj/MIXvnB+17veNT/+8Y8fdj760Y+ev/zlLw9b+ME3dlx99dXz7373u2HDm970pvH5bW972/mUU06Z99prrxGTSy65ZN58883nww8/fMx1xzvecf73v/89cvGFL3xhbLvjjjvOz33uc+dtttlmPuGEE8a8YvLhD394/u1vfzs/5jGPmb///e/Pz3jGM+ZFixbN559//vzkJz953nDDDUfMPvrRj86//vWv59///vdjv/e+973z8uXL50libnKTmwyHTfawhz1sJN8EEnW/+91vOPGOd7xj/u9//zsMkLy3ve1tw5lnPvOZIxjPe97zBhie9axnjX0vuuiiYdQrXvGKEWTOH3fccfP973//8f6ee+45ggZ05th2221HwATlDne4w/h74xvfeH7nO985DJaspz3tafPq1avnP/zhD/PZZ589H3TQQfNWW201QAq0wGdeCbjLXe4yf/CDHxzgsv/+++8/bPjPf/4zHAeitWvXDkBvvPHG82abbTZsOOqoo+ZVq1bN3/rWt4bf55xz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";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A QR code encoder: byte mode (UTF-8), versions 1 to 40, all four error correction levels, the
3
+ * mask chosen by the standard's penalty score. Ported from Project Nayuki's QR Code generator
4
+ * (MIT), trimmed to what a scene needs: a module matrix.
5
+ */
6
+ export type QrEcc = "L" | "M" | "Q" | "H";
7
+ /** The QR code for `text` as rows of modules (true is dark), without the quiet zone. */
8
+ export declare function qrMatrix(text: string, ecc?: QrEcc): boolean[][];
9
+ /** The dark modules as one path, `scale` px per module, offset by the quiet zone. */
10
+ export declare function qrPath(modules: boolean[][], scale: number, x0: number, y0: number): string;
@@ -0,0 +1,359 @@
1
+ /**
2
+ * A QR code encoder: byte mode (UTF-8), versions 1 to 40, all four error correction levels, the
3
+ * mask chosen by the standard's penalty score. Ported from Project Nayuki's QR Code generator
4
+ * (MIT), trimmed to what a scene needs: a module matrix.
5
+ */
6
+ const ORDINAL = { L: 0, M: 1, Q: 2, H: 3 };
7
+ const FORMAT_BITS = { L: 1, M: 0, Q: 3, H: 2 };
8
+ // prettier-ignore
9
+ const ECC_PER_BLOCK = [
10
+ [-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
11
+ [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28],
12
+ [-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
13
+ [-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
14
+ ];
15
+ // prettier-ignore
16
+ const BLOCKS = [
17
+ [-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25],
18
+ [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49],
19
+ [-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68],
20
+ [-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81],
21
+ ];
22
+ function table(rows, ecc, version) {
23
+ return rows[ORDINAL[ecc]]?.[version] ?? 0;
24
+ }
25
+ function rawDataModules(version) {
26
+ let result = (16 * version + 128) * version + 64;
27
+ if (version >= 2) {
28
+ const align = Math.floor(version / 7) + 2;
29
+ result -= (25 * align - 10) * align - 55;
30
+ if (version >= 7)
31
+ result -= 36;
32
+ }
33
+ return result;
34
+ }
35
+ function dataCodewords(version, ecc) {
36
+ return (Math.floor(rawDataModules(version) / 8) -
37
+ table(ECC_PER_BLOCK, ecc, version) * table(BLOCKS, ecc, version));
38
+ }
39
+ function gfMultiply(x, y) {
40
+ let z = 0;
41
+ for (let i = 7; i >= 0; i--) {
42
+ z = (z << 1) ^ ((z >>> 7) * 0x11d);
43
+ z ^= ((y >>> i) & 1) * x;
44
+ }
45
+ return z & 0xff;
46
+ }
47
+ function rsDivisor(degree) {
48
+ const result = new Array(degree).fill(0);
49
+ result[degree - 1] = 1;
50
+ let root = 1;
51
+ for (let i = 0; i < degree; i++) {
52
+ for (let j = 0; j < result.length; j++) {
53
+ result[j] = gfMultiply(result[j] ?? 0, root);
54
+ if (j + 1 < result.length)
55
+ result[j] = (result[j] ?? 0) ^ (result[j + 1] ?? 0);
56
+ }
57
+ root = gfMultiply(root, 0x02);
58
+ }
59
+ return result;
60
+ }
61
+ function rsRemainder(data, divisor) {
62
+ const result = divisor.map(() => 0);
63
+ for (const byte of data) {
64
+ const factor = byte ^ (result.shift() ?? 0);
65
+ result.push(0);
66
+ divisor.forEach((coefficient, index) => {
67
+ result[index] = (result[index] ?? 0) ^ gfMultiply(coefficient, factor);
68
+ });
69
+ }
70
+ return result;
71
+ }
72
+ const bit = (value, index) => ((value >>> index) & 1) !== 0;
73
+ /** The QR code for `text` as rows of modules (true is dark), without the quiet zone. */
74
+ export function qrMatrix(text, ecc = "M") {
75
+ const bytes = [...new TextEncoder().encode(text)];
76
+ let version = 1;
77
+ for (; version <= 40; version++) {
78
+ const countBits = version < 10 ? 8 : 16;
79
+ if (4 + countBits + bytes.length * 8 <= dataCodewords(version, ecc) * 8)
80
+ break;
81
+ }
82
+ if (version > 40)
83
+ throw new RangeError("That text is too long for a QR code.");
84
+ // The data bits: mode, count, bytes, terminator, padding.
85
+ const bits = [];
86
+ const push = (value, length) => {
87
+ for (let i = length - 1; i >= 0; i--)
88
+ bits.push((value >>> i) & 1);
89
+ };
90
+ push(0b0100, 4);
91
+ push(bytes.length, version < 10 ? 8 : 16);
92
+ for (const byte of bytes)
93
+ push(byte, 8);
94
+ const capacity = dataCodewords(version, ecc) * 8;
95
+ push(0, Math.min(4, capacity - bits.length));
96
+ push(0, (8 - (bits.length % 8)) % 8);
97
+ for (let pad = 0xec; bits.length < capacity; pad ^= 0xec ^ 0x11)
98
+ push(pad, 8);
99
+ const data = [];
100
+ for (let i = 0; i < bits.length; i += 8)
101
+ data.push(bits.slice(i, i + 8).reduce((acc, b) => (acc << 1) | b, 0));
102
+ // Error correction, split into blocks and interleaved.
103
+ const blockCount = table(BLOCKS, ecc, version);
104
+ const eccLength = table(ECC_PER_BLOCK, ecc, version);
105
+ const raw = Math.floor(rawDataModules(version) / 8);
106
+ const shortBlocks = blockCount - (raw % blockCount);
107
+ const shortLength = Math.floor(raw / blockCount);
108
+ const divisor = rsDivisor(eccLength);
109
+ const blocks = [];
110
+ for (let i = 0, k = 0; i < blockCount; i++) {
111
+ const chunk = data.slice(k, k + shortLength - eccLength + (i < shortBlocks ? 0 : 1));
112
+ k += chunk.length;
113
+ const remainder = rsRemainder(chunk, divisor);
114
+ if (i < shortBlocks)
115
+ chunk.push(0);
116
+ blocks.push(chunk.concat(remainder));
117
+ }
118
+ const codewords = [];
119
+ for (let i = 0; i < (blocks[0]?.length ?? 0); i++) {
120
+ blocks.forEach((block, j) => {
121
+ if (i !== shortLength - eccLength || j >= shortBlocks)
122
+ codewords.push(block[i] ?? 0);
123
+ });
124
+ }
125
+ const size = version * 4 + 17;
126
+ const modules = Array.from({ length: size }, () => new Array(size).fill(false));
127
+ const fixed = Array.from({ length: size }, () => new Array(size).fill(false));
128
+ const set = (x, y, dark) => {
129
+ const row = modules[y];
130
+ const fixedRow = fixed[y];
131
+ if (!row || !fixedRow)
132
+ return;
133
+ row[x] = dark;
134
+ fixedRow[x] = true;
135
+ };
136
+ for (let i = 0; i < size; i++) {
137
+ set(6, i, i % 2 === 0);
138
+ set(i, 6, i % 2 === 0);
139
+ }
140
+ const finder = (cx, cy) => {
141
+ for (let dy = -4; dy <= 4; dy++) {
142
+ for (let dx = -4; dx <= 4; dx++) {
143
+ const distance = Math.max(Math.abs(dx), Math.abs(dy));
144
+ const x = cx + dx;
145
+ const y = cy + dy;
146
+ if (x >= 0 && x < size && y >= 0 && y < size)
147
+ set(x, y, distance !== 2 && distance !== 4);
148
+ }
149
+ }
150
+ };
151
+ finder(3, 3);
152
+ finder(size - 4, 3);
153
+ finder(3, size - 4);
154
+ if (version > 1) {
155
+ const count = Math.floor(version / 7) + 2;
156
+ const step = Math.floor((version * 8 + count * 3 + 5) / (count * 4 - 4)) * 2;
157
+ const positions = [6];
158
+ for (let pos = size - 7; positions.length < count; pos -= step)
159
+ positions.splice(1, 0, pos);
160
+ positions.forEach((py, i) => {
161
+ positions.forEach((px, j) => {
162
+ const corner = (i === 0 && j === 0) ||
163
+ (i === 0 && j === count - 1) ||
164
+ (i === count - 1 && j === 0);
165
+ if (corner)
166
+ return;
167
+ for (let dy = -2; dy <= 2; dy++) {
168
+ for (let dx = -2; dx <= 2; dx++)
169
+ set(px + dx, py + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
170
+ }
171
+ });
172
+ });
173
+ }
174
+ const drawFormat = (mask) => {
175
+ const value = (FORMAT_BITS[ecc] << 3) | mask;
176
+ let rem = value;
177
+ for (let i = 0; i < 10; i++)
178
+ rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
179
+ const word = ((value << 10) | rem) ^ 0x5412;
180
+ for (let i = 0; i <= 5; i++)
181
+ set(8, i, bit(word, i));
182
+ set(8, 7, bit(word, 6));
183
+ set(8, 8, bit(word, 7));
184
+ set(7, 8, bit(word, 8));
185
+ for (let i = 9; i < 15; i++)
186
+ set(14 - i, 8, bit(word, i));
187
+ for (let i = 0; i < 8; i++)
188
+ set(size - 1 - i, 8, bit(word, i));
189
+ for (let i = 8; i < 15; i++)
190
+ set(8, size - 15 + i, bit(word, i));
191
+ set(8, size - 8, true);
192
+ };
193
+ drawFormat(0);
194
+ if (version >= 7) {
195
+ let rem = version;
196
+ for (let i = 0; i < 12; i++)
197
+ rem = (rem << 1) ^ ((rem >>> 11) * 0x1f25);
198
+ const word = (version << 12) | rem;
199
+ for (let i = 0; i < 18; i++) {
200
+ const a = size - 11 + (i % 3);
201
+ const b = Math.floor(i / 3);
202
+ set(a, b, bit(word, i));
203
+ set(b, a, bit(word, i));
204
+ }
205
+ }
206
+ // The codewords, in the zigzag the standard fixes.
207
+ let index = 0;
208
+ for (let right = size - 1; right >= 1; right -= 2) {
209
+ if (right === 6)
210
+ right = 5;
211
+ for (let vertical = 0; vertical < size; vertical++) {
212
+ for (let j = 0; j < 2; j++) {
213
+ const x = right - j;
214
+ const upward = ((right + 1) & 2) === 0;
215
+ const y = upward ? size - 1 - vertical : vertical;
216
+ const row = modules[y];
217
+ if (row && !fixed[y]?.[x] && index < codewords.length * 8) {
218
+ row[x] = bit(codewords[index >>> 3] ?? 0, 7 - (index & 7));
219
+ index++;
220
+ }
221
+ }
222
+ }
223
+ }
224
+ const masked = (mask, x, y) => {
225
+ switch (mask) {
226
+ case 0:
227
+ return (x + y) % 2 === 0;
228
+ case 1:
229
+ return y % 2 === 0;
230
+ case 2:
231
+ return x % 3 === 0;
232
+ case 3:
233
+ return (x + y) % 3 === 0;
234
+ case 4:
235
+ return (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
236
+ case 5:
237
+ return ((x * y) % 2) + ((x * y) % 3) === 0;
238
+ case 6:
239
+ return (((x * y) % 2) + ((x * y) % 3)) % 2 === 0;
240
+ default:
241
+ return (((x + y) % 2) + ((x * y) % 3)) % 2 === 0;
242
+ }
243
+ };
244
+ const applyMask = (mask) => {
245
+ for (let y = 0; y < size; y++) {
246
+ const row = modules[y];
247
+ if (!row)
248
+ continue;
249
+ for (let x = 0; x < size; x++)
250
+ if (!fixed[y]?.[x] && masked(mask, x, y))
251
+ row[x] = !row[x];
252
+ }
253
+ };
254
+ let best = 0;
255
+ let bestPenalty = Number.POSITIVE_INFINITY;
256
+ for (let mask = 0; mask < 8; mask++) {
257
+ applyMask(mask);
258
+ drawFormat(mask);
259
+ const score = penalty(modules);
260
+ if (score < bestPenalty) {
261
+ best = mask;
262
+ bestPenalty = score;
263
+ }
264
+ applyMask(mask);
265
+ }
266
+ applyMask(best);
267
+ drawFormat(best);
268
+ return modules;
269
+ }
270
+ function penalty(modules) {
271
+ const size = modules.length;
272
+ const at = (x, y) => modules[y]?.[x] ?? false;
273
+ let result = 0;
274
+ const lines = (get) => {
275
+ for (let i = 0; i < size; i++) {
276
+ let color = false;
277
+ let run = 0;
278
+ const history = [0, 0, 0, 0, 0, 0, 0];
279
+ const addHistory = (length) => {
280
+ if (history[0] === 0)
281
+ length += size;
282
+ history.pop();
283
+ history.unshift(length);
284
+ };
285
+ const patterns = () => {
286
+ const n = history[1] ?? 0;
287
+ const core = n > 0 &&
288
+ history[2] === n &&
289
+ history[3] === n * 3 &&
290
+ history[4] === n &&
291
+ history[5] === n;
292
+ return ((core && (history[0] ?? 0) >= n * 4 && (history[6] ?? 0) >= n ? 1 : 0) +
293
+ (core && (history[6] ?? 0) >= n * 4 && (history[0] ?? 0) >= n ? 1 : 0));
294
+ };
295
+ for (let j = 0; j < size; j++) {
296
+ if (get(i, j) === color) {
297
+ run++;
298
+ if (run === 5)
299
+ result += 3;
300
+ else if (run > 5)
301
+ result++;
302
+ }
303
+ else {
304
+ addHistory(run);
305
+ if (!color)
306
+ result += patterns() * 40;
307
+ color = get(i, j);
308
+ run = 1;
309
+ }
310
+ }
311
+ if (color) {
312
+ addHistory(run);
313
+ run = 0;
314
+ }
315
+ addHistory(run + size);
316
+ result += patterns() * 40;
317
+ }
318
+ };
319
+ lines((y, x) => at(x, y));
320
+ lines((x, y) => at(x, y));
321
+ let dark = 0;
322
+ for (let y = 0; y < size; y++) {
323
+ for (let x = 0; x < size; x++) {
324
+ const color = at(x, y);
325
+ if (color)
326
+ dark++;
327
+ if (x < size - 1 &&
328
+ y < size - 1 &&
329
+ color === at(x + 1, y) &&
330
+ color === at(x, y + 1) &&
331
+ color === at(x + 1, y + 1)) {
332
+ result += 3;
333
+ }
334
+ }
335
+ }
336
+ const total = size * size;
337
+ result += (Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1) * 10;
338
+ return result;
339
+ }
340
+ /** The dark modules as one path, `scale` px per module, offset by the quiet zone. */
341
+ export function qrPath(modules, scale, x0, y0) {
342
+ const parts = [];
343
+ const round = (value) => Math.round(value * 100) / 100;
344
+ modules.forEach((row, y) => {
345
+ let x = 0;
346
+ while (x < row.length) {
347
+ if (!row[x]) {
348
+ x++;
349
+ continue;
350
+ }
351
+ let end = x;
352
+ while (end < row.length && row[end])
353
+ end++;
354
+ parts.push(`M${round(x0 + x * scale)} ${round(y0 + y * scale)}h${round((end - x) * scale)}v${round(scale)}h${round(-(end - x) * scale)}z`);
355
+ x = end;
356
+ }
357
+ });
358
+ return parts.join("");
359
+ }
@@ -0,0 +1,76 @@
1
+ import type { Brand } from "../brand/schema.ts";
2
+ import type { FontResolver } from "../text/fonts.ts";
3
+ import { TextEngine, type TextLayout } from "../text/engine.ts";
4
+ import type { AssetRef, Frame, Scene } from "./schema.ts";
5
+ /**
6
+ * renderScene: one scene page and a brand in, one SVG string out. The studio shows the string
7
+ * inline and the server rasterizes the same string with resvg, so the editor, the derived files
8
+ * and live images match by construction. Only the features docs/spikes/render.md allows are
9
+ * written: glyph paths for text, linear and radial gradients (never `fr`), clipPaths, blend
10
+ * modes inside an isolated group, filters with userSpaceOnUse regions inside a budget, a PNG
11
+ * grain tile, and pre-sized images at whole pixels.
12
+ *
13
+ * Each layer is drawn in its own space inside `<g transform="translate(x y) rotate(r w/2 h/2)">`,
14
+ * so its position and turn live in that one attribute (docs/spikes/editor.md, rule E6). With a
15
+ * `cache`, a layer whose content did not change reuses its markup, and a drag frame rewrites
16
+ * one transform instead of every glyph path.
17
+ */
18
+ /** Bump when the output for the same scene and brand changes, so revisions change too. */
19
+ export declare const RENDERER_VERSION = "2";
20
+ /** Filter region pixels allowed per page: about two large shadows on a share card. */
21
+ export declare const FILTER_BUDGET_PX = 500000;
22
+ export type AssetResolver = (asset: AssetRef, drawn: {
23
+ width: number;
24
+ height: number;
25
+ }) => Promise<{
26
+ href: string;
27
+ } | undefined>;
28
+ /** Keeps each layer's markup between renders. Make one per editor stage with createRenderCache. */
29
+ export type RenderCache = {
30
+ readonly prefix: string;
31
+ };
32
+ export type RenderContext = {
33
+ fonts: FontResolver;
34
+ /** Turns an asset into an href (a data: URI or an https URL), sized to how it is drawn. */
35
+ assets?: AssetResolver;
36
+ /** Slot values, as `t.<slot>` (what live image URLs carry) or the bare slot name. */
37
+ params?: Record<string, string>;
38
+ /** Which page to draw. Default 0. */
39
+ page?: number;
40
+ /**
41
+ * Prefix for every id in the SVG. Default: the cache's own prefix, or one from the revision,
42
+ * so two scenes never clash.
43
+ */
44
+ idPrefix?: string;
45
+ /** Reuse the markup of layers that did not change since the last render with this cache. */
46
+ cache?: RenderCache;
47
+ };
48
+ export type SceneCheck = {
49
+ rule: string;
50
+ level: "error" | "warning";
51
+ layer?: string;
52
+ /** Plain words for the owner. */
53
+ message: string;
54
+ /** The numbers behind it, for "Details". */
55
+ details?: Record<string, string | number>;
56
+ };
57
+ /** A layer's frame in the page's space. Text lines are in the layer's own space. */
58
+ export type LayerBox = Frame & {
59
+ lines?: TextLayout["lines"];
60
+ fontSize?: number;
61
+ };
62
+ export type RenderResult = {
63
+ svg: string;
64
+ boxes: Record<string, LayerBox>;
65
+ checks: SceneCheck[];
66
+ revision: string;
67
+ };
68
+ /** One text engine per font resolver, shared by every render. */
69
+ export declare function engineFor(fonts: FontResolver): Promise<TextEngine>;
70
+ /** A cache for one editor stage. Its prefix keeps its ids apart from other stages on the page. */
71
+ export declare function createRenderCache(): RenderCache;
72
+ /** Sorted keys and no undefined values, so equal content always gives the same string. */
73
+ export declare function canonical(value: unknown): string;
74
+ /** sha256 of the canonical scene, the brand (its version when approved) and the renderer. */
75
+ export declare function sceneRevision(scene: Scene, brand: Brand, params?: Record<string, string>): Promise<string>;
76
+ export declare function renderScene(input: Scene, brand: Brand, ctx: RenderContext): Promise<RenderResult>;