@12ui/design 0.2.71 → 0.2.72

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 (116) hide show
  1. package/README.md +5 -0
  2. package/SKILL.md +1 -1
  3. package/dist/cli-capabilities.d.ts +9 -0
  4. package/dist/cli-capabilities.d.ts.map +1 -1
  5. package/dist/cli-capabilities.js +10 -0
  6. package/dist/cli-capabilities.js.map +1 -1
  7. package/dist/cli-help/index.d.ts +93 -0
  8. package/dist/cli-help/index.d.ts.map +1 -1
  9. package/dist/cli-help/index.js +2 -0
  10. package/dist/cli-help/index.js.map +1 -1
  11. package/dist/cli-help/scene.d.ts +96 -0
  12. package/dist/cli-help/scene.d.ts.map +1 -0
  13. package/dist/cli-help/scene.js +162 -0
  14. package/dist/cli-help/scene.js.map +1 -0
  15. package/dist/cli-run.d.ts.map +1 -1
  16. package/dist/cli-run.js +6 -0
  17. package/dist/cli-run.js.map +1 -1
  18. package/dist/cli-scene-command.d.ts +3 -0
  19. package/dist/cli-scene-command.d.ts.map +1 -0
  20. package/dist/cli-scene-command.js +292 -0
  21. package/dist/cli-scene-command.js.map +1 -0
  22. package/dist/cli-usage.d.ts +8 -0
  23. package/dist/cli-usage.d.ts.map +1 -1
  24. package/dist/cli-usage.js +26 -1
  25. package/dist/cli-usage.js.map +1 -1
  26. package/dist/legacy-skill-catalog.d.ts.map +1 -1
  27. package/dist/legacy-skill-catalog.js +11 -0
  28. package/dist/legacy-skill-catalog.js.map +1 -1
  29. package/dist/prototype-browsers.d.ts +8 -2
  30. package/dist/prototype-browsers.d.ts.map +1 -1
  31. package/dist/prototype-browsers.js +8 -3
  32. package/dist/prototype-browsers.js.map +1 -1
  33. package/dist/prototype-process.js +1 -1
  34. package/dist/prototype-process.js.map +1 -1
  35. package/dist/run-journal-commands.d.ts.map +1 -1
  36. package/dist/run-journal-commands.js +6 -0
  37. package/dist/run-journal-commands.js.map +1 -1
  38. package/dist/scene/camera-model.d.ts +48 -0
  39. package/dist/scene/camera-model.d.ts.map +1 -0
  40. package/dist/scene/camera-model.js +89 -0
  41. package/dist/scene/camera-model.js.map +1 -0
  42. package/dist/scene/camera-solve.d.ts +58 -0
  43. package/dist/scene/camera-solve.d.ts.map +1 -0
  44. package/dist/scene/camera-solve.js +288 -0
  45. package/dist/scene/camera-solve.js.map +1 -0
  46. package/dist/scene/capture-plan.d.ts +28 -0
  47. package/dist/scene/capture-plan.d.ts.map +1 -0
  48. package/dist/scene/capture-plan.js +79 -0
  49. package/dist/scene/capture-plan.js.map +1 -0
  50. package/dist/scene/capture.d.ts +21 -0
  51. package/dist/scene/capture.d.ts.map +1 -0
  52. package/dist/scene/capture.js +118 -0
  53. package/dist/scene/capture.js.map +1 -0
  54. package/dist/scene/image-colors.d.ts +25 -0
  55. package/dist/scene/image-colors.d.ts.map +1 -0
  56. package/dist/scene/image-colors.js +110 -0
  57. package/dist/scene/image-colors.js.map +1 -0
  58. package/dist/scene/image-rectify.d.ts +25 -0
  59. package/dist/scene/image-rectify.d.ts.map +1 -0
  60. package/dist/scene/image-rectify.js +82 -0
  61. package/dist/scene/image-rectify.js.map +1 -0
  62. package/dist/scene/image-sheet.d.ts +19 -0
  63. package/dist/scene/image-sheet.d.ts.map +1 -0
  64. package/dist/scene/image-sheet.js +118 -0
  65. package/dist/scene/image-sheet.js.map +1 -0
  66. package/dist/scene/least-squares.d.ts +31 -0
  67. package/dist/scene/least-squares.d.ts.map +1 -0
  68. package/dist/scene/least-squares.js +173 -0
  69. package/dist/scene/least-squares.js.map +1 -0
  70. package/dist/scene/numbers.d.ts +17 -0
  71. package/dist/scene/numbers.d.ts.map +1 -0
  72. package/dist/scene/numbers.js +39 -0
  73. package/dist/scene/numbers.js.map +1 -0
  74. package/dist/scene/placement.d.ts +43 -0
  75. package/dist/scene/placement.d.ts.map +1 -0
  76. package/dist/scene/placement.js +107 -0
  77. package/dist/scene/placement.js.map +1 -0
  78. package/dist/scene/raster.d.ts +18 -0
  79. package/dist/scene/raster.d.ts.map +1 -0
  80. package/dist/scene/raster.js +31 -0
  81. package/dist/scene/raster.js.map +1 -0
  82. package/dist/scene/scene-kit.d.ts +20 -0
  83. package/dist/scene/scene-kit.d.ts.map +1 -0
  84. package/dist/scene/scene-kit.js +74 -0
  85. package/dist/scene/scene-kit.js.map +1 -0
  86. package/dist/scene/scene-verbs.d.ts +4 -0
  87. package/dist/scene/scene-verbs.d.ts.map +1 -0
  88. package/dist/scene/scene-verbs.js +5 -0
  89. package/dist/scene/scene-verbs.js.map +1 -0
  90. package/dist/scene/seeded-random.d.ts +20 -0
  91. package/dist/scene/seeded-random.d.ts.map +1 -0
  92. package/dist/scene/seeded-random.js +42 -0
  93. package/dist/scene/seeded-random.js.map +1 -0
  94. package/dist/scene/spec-expression.d.ts +25 -0
  95. package/dist/scene/spec-expression.d.ts.map +1 -0
  96. package/dist/scene/spec-expression.js +234 -0
  97. package/dist/scene/spec-expression.js.map +1 -0
  98. package/dist/scene/static-server.d.ts +13 -0
  99. package/dist/scene/static-server.d.ts.map +1 -0
  100. package/dist/scene/static-server.js +99 -0
  101. package/dist/scene/static-server.js.map +1 -0
  102. package/open-design.json +2 -2
  103. package/package.json +3 -1
  104. package/scene-kit/starter/camera.js +10 -0
  105. package/scene-kit/starter/gobo.js +60 -0
  106. package/scene-kit/starter/index.html +23 -0
  107. package/scene-kit/starter/lib.js +84 -0
  108. package/scene-kit/starter/main.js +78 -0
  109. package/scene-kit/starter/scene.js +33 -0
  110. package/scene-kit/vendor/LICENSE +21 -0
  111. package/scene-kit/vendor/addons/geometries/RoundedBoxGeometry.js +216 -0
  112. package/scene-kit/vendor/addons/renderers/CSS3DRenderer.js +454 -0
  113. package/scene-kit/vendor/three.core.js +60586 -0
  114. package/scene-kit/vendor/three.module.js +19719 -0
  115. package/skills/12ui-design/SKILL.md +7 -1
  116. package/skills/12ui-design/scene.md +172 -0
