@xom11/whiteboard 0.29.0 → 0.31.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 (93) hide show
  1. package/dist/ai.d.mts +259 -33
  2. package/dist/ai.d.ts +259 -33
  3. package/dist/ai.js +5424 -470
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +4971 -351
  6. package/dist/ai.mjs.map +1 -1
  7. package/dist/catalog.json +5 -5
  8. package/dist/{chunk-V3YJ6JFL.mjs → chunk-44JY2AKC.mjs} +3 -3
  9. package/dist/{chunk-V3YJ6JFL.mjs.map → chunk-44JY2AKC.mjs.map} +1 -1
  10. package/dist/{chunk-GEC2D2EQ.mjs → chunk-BMYC2ILT.mjs} +4 -4
  11. package/dist/{chunk-GEC2D2EQ.mjs.map → chunk-BMYC2ILT.mjs.map} +1 -1
  12. package/dist/{chunk-PPKHCRRE.mjs → chunk-C76SOFXF.mjs} +3 -3
  13. package/dist/{chunk-PPKHCRRE.mjs.map → chunk-C76SOFXF.mjs.map} +1 -1
  14. package/dist/{chunk-IHUFOV7L.mjs → chunk-CH6SFONH.mjs} +15 -3
  15. package/dist/chunk-CH6SFONH.mjs.map +1 -0
  16. package/dist/{chunk-E6EDOPGT.mjs → chunk-DWIEVCGK.mjs} +254 -16
  17. package/dist/chunk-DWIEVCGK.mjs.map +1 -0
  18. package/dist/{chunk-SZDAS7LK.mjs → chunk-IE2GGHNF.mjs} +131 -81
  19. package/dist/chunk-IE2GGHNF.mjs.map +1 -0
  20. package/dist/{chunk-ZTQBUKLJ.mjs → chunk-JJ4FPCBE.mjs} +142 -22
  21. package/dist/chunk-JJ4FPCBE.mjs.map +1 -0
  22. package/dist/{chunk-QRUAEXLR.mjs → chunk-K5BS2H56.mjs} +5 -5
  23. package/dist/{chunk-QRUAEXLR.mjs.map → chunk-K5BS2H56.mjs.map} +1 -1
  24. package/dist/{chunk-BNBOIDO5.mjs → chunk-K7VJU7LQ.mjs} +3 -3
  25. package/dist/{chunk-BNBOIDO5.mjs.map → chunk-K7VJU7LQ.mjs.map} +1 -1
  26. package/dist/{chunk-H22OZYTW.mjs → chunk-KOXOC2FI.mjs} +48 -39
  27. package/dist/chunk-KOXOC2FI.mjs.map +1 -0
  28. package/dist/{chunk-CXHNVYMD.mjs → chunk-KWDBVLST.mjs} +5 -5
  29. package/dist/{chunk-CXHNVYMD.mjs.map → chunk-KWDBVLST.mjs.map} +1 -1
  30. package/dist/{chunk-OQIQNKPQ.mjs → chunk-LTLLQUMN.mjs} +4 -4
  31. package/dist/{chunk-OQIQNKPQ.mjs.map → chunk-LTLLQUMN.mjs.map} +1 -1
  32. package/dist/chunk-QK6OVDLC.mjs +103 -0
  33. package/dist/chunk-QK6OVDLC.mjs.map +1 -0
  34. package/dist/{chunk-QGNU34T7.mjs → chunk-QLQ4MJNO.mjs} +10 -4
  35. package/dist/chunk-QLQ4MJNO.mjs.map +1 -0
  36. package/dist/{chunk-BU5KLO3P.mjs → chunk-T3N4BSJV.mjs} +4 -4
  37. package/dist/{chunk-BU5KLO3P.mjs.map → chunk-T3N4BSJV.mjs.map} +1 -1
  38. package/dist/{chunk-5JM35CXV.mjs → chunk-TMRFSOM7.mjs} +4 -4
  39. package/dist/{chunk-5JM35CXV.mjs.map → chunk-TMRFSOM7.mjs.map} +1 -1
  40. package/dist/geometry-2d.d.mts +1 -1
  41. package/dist/geometry-2d.d.ts +1 -1
  42. package/dist/geometry-2d.js +841 -204
  43. package/dist/geometry-2d.js.map +1 -1
  44. package/dist/geometry-2d.mjs +5 -5
  45. package/dist/geometry-3d.d.mts +1 -1
  46. package/dist/geometry-3d.d.ts +1 -1
  47. package/dist/geometry-3d.js +172 -22
  48. package/dist/geometry-3d.js.map +1 -1
  49. package/dist/geometry-3d.mjs +4 -4
  50. package/dist/graph-2d.d.mts +1 -1
  51. package/dist/graph-2d.d.ts +1 -1
  52. package/dist/graph-2d.js +307 -100
  53. package/dist/graph-2d.js.map +1 -1
  54. package/dist/graph-2d.mjs +7 -7
  55. package/dist/handleExtractProblem-BrDY9ifM.d.mts +58 -0
  56. package/dist/handleExtractProblem-BrDY9ifM.d.ts +58 -0
  57. package/dist/{host-HOSJHQ5H.mjs → host-4FIUNIDQ.mjs} +13 -12
  58. package/dist/host-4FIUNIDQ.mjs.map +1 -0
  59. package/dist/{host-2ISGVO7O.mjs → host-4ZB4XD4S.mjs} +9 -8
  60. package/dist/host-4ZB4XD4S.mjs.map +1 -0
  61. package/dist/{host-ZQCDAT6O.mjs → host-H2IGOKJU.mjs} +3 -3
  62. package/dist/{host-ZQCDAT6O.mjs.map → host-H2IGOKJU.mjs.map} +1 -1
  63. package/dist/{host-HKMZSCIT.mjs → host-KMWP7KBT.mjs} +286 -74
  64. package/dist/host-KMWP7KBT.mjs.map +1 -0
  65. package/dist/index.d.mts +3 -2
  66. package/dist/index.d.ts +3 -2
  67. package/dist/index.js +849 -206
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +22 -21
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/latex.d.mts +1 -1
  72. package/dist/latex.d.ts +1 -1
  73. package/dist/latex.js +8 -2
  74. package/dist/latex.js.map +1 -1
  75. package/dist/latex.mjs +1 -1
  76. package/dist/render-NMS7OAV6.mjs +10 -0
  77. package/dist/{render-ZX2O2IK7.mjs.map → render-NMS7OAV6.mjs.map} +1 -1
  78. package/dist/serialize-PGHQZEPV.mjs +9 -0
  79. package/dist/{serialize-N4G6RFBB.mjs.map → serialize-PGHQZEPV.mjs.map} +1 -1
  80. package/dist/{types-C3FjpoUi.d.ts → types-tePd94vW.d.mts} +8 -0
  81. package/dist/{types-C3FjpoUi.d.mts → types-tePd94vW.d.ts} +8 -0
  82. package/package.json +2 -1
  83. package/dist/chunk-E6EDOPGT.mjs.map +0 -1
  84. package/dist/chunk-H22OZYTW.mjs.map +0 -1
  85. package/dist/chunk-IHUFOV7L.mjs.map +0 -1
  86. package/dist/chunk-QGNU34T7.mjs.map +0 -1
  87. package/dist/chunk-SZDAS7LK.mjs.map +0 -1
  88. package/dist/chunk-ZTQBUKLJ.mjs.map +0 -1
  89. package/dist/host-2ISGVO7O.mjs.map +0 -1
  90. package/dist/host-HKMZSCIT.mjs.map +0 -1
  91. package/dist/host-HOSJHQ5H.mjs.map +0 -1
  92. package/dist/render-ZX2O2IK7.mjs +0 -10
  93. package/dist/serialize-N4G6RFBB.mjs +0 -9
