@xom11/whiteboard 0.30.0 → 0.32.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 (99) hide show
  1. package/dist/ai.d.mts +374 -59
  2. package/dist/ai.d.ts +374 -59
  3. package/dist/ai.js +7542 -545
  4. package/dist/ai.js.map +1 -1
  5. package/dist/ai.mjs +7243 -569
  6. package/dist/ai.mjs.map +1 -1
  7. package/dist/catalog.json +5 -5
  8. package/dist/{chunk-ZTQBUKLJ.mjs → chunk-4EXRNZRX.mjs} +781 -95
  9. package/dist/chunk-4EXRNZRX.mjs.map +1 -0
  10. package/dist/{chunk-PPKHCRRE.mjs → chunk-C76SOFXF.mjs} +3 -3
  11. package/dist/{chunk-PPKHCRRE.mjs.map → chunk-C76SOFXF.mjs.map} +1 -1
  12. package/dist/{chunk-IHUFOV7L.mjs → chunk-CH6SFONH.mjs} +15 -3
  13. package/dist/chunk-CH6SFONH.mjs.map +1 -0
  14. package/dist/{chunk-XVVLT6B3.mjs → chunk-DBG6DZ2V.mjs} +4 -4
  15. package/dist/{chunk-XVVLT6B3.mjs.map → chunk-DBG6DZ2V.mjs.map} +1 -1
  16. package/dist/{chunk-BU5KLO3P.mjs → chunk-DCFZTKFE.mjs} +14 -6
  17. package/dist/chunk-DCFZTKFE.mjs.map +1 -0
  18. package/dist/{chunk-SF3U7ZF4.mjs → chunk-DJM5EWTT.mjs} +231 -16
  19. package/dist/chunk-DJM5EWTT.mjs.map +1 -0
  20. package/dist/{chunk-V3YJ6JFL.mjs → chunk-F42MZ745.mjs} +3 -3
  21. package/dist/{chunk-V3YJ6JFL.mjs.map → chunk-F42MZ745.mjs.map} +1 -1
  22. package/dist/{chunk-5JM35CXV.mjs → chunk-FI2MGX5H.mjs} +4 -4
  23. package/dist/{chunk-5JM35CXV.mjs.map → chunk-FI2MGX5H.mjs.map} +1 -1
  24. package/dist/{chunk-SZDAS7LK.mjs → chunk-IE2GGHNF.mjs} +131 -81
  25. package/dist/chunk-IE2GGHNF.mjs.map +1 -0
  26. package/dist/{chunk-BNBOIDO5.mjs → chunk-K7VJU7LQ.mjs} +3 -3
  27. package/dist/{chunk-BNBOIDO5.mjs.map → chunk-K7VJU7LQ.mjs.map} +1 -1
  28. package/dist/{chunk-H22OZYTW.mjs → chunk-KLGPAMJS.mjs} +55 -43
  29. package/dist/chunk-KLGPAMJS.mjs.map +1 -0
  30. package/dist/{chunk-CXHNVYMD.mjs → chunk-KWDBVLST.mjs} +5 -5
  31. package/dist/{chunk-CXHNVYMD.mjs.map → chunk-KWDBVLST.mjs.map} +1 -1
  32. package/dist/{chunk-73Q7ADVL.mjs → chunk-MNHOFOM5.mjs} +2 -2
  33. package/dist/{chunk-73Q7ADVL.mjs.map → chunk-MNHOFOM5.mjs.map} +1 -1
  34. package/dist/{chunk-QRUAEXLR.mjs → chunk-MOAXHVKI.mjs} +5 -5
  35. package/dist/{chunk-QRUAEXLR.mjs.map → chunk-MOAXHVKI.mjs.map} +1 -1
  36. package/dist/{chunk-QGNU34T7.mjs → chunk-QLQ4MJNO.mjs} +10 -4
  37. package/dist/chunk-QLQ4MJNO.mjs.map +1 -0
  38. package/dist/chunk-SUXIMLYN.mjs +238 -0
  39. package/dist/chunk-SUXIMLYN.mjs.map +1 -0
  40. package/dist/{chunk-OQIQNKPQ.mjs → chunk-XSTGTEGP.mjs} +5 -5
  41. package/dist/{chunk-OQIQNKPQ.mjs.map → chunk-XSTGTEGP.mjs.map} +1 -1
  42. package/dist/geometry-2d.d.mts +1 -1
  43. package/dist/geometry-2d.d.ts +1 -1
  44. package/dist/geometry-2d.js +1329 -288
  45. package/dist/geometry-2d.js.map +1 -1
  46. package/dist/geometry-2d.mjs +6 -6
  47. package/dist/geometry-3d.d.mts +1 -1
  48. package/dist/geometry-3d.d.ts +1 -1
  49. package/dist/geometry-3d.js +4136 -462
  50. package/dist/geometry-3d.js.map +1 -1
  51. package/dist/geometry-3d.mjs +5 -5
  52. package/dist/graph-2d.d.mts +1 -1
  53. package/dist/graph-2d.d.ts +1 -1
  54. package/dist/graph-2d.js +1010 -208
  55. package/dist/graph-2d.js.map +1 -1
  56. package/dist/graph-2d.mjs +8 -8
  57. package/dist/{handleExtractProblem-BrDY9ifM.d.ts → handleExtractProblem-mtJyhEw3.d.mts} +2 -0
  58. package/dist/{handleExtractProblem-BrDY9ifM.d.mts → handleExtractProblem-mtJyhEw3.d.ts} +2 -0
  59. package/dist/{host-ZQCDAT6O.mjs → host-H2IGOKJU.mjs} +3 -3
  60. package/dist/{host-ZQCDAT6O.mjs.map → host-H2IGOKJU.mjs.map} +1 -1
  61. package/dist/{host-3UFGFMJ2.mjs → host-JNLJ5BVR.mjs} +92 -45
  62. package/dist/host-JNLJ5BVR.mjs.map +1 -0
  63. package/dist/{host-HOSJHQ5H.mjs → host-VRWLQSMH.mjs} +14 -13
  64. package/dist/host-VRWLQSMH.mjs.map +1 -0
  65. package/dist/host-W4U6YCSX.mjs +4973 -0
  66. package/dist/host-W4U6YCSX.mjs.map +1 -0
  67. package/dist/index.d.mts +3 -3
  68. package/dist/index.d.ts +3 -3
  69. package/dist/index.js +4577 -600
  70. package/dist/index.js.map +1 -1
  71. package/dist/index.mjs +35 -29
  72. package/dist/index.mjs.map +1 -1
  73. package/dist/latex.d.mts +1 -1
  74. package/dist/latex.d.ts +1 -1
  75. package/dist/latex.js +8 -2
  76. package/dist/latex.js.map +1 -1
  77. package/dist/latex.mjs +1 -1
  78. package/dist/render-NMS7OAV6.mjs +10 -0
  79. package/dist/{render-ZX2O2IK7.mjs.map → render-NMS7OAV6.mjs.map} +1 -1
  80. package/dist/serialize-7UZWQQ4I.mjs +9 -0
  81. package/dist/{serialize-N4G6RFBB.mjs.map → serialize-7UZWQQ4I.mjs.map} +1 -1
  82. package/dist/{types-C3FjpoUi.d.mts → types-tePd94vW.d.mts} +8 -0
  83. package/dist/{types-C3FjpoUi.d.ts → types-tePd94vW.d.ts} +8 -0
  84. package/package.json +4 -1
  85. package/dist/chunk-BU5KLO3P.mjs.map +0 -1
  86. package/dist/chunk-H22OZYTW.mjs.map +0 -1
  87. package/dist/chunk-IHUFOV7L.mjs.map +0 -1
  88. package/dist/chunk-QGNU34T7.mjs.map +0 -1
  89. package/dist/chunk-QK6OVDLC.mjs +0 -103
  90. package/dist/chunk-QK6OVDLC.mjs.map +0 -1
  91. package/dist/chunk-SF3U7ZF4.mjs.map +0 -1
  92. package/dist/chunk-SZDAS7LK.mjs.map +0 -1
  93. package/dist/chunk-ZTQBUKLJ.mjs.map +0 -1
  94. package/dist/host-2ISGVO7O.mjs +0 -2377
  95. package/dist/host-2ISGVO7O.mjs.map +0 -1
  96. package/dist/host-3UFGFMJ2.mjs.map +0 -1
  97. package/dist/host-HOSJHQ5H.mjs.map +0 -1
  98. package/dist/render-ZX2O2IK7.mjs +0 -10
  99. package/dist/serialize-N4G6RFBB.mjs +0 -9