@@ -0,0 +1,118 @@
1
+ import path from 'node:path';
2
+ import sharp from 'sharp';
3
+ import { SceneArgumentError } from './numbers.js';
4
+ import { encodePng, readRgb, resizeRgb } from './raster.js';
5
+ /**
6
+ * The two pictures the self-review loop looks at. A port of `sheet.py`.
7
+ *
8
+ * Sheet: SOURCE first, then each capture, in 640 px wide tiles with a large
9
+ * label on each (the file name; --note is added to the SOURCE tile).
10
+ * Blend (2x2 of 900 px tiles): SOURCE | RENDER above, 50% BLEND | DIFFERENCE x3
11
+ * below. Labels are Pango text rendered by sharp's bundled libvips: no font file
12
+ * and no network.
13
+ */
14
+ const escapeMarkup = (text) => text
15
+ .replaceAll('&', '&')
16
+ .replaceAll('<', '&lt;')
17
+ .replaceAll('>', '&gt;');
18
+ /** A white label on a black box, as a PNG to composite at (x - 6, y - 3) of the text origin. */
19
+ const label = async (text, fontPx) => {
20
+ const { data, info } = await sharp({
21
+ text: {
22
+ text: `<span foreground="white">${escapeMarkup(text)}</span>`,
23
+ font: `sans ${fontPx}`,
24
+ dpi: 72,
25
+ rgba: true,
26
+ },
27
+ }).png().toBuffer({ resolveWithObject: true });
28
+ const width = info.width + 12;
29
+ const height = info.height + 6;
30
+ const input = await sharp({
31
+ create: { width, height, channels: 4, background: { r: 0, g: 0, b: 0, alpha: 1 } },
32
+ }).composite([{ input: data, left: 6, top: 3 }]).png().toBuffer();
33
+ return { input, width, height };
34
+ };
35
+ const composeGrid = async (args) => {
36
+ const rows = Math.ceil(args.tiles.length / args.columns);
37
+ const width = args.columns * args.tileWidth;
38
+ const height = rows * args.tileHeight;
39
+ const layers = [];
40
+ for (const [index, tile] of args.tiles.entries()) {
41
+ const left = (index % args.columns) * args.tileWidth;
42
+ const top = Math.floor(index / args.columns) * args.tileHeight;
43
+ const resized = await resizeRgb(tile.image, args.tileWidth, args.tileHeight);
44
+ layers.push({ input: await encodePng(resized), left, top });
45
+ const tag = await label(tile.name, args.fontPx);
46
+ layers.push({
47
+ input: tag.input,
48
+ left: Math.min(left + args.labelOffset - 6, Math.max(width - tag.width, 0)),
49
+ top: top + args.labelOffset - 3,
50
+ });
51
+ }
52
+ await sharp({ create: { width, height, channels: 3, background: args.background } })
53
+ .composite(layers)
54
+ .png()
55
+ .toFile(args.outFile);
56
+ return { width, height };
57
+ };
58
+ /** Python's round() for the tile height: ties go to the even neighbour. */
59
+ const roundHalfEven = (value) => {
60
+ const floor = Math.floor(value);
61
+ const fraction = value - floor;
62
+ if (Math.abs(fraction - 0.5) > 1e-9)
63
+ return Math.round(value);
64
+ return floor % 2 === 0 ? floor : floor + 1;
65
+ };
66
+ const captureName = (file) => path.basename(file).replace(/\.[^.]*$/u, '');
67
+ export const writeContactSheet = async (args) => {
68
+ const columns = args.columns ?? 3;
69
+ if (!Number.isInteger(columns) || columns < 1)
70
+ throw new SceneArgumentError('--cols must be a positive integer');
71
+ const source = await readRgb(args.sourceFile);
72
+ const tileWidth = 640;
73
+ const tileHeight = roundHalfEven((source.height * tileWidth) / source.width);
74
+ const tiles = [
75
+ { name: `SOURCE${args.note ? ` ${args.note}` : ''}`, image: source },
76
+ ...await Promise.all(args.captureFiles.map(async (file) => ({ name: captureName(file), image: await readRgb(file) }))),
77
+ ];
78
+ return composeGrid({
79
+ tiles,
80
+ columns,
81
+ tileWidth,
82
+ tileHeight,
83
+ background: { r: 24, g: 24, b: 24 },
84
+ labelOffset: 10,
85
+ fontPx: 22,
86
+ outFile: args.outFile,
87
+ });
88
+ };
89
+ export const writeBlend = async (args) => {
90
+ const source = await readRgb(args.sourceFile);
91
+ const render = await resizeRgb(await readRgb(args.renderFile), source.width, source.height);
92
+ const blend = Buffer.alloc(source.data.length);
93
+ const difference = Buffer.alloc(source.data.length);
94
+ for (let index = 0; index < source.data.length; index += 1) {
95
+ const a = source.data[index], b = render.data[index];
96
+ blend[index] = Math.round((a + b) / 2);
97
+ difference[index] = Math.min(255, Math.abs(a - b) * 3);
98
+ }
99
+ const tileWidth = 900;
100
+ const tileHeight = roundHalfEven((source.height * tileWidth) / source.width);
101
+ const same = { width: source.width, height: source.height };
102
+ return composeGrid({
103
+ tiles: [
104
+ { name: 'SOURCE', image: source },
105
+ { name: 'RENDER', image: render },
106
+ { name: '50% BLEND', image: { ...same, data: blend } },
107
+ { name: 'DIFFERENCE x3', image: { ...same, data: difference } },
108
+ ],
109
+ columns: 2,
110
+ tileWidth,
111
+ tileHeight,
112
+ background: { r: 0, g: 0, b: 0 },
113
+ labelOffset: 12,
114
+ fontPx: 26,
115
+ outFile: args.outFile,
116
+ });
117
+ };
118
+ //# sourceMappingURL=image-sheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-sheet.js","sourceRoot":"","sources":["../../src/scene/image-sheet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Box-constrained Levenberg-Marquardt with a numeric Jacobian, and a multistart
3
+ * around it. A line-for-line port of the proven Python solver
4
+ * (`solve_camera.py` lm/multistart): the same damping schedule, the same
5
+ * forward-difference step, the same clamping, so a spec solves to the same
6
+ * minimum in both.
7
+ */
8
+ export type Residuals = (parameters: Float64Array) => Float64Array;
9
+ export declare class SingularMatrixError extends Error {
10
+ constructor();
11
+ }
12
+ /**
13
+ * Solves `matrix * x = rhs` by Gaussian elimination with partial pivoting.
14
+ * An exactly zero pivot is a singular system, as LAPACK reports it.
15
+ */
16
+ export declare const solveLinearSystem: (matrix: readonly Float64Array[], rhs: Float64Array) => Float64Array;
17
+ export type LeastSquaresResult = {
18
+ parameters: Float64Array;
19
+ cost: number;
20
+ };
21
+ export declare const levenbergMarquardt: (residuals: Residuals, start: ArrayLike<number>, low: ArrayLike<number>, high: ArrayLike<number>, iterations?: number) => LeastSquaresResult;
22
+ /**
23
+ * Every start gets a short coarse run; the best `keep` are refined fully and
24
+ * the lowest cost wins. Ties keep the earlier start, as Python's stable sort did.
25
+ */
26
+ export declare const multistart: (residuals: Residuals, starts: readonly ArrayLike<number>[], low: ArrayLike<number>, high: ArrayLike<number>, { keep, coarse, refine }?: {
27
+ keep?: number;
28
+ coarse?: number;
29
+ refine?: number;
30
+ }) => LeastSquaresResult;
31
+ //# sourceMappingURL=least-squares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"least-squares.d.ts","sourceRoot":"","sources":["../../src/scene/least-squares.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,UAAU,EAAE,YAAY,KAAK,YAAY,CAAC;AAEnE,qBAAa,mBAAoB,SAAQ,KAAK;;CAK7C;AAgBD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,SAAS,YAAY,EAAE,EAAE,KAAK,YAAY,KAAG,YAoCtF,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAAE,UAAU,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,eAAO,MAAM,kBAAkB,GAC7B,WAAW,SAAS,EACpB,OAAO,SAAS,CAAC,MAAM,CAAC,EACxB,KAAK,SAAS,CAAC,MAAM,CAAC,EACtB,MAAM,SAAS,CAAC,MAAM,CAAC,EACvB,mBAAe,KACd,kBAmEF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,WAAW,SAAS,EACpB,QAAQ,SAAS,SAAS,CAAC,MAAM,CAAC,EAAE,EACpC,KAAK,SAAS,CAAC,MAAM,CAAC,EACtB,MAAM,SAAS,CAAC,MAAM,CAAC,EACvB,2BAAyC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,KAChG,kBAeF,CAAC"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Box-constrained Levenberg-Marquardt with a numeric Jacobian, and a multistart
3
+ * around it. A line-for-line port of the proven Python solver
4
+ * (`solve_camera.py` lm/multistart): the same damping schedule, the same
5
+ * forward-difference step, the same clamping, so a spec solves to the same
6
+ * minimum in both.
7
+ */
8
+ export class SingularMatrixError extends Error {
9
+ constructor() {
10
+ super('singular matrix');
11
+ this.name = 'SingularMatrixError';
12
+ }
13
+ }
14
+ const clamp = (values, low, high) => {
15
+ const out = new Float64Array(values.length);
16
+ for (let index = 0; index < values.length; index += 1) {
17
+ out[index] = Math.min(Math.max(values[index], low[index]), high[index]);
18
+ }
19
+ return out;
20
+ };
21
+ const sumOfSquares = (values) => {
22
+ let total = 0;
23
+ for (const value of values)
24
+ total += value * value;
25
+ return total;
26
+ };
27
+ /**
28
+ * Solves `matrix * x = rhs` by Gaussian elimination with partial pivoting.
29
+ * An exactly zero pivot is a singular system, as LAPACK reports it.
30
+ */
31
+ export const solveLinearSystem = (matrix, rhs) => {
32
+ const size = rhs.length;
33
+ const a = matrix.map((row) => Float64Array.from(row));
34
+ const b = Float64Array.from(rhs);
35
+ for (let column = 0; column < size; column += 1) {
36
+ let pivotRow = column;
37
+ let pivotSize = Math.abs(a[column][column]);
38
+ for (let row = column + 1; row < size; row += 1) {
39
+ const candidate = Math.abs(a[row][column]);
40
+ if (candidate > pivotSize) {
41
+ pivotSize = candidate;
42
+ pivotRow = row;
43
+ }
44
+ }
45
+ if (pivotSize === 0)
46
+ throw new SingularMatrixError();
47
+ if (pivotRow !== column) {
48
+ [a[column], a[pivotRow]] = [a[pivotRow], a[column]];
49
+ [b[column], b[pivotRow]] = [b[pivotRow], b[column]];
50
+ }
51
+ const pivot = a[column];
52
+ for (let row = column + 1; row < size; row += 1) {
53
+ const target = a[row];
54
+ const factor = target[column] / pivot[column];
55
+ if (factor === 0)
56
+ continue;
57
+ for (let k = column; k < size; k += 1)
58
+ target[k] -= factor * pivot[k];
59
+ b[row] -= factor * b[column];
60
+ }
61
+ }
62
+ const x = new Float64Array(size);
63
+ for (let row = size - 1; row >= 0; row -= 1) {
64
+ let total = b[row];
65
+ const current = a[row];
66
+ for (let k = row + 1; k < size; k += 1)
67
+ total -= current[k] * x[k];
68
+ x[row] = total / current[row];
69
+ }
70
+ return x;
71
+ };
72
+ export const levenbergMarquardt = (residuals, start, low, high, iterations = 60) => {
73
+ let p = clamp(start, low, high);
74
+ let lambda = 1e-2;
75
+ let r = residuals(p);
76
+ let cost = sumOfSquares(r);
77
+ const n = p.length;
78
+ for (let iteration = 0; iteration < iterations; iteration += 1) {
79
+ const m = r.length;
80
+ // Forward-difference Jacobian, column by column.
81
+ const jacobian = [];
82
+ for (let i = 0; i < n; i += 1) {
83
+ const step = 1e-6 * Math.max(1, Math.abs(p[i]));
84
+ const q = Float64Array.from(p);
85
+ q[i] += step;
86
+ const rq = residuals(q);
87
+ const column = new Float64Array(m);
88
+ for (let k = 0; k < m; k += 1)
89
+ column[k] = (rq[k] - r[k]) / step;
90
+ jacobian.push(column);
91
+ }
92
+ const normal = Array.from({ length: n }, () => new Float64Array(n));
93
+ const gradient = new Float64Array(n);
94
+ for (let i = 0; i < n; i += 1) {
95
+ const ci = jacobian[i];
96
+ let g = 0;
97
+ for (let k = 0; k < m; k += 1)
98
+ g += ci[k] * r[k];
99
+ gradient[i] = g;
100
+ for (let j = i; j < n; j += 1) {
101
+ const cj = jacobian[j];
102
+ let total = 0;
103
+ for (let k = 0; k < m; k += 1)
104
+ total += ci[k] * cj[k];
105
+ normal[i][j] = total;
106
+ normal[j][i] = total;
107
+ }
108
+ }
109
+ let improved = false;
110
+ for (let attempt = 0; attempt < 12; attempt += 1) {
111
+ const damped = normal.map((row, i) => {
112
+ const copy = Float64Array.from(row);
113
+ copy[i] += lambda * (row[i] + 1e-9);
114
+ return copy;
115
+ });
116
+ let step;
117
+ try {
118
+ step = solveLinearSystem(damped, gradient.map((value) => -value));
119
+ }
120
+ catch (error) {
121
+ if (error instanceof SingularMatrixError) {
122
+ lambda *= 10;
123
+ continue;
124
+ }
125
+ throw error;
126
+ }
127
+ const candidate = clamp(p.map((value, index) => value + step[index]), low, high);
128
+ const rq = residuals(candidate);
129
+ const cq = sumOfSquares(rq);
130
+ if (cq < cost) {
131
+ p = candidate;
132
+ r = rq;
133
+ cost = cq;
134
+ lambda = Math.max(lambda / 3, 1e-9);
135
+ improved = true;
136
+ break;
137
+ }
138
+ lambda *= 4;
139
+ }
140
+ if (!improved || cost < 1e-10)
141
+ break;
142
+ }
143
+ return { parameters: p, cost };
144
+ };
145
+ /**
146
+ * Every start gets a short coarse run; the best `keep` are refined fully and
147
+ * the lowest cost wins. Ties keep the earlier start, as Python's stable sort did.
148
+ */
149
+ export const multistart = (residuals, starts, low, high, { keep = 6, coarse = 25, refine = 200 } = {}) => {
150
+ const scored = starts.map((start, index) => ({
151
+ index,
152
+ ...levenbergMarquardt(residuals, start, low, high, coarse),
153
+ }));
154
+ scored.sort((left, right) => (compareCost(left.cost, right.cost) || left.index - right.index));
155
+ let best = null;
156
+ for (const candidate of scored.slice(0, keep)) {
157
+ const refined = levenbergMarquardt(residuals, candidate.parameters, low, high, refine);
158
+ if (best === null || refined.cost < best.cost)
159
+ best = refined;
160
+ }
161
+ if (best === null)
162
+ throw new Error('multistart needs at least one start');
163
+ return best;
164
+ };
165
+ /** NaN sorts last, like a failed start should. */
166
+ const compareCost = (left, right) => {
167
+ if (Number.isNaN(left))
168
+ return Number.isNaN(right) ? 0 : 1;
169
+ if (Number.isNaN(right))
170
+ return -1;
171
+ return left - right;
172
+ };
173
+ //# sourceMappingURL=least-squares.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"least-squares.js","sourceRoot":"","sources":["../../src/scene/least-squares.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C;QACE,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,KAAK,GAAG,CAAC,MAAyB,EAAE,GAAsB,EAAE,IAAuB,EAAgB,EAAE;IACzG,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAE,EAAE,GAAG,CAAC,KAAK,CAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,MAAoB,EAAU,EAAE;IACpD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC;IACnD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAA+B,EAAE,GAAiB,EAAgB,EAAE;IACpG,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC;IACxB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;QAChD,IAAI,QAAQ,GAAG,MAAM,CAAC;QACtB,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAE,CAAC,MAAM,CAAE,CAAC,CAAC;QAC9C,KAAK,IAAI,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAE,CAAC,MAAM,CAAE,CAAC,CAAC;YAC7C,IAAI,SAAS,GAAG,SAAS,EAAE,CAAC;gBAC1B,SAAS,GAAG,SAAS,CAAC;gBACtB,QAAQ,GAAG,GAAG,CAAC;YACjB,CAAC;QACH,CAAC;QACD,IAAI,SAAS,KAAK,CAAC;YAAE,MAAM,IAAI,mBAAmB,EAAE,CAAC;QACrD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAE,EAAE,CAAC,CAAC,MAAM,CAAE,CAAC,CAAC;YACtD,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAE,EAAE,CAAC,CAAC,MAAM,CAAE,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAE,CAAC;QACzB,KAAK,IAAI,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAE,CAAC;YACvB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAE,GAAG,KAAK,CAAC,MAAM,CAAE,CAAC;YAChD,IAAI,MAAM,KAAK,CAAC;gBAAE,SAAS;YAC3B,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,CAAC,CAAE,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACxE,CAAC,CAAC,GAAG,CAAE,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,CAAE,CAAC;QACjC,CAAC;IACH,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,KAAK,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,CAAC,CAAC,GAAG,CAAE,CAAC;QACpB,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAE,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC;YAAE,KAAK,IAAI,OAAO,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACrE,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,OAAO,CAAC,GAAG,CAAE,CAAC;IACjC,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAIF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,SAAoB,EACpB,KAAwB,EACxB,GAAsB,EACtB,IAAuB,EACvB,UAAU,GAAG,EAAE,EACK,EAAE;IACtB,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAChC,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,UAAU,EAAE,SAAS,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACnB,iDAAiD;QACjD,MAAM,QAAQ,GAAmB,EAAE,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC,CAAE,IAAI,IAAI,CAAC;YACd,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;YACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;gBAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,CAAC;YACnE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;QACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;YACxB,IAAI,CAAC,GAAG,CAAC,CAAC;YACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;gBAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;YACnD,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;gBACxB,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;oBAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC;gBACxD,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;gBACtB,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBACnC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpC,IAAI,CAAC,CAAC,CAAE,IAAI,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC;gBACtC,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;YACH,IAAI,IAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,IAAI,GAAG,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACpE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;oBACzC,MAAM,IAAI,EAAE,CAAC;oBACb,SAAS;gBACX,CAAC;gBACD,MAAM,KAAK,CAAC;YACd,CAAC;YACD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAClF,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,EAAE,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;YAC5B,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;gBACd,CAAC,GAAG,SAAS,CAAC;gBACd,CAAC,GAAG,EAAE,CAAC;gBACP,IAAI,GAAG,EAAE,CAAC;gBACV,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;gBACpC,QAAQ,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,CAAC;YACD,MAAM,IAAI,CAAC,CAAC;QACd,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,IAAI,GAAG,KAAK;YAAE,MAAM;IACvC,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;AACjC,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,SAAoB,EACpB,MAAoC,EACpC,GAAsB,EACtB,IAAuB,EACvB,EAAE,IAAI,GAAG,CAAC,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,GAAG,KAA0D,EAAE,EAC7E,EAAE;IACtB,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3C,KAAK;QACL,GAAG,kBAAkB,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC;KAC3D,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC3B,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAC/D,CAAC,CAAC;IACH,IAAI,IAAI,GAA8B,IAAI,CAAC;IAC3C,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,OAAO,GAAG,kBAAkB,CAAC,SAAS,EAAE,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACvF,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI;YAAE,IAAI,GAAG,OAAO,CAAC;IAChE,CAAC;IACD,IAAI,IAAI,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAC1E,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE;IAC1D,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;IACnC,OAAO,IAAI,GAAG,KAAK,CAAC;AACtB,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /** A malformed scene argument: a refusal, raised before any work starts. */
2
+ export declare class SceneArgumentError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /** Round to `digits` decimals for JSON output (the Python helpers' `round`). */
6
+ export declare const roundTo: (value: number, digits: number) => number;
7
+ /** Fixed-point text, like Python's `f"{value:.Nf}"`. */
8
+ export declare const fixed: (value: number, digits: number) => string;
9
+ /** Parses "a,b" or "a,b,c" into numbers, naming the argument when it is malformed. */
10
+ export declare const parseNumberTuple: (text: string, count: number, what: string) => number[];
11
+ /** Parses a box "x0,y0,x1,y1" into integers (fractions truncate, as Python's int() did). */
12
+ export declare const parseBox: (text: string, what: string) => [number, number, number, number];
13
+ /** Splits a `;`-separated list, dropping empty entries. */
14
+ export declare const splitList: (text: string) => string[];
15
+ /** "WxH" into two positive integers. */
16
+ export declare const parseSize: (text: string, what: string) => [number, number];
17
+ //# sourceMappingURL=numbers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.d.ts","sourceRoot":"","sources":["../../src/scene/numbers.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,gFAAgF;AAChF,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MAGvD,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,MAA+B,CAAC;AAEtF,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MAAM,EAOlF,CAAC;AAEF,4FAA4F;AAC5F,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAGpF,CAAC;AAEF,2DAA2D;AAC3D,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAAM,EAAgE,CAAC;AAEhH,wCAAwC;AACxC,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,CAMrE,CAAC"}
@@ -0,0 +1,39 @@
1
+ /** A malformed scene argument: a refusal, raised before any work starts. */
2
+ export class SceneArgumentError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = 'SceneArgumentError';
6
+ }
7
+ }
8
+ /** Round to `digits` decimals for JSON output (the Python helpers' `round`). */
9
+ export const roundTo = (value, digits) => {
10
+ const rounded = Number(value.toFixed(digits));
11
+ return Object.is(rounded, -0) ? 0 : rounded;
12
+ };
13
+ /** Fixed-point text, like Python's `f"{value:.Nf}"`. */
14
+ export const fixed = (value, digits) => value.toFixed(digits);
15
+ /** Parses "a,b" or "a,b,c" into numbers, naming the argument when it is malformed. */
16
+ export const parseNumberTuple = (text, count, what) => {
17
+ const parts = text.split(',').map((part) => part.trim());
18
+ const values = parts.map(Number);
19
+ if (parts.length !== count || parts.some((part) => part === '') || values.some((value) => !Number.isFinite(value))) {
20
+ throw new SceneArgumentError(`${what} must be ${count} comma-separated numbers, got "${text}"`);
21
+ }
22
+ return values;
23
+ };
24
+ /** Parses a box "x0,y0,x1,y1" into integers (fractions truncate, as Python's int() did). */
25
+ export const parseBox = (text, what) => {
26
+ const [x0, y0, x1, y1] = parseNumberTuple(text, 4, what).map(Math.trunc);
27
+ return [x0, y0, x1, y1];
28
+ };
29
+ /** Splits a `;`-separated list, dropping empty entries. */
30
+ export const splitList = (text) => text.split(';').map((part) => part.trim()).filter(Boolean);
31
+ /** "WxH" into two positive integers. */
32
+ export const parseSize = (text, what) => {
33
+ const match = /^(\d+)x(\d+)$/u.exec(text.trim());
34
+ if (!match || Number(match[1]) < 1 || Number(match[2]) < 1) {
35
+ throw new SceneArgumentError(`${what} must be <width>x<height> in pixels, got "${text}"`);
36
+ }
37
+ return [Number(match[1]), Number(match[2])];
38
+ };
39
+ //# sourceMappingURL=numbers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"numbers.js","sourceRoot":"","sources":["../../src/scene/numbers.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,gFAAgF;AAChF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,MAAc,EAAU,EAAE;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,OAAO,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAC9C,CAAC,CAAC;AAEF,wDAAwD;AACxD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,MAAc,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtF,sFAAsF;AACtF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,IAAY,EAAY,EAAE;IACtF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACnH,MAAM,IAAI,kBAAkB,CAAC,GAAG,IAAI,YAAY,KAAK,kCAAkC,IAAI,GAAG,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,4FAA4F;AAC5F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,IAAY,EAAoC,EAAE;IACvF,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAqC,CAAC;IAC7G,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC,CAAC;AAEF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAY,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEhH,wCAAwC;AACxC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,IAAY,EAAoB,EAAE;IACxE,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,kBAAkB,CAAC,GAAG,IAAI,6CAA6C,IAAI,GAAG,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { type Camera, type ImageSize, type Vec3 } from './camera-model.js';
2
+ /**
3
+ * Placing objects through a solved camera: pixel rays onto a plane, world
4
+ * points back to pixels, and the pose of a rectangle from its four corners.
5
+ * Ports of `solve_camera.py ray|project|rect`, with the sized rectangle fixed:
6
+ * the Python helper crashed whenever both sides were known.
7
+ */
8
+ export type RayLine = {
9
+ u: number;
10
+ v: number;
11
+ point: Vec3;
12
+ behind: boolean;
13
+ };
14
+ export declare const castRays: (camera: Camera, size: ImageSize, pixels: ReadonlyArray<[number, number]>, planeY: number) => RayLine[];
15
+ export declare const formatRayLine: (line: RayLine) => string;
16
+ export declare const formatProjectLine: (point: Vec3, u: number, v: number) => string;
17
+ export type RectPose = {
18
+ position: Vec3;
19
+ w: number;
20
+ h: number;
21
+ rotation: {
22
+ x: number;
23
+ y: number;
24
+ z: number;
25
+ order: 'YXZ';
26
+ };
27
+ rmsPx?: number;
28
+ note: string;
29
+ };
30
+ /** A rectangle lying flat on the plane y = planeY, any size. Corners TL;TR;BR;BL in pixels. */
31
+ export declare const rectOnPlane: (camera: Camera, size: ImageSize, corners: ReadonlyArray<[number, number]>, planeY: number) => {
32
+ pose: RectPose;
33
+ behind: boolean;
34
+ };
35
+ /**
36
+ * Free pose (position, lean, roll) of a rectangle whose width, height or both
37
+ * are known. With one side known the other is solved, less well determined.
38
+ */
39
+ export declare const rectOfKnownSize: (camera: Camera, size: ImageSize, corners: ReadonlyArray<[number, number]>, known: {
40
+ width?: number;
41
+ height?: number;
42
+ }) => RectPose;
43
+ //# sourceMappingURL=placement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../../src/scene/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,IAAI,EACV,MAAM,mBAAmB,CAAC;AAK3B;;;;;GAKG;AAEH,MAAM,MAAM,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7E,eAAO,MAAM,QAAQ,GACnB,QAAQ,MAAM,EACd,MAAM,SAAS,EACf,QAAQ,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,QAAQ,MAAM,KACb,OAAO,EAAiF,CAAC;AAE5F,eAAO,MAAM,aAAa,GAAI,MAAM,OAAO,KAAG,MAG7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,OAAO,IAAI,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,MAErE,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,IAAI,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAYF,+FAA+F;AAC/F,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,EACd,MAAM,SAAS,EACf,SAAS,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACxC,QAAQ,MAAM,KACb;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAoBnC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,EACd,MAAM,SAAS,EACf,SAAS,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACxC,OAAO;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KACzC,QA+DF,CAAC"}
@@ -0,0 +1,107 @@
1
+ import { planeHit, pixelRay, projectPoints, rotationMatrix, } from './camera-model.js';
2
+ import { multistart } from './least-squares.js';
3
+ import { fixed, roundTo, SceneArgumentError } from './numbers.js';
4
+ import { seededRandom } from './seeded-random.js';
5
+ export const castRays = (camera, size, pixels, planeY) => pixels.map(([u, v]) => ({ u, v, ...planeHit(camera, size, u, v, planeY) }));
6
+ export const formatRayLine = (line) => (`${fixed(line.u, 0)},${fixed(line.v, 0)} -> x=${fixed(line.point[0], 4)}`
7
+ + ` y=${fixed(line.point[1], 4)} z=${fixed(line.point[2], 4)}`);
8
+ export const formatProjectLine = (point, u, v) => (`${fixed(point[0], 4)},${fixed(point[1], 4)},${fixed(point[2], 4)} -> px ${fixed(u, 1)},${fixed(v, 1)}`);
9
+ const FLAT_NOTE = 'mesh face is local xy facing +z; rotation.x=-pi/2 lays it flat facing up,'
10
+ + ' local +y points away from the camera';
11
+ const AMBIGUITY_NOTE = 'rectangles seen from one view are ambiguous in lean versus depth; if it lands inside'
12
+ + ' another object, constrain it with what you know (rests on a surface, leans on a wall)';
13
+ const SOLVED_SIDE_NOTE = 'one dimension was solved, so lean, roll and that dimension trade against each other;'
14
+ + ' prefer --plane-y for anything lying flat. ';
15
+ const subtract = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
16
+ const norm = (a) => Math.hypot(...a);
17
+ /** A rectangle lying flat on the plane y = planeY, any size. Corners TL;TR;BR;BL in pixels. */
18
+ export const rectOnPlane = (camera, size, corners, planeY) => {
19
+ const hits = corners.map(([u, v]) => planeHit(camera, size, u, v, planeY));
20
+ const P = hits.map((hit) => hit.point);
21
+ const centre = [0, 0, 0];
22
+ for (const point of P)
23
+ for (let axis = 0; axis < 3; axis += 1)
24
+ centre[axis] += point[axis] / P.length;
25
+ const top = subtract(P[1], P[0]);
26
+ const bottom = subtract(P[2], P[3]);
27
+ const width = (norm(top) + norm(bottom)) / 2;
28
+ const height = (norm(subtract(P[3], P[0])) + norm(subtract(P[2], P[1]))) / 2;
29
+ const yaw = Math.atan2(-(top[2] + bottom[2]), top[0] + bottom[0]);
30
+ return {
31
+ pose: {
32
+ position: [roundTo(centre[0], 4), roundTo(centre[1], 4), roundTo(centre[2], 4)],
33
+ w: roundTo(width, 4),
34
+ h: roundTo(height, 4),
35
+ rotation: { x: roundTo(-Math.PI / 2, 6), y: roundTo(yaw, 6), z: 0, order: 'YXZ' },
36
+ note: FLAT_NOTE,
37
+ },
38
+ behind: hits.some((hit) => hit.behind),
39
+ };
40
+ };
41
+ /**
42
+ * Free pose (position, lean, roll) of a rectangle whose width, height or both
43
+ * are known. With one side known the other is solved, less well determined.
44
+ */
45
+ export const rectOfKnownSize = (camera, size, corners, known) => {
46
+ const { width, height } = known;
47
+ if (width === undefined && height === undefined) {
48
+ throw new SceneArgumentError('rect needs --plane-y, or --width and/or --height');
49
+ }
50
+ const seed = Math.max(...[width, height].filter((value) => value !== undefined));
51
+ const solvedSide = width === undefined || height === undefined ? 1 : 0;
52
+ const centroid = corners.reduce((total, [u, v]) => [total[0] + u / corners.length, total[1] + v / corners.length], [0, 0]);
53
+ const ray = pixelRay(camera, size, centroid[0], centroid[1]);
54
+ const sides = (p) => [
55
+ width ?? p[6],
56
+ height ?? p[6],
57
+ ];
58
+ const residuals = (p) => {
59
+ const [w, h] = sides(p);
60
+ const local = [[-w / 2, h / 2, 0], [w / 2, h / 2, 0], [w / 2, -h / 2, 0], [-w / 2, -h / 2, 0]];
61
+ // Euler YXZ with rotation.set(x = p[4], y = p[3], z = p[5]); lean is rotation.x.
62
+ const r = rotationMatrix(p[3], p[4], p[5]);
63
+ const world = local.map((point) => [
64
+ r[0][0] * point[0] + r[0][1] * point[1] + r[0][2] * point[2] + p[0],
65
+ r[1][0] * point[0] + r[1][1] * point[1] + r[1][2] * point[2] + p[1],
66
+ r[2][0] * point[0] + r[2][1] * point[1] + r[2][2] * point[2] + p[2],
67
+ ]);
68
+ const projected = projectPoints(camera, world, size);
69
+ const out = new Float64Array(8);
70
+ projected.forEach((projection, index) => {
71
+ const penalty = Math.max(projection.depth + 0.01, 0) * 1e4;
72
+ out[2 * index] = projection.u - corners[index][0] + penalty;
73
+ out[2 * index + 1] = projection.v - corners[index][1] + penalty;
74
+ });
75
+ return out;
76
+ };
77
+ const random = seededRandom(2);
78
+ const starts = [];
79
+ for (let index = 0; index < 300; index += 1) {
80
+ const reach = random.uniform(0.2, 3) * seed * 3;
81
+ const start = [
82
+ camera.pos[0] + ray[0] * reach,
83
+ camera.pos[1] + ray[1] * reach,
84
+ camera.pos[2] + ray[2] * reach,
85
+ random.uniform(-1.2, 1.2),
86
+ random.uniform(-1.4, 1.4),
87
+ random.uniform(-0.6, 0.6),
88
+ ];
89
+ if (solvedSide)
90
+ start.push(seed * random.uniform(0.5, 2));
91
+ starts.push(Float64Array.from(start));
92
+ }
93
+ const low = [-1e4, -1e4, -1e4, -4, -1.6, -3.2, ...(solvedSide ? [seed * 0.05] : [])];
94
+ const high = [1e4, 1e4, 1e4, 4, 1.6, 3.2, ...(solvedSide ? [seed * 20] : [])];
95
+ const best = multistart(residuals, starts, low, high);
96
+ const p = best.parameters;
97
+ const [w, h] = sides(p);
98
+ return {
99
+ position: [roundTo(p[0], 4), roundTo(p[1], 4), roundTo(p[2], 4)],
100
+ w: roundTo(w, 4),
101
+ h: roundTo(h, 4),
102
+ rotation: { x: roundTo(p[4], 6), y: roundTo(p[3], 6), z: roundTo(p[5], 6), order: 'YXZ' },
103
+ rmsPx: roundTo(Math.sqrt(best.cost / 8), 2),
104
+ note: (solvedSide ? SOLVED_SIDE_NOTE : '') + AMBIGUITY_NOTE,
105
+ };
106
+ };
107
+ //# sourceMappingURL=placement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placement.js","sourceRoot":"","sources":["../../src/scene/placement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 8-bit RGB pixels in memory: the one image shape every scene helper works on.
3
+ * Alpha is dropped without compositing, as the Python helpers' convert("RGB")
4
+ * did, and before any resize so a transparent edge never bleeds into colour.
5
+ */
6
+ export type RgbImage = {
7
+ data: Buffer;
8
+ width: number;
9
+ height: number;
10
+ };
11
+ export declare const readRgb: (file: string) => Promise<RgbImage>;
12
+ /** Lanczos resize to an exact size; the same size is returned untouched. */
13
+ export declare const resizeRgb: (image: RgbImage, width: number, height: number) => Promise<RgbImage>;
14
+ export declare const readRgbAt: (file: string, width: number, height: number) => Promise<RgbImage>;
15
+ /** PNG bytes of an in-memory image. */
16
+ export declare const encodePng: (image: RgbImage) => Promise<Buffer>;
17
+ export declare const writePng: (image: RgbImage, file: string) => Promise<void>;
18
+ //# sourceMappingURL=raster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raster.d.ts","sourceRoot":"","sources":["../../src/scene/raster.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,eAAO,MAAM,OAAO,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,QAAQ,CAQ5D,CAAC;AAMF,4EAA4E;AAC5E,eAAO,MAAM,SAAS,GAAU,OAAO,QAAQ,EAAE,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,QAAQ,CAOhG,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,QAAQ,CAE7F,CAAC;AAEF,uCAAuC;AACvC,eAAO,MAAM,SAAS,GAAU,OAAO,QAAQ,KAAG,OAAO,CAAC,MAAM,CAE/D,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAU,OAAO,QAAQ,EAAE,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,CAE1E,CAAC"}