@@ -2,6 +2,79 @@
2
2
  import { getKind } from './chunk-B4NJJZFR.mjs';
3
3
  import { z } from 'zod';
4
4
 
5
+ // src/stamps/geometry-2d/ai/vision/preprocess.ts
6
+ var MAX_EDGE_PX = 2048;
7
+ var MAX_RAW_BYTES = 10 * 1024 * 1024;
8
+ var MAX_ENCODED_BYTES = 3 * 1024 * 1024;
9
+ var ALLOWED_TYPES = ["image/png", "image/jpeg", "image/webp"];
10
+ function inferMediaType(file) {
11
+ const t = file.type.toLowerCase();
12
+ if (ALLOWED_TYPES.includes(t)) return t;
13
+ return null;
14
+ }
15
+ function validateFile(file) {
16
+ const mt = inferMediaType(file);
17
+ if (mt == null) {
18
+ return {
19
+ ok: false,
20
+ code: "invalid-format",
21
+ message: "Ch\u1EC9 h\u1ED7 tr\u1EE3 PNG, JPEG, WEBP."
22
+ };
23
+ }
24
+ if (file.size > MAX_RAW_BYTES) {
25
+ return {
26
+ ok: false,
27
+ code: "too-large",
28
+ message: `\u1EA2nh qu\xE1 l\u1EDBn (> ${Math.round(MAX_RAW_BYTES / 1024 / 1024)} MB). Crop ho\u1EB7c resize tr\u01B0\u1EDBc.`
29
+ };
30
+ }
31
+ return { ok: true, mediaType: mt };
32
+ }
33
+ async function fileToImagePart(file) {
34
+ const v = validateFile(file);
35
+ if (!v.ok) throw new Error(v.message);
36
+ const bitmap = await createImageBitmap(file);
37
+ const { width, height } = bitmap;
38
+ const maxEdge = Math.max(width, height);
39
+ const scale = maxEdge > MAX_EDGE_PX ? MAX_EDGE_PX / maxEdge : 1;
40
+ const targetW = Math.round(width * scale);
41
+ const targetH = Math.round(height * scale);
42
+ const canvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(targetW, targetH) : Object.assign(document.createElement("canvas"), { width: targetW, height: targetH });
43
+ const ctx = canvas.getContext("2d");
44
+ if (!ctx) throw new Error("Kh\xF4ng t\u1EA1o \u0111\u01B0\u1EE3c canvas 2D context");
45
+ ctx.drawImage(bitmap, 0, 0, targetW, targetH);
46
+ bitmap.close();
47
+ let outputType = v.mediaType === "image/png" ? "image/png" : "image/jpeg";
48
+ let finalBlob = await canvasToBlob(canvas, outputType, 0.92);
49
+ if (finalBlob.size > MAX_ENCODED_BYTES) {
50
+ outputType = "image/jpeg";
51
+ finalBlob = await canvasToBlob(canvas, "image/jpeg", 0.7);
52
+ }
53
+ const base64 = await blobToBase64(finalBlob);
54
+ return { mediaType: outputType, base64 };
55
+ }
56
+ async function canvasToBlob(canvas, type, quality) {
57
+ if ("convertToBlob" in canvas) {
58
+ return canvas.convertToBlob({ type, quality });
59
+ }
60
+ return new Promise((resolve, reject) => {
61
+ canvas.toBlob(
62
+ (b) => b ? resolve(b) : reject(new Error("Canvas encode fail")),
63
+ type,
64
+ quality
65
+ );
66
+ });
67
+ }
68
+ async function blobToBase64(blob) {
69
+ const buf = await blob.arrayBuffer();
70
+ let binary = "";
71
+ const bytes = new Uint8Array(buf);
72
+ const chunk = 32768;
73
+ for (let i = 0; i < bytes.length; i += chunk) {
74
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
75
+ }
76
+ return typeof btoa === "function" ? btoa(binary) : Buffer.from(binary, "binary").toString("base64");
77
+ }
5
78
  var NameZ = z.string().regex(/^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/);