@@ -122,6 +122,8 @@ var freeModule = defineModule({
122
122
  y: z.number().finite()
123
123
  }),
124
124
  collectRefs: () => [],
125
+ refSpecs: [],
126
+ // không có ref — khai rỗng để registry-handled tường minh
125
127
  emit: (e, ctx) => [{
126
128
  role: "primary",
127
129
  object: emitPointObject(ctx.resolveId(e.name), e.name, { kind: "free", x: e.x, y: e.y })
@@ -140,6 +142,10 @@ var midpointModule = defineModule({
140
142
  visible: z.boolean().optional()
141
143
  }),
142
144
  collectRefs: (e) => [e.p1, e.p2],
145
+ refSpecs: [
146
+ { field: "p1", role: "point" },
147
+ { field: "p2", role: "point" }
148
+ ],
143
149
  emit: (e, ctx) => [{
144
150
  role: "primary",
145
151
  object: emitPointObject(
@@ -150,6 +156,30 @@ var midpointModule = defineModule({
150
156
  )
151
157
  }]
152
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
+ refSpecs: [{ field: "p1", role: "point" }, { field: "p2", role: "point" }],
173
+ emit: (e, ctx) => [{
174
+ role: "primary",
175
+ object: emitPointObject(ctx.resolveId(e.name), e.name, {
176
+ kind: "onPerpBisector",
177
+ p1: ctx.resolveId(e.p1),
178
+ p2: ctx.resolveId(e.p2),
179
+ t: e.t ?? 3
180
+ })
181
+ }]
182
+ });
153
183
  var onSegmentModule = defineModule({
154
184
  kind: "onSegment",
155
185
  role: "point",
@@ -162,6 +192,7 @@ var onSegmentModule = defineModule({
162
192
  t: z.number().min(0).max(1)
163
193
  }),
164
194
  collectRefs: (e) => [e.segmentId],
195
+ refSpecs: [{ field: "segmentId", role: "segment" }],
165
196
  emit: (e, ctx) => [{
166
197
  role: "primary",
167
198
  object: emitPointObject(
@@ -183,6 +214,7 @@ var onLineModule = defineModule({
183
214
  t: z.number().finite()
184
215
  }),
185
216
  collectRefs: (e) => [e.lineId],
217
+ refSpecs: [{ field: "lineId", role: "line-like" }],
186
218
  emit: (e, ctx) => [{
187
219
  role: "primary",
188
220
  object: emitPointObject(
@@ -204,6 +236,7 @@ var onCircleModule = defineModule({
204
236
  theta: z.number().finite()
205
237
  }),
206
238
  collectRefs: (e) => [e.circleId],
239
+ refSpecs: [{ field: "circleId", role: "circle" }],
207
240
  emit: (e, ctx) => [{
208
241
  role: "primary",
209
242
  object: emitPointObject(
@@ -225,6 +258,10 @@ var perpFootModule = defineModule({
225
258
  onLine: NameZ
226
259
  }),
227
260
  collectRefs: (e) => [e.from, e.onLine],
261
+ refSpecs: [
262
+ { field: "from", role: "point" },
263
+ { field: "onLine", role: "line-like" }
264
+ ],
228
265
  emit: (e, ctx) => [{
229
266
  role: "primary",
230
267
  object: emitPointObject(
@@ -245,6 +282,7 @@ var circumcenterModule = defineModule({
245
282
  vertices: z.tuple([NameZ, NameZ, NameZ])
246
283
  }),
247
284
  collectRefs: (e) => [...e.vertices],
285
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
248
286
  emit: (e, ctx) => [{
249
287
  role: "primary",
250
288
  object: emitPointObject(
@@ -265,6 +303,7 @@ var incenterModule = defineModule({
265
303
  vertices: z.tuple([NameZ, NameZ, NameZ])
266
304
  }),
267
305
  collectRefs: (e) => [...e.vertices],
306
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
268
307
  emit: (e, ctx) => [{
269
308
  role: "primary",
270
309
  object: emitPointObject(
@@ -285,6 +324,7 @@ var centroidModule = defineModule({
285
324
  vertices: z.tuple([NameZ, NameZ, NameZ])
286
325
  }),
287
326
  collectRefs: (e) => [...e.vertices],
327
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
288
328
  emit: (e, ctx) => [{
289
329
  role: "primary",
290
330
  object: emitPointObject(
@@ -305,6 +345,7 @@ var orthocenterModule = defineModule({
305
345
  vertices: z.tuple([NameZ, NameZ, NameZ])
306
346
  }),
307
347
  collectRefs: (e) => [...e.vertices],
348
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
308
349
  emit: (e, ctx) => [{
309
350
  role: "primary",
310
351
  object: emitPointObject(
@@ -327,6 +368,10 @@ var intersectionModule = defineModule({
327
368
  branch: z.union([z.literal(0), z.literal(1)]).optional()
328
369
  }),
329
370
  collectRefs: (e) => [e.ref1, e.ref2],
371
+ refSpecs: [
372
+ { field: "ref1", role: "line-or-circle" },
373
+ { field: "ref2", role: "line-or-circle" }
374
+ ],
330
375
  emit: (e, ctx) => {
331
376
  const r1IsCircle = ctx.hintOf(e.ref1) === "circle";
332
377
  const r2IsCircle = ctx.hintOf(e.ref2) === "circle";
@@ -366,6 +411,10 @@ var segmentModule = defineModule({
366
411
  p2: NameZ
367
412
  }),
368
413
  collectRefs: (e) => [e.p1, e.p2],
414
+ refSpecs: [
415
+ { field: "p1", role: "point" },
416
+ { field: "p2", role: "point" }
417
+ ],
369
418
  emit: (e, ctx) => [{
370
419
  role: "primary",
371
420
  object: {
@@ -389,6 +438,10 @@ var lineModule = defineModule({
389
438
  p2: NameZ
390
439
  }),
391
440
  collectRefs: (e) => [e.p1, e.p2],
441
+ refSpecs: [
442
+ { field: "p1", role: "point" },
443
+ { field: "p2", role: "point" }
444
+ ],
392
445
  emit: (e, ctx) => [{
393
446
  role: "primary",
394
447
  object: {
@@ -412,6 +465,10 @@ var rayModule = defineModule({
412
465
  through: NameZ
413
466
  }),
414
467
  collectRefs: (e) => [e.origin, e.through],
468
+ refSpecs: [
469
+ { field: "origin", role: "point" },
470
+ { field: "through", role: "point" }
471
+ ],
415
472
  emit: (e, ctx) => [{
416
473
  role: "primary",
417
474
  object: {
@@ -435,6 +492,10 @@ var perpendicularModule = defineModule({
435
492
  toLine: NameZ
436
493
  }),
437
494
  collectRefs: (e) => [e.throughPoint, e.toLine],
495
+ refSpecs: [
496
+ { field: "throughPoint", role: "point" },
497
+ { field: "toLine", role: "line-like" }
498
+ ],
438
499
  emit: (e, ctx) => [{
439
500
  role: "primary",
440
501
  object: {
@@ -464,6 +525,10 @@ var parallelModule = defineModule({
464
525
  toLine: NameZ
465
526
  }),
466
527
  collectRefs: (e) => [e.throughPoint, e.toLine],
528
+ refSpecs: [
529
+ { field: "throughPoint", role: "point" },
530
+ { field: "toLine", role: "line-like" }
531
+ ],
467
532
  emit: (e, ctx) => [{
468
533
  role: "primary",
469
534
  object: {
@@ -493,6 +558,10 @@ var perpBisectorModule = defineModule({
493
558
  p2: NameZ
494
559
  }),
495
560
  collectRefs: (e) => [e.p1, e.p2],
561
+ refSpecs: [
562
+ { field: "p1", role: "point" },
563
+ { field: "p2", role: "point" }
564
+ ],
496
565
  emit: (e, ctx) => [{
497
566
  role: "primary",
498
567
  object: {
@@ -523,6 +592,11 @@ var angleBisectorModule = defineModule({
523
592
  p2: NameZ
524
593
  }),
525
594
  collectRefs: (e) => [e.p1, e.vertex, e.p2],
595
+ refSpecs: [
596
+ { field: "p1", role: "point" },
597
+ { field: "vertex", role: "point" },
598
+ { field: "p2", role: "point" }
599
+ ],
526
600
  emit: (e, ctx) => [{
527
601
  role: "primary",
528
602
  object: {
@@ -615,6 +689,10 @@ var tangentModule = defineModule({
615
689
  branch: z.union([z.literal(0), z.literal(1), z.literal("on")]).optional()
616
690
  }),
617
691
  collectRefs: (e) => [e.throughPoint, e.toCircle],
692
+ refSpecs: [
693
+ { field: "throughPoint", role: "point" },
694
+ { field: "toCircle", role: "circle" }
695
+ ],
618
696
  emit: (e, ctx) => {
619
697
  const construction = {
620
698
  kind: "tangent",
@@ -645,6 +723,7 @@ var polygonModule = defineModule({
645
723
  vertices: z.array(NameZ).min(3)
646
724
  }),
647
725
  collectRefs: (e) => [...e.vertices],
726
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
648
727
  emit: (e, ctx) => [{
649
728
  role: "primary",
650
729
  object: {
@@ -669,6 +748,10 @@ var circleCPModule = defineModule({
669
748
  visible: z.boolean().optional()
670
749
  }),
671
750
  collectRefs: (e) => [e.center, e.surfacePoint],
751
+ refSpecs: [
752
+ { field: "center", role: "point" },
753
+ { field: "surfacePoint", role: "point" }
754
+ ],
672
755
  emit: (e, ctx) => [{
673
756
  role: "primary",
674
757
  object: {
@@ -694,6 +777,11 @@ var circle3Module = defineModule({
694
777
  p3: NameZ
695
778
  }),
696
779
  collectRefs: (e) => [e.p1, e.p2, e.p3],
780
+ refSpecs: [
781
+ { field: "p1", role: "point" },
782
+ { field: "p2", role: "point" },
783
+ { field: "p3", role: "point" }
784
+ ],
697
785
  emit: (e, ctx) => [{
698
786
  role: "primary",
699
787
  object: {
@@ -725,6 +813,7 @@ var circleDiameterModule = defineModule({
725
813
  visible: z.boolean().optional()
726
814
  }),
727
815
  collectRefs: (e) => [e.p1, e.p2],
816
+ refSpecs: [{ field: "p1", role: "point" }, { field: "p2", role: "point" }],
728
817
  emit: (e, ctx) => [{
729
818
  role: "primary",
730
819
  object: {
@@ -998,9 +1087,30 @@ var arcMidpointModule = defineModule({
998
1087
  circle: NameZ,
999
1088
  a: NameZ,
1000
1089
  b: NameZ,
1001
- notContaining: NameZ
1090
+ // Đúng 1 trong notContaining / containing — bất biến cứng kiểm ở
1091
+ // scene-constraint validate (không .refine vì registry dựng
1092
+ // discriminatedUnion yêu cầu ZodObject thuần).
1093
+ notContaining: NameZ.optional(),
1094
+ containing: NameZ.optional()
1002
1095
  }),
1003
- collectRefs: (e) => [e.circle, e.a, e.b, e.notContaining],
1096
+ collectRefs: (e) => {
1097
+ const refs = [e.circle, e.a, e.b];
1098
+ const containment = e.notContaining ?? e.containing;
1099
+ if (containment) refs.push(containment);
1100
+ return refs;
1101
+ },
1102
+ // refSpecs động: notContaining/containing TỐI ĐA 1 — có thể không có (cung không mơ hồ).
1103
+ refSpecs: (e) => {
1104
+ const specs = [
1105
+ { field: "circle", role: "circle" },
1106
+ { field: "a", role: "point" },
1107
+ { field: "b", role: "point" }
1108
+ ];
1109
+ if (e.containing ?? e.notContaining) {
1110
+ specs.push({ field: e.containing ? "containing" : "notContaining", role: "point" });
1111
+ }
1112
+ return specs;
1113
+ },
1004
1114
  emit: (e, ctx) => [{
1005
1115
  role: "primary",
1006
1116
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -1008,7 +1118,8 @@ var arcMidpointModule = defineModule({
1008
1118
  circle: ctx.resolveId(e.circle),
1009
1119
  a: ctx.resolveId(e.a),
1010
1120
  b: ctx.resolveId(e.b),
1011
- notContaining: ctx.resolveId(e.notContaining)
1121
+ // notContaining/containing optional: cung KHÔNG mơ hồ (nửa đường tròn) → bỏ cả hai.
1122
+ ...e.containing ? { containing: ctx.resolveId(e.containing) } : e.notContaining ? { notContaining: ctx.resolveId(e.notContaining) } : {}
1012
1123
  })
1013
1124
  }]
1014
1125
  });
@@ -1024,6 +1135,10 @@ var excenterModule = defineModule({
1024
1135
  opposite: NameZ
1025
1136
  }),
1026
1137
  collectRefs: (e) => [...e.vertices],
1138
+ refSpecs: [
1139
+ { field: "vertices", role: "point", many: true },
1140
+ { field: "opposite", role: "point" }
1141
+ ],
1027
1142
  emit: (e, ctx) => [{
1028
1143
  role: "primary",
1029
1144
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -1033,6 +1148,28 @@ var excenterModule = defineModule({
1033
1148
  })
1034
1149
  }]
1035
1150
  });
1151
+ var mixtilinearPointModule = defineModule({
1152
+ kind: "mixtilinearPoint",
1153
+ role: "point",
1154
+ category: "points",
1155
+ prefix: "p",
1156
+ schema: z.object({
1157
+ name: NameZ,
1158
+ kind: z.literal("mixtilinearPoint"),
1159
+ vertices: z.tuple([NameZ, NameZ, NameZ]),
1160
+ which: z.union([z.literal("center"), z.literal("touch")])
1161
+ }),
1162
+ collectRefs: (e) => [...e.vertices],
1163
+ refSpecs: [{ field: "vertices", role: "point", many: true }],
1164
+ emit: (e, ctx) => [{
1165
+ role: "primary",
1166
+ object: emitPointObject(ctx.resolveId(e.name), e.name, {
1167
+ kind: "mixtilinearPoint",
1168
+ vertices: resolveTriangleVertices(ctx, e.vertices),
1169
+ which: e.which
1170
+ })
1171
+ }]
1172
+ });
1036
1173
  var reflectPointModule = defineModule({
1037
1174
  kind: "reflectPoint",
1038
1175
  role: "point",
@@ -1040,6 +1177,10 @@ var reflectPointModule = defineModule({
1040
1177
  prefix: "p",
1041
1178
  schema: z.object({ name: NameZ, kind: z.literal("reflectPoint"), of: NameZ, through: NameZ }),
1042
1179
  collectRefs: (e) => [e.of, e.through],
1180
+ refSpecs: [
1181
+ { field: "of", role: "point" },
1182
+ { field: "through", role: "point" }
1183
+ ],
1043
1184
  emit: (e, ctx) => [{
1044
1185
  role: "primary",
1045
1186
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -1056,6 +1197,10 @@ var reflectLineModule = defineModule({
1056
1197
  prefix: "p",
1057
1198
  schema: z.object({ name: NameZ, kind: z.literal("reflectLine"), of: NameZ, through: NameZ }),
1058
1199
  collectRefs: (e) => [e.of, e.through],
1200
+ refSpecs: [
1201
+ { field: "of", role: "point" },
1202
+ { field: "through", role: "line-like" }
1203
+ ],
1059
1204
  emit: (e, ctx) => [{
1060
1205
  role: "primary",
1061
1206
  object: emitPointObject(ctx.resolveId(e.name), e.name, {
@@ -1097,12 +1242,25 @@ var pointAtDistanceModule = defineModule({
1097
1242
  const extra = d.kind === "circleRadius" ? [d.circle] : d.kind === "segmentLength" ? [d.p1, d.p2] : [];
1098
1243
  return [e.from, e.through, ...extra];
1099
1244
  },
1100
- // TODO(Mức 1 defer): distance.{circle,p1,p2} nested trong `distance` refSpec
1101
- // phẳng đọc top-level không với tới, validate riêng nếu cần. Hiện validate from/through.
1102
- refSpecs: [
1103
- { field: "from", role: "point" },
1104
- { field: "through", role: "point" }
1105
- ],
1245
+ // refSpecs động: distance.{circle,p1,p2} nested validate qua dotted path
1246
+ // ('distance.circle' runSpecs transpile/refs.ts đọc bằng reduce theo '.').
1247
+ refSpecs: (e) => {
1248
+ const base = [
1249
+ { field: "from", role: "point" },
1250
+ { field: "through", role: "point" }
1251
+ ];
1252
+ if (e.distance.kind === "circleRadius") {
1253
+ return [...base, { field: "distance.circle", role: "circle" }];
1254
+ }
1255
+ if (e.distance.kind === "segmentLength") {
1256
+ return [
1257
+ ...base,
1258
+ { field: "distance.p1", role: "point" },
1259
+ { field: "distance.p2", role: "point" }
1260
+ ];
1261
+ }
1262
+ return base;
1263
+ },
1106
1264
  emit: (e, ctx) => {
1107
1265
  const d = e.distance;
1108
1266
  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);
@@ -1117,11 +1275,38 @@ var pointAtDistanceModule = defineModule({
1117
1275
  }];
1118
1276
  }
1119
1277
  });
1278
+ var commonTangentPointModule = defineModule({
1279
+ kind: "commonTangentPoint",
1280
+ role: "point",
1281
+ category: "points",
1282
+ prefix: "p",
1283
+ schema: z.object({
1284
+ name: NameZ,
1285
+ kind: z.literal("commonTangentPoint"),
1286
+ circles: z.tuple([NameZ, NameZ]),
1287
+ on: z.union([z.literal(0), z.literal(1)]),
1288
+ variant: z.enum(["external", "internal"]),
1289
+ side: z.union([z.literal(0), z.literal(1)])
1290
+ }),
1291
+ collectRefs: (e) => [e.circles[0], e.circles[1]],
1292
+ refSpecs: [{ field: "circles", role: "circle", many: true }],
1293
+ emit: (e, ctx) => [{
1294
+ role: "primary",
1295
+ object: emitPointObject(ctx.resolveId(e.name), e.name, {
1296
+ kind: "commonTangentPoint",
1297
+ circles: [ctx.resolveId(e.circles[0]), ctx.resolveId(e.circles[1])],
1298
+ on: e.on,
1299
+ variant: e.variant,
1300
+ side: e.side
1301
+ })
1302
+ }]
1303
+ });
1120
1304
 
1121
1305
  // src/stamps/geometry-2d/dsl/registry.ts
1122
1306
  var ALL_MODULES = [
1123
1307
  freeModule,
1124
1308
  midpointModule,
1309
+ onPerpBisectorModule,
1125
1310
  onSegmentModule,
1126
1311
  onLineModule,
1127
1312
  onCircleModule,
@@ -1158,10 +1343,13 @@ var ALL_MODULES = [
1158
1343
  // Cụm A points
1159
1344
  arcMidpointModule,
1160
1345
  excenterModule,
1346
+ mixtilinearPointModule,
1161
1347
  reflectPointModule,
1162
1348
  reflectLineModule,
1163
1349
  // Cụm B points
1164
- pointAtDistanceModule
1350
+ pointAtDistanceModule,
1351
+ // 2-circle relations (spec mục A)
1352
+ commonTangentPointModule
1165
1353
  ];
1166
1354
  var KIND_REGISTRY = new Map(ALL_MODULES.map((m) => [m.kind, m]));
1167
1355
  var POINT_KINDS = new Set(
@@ -1294,8 +1482,11 @@ function serializePoint(obj, state) {
1294
1482
  };
1295
1483
  }
1296
1484
  case "arcMidpoint": {
1297
- const refs = resolveRefs([c.circle, c.a, c.b, c.notContaining], state);
1298
- if (!refs) return fail("unresolved-ref", `${c.circle},${c.a},${c.b},${c.notContaining}`);
1485
+ const containment = c.containing ?? c.notContaining;
1486
+ const baseRefs = [c.circle, c.a, c.b];
1487
+ if (containment) baseRefs.push(containment);
1488
+ const refs = resolveRefs(baseRefs, state);
1489
+ if (!refs) return fail("unresolved-ref", baseRefs.join(","));
1299
1490
  return {
1300
1491
  ok: true,
1301
1492
  entity: {
@@ -1304,7 +1495,7 @@ function serializePoint(obj, state) {
1304
1495
  circle: refs[0],
1305
1496
  a: refs[1],
1306
1497
  b: refs[2],
1307
- notContaining: refs[3]
1498
+ ...c.containing ? { containing: refs[3] } : c.notContaining ? { notContaining: refs[3] } : {}
1308
1499
  }
1309
1500
  };
1310
1501
  }
@@ -1341,6 +1532,21 @@ function serializePoint(obj, state) {
1341
1532
  entity: { name: obj.label, kind: "pointAtDistance", from: refs[0], through: refs[1], distance }
1342
1533
  };
1343
1534
  }
1535
+ case "commonTangentPoint": {
1536
+ const refs = resolveRefs([c.circles[0], c.circles[1]], state);
1537
+ if (!refs) return fail("unresolved-ref", `${c.circles[0]},${c.circles[1]}`);
1538
+ return {
1539
+ ok: true,
1540
+ entity: {
1541
+ name: obj.label,
1542
+ kind: "commonTangentPoint",
1543
+ circles: [refs[0], refs[1]],
1544
+ on: c.on,
1545
+ variant: c.variant,
1546
+ side: c.side
1547
+ }
1548
+ };
1549
+ }
1344
1550
  // Out of DSL v1:
1345
1551
  case "onAxis":
1346
1552
  case "onPolygon":
@@ -1348,6 +1554,7 @@ function serializePoint(obj, state) {
1348
1554
  case "onPerpendicular":
1349
1555
  case "onPerpBisector":
1350
1556
  case "onCircleAroundPoint":
1557
+ case "mixtilinearPoint":
1351
1558
  return fail("unsupported-constraint", c.kind);
1352
1559
  default: {
1353
1560
  return fail("unsupported-constraint");
@@ -1644,9 +1851,11 @@ function describeEntity(e) {
1644
1851
  return `${e.name} = \u0111\u01B0\u1EDDng tr\xF2n b\xE0ng ti\u1EBFp ${e.vertices.join("")} \u0111\u1ED1i di\u1EC7n ${e.opposite}`;
1645
1852
  // Cụm A
1646
1853
  case "arcMidpoint":
1647
- return `${e.name} = trung \u0111i\u1EC3m cung ${e.a}${e.b} (kh\xF4ng ch\u1EE9a ${e.notContaining}) tr\xEAn ${e.circle}`;
1854
+ 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}`;
1648
1855
  case "excenter":
1649
1856
  return `${e.name} = t\xE2m b\xE0ng ti\u1EBFp ${e.vertices.join("")} \u0111\u1ED1i di\u1EC7n ${e.opposite}`;
1857
+ case "mixtilinearPoint":
1858
+ return `${e.name} = ${e.which === "center" ? "t\xE2m" : "ti\u1EBFp \u0111i\u1EC3m"} mixtilinear ${e.vertices.join("")}`;
1650
1859
  case "reflectPoint":
1651
1860
  return `${e.name} = \u0111\u1ED1i x\u1EE9ng ${e.of} qua \u0111i\u1EC3m ${e.through}`;
1652
1861
  case "reflectLine":
@@ -1657,6 +1866,12 @@ function describeEntity(e) {
1657
1866
  const distStr = d.kind === "circleRadius" ? `r(${d.circle})` : d.kind === "segmentLength" ? `|${d.p1}${d.p2}|` : `${d.value}`;
1658
1867
  return `${e.name} = \u0111i\u1EC3m tr\xEAn tia ${e.from}${e.through} c\xE1ch ${e.through} m\u1ED9t kho\u1EA3ng ${distStr}`;
1659
1868
  }
1869
+ case "onPerpBisector":
1870
+ return `${e.name} = \u0111i\u1EC3m tr\xEAn trung tr\u1EF1c ${e.p1}${e.p2}`;
1871
+ case "commonTangentPoint": {
1872
+ const v = e.variant === "internal" ? "trong" : "ngo\xE0i";
1873
+ return `${e.name} = ti\u1EBFp \u0111i\u1EC3m ti\u1EBFp tuy\u1EBFn chung ${v} ${e.circles[0]},${e.circles[1]} (tr\xEAn ${e.circles[e.on]})`;
1874
+ }
1660
1875
  default: {
1661
1876
  return "";
1662
1877
  }
@@ -1675,5 +1890,5 @@ function describeDsl(obj, state) {
1675
1890
  }
1676
1891
 
1677
1892
  export { CIRCLE_KINDS, KIND_REGISTRY, LINE_LIKE_SHAPE_KINDS, POINT_KINDS, describeDsl, fileToImagePart, inferMediaType, validateFile };
1678
- //# sourceMappingURL=chunk-SF3U7ZF4.mjs.map
1679
- //# sourceMappingURL=chunk-SF3U7ZF4.mjs.map
1893
+ //# sourceMappingURL=chunk-DJM5EWTT.mjs.map
1894
+ //# sourceMappingURL=chunk-DJM5EWTT.mjs.map