6
79
 
7
80
  // src/stamps/geometry-2d/dsl/kinds/_types.ts
@@ -49,6 +122,8 @@ var freeModule = defineModule({
49
122
  y: z.number().finite()
50
123
  }),
51
124
  collectRefs: () => [],
125
+ refSpecs: [],
126
+ // không có ref — khai rỗng để registry-handled tường minh
52
127
  emit: (e, ctx) => [{
53
128
  role: "primary",
54
129
  object: emitPointObject(ctx.resolveId(e.name), e.name, { kind: "free", x: e.x, y: e.y })
@@ -67,6 +142,10 @@ var midpointModule = defineModule({
67
142
  visible: z.boolean().optional()
68
143
  }),
69
144
  collectRefs: (e) => [e.p1, e.p2],
145
+ refSpecs: [
146
+ { field: "p1", role: "point" },
147
+ { field: "p2", role: "point" }
148
+ ],
70
149
  emit: (e, ctx) => [{
71
150
  role: "primary",
72
151
  object: emitPointObject(
@@ -77,6 +156,29 @@ var midpointModule = defineModule({
77
156
  )
78
157
  }]
79
158
  });
159
+ var onPerpBisectorModule = defineModule({
160
+ kind: "onPerpBisector",
161
+ role: "point",
162
+ category: "points",
163
+ prefix: "p",
164
+ schema: z.object({
165
+ name: NameZ,
166
+ kind: z.literal("onPerpBisector"),
167
+ p1: NameZ,
168
+ p2: NameZ,
169
+ t: z.number().optional()
170
+ }),
171
+ collectRefs: (e) => [e.p1, e.p2],
172
+ emit: (e, ctx) => [{
173
+ role: "primary",
174
+ object: emitPointObject(ctx.resolveId(e.name), e.name, {
175
+ kind: "onPerpBisector",
176
+ p1: ctx.resolveId(e.p1),
177
+ p2: ctx.resolveId(e.p2),
178
+ t: e.t ?? 3
179
+ })
180
+ }]
181
+ });
80
182
  var onSegmentModule = defineModule({
81
183
  kind: "onSegment",
82
184
  role: "point",
@@ -89,6 +191,7 @@ var onSegmentModule = defineModule({
89
191
  t: z.number().min(0).max(1)
90
192
  }),
91
193
  collectRefs: (e) => [e.segmentId],
194
+ refSpecs: [{ field: "segmentId", role: "segment" }],
92
195
  emit: (e, ctx) => [{
93
196
  role: "primary",
94
197
  object: emitPointObject(
@@ -110,6 +213,7 @@ var onLineModule = defineModule({
110
213
  t: z.number().finite()
111
214
  }),
112
215
  collectRefs: (e) => [e.lineId],
216
+ refSpecs: [{ field: "lineId", role: "line-like" }],
113
217
  emit: (e, ctx) => [{
114
218
  role: "primary",
115
219
  object: emitPointObject(
@@ -131,6 +235,7 @@ var onCircleModule = defineModule({
131
235
  theta: z.number().finite()
132
236
  }),
133
237
  collectRefs: (e) => [e.circleId],
238
+ refSpecs: [{ field: "circleId", role: "circle" }],
134
239
  emit: (e, ctx) => [{
135
240
  role: "primary",
136
241
  object: emitPointObject(
@@ -152,6 +257,10 @@ var perpFootModule = defineModule({
152
257
  onLine: NameZ
153
258
  }),
154
259
  collectRefs: (e) => [e.from, e.onLine],
260
+ refSpecs: [
261
+ { field: "from", role: "point" },
262
+ { field: "onLine", role: "line-like" }
263
+ ],
155
264
  emit: (e, ctx) => [{
156
265
  role: "primary",
157
266
  object: emitPointObject(
@@ -172,6 +281,7 @@ var circumcenterModule = defineModule({
172
281
  vertices: z.tuple([NameZ, NameZ, NameZ])
173
282
  }),
174
283
  collectRefs: (e) => [...e.vertices],
284
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
175
285
  emit: (e, ctx) => [{
176
286
  role: "primary",
177
287
  object: emitPointObject(
@@ -192,6 +302,7 @@ var incenterModule = defineModule({
192
302
  vertices: z.tuple([NameZ, NameZ, NameZ])
193
303
  }),
194
304
  collectRefs: (e) => [...e.vertices],
305
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
195
306
  emit: (e, ctx) => [{
196
307
  role: "primary",
197
308
  object: emitPointObject(
@@ -212,6 +323,7 @@ var centroidModule = defineModule({
212
323
  vertices: z.tuple([NameZ, NameZ, NameZ])
213
324
  }),
214
325
  collectRefs: (e) => [...e.vertices],
326
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
215
327
  emit: (e, ctx) => [{
216
328
  role: "primary",
217
329
  object: emitPointObject(
@@ -232,6 +344,7 @@ var orthocenterModule = defineModule({
232
344
  vertices: z.tuple([NameZ, NameZ, NameZ])
233
345
  }),
234
346
  collectRefs: (e) => [...e.vertices],
347
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
235
348
  emit: (e, ctx) => [{
236
349
  role: "primary",
237
350
  object: emitPointObject(
@@ -254,6 +367,10 @@ var intersectionModule = defineModule({
254
367
  branch: z.union([z.literal(0), z.literal(1)]).optional()
255
368
  }),
256
369
  collectRefs: (e) => [e.ref1, e.ref2],
370
+ refSpecs: [
371
+ { field: "ref1", role: "line-or-circle" },
372
+ { field: "ref2", role: "line-or-circle" }
373
+ ],
257
374
  emit: (e, ctx) => {
258
375
  const r1IsCircle = ctx.hintOf(e.ref1) === "circle";
259
376
  const r2IsCircle = ctx.hintOf(e.ref2) === "circle";
@@ -293,6 +410,10 @@ var segmentModule = defineModule({
293
410
  p2: NameZ
294
411
  }),
295
412
  collectRefs: (e) => [e.p1, e.p2],
413
+ refSpecs: [
414
+ { field: "p1", role: "point" },
415
+ { field: "p2", role: "point" }
416
+ ],
296
417
  emit: (e, ctx) => [{
297
418
  role: "primary",
298
419
  object: {
@@ -316,6 +437,10 @@ var lineModule = defineModule({
316
437
  p2: NameZ
317
438
  }),
318
439
  collectRefs: (e) => [e.p1, e.p2],
440
+ refSpecs: [
441
+ { field: "p1", role: "point" },
442
+ { field: "p2", role: "point" }
443
+ ],
319
444
  emit: (e, ctx) => [{
320
445
  role: "primary",
321
446
  object: {
@@ -339,6 +464,10 @@ var rayModule = defineModule({
339
464
  through: NameZ
340
465
  }),
341
466
  collectRefs: (e) => [e.origin, e.through],
467
+ refSpecs: [
468
+ { field: "origin", role: "point" },
469
+ { field: "through", role: "point" }
470
+ ],
342
471
  emit: (e, ctx) => [{
343
472
  role: "primary",
344
473
  object: {
@@ -362,6 +491,10 @@ var perpendicularModule = defineModule({
362
491
  toLine: NameZ
363
492
  }),
364
493
  collectRefs: (e) => [e.throughPoint, e.toLine],
494
+ refSpecs: [
495
+ { field: "throughPoint", role: "point" },
496
+ { field: "toLine", role: "line-like" }
497
+ ],
365
498
  emit: (e, ctx) => [{
366
499
  role: "primary",
367
500
  object: {
@@ -391,6 +524,10 @@ var parallelModule = defineModule({
391
524
  toLine: NameZ
392
525
  }),
393
526
  collectRefs: (e) => [e.throughPoint, e.toLine],
527
+ refSpecs: [
528
+ { field: "throughPoint", role: "point" },
529
+ { field: "toLine", role: "line-like" }
530
+ ],
394
531
  emit: (e, ctx) => [{
395
532
  role: "primary",
396
533
  object: {
@@ -420,6 +557,10 @@ var perpBisectorModule = defineModule({
420
557
  p2: NameZ
421
558
  }),
422
559
  collectRefs: (e) => [e.p1, e.p2],
560
+ refSpecs: [
561
+ { field: "p1", role: "point" },
562
+ { field: "p2", role: "point" }
563
+ ],
423
564
  emit: (e, ctx) => [{
424
565
  role: "primary",
425
566
  object: {
@@ -450,6 +591,11 @@ var angleBisectorModule = defineModule({
450
591
  p2: NameZ
451
592
  }),
452
593
  collectRefs: (e) => [e.p1, e.vertex, e.p2],
594
+ refSpecs: [
595
+ { field: "p1", role: "point" },
596
+ { field: "vertex", role: "point" },
597
+ { field: "p2", role: "point" }
598
+ ],
453
599
  emit: (e, ctx) => [{
454
600
  role: "primary",
455
601
  object: {
@@ -542,6 +688,10 @@ var tangentModule = defineModule({
542
688
  branch: z.union([z.literal(0), z.literal(1), z.literal("on")]).optional()
543
689
  }),
544
690
  collectRefs: (e) => [e.throughPoint, e.toCircle],
691
+ refSpecs: [
692
+ { field: "throughPoint", role: "point" },
693
+ { field: "toCircle", role: "circle" }
694
+ ],
545
695
  emit: (e, ctx) => {
546
696
  const construction = {
547
697
  kind: "tangent",
@@ -572,6 +722,7 @@ var polygonModule = defineModule({
572
722
  vertices: z.array(NameZ).min(3)
573
723
  }),
574
724
  collectRefs: (e) => [...e.vertices],
725
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
575
726
  emit: (e, ctx) => [{
576
727
  role: "primary",
577
728
  object: {
@@ -596,6 +747,10 @@ var circleCPModule = defineModule({
596
747
  visible: z.boolean().optional()
597
748
  }),
598
749
  collectRefs: (e) => [e.center, e.surfacePoint],
750
+ refSpecs: [
751
+ { field: "center", role: "point" },
752
+ { field: "surfacePoint", role: "point" }
753
+ ],
599
754
  emit: (e, ctx) => [{
600
755
  role: "primary",
601
756
  object: {
@@ -621,6 +776,11 @@ var circle3Module = defineModule({
621
776
  p3: NameZ
622
777
  }),
623
778
  collectRefs: (e) => [e.p1, e.p2, e.p3],
779
+ refSpecs: [
780
+ { field: "p1", role: "point" },
781
+ { field: "p2", role: "point" },
782
+ { field: "p3", role: "point" }
783
+ ],
624
784
  emit: (e, ctx) => [{
625
785
  role: "primary",
626
786
  object: {
@@ -925,9 +1085,30 @@ var arcMidpointModule = defineModule({
925
1085
  circle: NameZ,
926
1086
  a: NameZ,
927
1087
  b: NameZ,
928
- notContaining: NameZ
1088
+ // Đúng 1 trong notContaining / containing — bất biến cứng kiểm ở
1089
+ // scene-constraint validate (không .refine vì registry dựng
1090
+ // discriminatedUnion yêu cầu ZodObject thuần).
1091
+ notContaining: NameZ.optional(),
1092
+ containing: NameZ.optional()
929
1093
  }),
930
- collectRefs: (e) => [e.circle, e.a, e.b, e.notContaining],
1094
+ collectRefs: (e) => {
1095
+ const refs = [e.circle, e.a, e.b];
1096
+ const containment = e.notContaining ?? e.containing;
1097
+ if (containment) refs.push(containment);
1098
+ return refs;
1099
+ },
1100
+ // refSpecs động: notContaining/containing TỐI ĐA 1 — có thể không có (cung không mơ hồ).
1101
+ refSpecs: (e) => {
1102
+ const specs = [
1103
+ { field: "circle", role: "circle" },
1104
+ { field: "a", role: "point" },
1105
+ { field: "b", role: "point" }
1106
+ ];
1107
+ if (e.containing ?? e.notContaining) {
1108
+ specs.push({ field: e.containing ? "containing" : "notContaining", role: "point" });
1109
+ }
1110
+ return specs;
1111
+ },
931
1112
  emit: (e, ctx) => [{
932
1113
  role: "primary",
933
1114
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -935,7 +1116,8 @@ var arcMidpointModule = defineModule({
935
1116
  circle: ctx.resolveId(e.circle),
936
1117
  a: ctx.resolveId(e.a),
937
1118
  b: ctx.resolveId(e.b),
938
- notContaining: ctx.resolveId(e.notContaining)
1119
+ // notContaining/containing optional: cung KHÔNG mơ hồ (nửa đường tròn) → bỏ cả hai.
1120
+ ...e.containing ? { containing: ctx.resolveId(e.containing) } : e.notContaining ? { notContaining: ctx.resolveId(e.notContaining) } : {}
939
1121
  })
940
1122
  }]
941
1123
  });
@@ -951,6 +1133,10 @@ var excenterModule = defineModule({
951
1133
  opposite: NameZ
952
1134
  }),
953
1135
  collectRefs: (e) => [...e.vertices],
1136
+ refSpecs: [
1137
+ { field: "vertices", role: "point", many: true },
1138
+ { field: "opposite", role: "point" }
1139
+ ],
954
1140
  emit: (e, ctx) => [{
955
1141
  role: "primary",
956
1142
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -960,6 +1146,27 @@ var excenterModule = defineModule({
960
1146
  })
961
1147
  }]
962
1148
  });
1149
+ var mixtilinearPointModule = defineModule({
1150
+ kind: "mixtilinearPoint",
1151
+ role: "point",
1152
+ category: "points",
1153
+ prefix: "p",
1154
+ schema: z.object({
1155
+ name: NameZ,
1156
+ kind: z.literal("mixtilinearPoint"),
1157
+ vertices: z.tuple([NameZ, NameZ, NameZ]),
1158
+ which: z.union([z.literal("center"), z.literal("touch")])
1159
+ }),
1160
+ collectRefs: (e) => [...e.vertices],
1161
+ emit: (e, ctx) => [{
1162
+ role: "primary",
1163
+ object: emitPointObject(ctx.resolveId(e.name), e.name, {
1164
+ kind: "mixtilinearPoint",
1165
+ vertices: resolveTriangleVertices(ctx, e.vertices),
1166
+ which: e.which
1167
+ })
1168
+ }]
1169
+ });
963
1170
  var reflectPointModule = defineModule({
964
1171
  kind: "reflectPoint",
965
1172
  role: "point",
@@ -967,6 +1174,10 @@ var reflectPointModule = defineModule({
967
1174
  prefix: "p",
968
1175
  schema: z.object({ name: NameZ, kind: z.literal("reflectPoint"), of: NameZ, through: NameZ }),
969
1176
  collectRefs: (e) => [e.of, e.through],
1177
+ refSpecs: [
1178
+ { field: "of", role: "point" },
1179
+ { field: "through", role: "point" }
1180
+ ],
970
1181
  emit: (e, ctx) => [{
971
1182
  role: "primary",
972
1183
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -983,6 +1194,10 @@ var reflectLineModule = defineModule({
983
1194
  prefix: "p",
984
1195
  schema: z.object({ name: NameZ, kind: z.literal("reflectLine"), of: NameZ, through: NameZ }),
985
1196
  collectRefs: (e) => [e.of, e.through],
1197
+ refSpecs: [
1198
+ { field: "of", role: "point" },
1199
+ { field: "through", role: "line-like" }
1200
+ ],
986
1201
  emit: (e, ctx) => [{
987
1202
  role: "primary",
988
1203
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -1024,12 +1239,25 @@ var pointAtDistanceModule = defineModule({
1024
1239
  const extra = d.kind === "circleRadius" ? [d.circle] : d.kind === "segmentLength" ? [d.p1, d.p2] : [];
1025
1240
  return [e.from, e.through, ...extra];
1026
1241
  },
1027
- // TODO(Mức 1 defer): distance.{circle,p1,p2} nested trong `distance` refSpec
1028
- // phẳng đọc top-level không với tới, validate riêng nếu cần. Hiện validate from/through.
1029
- refSpecs: [
1030
- { field: "from", role: "point" },
1031
- { field: "through", role: "point" }
1032
- ],
1242
+ // refSpecs động: distance.{circle,p1,p2} nested validate qua dotted path
1243
+ // ('distance.circle' runSpecs transpile/refs.ts đọc bằng reduce theo '.').
1244
+ refSpecs: (e) => {
1245
+ const base = [
1246
+ { field: "from", role: "point" },
1247
+ { field: "through", role: "point" }
1248
+ ];
1249
+ if (e.distance.kind === "circleRadius") {
1250
+ return [...base, { field: "distance.circle", role: "circle" }];
1251
+ }
1252
+ if (e.distance.kind === "segmentLength") {
1253
+ return [
1254
+ ...base,
1255
+ { field: "distance.p1", role: "point" },
1256
+ { field: "distance.p2", role: "point" }
1257
+ ];
1258
+ }
1259
+ return base;
1260
+ },
1033
1261
  emit: (e, ctx) => {
1034
1262
  const d = e.distance;
1035
1263
  const distance = d.kind === "circleRadius" ? withScaleOffset({ kind: "circleRadius", circle: ctx.resolveId(d.circle) }, d) : d.kind === "segmentLength" ? withScaleOffset({ kind: "segmentLength", p1: ctx.resolveId(d.p1), p2: ctx.resolveId(d.p2) }, d) : withScaleOffset({ kind: "literal", value: d.value }, d);
@@ -1049,6 +1277,7 @@ var pointAtDistanceModule = defineModule({
1049
1277
  var ALL_MODULES = [
1050
1278
  freeModule,
1051
1279
  midpointModule,
1280
+ onPerpBisectorModule,
1052
1281
  onSegmentModule,
1053
1282
  onLineModule,
1054
1283
  onCircleModule,
@@ -1085,6 +1314,7 @@ var ALL_MODULES = [
1085
1314
  // Cụm A points
1086
1315
  arcMidpointModule,
1087
1316
  excenterModule,
1317
+ mixtilinearPointModule,
1088
1318
  reflectPointModule,
1089
1319
  reflectLineModule,
1090
1320
  // Cụm B points
@@ -1221,8 +1451,11 @@ function serializePoint(obj, state) {
1221
1451
  };
1222
1452
  }
1223
1453
  case "arcMidpoint": {
1224
- const refs = resolveRefs([c.circle, c.a, c.b, c.notContaining], state);
1225
- if (!refs) return fail("unresolved-ref", `${c.circle},${c.a},${c.b},${c.notContaining}`);
1454
+ const containment = c.containing ?? c.notContaining;
1455
+ const baseRefs = [c.circle, c.a, c.b];
1456
+ if (containment) baseRefs.push(containment);
1457
+ const refs = resolveRefs(baseRefs, state);
1458
+ if (!refs) return fail("unresolved-ref", baseRefs.join(","));
1226
1459
  return {
1227
1460
  ok: true,
1228
1461
  entity: {
@@ -1231,7 +1464,7 @@ function serializePoint(obj, state) {
1231
1464
  circle: refs[0],
1232
1465
  a: refs[1],
1233
1466
  b: refs[2],
1234
- notContaining: refs[3]
1467
+ ...c.containing ? { containing: refs[3] } : c.notContaining ? { notContaining: refs[3] } : {}
1235
1468
  }
1236
1469
  };
1237
1470
  }
@@ -1275,6 +1508,7 @@ function serializePoint(obj, state) {
1275
1508
  case "onPerpendicular":
1276
1509
  case "onPerpBisector":
1277
1510
  case "onCircleAroundPoint":
1511
+ case "mixtilinearPoint":
1278
1512
  return fail("unsupported-constraint", c.kind);
1279
1513
  default: {
1280
1514
  return fail("unsupported-constraint");
@@ -1571,9 +1805,11 @@ function describeEntity(e) {
1571
1805
  return `${e.name} = \u0111\u01B0\u1EDDng tr\xF2n b\xE0ng ti\u1EBFp ${e.vertices.join("")} \u0111\u1ED1i di\u1EC7n ${e.opposite}`;
1572
1806
  // Cụm A
1573
1807
  case "arcMidpoint":
1574
- return `${e.name} = trung \u0111i\u1EC3m cung ${e.a}${e.b} (kh\xF4ng ch\u1EE9a ${e.notContaining}) tr\xEAn ${e.circle}`;
1808
+ return `${e.name} = trung \u0111i\u1EC3m cung ${e.a}${e.b}${e.containing || e.notContaining ? ` (${e.containing ? "ch\u1EE9a" : "kh\xF4ng ch\u1EE9a"} ${e.containing ?? e.notContaining})` : ""} tr\xEAn ${e.circle}`;
1575
1809
  case "excenter":
1576
1810
  return `${e.name} = t\xE2m b\xE0ng ti\u1EBFp ${e.vertices.join("")} \u0111\u1ED1i di\u1EC7n ${e.opposite}`;
1811
+ case "mixtilinearPoint":
1812
+ return `${e.name} = ${e.which === "center" ? "t\xE2m" : "ti\u1EBFp \u0111i\u1EC3m"} mixtilinear ${e.vertices.join("")}`;
1577
1813
  case "reflectPoint":
1578
1814
  return `${e.name} = \u0111\u1ED1i x\u1EE9ng ${e.of} qua \u0111i\u1EC3m ${e.through}`;
1579
1815
  case "reflectLine":
@@ -1584,6 +1820,8 @@ function describeEntity(e) {
1584
1820
  const distStr = d.kind === "circleRadius" ? `r(${d.circle})` : d.kind === "segmentLength" ? `|${d.p1}${d.p2}|` : `${d.value}`;
1585
1821
  return `${e.name} = \u0111i\u1EC3m tr\xEAn tia ${e.from}${e.through} c\xE1ch ${e.through} m\u1ED9t kho\u1EA3ng ${distStr}`;
1586
1822
  }
1823
+ case "onPerpBisector":
1824
+ return `${e.name} = \u0111i\u1EC3m tr\xEAn trung tr\u1EF1c ${e.p1}${e.p2}`;
1587
1825
  default: {
1588
1826
  return "";
1589
1827
  }
@@ -1601,6 +1839,6 @@ function describeDsl(obj, state) {
1601
1839
  return `${base} (kh\xF4ng h\u1ED7 tr\u1EE3 DSL)`;
1602
1840
  }
1603
1841
 
1604
- export { CIRCLE_KINDS, KIND_REGISTRY, LINE_LIKE_SHAPE_KINDS, POINT_KINDS, describeDsl };
1605
- //# sourceMappingURL=chunk-E6EDOPGT.mjs.map
1606
- //# sourceMappingURL=chunk-E6EDOPGT.mjs.map
1842
+ export { CIRCLE_KINDS, KIND_REGISTRY, LINE_LIKE_SHAPE_KINDS, POINT_KINDS, describeDsl, fileToImagePart, inferMediaType, validateFile };
1843
+ //# sourceMappingURL=chunk-DWIEVCGK.mjs.map
1844
+ //# sourceMappingURL=chunk-DWIEVCGK.mjs.map