@xom11/whiteboard 0.24.2 → 0.25.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 (84) hide show
  1. package/README.md +84 -11
  2. package/dist/ai.d.mts +422 -566
  3. package/dist/ai.d.ts +422 -566
  4. package/dist/ai.js +1527 -407
  5. package/dist/ai.js.map +1 -1
  6. package/dist/ai.mjs +1008 -512
  7. package/dist/ai.mjs.map +1 -1
  8. package/dist/catalog.json +4 -4
  9. package/dist/{chunk-BKSXPNPQ.mjs → chunk-AYSFWUPK.mjs} +4 -3
  10. package/dist/chunk-AYSFWUPK.mjs.map +1 -0
  11. package/dist/chunk-B4NJJZFR.mjs +18 -0
  12. package/dist/chunk-B4NJJZFR.mjs.map +1 -0
  13. package/dist/{chunk-LVNCYP4J.mjs → chunk-CJBLJUWG.mjs} +5 -5
  14. package/dist/{chunk-LVNCYP4J.mjs.map → chunk-CJBLJUWG.mjs.map} +1 -1
  15. package/dist/{chunk-7WQXXEVR.mjs → chunk-ESVPQWHX.mjs} +5 -5
  16. package/dist/{chunk-7WQXXEVR.mjs.map → chunk-ESVPQWHX.mjs.map} +1 -1
  17. package/dist/{chunk-KRC2XOIG.mjs → chunk-I24QOHPU.mjs} +3 -3
  18. package/dist/{chunk-KRC2XOIG.mjs.map → chunk-I24QOHPU.mjs.map} +1 -1
  19. package/dist/{chunk-ZBJBQKJ2.mjs → chunk-IHUFOV7L.mjs} +4 -19
  20. package/dist/chunk-IHUFOV7L.mjs.map +1 -0
  21. package/dist/{chunk-AZIARTGX.mjs → chunk-M42TGYT6.mjs} +3 -3
  22. package/dist/{chunk-AZIARTGX.mjs.map → chunk-M42TGYT6.mjs.map} +1 -1
  23. package/dist/{chunk-45CGKJ7S.mjs → chunk-NDEZJKNY.mjs} +4 -4
  24. package/dist/{chunk-45CGKJ7S.mjs.map → chunk-NDEZJKNY.mjs.map} +1 -1
  25. package/dist/{chunk-BEZSQKPY.mjs → chunk-ONBCUWVI.mjs} +5 -4
  26. package/dist/chunk-ONBCUWVI.mjs.map +1 -0
  27. package/dist/{chunk-WM2VDYQA.mjs → chunk-REIJZDVZ.mjs} +4 -3
  28. package/dist/chunk-REIJZDVZ.mjs.map +1 -0
  29. package/dist/{chunk-2WF6KIGF.mjs → chunk-TB4CL25L.mjs} +9 -8
  30. package/dist/chunk-TB4CL25L.mjs.map +1 -0
  31. package/dist/chunk-VNCCIV6O.mjs +938 -0
  32. package/dist/chunk-VNCCIV6O.mjs.map +1 -0
  33. package/dist/{chunk-CGZZO4BX.mjs → chunk-VRHWDZ66.mjs} +5 -5
  34. package/dist/{chunk-CGZZO4BX.mjs.map → chunk-VRHWDZ66.mjs.map} +1 -1
  35. package/dist/{chunk-4DS3MKID.mjs → chunk-YSJOVBCD.mjs} +4 -4
  36. package/dist/{chunk-4DS3MKID.mjs.map → chunk-YSJOVBCD.mjs.map} +1 -1
  37. package/dist/geometry-2d.d.mts +2 -2
  38. package/dist/geometry-2d.d.ts +2 -2
  39. package/dist/geometry-2d.js +1383 -23
  40. package/dist/geometry-2d.js.map +1 -1
  41. package/dist/geometry-2d.mjs +6 -5
  42. package/dist/geometry-3d.d.mts +2 -2
  43. package/dist/geometry-3d.d.ts +2 -2
  44. package/dist/geometry-3d.js +2 -2
  45. package/dist/geometry-3d.js.map +1 -1
  46. package/dist/geometry-3d.mjs +5 -4
  47. package/dist/graph-2d.d.mts +2 -2
  48. package/dist/graph-2d.d.ts +2 -2
  49. package/dist/graph-2d.js +2 -2
  50. package/dist/graph-2d.js.map +1 -1
  51. package/dist/graph-2d.mjs +8 -7
  52. package/dist/{host-ZIQ77W33.mjs → host-A64ITWVX.mjs} +7 -6
  53. package/dist/host-A64ITWVX.mjs.map +1 -0
  54. package/dist/{host-EPZCNFLH.mjs → host-L7FMFZUW.mjs} +226 -29
  55. package/dist/host-L7FMFZUW.mjs.map +1 -0
  56. package/dist/{host-LKCMYEAV.mjs → host-QK53UYMD.mjs} +11 -10
  57. package/dist/host-QK53UYMD.mjs.map +1 -0
  58. package/dist/index.d.mts +3 -3
  59. package/dist/index.d.ts +3 -3
  60. package/dist/index.js +1414 -54
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.mjs +18 -17
  63. package/dist/index.mjs.map +1 -1
  64. package/dist/latex.d.mts +2 -2
  65. package/dist/latex.d.ts +2 -2
  66. package/dist/render-3WTY7NZB.mjs +9 -0
  67. package/dist/{render-SA4JTOW3.mjs.map → render-3WTY7NZB.mjs.map} +1 -1
  68. package/dist/serialize-SRJVKYUG.mjs +8 -0
  69. package/dist/{serialize-JAVOU22E.mjs.map → serialize-SRJVKYUG.mjs.map} +1 -1
  70. package/dist/{types-vtvyKGAA.d.mts → types-DWRyCa2m.d.mts} +187 -2
  71. package/dist/{types-Crbefnfe.d.ts → types-DWRyCa2m.d.ts} +187 -2
  72. package/package.json +1 -1
  73. package/dist/chunk-2WF6KIGF.mjs.map +0 -1
  74. package/dist/chunk-BEZSQKPY.mjs.map +0 -1
  75. package/dist/chunk-BKSXPNPQ.mjs.map +0 -1
  76. package/dist/chunk-WM2VDYQA.mjs.map +0 -1
  77. package/dist/chunk-ZBJBQKJ2.mjs.map +0 -1
  78. package/dist/host-EPZCNFLH.mjs.map +0 -1
  79. package/dist/host-LKCMYEAV.mjs.map +0 -1
  80. package/dist/host-ZIQ77W33.mjs.map +0 -1
  81. package/dist/render-SA4JTOW3.mjs +0 -8
  82. package/dist/serialize-JAVOU22E.mjs +0 -7
  83. package/dist/types-DxlMPh-6.d.mts +0 -49
  84. package/dist/types-DxlMPh-6.d.ts +0 -49
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ var immer = require('immer');
6
6
  var React18 = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var reactDom = require('react-dom');
9
+ var zod = require('zod');
9
10
  var excalidraw = require('@excalidraw/excalidraw');
10
11
  require('@excalidraw/excalidraw/index.css');
11
12
 
@@ -3269,11 +3270,11 @@ function formatMeasure(items) {
3269
3270
  return items.map((it) => `${it.label} = ${it.value.toFixed(2)}`).join(", ");
3270
3271
  }
3271
3272
  function ObjectRow(props) {
3272
- const { obj, state, selected, onSelect, onToggleVisible, onToggleLocked, onRename, onChangeColor, onDelete } = props;
3273
+ const { obj, state, selected, onSelect, onToggleVisible, onToggleLocked, onRename, onChangeColor, onDelete, describe } = props;
3273
3274
  const meta = getKindUiMeta(obj.kind);
3274
3275
  let title = "";
3275
3276
  try {
3276
- title = getKind(obj.kind).describe(obj, state);
3277
+ title = describe ? describe(obj, state) : getKind(obj.kind).describe(obj, state);
3277
3278
  } catch {
3278
3279
  title = `${meta.displayName} ${obj.label}`;
3279
3280
  }
@@ -7210,12 +7211,1122 @@ var init_Toast2 = __esm({
7210
7211
  init_useToast();
7211
7212
  }
7212
7213
  });
7213
- function useAiFigure(generator) {
7214
+ var NameZ;
7215
+ var init_names = __esm({
7216
+ "src/stamps/geometry-2d/dsl/names.ts"() {
7217
+ NameZ = zod.z.string().regex(/^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/);
7218
+ }
7219
+ });
7220
+
7221
+ // src/stamps/geometry-2d/dsl/kinds/_types.ts
7222
+ function defineModule(m) {
7223
+ return m;
7224
+ }
7225
+ var init_types4 = __esm({
7226
+ "src/stamps/geometry-2d/dsl/kinds/_types.ts"() {
7227
+ }
7228
+ });
7229
+
7230
+ // src/stamps/geometry-2d/dsl/kinds/_shared.ts
7231
+ function emitPointObject(id, name, constraint) {
7232
+ return {
7233
+ id,
7234
+ kind: "point",
7235
+ label: name,
7236
+ ...POINT_BASE_FIELDS,
7237
+ attrs: { constraint }
7238
+ };
7239
+ }
7240
+ function resolveTriangleVertices(ctx, vertices) {
7241
+ return [ctx.resolveId(vertices[0]), ctx.resolveId(vertices[1]), ctx.resolveId(vertices[2])];
7242
+ }
7243
+ var POINT_BASE_FIELDS, SHAPE_BASE_FIELDS;
7244
+ var init_shared = __esm({
7245
+ "src/stamps/geometry-2d/dsl/kinds/_shared.ts"() {
7246
+ POINT_BASE_FIELDS = {
7247
+ visible: true,
7248
+ locked: false,
7249
+ layer: "default",
7250
+ schemaVersion: 1
7251
+ };
7252
+ SHAPE_BASE_FIELDS = {
7253
+ visible: true,
7254
+ locked: false,
7255
+ layer: "default",
7256
+ schemaVersion: 1
7257
+ };
7258
+ }
7259
+ });
7260
+ var freeModule;
7261
+ var init_free = __esm({
7262
+ "src/stamps/geometry-2d/dsl/kinds/points/free.ts"() {
7263
+ init_names();
7264
+ init_types4();
7265
+ init_shared();
7266
+ freeModule = defineModule({
7267
+ kind: "free",
7268
+ role: "point",
7269
+ category: "points",
7270
+ prefix: "p",
7271
+ schema: zod.z.object({
7272
+ name: NameZ,
7273
+ kind: zod.z.literal("free"),
7274
+ x: zod.z.number().finite(),
7275
+ y: zod.z.number().finite()
7276
+ }),
7277
+ collectRefs: () => [],
7278
+ emit: (e, ctx) => [{
7279
+ role: "primary",
7280
+ object: emitPointObject(ctx.resolveId(e.name), e.name, { kind: "free", x: e.x, y: e.y })
7281
+ }]
7282
+ });
7283
+ }
7284
+ });
7285
+ var midpointModule;
7286
+ var init_midpoint = __esm({
7287
+ "src/stamps/geometry-2d/dsl/kinds/points/midpoint.ts"() {
7288
+ init_names();
7289
+ init_types4();
7290
+ init_shared();
7291
+ midpointModule = defineModule({
7292
+ kind: "midpoint",
7293
+ role: "point",
7294
+ category: "points",
7295
+ prefix: "p",
7296
+ schema: zod.z.object({
7297
+ name: NameZ,
7298
+ kind: zod.z.literal("midpoint"),
7299
+ p1: NameZ,
7300
+ p2: NameZ
7301
+ }),
7302
+ collectRefs: (e) => [e.p1, e.p2],
7303
+ emit: (e, ctx) => [{
7304
+ role: "primary",
7305
+ object: emitPointObject(
7306
+ ctx.resolveId(e.name),
7307
+ e.name,
7308
+ { kind: "midpoint", p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7309
+ )
7310
+ }]
7311
+ });
7312
+ }
7313
+ });
7314
+ var onSegmentModule;
7315
+ var init_onSegment = __esm({
7316
+ "src/stamps/geometry-2d/dsl/kinds/points/onSegment.ts"() {
7317
+ init_names();
7318
+ init_types4();
7319
+ init_shared();
7320
+ onSegmentModule = defineModule({
7321
+ kind: "onSegment",
7322
+ role: "point",
7323
+ category: "points",
7324
+ prefix: "p",
7325
+ schema: zod.z.object({
7326
+ name: NameZ,
7327
+ kind: zod.z.literal("onSegment"),
7328
+ segmentId: NameZ,
7329
+ t: zod.z.number().min(0).max(1)
7330
+ }),
7331
+ collectRefs: (e) => [e.segmentId],
7332
+ emit: (e, ctx) => [{
7333
+ role: "primary",
7334
+ object: emitPointObject(
7335
+ ctx.resolveId(e.name),
7336
+ e.name,
7337
+ { kind: "onSegment", segmentId: ctx.resolveId(e.segmentId), t: e.t }
7338
+ )
7339
+ }]
7340
+ });
7341
+ }
7342
+ });
7343
+ var onLineModule;
7344
+ var init_onLine = __esm({
7345
+ "src/stamps/geometry-2d/dsl/kinds/points/onLine.ts"() {
7346
+ init_names();
7347
+ init_types4();
7348
+ init_shared();
7349
+ onLineModule = defineModule({
7350
+ kind: "onLine",
7351
+ role: "point",
7352
+ category: "points",
7353
+ prefix: "p",
7354
+ schema: zod.z.object({
7355
+ name: NameZ,
7356
+ kind: zod.z.literal("onLine"),
7357
+ lineId: NameZ,
7358
+ t: zod.z.number().finite()
7359
+ }),
7360
+ collectRefs: (e) => [e.lineId],
7361
+ emit: (e, ctx) => [{
7362
+ role: "primary",
7363
+ object: emitPointObject(
7364
+ ctx.resolveId(e.name),
7365
+ e.name,
7366
+ { kind: "onLine", lineId: ctx.resolveId(e.lineId), t: e.t }
7367
+ )
7368
+ }]
7369
+ });
7370
+ }
7371
+ });
7372
+ var onCircleModule;
7373
+ var init_onCircle = __esm({
7374
+ "src/stamps/geometry-2d/dsl/kinds/points/onCircle.ts"() {
7375
+ init_names();
7376
+ init_types4();
7377
+ init_shared();
7378
+ onCircleModule = defineModule({
7379
+ kind: "onCircle",
7380
+ role: "point",
7381
+ category: "points",
7382
+ prefix: "p",
7383
+ schema: zod.z.object({
7384
+ name: NameZ,
7385
+ kind: zod.z.literal("onCircle"),
7386
+ circleId: NameZ,
7387
+ theta: zod.z.number().finite()
7388
+ }),
7389
+ collectRefs: (e) => [e.circleId],
7390
+ emit: (e, ctx) => [{
7391
+ role: "primary",
7392
+ object: emitPointObject(
7393
+ ctx.resolveId(e.name),
7394
+ e.name,
7395
+ { kind: "onCircle", circleId: ctx.resolveId(e.circleId), theta: e.theta }
7396
+ )
7397
+ }]
7398
+ });
7399
+ }
7400
+ });
7401
+ var perpFootModule;
7402
+ var init_perpFoot = __esm({
7403
+ "src/stamps/geometry-2d/dsl/kinds/points/perpFoot.ts"() {
7404
+ init_names();
7405
+ init_types4();
7406
+ init_shared();
7407
+ perpFootModule = defineModule({
7408
+ kind: "perpFoot",
7409
+ role: "point",
7410
+ category: "points",
7411
+ prefix: "p",
7412
+ schema: zod.z.object({
7413
+ name: NameZ,
7414
+ kind: zod.z.literal("perpFoot"),
7415
+ from: NameZ,
7416
+ onLine: NameZ
7417
+ }),
7418
+ collectRefs: (e) => [e.from, e.onLine],
7419
+ emit: (e, ctx) => [{
7420
+ role: "primary",
7421
+ object: emitPointObject(
7422
+ ctx.resolveId(e.name),
7423
+ e.name,
7424
+ { kind: "perpFoot", from: ctx.resolveId(e.from), onLine: ctx.resolveId(e.onLine) }
7425
+ )
7426
+ }]
7427
+ });
7428
+ }
7429
+ });
7430
+ var circumcenterModule;
7431
+ var init_circumcenter = __esm({
7432
+ "src/stamps/geometry-2d/dsl/kinds/points/circumcenter.ts"() {
7433
+ init_names();
7434
+ init_types4();
7435
+ init_shared();
7436
+ circumcenterModule = defineModule({
7437
+ kind: "circumcenter",
7438
+ role: "point",
7439
+ category: "points",
7440
+ prefix: "p",
7441
+ schema: zod.z.object({
7442
+ name: NameZ,
7443
+ kind: zod.z.literal("circumcenter"),
7444
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7445
+ }),
7446
+ collectRefs: (e) => [...e.vertices],
7447
+ emit: (e, ctx) => [{
7448
+ role: "primary",
7449
+ object: emitPointObject(
7450
+ ctx.resolveId(e.name),
7451
+ e.name,
7452
+ { kind: "circumcenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7453
+ )
7454
+ }]
7455
+ });
7456
+ }
7457
+ });
7458
+ var incenterModule;
7459
+ var init_incenter = __esm({
7460
+ "src/stamps/geometry-2d/dsl/kinds/points/incenter.ts"() {
7461
+ init_names();
7462
+ init_types4();
7463
+ init_shared();
7464
+ incenterModule = defineModule({
7465
+ kind: "incenter",
7466
+ role: "point",
7467
+ category: "points",
7468
+ prefix: "p",
7469
+ schema: zod.z.object({
7470
+ name: NameZ,
7471
+ kind: zod.z.literal("incenter"),
7472
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7473
+ }),
7474
+ collectRefs: (e) => [...e.vertices],
7475
+ emit: (e, ctx) => [{
7476
+ role: "primary",
7477
+ object: emitPointObject(
7478
+ ctx.resolveId(e.name),
7479
+ e.name,
7480
+ { kind: "incenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7481
+ )
7482
+ }]
7483
+ });
7484
+ }
7485
+ });
7486
+ var centroidModule;
7487
+ var init_centroid = __esm({
7488
+ "src/stamps/geometry-2d/dsl/kinds/points/centroid.ts"() {
7489
+ init_names();
7490
+ init_types4();
7491
+ init_shared();
7492
+ centroidModule = defineModule({
7493
+ kind: "centroid",
7494
+ role: "point",
7495
+ category: "points",
7496
+ prefix: "p",
7497
+ schema: zod.z.object({
7498
+ name: NameZ,
7499
+ kind: zod.z.literal("centroid"),
7500
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7501
+ }),
7502
+ collectRefs: (e) => [...e.vertices],
7503
+ emit: (e, ctx) => [{
7504
+ role: "primary",
7505
+ object: emitPointObject(
7506
+ ctx.resolveId(e.name),
7507
+ e.name,
7508
+ { kind: "centroid", vertices: resolveTriangleVertices(ctx, e.vertices) }
7509
+ )
7510
+ }]
7511
+ });
7512
+ }
7513
+ });
7514
+ var orthocenterModule;
7515
+ var init_orthocenter = __esm({
7516
+ "src/stamps/geometry-2d/dsl/kinds/points/orthocenter.ts"() {
7517
+ init_names();
7518
+ init_types4();
7519
+ init_shared();
7520
+ orthocenterModule = defineModule({
7521
+ kind: "orthocenter",
7522
+ role: "point",
7523
+ category: "points",
7524
+ prefix: "p",
7525
+ schema: zod.z.object({
7526
+ name: NameZ,
7527
+ kind: zod.z.literal("orthocenter"),
7528
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7529
+ }),
7530
+ collectRefs: (e) => [...e.vertices],
7531
+ emit: (e, ctx) => [{
7532
+ role: "primary",
7533
+ object: emitPointObject(
7534
+ ctx.resolveId(e.name),
7535
+ e.name,
7536
+ { kind: "orthocenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7537
+ )
7538
+ }]
7539
+ });
7540
+ }
7541
+ });
7542
+ var intersectionModule;
7543
+ var init_intersection2 = __esm({
7544
+ "src/stamps/geometry-2d/dsl/kinds/points/intersection.ts"() {
7545
+ init_names();
7546
+ init_types4();
7547
+ init_shared();
7548
+ intersectionModule = defineModule({
7549
+ kind: "intersection",
7550
+ role: "point",
7551
+ category: "points",
7552
+ prefix: "i",
7553
+ schema: zod.z.object({
7554
+ name: NameZ,
7555
+ kind: zod.z.literal("intersection"),
7556
+ ref1: NameZ,
7557
+ ref2: NameZ,
7558
+ branch: zod.z.union([zod.z.literal(0), zod.z.literal(1)]).optional()
7559
+ }),
7560
+ collectRefs: (e) => [e.ref1, e.ref2],
7561
+ emit: (e, ctx) => {
7562
+ const r1IsCircle = ctx.hintOf(e.ref1) === "circle";
7563
+ const r2IsCircle = ctx.hintOf(e.ref2) === "circle";
7564
+ let intersectKind;
7565
+ if (r1IsCircle && r2IsCircle) intersectKind = "circleCircle";
7566
+ else if (r1IsCircle || r2IsCircle) intersectKind = "lineCircle";
7567
+ else intersectKind = "lineLine";
7568
+ const attrs = {
7569
+ kind: intersectKind,
7570
+ ref1: ctx.resolveId(e.ref1),
7571
+ ref2: ctx.resolveId(e.ref2)
7572
+ };
7573
+ if (intersectKind !== "lineLine") {
7574
+ attrs.branch = e.branch ?? 0;
7575
+ }
7576
+ return [{
7577
+ role: "primary",
7578
+ object: {
7579
+ id: ctx.resolveId(e.name),
7580
+ kind: "intersection",
7581
+ label: e.name,
7582
+ ...POINT_BASE_FIELDS,
7583
+ attrs
7584
+ }
7585
+ }];
7586
+ }
7587
+ });
7588
+ }
7589
+ });
7590
+ var segmentModule;
7591
+ var init_segment2 = __esm({
7592
+ "src/stamps/geometry-2d/dsl/kinds/lines/segment.ts"() {
7593
+ init_names();
7594
+ init_types4();
7595
+ init_shared();
7596
+ segmentModule = defineModule({
7597
+ kind: "segment",
7598
+ role: "segment",
7599
+ category: "lines",
7600
+ prefix: "s",
7601
+ schema: zod.z.object({
7602
+ name: NameZ,
7603
+ kind: zod.z.literal("segment"),
7604
+ p1: NameZ,
7605
+ p2: NameZ
7606
+ }),
7607
+ collectRefs: (e) => [e.p1, e.p2],
7608
+ emit: (e, ctx) => [{
7609
+ role: "primary",
7610
+ object: {
7611
+ id: ctx.resolveId(e.name),
7612
+ kind: "segment",
7613
+ label: e.name,
7614
+ ...SHAPE_BASE_FIELDS,
7615
+ attrs: { p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7616
+ }
7617
+ }]
7618
+ });
7619
+ }
7620
+ });
7621
+ var lineModule;
7622
+ var init_line2 = __esm({
7623
+ "src/stamps/geometry-2d/dsl/kinds/lines/line.ts"() {
7624
+ init_names();
7625
+ init_types4();
7626
+ init_shared();
7627
+ lineModule = defineModule({
7628
+ kind: "line",
7629
+ role: "line",
7630
+ category: "lines",
7631
+ prefix: "l",
7632
+ schema: zod.z.object({
7633
+ name: NameZ,
7634
+ kind: zod.z.literal("line"),
7635
+ p1: NameZ,
7636
+ p2: NameZ
7637
+ }),
7638
+ collectRefs: (e) => [e.p1, e.p2],
7639
+ emit: (e, ctx) => [{
7640
+ role: "primary",
7641
+ object: {
7642
+ id: ctx.resolveId(e.name),
7643
+ kind: "line",
7644
+ label: e.name,
7645
+ ...SHAPE_BASE_FIELDS,
7646
+ attrs: { p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7647
+ }
7648
+ }]
7649
+ });
7650
+ }
7651
+ });
7652
+ var rayModule;
7653
+ var init_ray2 = __esm({
7654
+ "src/stamps/geometry-2d/dsl/kinds/lines/ray.ts"() {
7655
+ init_names();
7656
+ init_types4();
7657
+ init_shared();
7658
+ rayModule = defineModule({
7659
+ kind: "ray",
7660
+ role: "ray",
7661
+ category: "lines",
7662
+ prefix: "r",
7663
+ schema: zod.z.object({
7664
+ name: NameZ,
7665
+ kind: zod.z.literal("ray"),
7666
+ origin: NameZ,
7667
+ through: NameZ
7668
+ }),
7669
+ collectRefs: (e) => [e.origin, e.through],
7670
+ emit: (e, ctx) => [{
7671
+ role: "primary",
7672
+ object: {
7673
+ id: ctx.resolveId(e.name),
7674
+ kind: "ray",
7675
+ label: e.name,
7676
+ ...SHAPE_BASE_FIELDS,
7677
+ attrs: { origin: ctx.resolveId(e.origin), through: ctx.resolveId(e.through) }
7678
+ }
7679
+ }]
7680
+ });
7681
+ }
7682
+ });
7683
+ var perpendicularModule;
7684
+ var init_perpendicular = __esm({
7685
+ "src/stamps/geometry-2d/dsl/kinds/lines/perpendicular.ts"() {
7686
+ init_names();
7687
+ init_types4();
7688
+ init_shared();
7689
+ perpendicularModule = defineModule({
7690
+ kind: "perpendicular",
7691
+ role: "lineConstruction",
7692
+ category: "lines",
7693
+ prefix: "l",
7694
+ schema: zod.z.object({
7695
+ name: NameZ,
7696
+ kind: zod.z.literal("perpendicular"),
7697
+ throughPoint: NameZ,
7698
+ toLine: NameZ
7699
+ }),
7700
+ collectRefs: (e) => [e.throughPoint, e.toLine],
7701
+ emit: (e, ctx) => [{
7702
+ role: "primary",
7703
+ object: {
7704
+ id: ctx.resolveId(e.name),
7705
+ kind: "line",
7706
+ label: e.name,
7707
+ ...SHAPE_BASE_FIELDS,
7708
+ attrs: {
7709
+ construction: {
7710
+ kind: "perpendicular",
7711
+ throughPoint: ctx.resolveId(e.throughPoint),
7712
+ toLine: ctx.resolveId(e.toLine)
7713
+ }
7714
+ }
7715
+ }
7716
+ }]
7717
+ });
7718
+ }
7719
+ });
7720
+ var parallelModule;
7721
+ var init_parallel = __esm({
7722
+ "src/stamps/geometry-2d/dsl/kinds/lines/parallel.ts"() {
7723
+ init_names();
7724
+ init_types4();
7725
+ init_shared();
7726
+ parallelModule = defineModule({
7727
+ kind: "parallel",
7728
+ role: "lineConstruction",
7729
+ category: "lines",
7730
+ prefix: "l",
7731
+ schema: zod.z.object({
7732
+ name: NameZ,
7733
+ kind: zod.z.literal("parallel"),
7734
+ throughPoint: NameZ,
7735
+ toLine: NameZ
7736
+ }),
7737
+ collectRefs: (e) => [e.throughPoint, e.toLine],
7738
+ emit: (e, ctx) => [{
7739
+ role: "primary",
7740
+ object: {
7741
+ id: ctx.resolveId(e.name),
7742
+ kind: "line",
7743
+ label: e.name,
7744
+ ...SHAPE_BASE_FIELDS,
7745
+ attrs: {
7746
+ construction: {
7747
+ kind: "parallel",
7748
+ throughPoint: ctx.resolveId(e.throughPoint),
7749
+ toLine: ctx.resolveId(e.toLine)
7750
+ }
7751
+ }
7752
+ }
7753
+ }]
7754
+ });
7755
+ }
7756
+ });
7757
+ var perpBisectorModule;
7758
+ var init_perpBisector = __esm({
7759
+ "src/stamps/geometry-2d/dsl/kinds/lines/perpBisector.ts"() {
7760
+ init_names();
7761
+ init_types4();
7762
+ init_shared();
7763
+ perpBisectorModule = defineModule({
7764
+ kind: "perpBisector",
7765
+ role: "lineConstruction",
7766
+ category: "lines",
7767
+ prefix: "l",
7768
+ schema: zod.z.object({
7769
+ name: NameZ,
7770
+ kind: zod.z.literal("perpBisector"),
7771
+ p1: NameZ,
7772
+ p2: NameZ
7773
+ }),
7774
+ collectRefs: (e) => [e.p1, e.p2],
7775
+ emit: (e, ctx) => [{
7776
+ role: "primary",
7777
+ object: {
7778
+ id: ctx.resolveId(e.name),
7779
+ kind: "line",
7780
+ label: e.name,
7781
+ ...SHAPE_BASE_FIELDS,
7782
+ attrs: {
7783
+ construction: {
7784
+ kind: "perpBisector",
7785
+ p1: ctx.resolveId(e.p1),
7786
+ p2: ctx.resolveId(e.p2)
7787
+ }
7788
+ }
7789
+ }
7790
+ }]
7791
+ });
7792
+ }
7793
+ });
7794
+ var angleBisectorModule;
7795
+ var init_angleBisector = __esm({
7796
+ "src/stamps/geometry-2d/dsl/kinds/lines/angleBisector.ts"() {
7797
+ init_names();
7798
+ init_types4();
7799
+ init_shared();
7800
+ angleBisectorModule = defineModule({
7801
+ kind: "angleBisector",
7802
+ role: "lineConstruction",
7803
+ category: "lines",
7804
+ prefix: "l",
7805
+ schema: zod.z.object({
7806
+ name: NameZ,
7807
+ kind: zod.z.literal("angleBisector"),
7808
+ p1: NameZ,
7809
+ vertex: NameZ,
7810
+ p2: NameZ
7811
+ }),
7812
+ collectRefs: (e) => [e.p1, e.vertex, e.p2],
7813
+ emit: (e, ctx) => [{
7814
+ role: "primary",
7815
+ object: {
7816
+ id: ctx.resolveId(e.name),
7817
+ kind: "line",
7818
+ label: e.name,
7819
+ ...SHAPE_BASE_FIELDS,
7820
+ attrs: {
7821
+ construction: {
7822
+ kind: "angleBisector",
7823
+ p1: ctx.resolveId(e.p1),
7824
+ vertex: ctx.resolveId(e.vertex),
7825
+ p2: ctx.resolveId(e.p2)
7826
+ }
7827
+ }
7828
+ }
7829
+ }]
7830
+ });
7831
+ }
7832
+ });
7833
+ var tangentModule;
7834
+ var init_tangent = __esm({
7835
+ "src/stamps/geometry-2d/dsl/kinds/lines/tangent.ts"() {
7836
+ init_names();
7837
+ init_types4();
7838
+ init_shared();
7839
+ tangentModule = defineModule({
7840
+ kind: "tangent",
7841
+ role: "lineConstruction",
7842
+ category: "lines",
7843
+ prefix: "l",
7844
+ schema: zod.z.object({
7845
+ name: NameZ,
7846
+ kind: zod.z.literal("tangent"),
7847
+ throughPoint: NameZ,
7848
+ toCircle: NameZ,
7849
+ branch: zod.z.union([zod.z.literal(0), zod.z.literal(1), zod.z.literal("on")]).optional()
7850
+ }),
7851
+ collectRefs: (e) => [e.throughPoint, e.toCircle],
7852
+ emit: (e, ctx) => {
7853
+ const construction = {
7854
+ kind: "tangent",
7855
+ throughPoint: ctx.resolveId(e.throughPoint),
7856
+ toCircle: ctx.resolveId(e.toCircle)
7857
+ };
7858
+ if (e.branch !== void 0) construction.branch = e.branch;
7859
+ return [{
7860
+ role: "primary",
7861
+ object: {
7862
+ id: ctx.resolveId(e.name),
7863
+ kind: "line",
7864
+ label: e.name,
7865
+ ...SHAPE_BASE_FIELDS,
7866
+ attrs: { construction }
7867
+ }
7868
+ }];
7869
+ }
7870
+ });
7871
+ }
7872
+ });
7873
+ var polygonModule;
7874
+ var init_polygon3 = __esm({
7875
+ "src/stamps/geometry-2d/dsl/kinds/polygons/polygon.ts"() {
7876
+ init_names();
7877
+ init_types4();
7878
+ init_shared();
7879
+ polygonModule = defineModule({
7880
+ kind: "polygon",
7881
+ role: "polygon",
7882
+ category: "polygons",
7883
+ prefix: "poly",
7884
+ schema: zod.z.object({
7885
+ name: NameZ,
7886
+ kind: zod.z.literal("polygon"),
7887
+ vertices: zod.z.array(NameZ).min(3)
7888
+ }),
7889
+ collectRefs: (e) => [...e.vertices],
7890
+ emit: (e, ctx) => [{
7891
+ role: "primary",
7892
+ object: {
7893
+ id: ctx.resolveId(e.name),
7894
+ kind: "polygon",
7895
+ label: e.name,
7896
+ ...SHAPE_BASE_FIELDS,
7897
+ attrs: { vertices: e.vertices.map((v) => ctx.resolveId(v)) }
7898
+ }
7899
+ }]
7900
+ });
7901
+ }
7902
+ });
7903
+ var circleCPModule;
7904
+ var init_circleCP = __esm({
7905
+ "src/stamps/geometry-2d/dsl/kinds/circles/circleCP.ts"() {
7906
+ init_names();
7907
+ init_types4();
7908
+ init_shared();
7909
+ circleCPModule = defineModule({
7910
+ kind: "circleCP",
7911
+ role: "circle",
7912
+ category: "circles",
7913
+ prefix: "c",
7914
+ schema: zod.z.object({
7915
+ name: NameZ,
7916
+ kind: zod.z.literal("circleCP"),
7917
+ center: NameZ,
7918
+ surfacePoint: NameZ
7919
+ }),
7920
+ collectRefs: (e) => [e.center, e.surfacePoint],
7921
+ emit: (e, ctx) => [{
7922
+ role: "primary",
7923
+ object: {
7924
+ id: ctx.resolveId(e.name),
7925
+ kind: "circle",
7926
+ label: e.name,
7927
+ ...SHAPE_BASE_FIELDS,
7928
+ attrs: { center: ctx.resolveId(e.center), surfacePoint: ctx.resolveId(e.surfacePoint) }
7929
+ }
7930
+ }]
7931
+ });
7932
+ }
7933
+ });
7934
+ var circle3Module;
7935
+ var init_circle3 = __esm({
7936
+ "src/stamps/geometry-2d/dsl/kinds/circles/circle3.ts"() {
7937
+ init_names();
7938
+ init_types4();
7939
+ init_shared();
7940
+ circle3Module = defineModule({
7941
+ kind: "circle3",
7942
+ role: "circle",
7943
+ category: "circles",
7944
+ prefix: "c",
7945
+ schema: zod.z.object({
7946
+ name: NameZ,
7947
+ kind: zod.z.literal("circle3"),
7948
+ p1: NameZ,
7949
+ p2: NameZ,
7950
+ p3: NameZ
7951
+ }),
7952
+ collectRefs: (e) => [e.p1, e.p2, e.p3],
7953
+ emit: (e, ctx) => [{
7954
+ role: "primary",
7955
+ object: {
7956
+ id: ctx.resolveId(e.name),
7957
+ kind: "circle",
7958
+ label: e.name,
7959
+ ...SHAPE_BASE_FIELDS,
7960
+ attrs: {
7961
+ construction: {
7962
+ kind: "circumscribed",
7963
+ p1: ctx.resolveId(e.p1),
7964
+ p2: ctx.resolveId(e.p2),
7965
+ p3: ctx.resolveId(e.p3)
7966
+ }
7967
+ }
7968
+ }
7969
+ }]
7970
+ });
7971
+ }
7972
+ });
7973
+ var ALL_MODULES, POINT_KINDS;
7974
+ var init_registry2 = __esm({
7975
+ "src/stamps/geometry-2d/dsl/registry.ts"() {
7976
+ init_free();
7977
+ init_midpoint();
7978
+ init_onSegment();
7979
+ init_onLine();
7980
+ init_onCircle();
7981
+ init_perpFoot();
7982
+ init_circumcenter();
7983
+ init_incenter();
7984
+ init_centroid();
7985
+ init_orthocenter();
7986
+ init_intersection2();
7987
+ init_segment2();
7988
+ init_line2();
7989
+ init_ray2();
7990
+ init_perpendicular();
7991
+ init_parallel();
7992
+ init_perpBisector();
7993
+ init_angleBisector();
7994
+ init_tangent();
7995
+ init_polygon3();
7996
+ init_circleCP();
7997
+ init_circle3();
7998
+ ALL_MODULES = [
7999
+ freeModule,
8000
+ midpointModule,
8001
+ onSegmentModule,
8002
+ onLineModule,
8003
+ onCircleModule,
8004
+ perpFootModule,
8005
+ circumcenterModule,
8006
+ incenterModule,
8007
+ centroidModule,
8008
+ orthocenterModule,
8009
+ intersectionModule,
8010
+ segmentModule,
8011
+ lineModule,
8012
+ rayModule,
8013
+ perpendicularModule,
8014
+ parallelModule,
8015
+ perpBisectorModule,
8016
+ angleBisectorModule,
8017
+ tangentModule,
8018
+ polygonModule,
8019
+ circleCPModule,
8020
+ circle3Module
8021
+ ];
8022
+ new Map(ALL_MODULES.map((m) => [m.kind, m]));
8023
+ POINT_KINDS = new Set(
8024
+ ALL_MODULES.filter((m) => m.role === "point").map((m) => m.kind)
8025
+ );
8026
+ new Set(
8027
+ ALL_MODULES.filter(
8028
+ (m) => m.role === "segment" || m.role === "line" || m.role === "ray" || m.role === "lineConstruction"
8029
+ ).map((m) => m.kind)
8030
+ );
8031
+ new Set(
8032
+ ALL_MODULES.filter((m) => m.role === "circle").map((m) => m.kind)
8033
+ );
8034
+ zod.z.discriminatedUnion(
8035
+ "kind",
8036
+ ALL_MODULES.map((m) => m.schema)
8037
+ );
8038
+ }
8039
+ });
8040
+
8041
+ // src/stamps/geometry-2d/dsl/serialize.ts
8042
+ function isValidName(s) {
8043
+ return NAME_REGEX.test(s);
8044
+ }
8045
+ function labelOf2(id, state) {
8046
+ const obj = state.objects[id];
8047
+ return obj ? obj.label : null;
8048
+ }
8049
+ function resolveRefs(ids, state) {
8050
+ const out = [];
8051
+ for (const id of ids) {
8052
+ const lab = labelOf2(id, state);
8053
+ if (lab == null || !isValidName(lab)) return null;
8054
+ out.push(lab);
8055
+ }
8056
+ return out;
8057
+ }
8058
+ function fail(reason, detail) {
8059
+ return { ok: false, reason, detail };
8060
+ }
8061
+ function serializePoint(obj, state) {
8062
+ const c = obj.attrs?.constraint;
8063
+ if (!c) return fail("unsupported-constraint", "missing");
8064
+ switch (c.kind) {
8065
+ case "free":
8066
+ return { ok: true, entity: { name: obj.label, kind: "free", x: c.x, y: c.y } };
8067
+ case "midpoint": {
8068
+ const refs = resolveRefs([c.p1, c.p2], state);
8069
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2}`);
8070
+ return { ok: true, entity: { name: obj.label, kind: "midpoint", p1: refs[0], p2: refs[1] } };
8071
+ }
8072
+ case "onSegment": {
8073
+ const refs = resolveRefs([c.segmentId], state);
8074
+ if (!refs) return fail("unresolved-ref", c.segmentId);
8075
+ return { ok: true, entity: { name: obj.label, kind: "onSegment", segmentId: refs[0], t: c.t } };
8076
+ }
8077
+ case "onLine": {
8078
+ const refs = resolveRefs([c.lineId], state);
8079
+ if (!refs) return fail("unresolved-ref", c.lineId);
8080
+ return { ok: true, entity: { name: obj.label, kind: "onLine", lineId: refs[0], t: c.t } };
8081
+ }
8082
+ case "onCircle": {
8083
+ const refs = resolveRefs([c.circleId], state);
8084
+ if (!refs) return fail("unresolved-ref", c.circleId);
8085
+ return { ok: true, entity: { name: obj.label, kind: "onCircle", circleId: refs[0], theta: c.theta } };
8086
+ }
8087
+ case "perpFoot": {
8088
+ const refs = resolveRefs([c.from, c.onLine], state);
8089
+ if (!refs) return fail("unresolved-ref", `${c.from},${c.onLine}`);
8090
+ return { ok: true, entity: { name: obj.label, kind: "perpFoot", from: refs[0], onLine: refs[1] } };
8091
+ }
8092
+ case "circumcenter":
8093
+ case "incenter":
8094
+ case "centroid":
8095
+ case "orthocenter": {
8096
+ const refs = resolveRefs(c.vertices, state);
8097
+ if (!refs || refs.length !== 3) return fail("unresolved-ref", c.vertices.join(","));
8098
+ return {
8099
+ ok: true,
8100
+ entity: {
8101
+ name: obj.label,
8102
+ kind: c.kind,
8103
+ vertices: [refs[0], refs[1], refs[2]]
8104
+ }
8105
+ };
8106
+ }
8107
+ // Out of DSL v1:
8108
+ case "onAxis":
8109
+ case "onPolygon":
8110
+ case "transformed":
8111
+ return fail("unsupported-constraint", c.kind);
8112
+ default: {
8113
+ return fail("unsupported-constraint");
8114
+ }
8115
+ }
8116
+ }
8117
+ function serializeIntersection(obj, state) {
8118
+ const a = obj.attrs;
8119
+ const refs = resolveRefs([a.ref1, a.ref2], state);
8120
+ if (!refs) return fail("unresolved-ref", `${a.ref1},${a.ref2}`);
8121
+ if (a.kind === "lineLine") {
8122
+ return { ok: true, entity: { name: obj.label, kind: "intersection", ref1: refs[0], ref2: refs[1] } };
8123
+ }
8124
+ return {
8125
+ ok: true,
8126
+ entity: {
8127
+ name: obj.label,
8128
+ kind: "intersection",
8129
+ ref1: refs[0],
8130
+ ref2: refs[1],
8131
+ branch: a.branch
8132
+ }
8133
+ };
8134
+ }
8135
+ function serializeSegment(obj, state) {
8136
+ const refs = resolveRefs([obj.attrs.p1, obj.attrs.p2], state);
8137
+ if (!refs) return fail("unresolved-ref", `${obj.attrs.p1},${obj.attrs.p2}`);
8138
+ return { ok: true, entity: { name: obj.label, kind: "segment", p1: refs[0], p2: refs[1] } };
8139
+ }
8140
+ function serializeRay(obj, state) {
8141
+ const refs = resolveRefs([obj.attrs.origin, obj.attrs.through], state);
8142
+ if (!refs) return fail("unresolved-ref", `${obj.attrs.origin},${obj.attrs.through}`);
8143
+ return { ok: true, entity: { name: obj.label, kind: "ray", origin: refs[0], through: refs[1] } };
8144
+ }
8145
+ function serializeLine(obj, state) {
8146
+ const a = obj.attrs;
8147
+ const c = a.construction;
8148
+ if (!c) {
8149
+ if (!a.p1 || !a.p2) return fail("unsupported-construction", "missing p1/p2");
8150
+ const refs = resolveRefs([a.p1, a.p2], state);
8151
+ if (!refs) return fail("unresolved-ref", `${a.p1},${a.p2}`);
8152
+ return { ok: true, entity: { name: obj.label, kind: "line", p1: refs[0], p2: refs[1] } };
8153
+ }
8154
+ switch (c.kind) {
8155
+ case "perpendicular":
8156
+ case "parallel": {
8157
+ const refs = resolveRefs([c.throughPoint, c.toLine], state);
8158
+ if (!refs) return fail("unresolved-ref", `${c.throughPoint},${c.toLine}`);
8159
+ return {
8160
+ ok: true,
8161
+ entity: { name: obj.label, kind: c.kind, throughPoint: refs[0], toLine: refs[1] }
8162
+ };
8163
+ }
8164
+ case "perpBisector": {
8165
+ const refs = resolveRefs([c.p1, c.p2], state);
8166
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2}`);
8167
+ return { ok: true, entity: { name: obj.label, kind: "perpBisector", p1: refs[0], p2: refs[1] } };
8168
+ }
8169
+ case "angleBisector": {
8170
+ const refs = resolveRefs([c.p1, c.vertex, c.p2], state);
8171
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.vertex},${c.p2}`);
8172
+ return {
8173
+ ok: true,
8174
+ entity: {
8175
+ name: obj.label,
8176
+ kind: "angleBisector",
8177
+ p1: refs[0],
8178
+ vertex: refs[1],
8179
+ p2: refs[2]
8180
+ }
8181
+ };
8182
+ }
8183
+ case "tangent": {
8184
+ const refs = resolveRefs([c.throughPoint, c.toCircle], state);
8185
+ if (!refs) return fail("unresolved-ref", `${c.throughPoint},${c.toCircle}`);
8186
+ const entity = c.branch !== void 0 ? {
8187
+ name: obj.label,
8188
+ kind: "tangent",
8189
+ throughPoint: refs[0],
8190
+ toCircle: refs[1],
8191
+ branch: c.branch
8192
+ } : { name: obj.label, kind: "tangent", throughPoint: refs[0], toCircle: refs[1] };
8193
+ return { ok: true, entity };
8194
+ }
8195
+ case "angleBisectorLines":
8196
+ return fail("unsupported-construction", "angleBisectorLines");
8197
+ default: {
8198
+ return fail("unsupported-construction");
8199
+ }
8200
+ }
8201
+ }
8202
+ function serializePolygon(obj, state) {
8203
+ const a = obj.attrs;
8204
+ if (a.construction) return fail("unsupported-construction", a.construction.kind);
8205
+ if (!Array.isArray(a.vertices) || a.vertices.length < 3) {
8206
+ return fail("unsupported-construction", "missing vertices");
8207
+ }
8208
+ const refs = resolveRefs(a.vertices, state);
8209
+ if (!refs) return fail("unresolved-ref", a.vertices.join(","));
8210
+ return { ok: true, entity: { name: obj.label, kind: "polygon", vertices: refs } };
8211
+ }
8212
+ function serializeCircle(obj, state) {
8213
+ const a = obj.attrs;
8214
+ const c = a.construction;
8215
+ if (!c) {
8216
+ if (!a.center || !a.surfacePoint) {
8217
+ return fail("unsupported-construction", "missing center/surfacePoint");
8218
+ }
8219
+ const refs = resolveRefs([a.center, a.surfacePoint], state);
8220
+ if (!refs) return fail("unresolved-ref", `${a.center},${a.surfacePoint}`);
8221
+ return {
8222
+ ok: true,
8223
+ entity: { name: obj.label, kind: "circleCP", center: refs[0], surfacePoint: refs[1] }
8224
+ };
8225
+ }
8226
+ if (c.kind === "circumscribed") {
8227
+ const refs = resolveRefs([c.p1, c.p2, c.p3], state);
8228
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2},${c.p3}`);
8229
+ return {
8230
+ ok: true,
8231
+ entity: { name: obj.label, kind: "circle3", p1: refs[0], p2: refs[1], p3: refs[2] }
8232
+ };
8233
+ }
8234
+ return fail("unsupported-construction");
8235
+ }
8236
+ function serializeObject(obj, state) {
8237
+ if (!isValidName(obj.label)) {
8238
+ return fail("invalid-label", obj.label);
8239
+ }
8240
+ switch (obj.kind) {
8241
+ case "point":
8242
+ return serializePoint(obj, state);
8243
+ case "segment":
8244
+ return serializeSegment(obj, state);
8245
+ case "ray":
8246
+ return serializeRay(obj, state);
8247
+ case "line":
8248
+ return serializeLine(obj, state);
8249
+ case "polygon":
8250
+ return serializePolygon(obj, state);
8251
+ case "circle":
8252
+ return serializeCircle(obj, state);
8253
+ case "intersection":
8254
+ return serializeIntersection(obj, state);
8255
+ default:
8256
+ return fail("unsupported-kind", obj.kind);
8257
+ }
8258
+ }
8259
+ function serializeState(state) {
8260
+ const points = [];
8261
+ const shapes = [];
8262
+ const unsupported = [];
8263
+ for (const id of state.order) {
8264
+ const obj = state.objects[id];
8265
+ if (!obj) continue;
8266
+ const r = serializeObject(obj, state);
8267
+ if (!r.ok) {
8268
+ unsupported.push({
8269
+ id: obj.id,
8270
+ label: obj.label,
8271
+ kind: obj.kind,
8272
+ reason: r.reason,
8273
+ detail: r.detail
8274
+ });
8275
+ continue;
8276
+ }
8277
+ if (POINT_KINDS.has(r.entity.kind)) {
8278
+ points.push(r.entity);
8279
+ } else {
8280
+ shapes.push(r.entity);
8281
+ }
8282
+ }
8283
+ return {
8284
+ dsl: { version: 1, points, shapes },
8285
+ unsupported
8286
+ };
8287
+ }
8288
+ var NAME_REGEX;
8289
+ var init_serialize2 = __esm({
8290
+ "src/stamps/geometry-2d/dsl/serialize.ts"() {
8291
+ init_registry2();
8292
+ NAME_REGEX = /^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/;
8293
+ }
8294
+ });
8295
+ function useAiFigure(generator, options = {}) {
8296
+ const { currentState } = options;
7214
8297
  const [prompt, setPrompt] = React18.useState("");
7215
8298
  const [isLoading, setIsLoading] = React18.useState(false);
7216
8299
  const [error, setError] = React18.useState(null);
8300
+ const [tokens, setTokens] = React18.useState(0);
7217
8301
  const abortRef = React18.useRef(null);
7218
8302
  const requestIdRef = React18.useRef(0);
8303
+ const { dsl: currentDsl, unsupported, entityCount, hasContent } = React18.useMemo(() => {
8304
+ if (!currentState || currentState.order.length === 0) {
8305
+ return {
8306
+ dsl: null,
8307
+ unsupported: [],
8308
+ entityCount: { points: 0, shapes: 0 },
8309
+ hasContent: false
8310
+ };
8311
+ }
8312
+ const { dsl, unsupported: unsupported2 } = serializeState(currentState);
8313
+ return {
8314
+ dsl,
8315
+ unsupported: unsupported2,
8316
+ entityCount: { points: dsl.points.length, shapes: dsl.shapes.length },
8317
+ hasContent: true
8318
+ };
8319
+ }, [currentState]);
8320
+ const hasUnsupported = unsupported.length > 0;
8321
+ const initialMode = hasContent && !hasUnsupported ? "refine" : "build";
8322
+ const [mode, setModeInternal] = React18.useState(initialMode);
8323
+ React18.useEffect(() => {
8324
+ if (!hasContent && mode === "refine") setModeInternal("build");
8325
+ if (hasUnsupported && mode === "refine") setModeInternal("build");
8326
+ }, [hasContent, hasUnsupported, mode]);
8327
+ const setMode = React18.useCallback((next) => {
8328
+ setModeInternal(next);
8329
+ }, []);
7219
8330
  React18.useEffect(() => () => abortRef.current?.abort(), []);
7220
8331
  const submit = React18.useCallback(async () => {
7221
8332
  const problem = prompt.trim();
@@ -7233,8 +8344,15 @@ function useAiFigure(generator) {
7233
8344
  abortRef.current = controller;
7234
8345
  setIsLoading(true);
7235
8346
  setError(null);
8347
+ setTokens(0);
7236
8348
  try {
7237
- const generated = await generator(problem, { signal: controller.signal });
8349
+ const generated = await generator(problem, {
8350
+ signal: controller.signal,
8351
+ onProgress: (info) => {
8352
+ if (requestId === requestIdRef.current) setTokens(info.tokens);
8353
+ },
8354
+ ...mode === "refine" && currentDsl ? { currentDsl } : {}
8355
+ });
7238
8356
  if (controller.signal.aborted || requestId !== requestIdRef.current) return null;
7239
8357
  if (!generated.ok) {
7240
8358
  setError(generated.message);
@@ -7246,7 +8364,9 @@ function useAiFigure(generator) {
7246
8364
  return null;
7247
8365
  }
7248
8366
  if (requestId === requestIdRef.current) {
7249
- setError(caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI.");
8367
+ setError(
8368
+ caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI."
8369
+ );
7250
8370
  }
7251
8371
  return null;
7252
8372
  } finally {
@@ -7255,27 +8375,75 @@ function useAiFigure(generator) {
7255
8375
  setIsLoading(false);
7256
8376
  }
7257
8377
  }
7258
- }, [generator, prompt]);
7259
- return { prompt, setPrompt, isLoading, error, submit };
8378
+ }, [generator, prompt, mode, currentDsl]);
8379
+ const cancel = React18.useCallback(() => {
8380
+ abortRef.current?.abort();
8381
+ }, []);
8382
+ return {
8383
+ prompt,
8384
+ setPrompt,
8385
+ isLoading,
8386
+ error,
8387
+ submit,
8388
+ cancel,
8389
+ tokens,
8390
+ mode,
8391
+ setMode,
8392
+ entityCount,
8393
+ hasUnsupported
8394
+ };
7260
8395
  }
7261
8396
  var init_useAiFigure = __esm({
7262
8397
  "src/stamps/geometry-2d/editor/useAiFigure.ts"() {
7263
8398
  "use client";
8399
+ init_serialize2();
7264
8400
  }
7265
8401
  });
7266
- function AiFigurePrompt({ generator, onGenerated }) {
8402
+ function AiFigurePrompt({ generator, onGenerated, currentState }) {
7267
8403
  const {
7268
8404
  prompt,
7269
8405
  setPrompt,
7270
8406
  isLoading,
7271
8407
  error,
7272
- submit
7273
- } = useAiFigure(generator);
7274
- const handleSubmit = React18.useCallback(async (event) => {
7275
- event.preventDefault();
7276
- const generated = await submit();
7277
- if (generated) onGenerated(generated);
7278
- }, [onGenerated, submit]);
8408
+ submit,
8409
+ cancel,
8410
+ tokens,
8411
+ mode,
8412
+ setMode,
8413
+ entityCount,
8414
+ hasUnsupported
8415
+ } = useAiFigure(generator, { currentState });
8416
+ const [elapsed, setElapsed] = React18.useState(0);
8417
+ React18.useEffect(() => {
8418
+ if (!isLoading) {
8419
+ setElapsed(0);
8420
+ return;
8421
+ }
8422
+ setElapsed(0);
8423
+ const id = setInterval(() => setElapsed((s) => s + 1), 1e3);
8424
+ return () => clearInterval(id);
8425
+ }, [isLoading]);
8426
+ const handleSubmit = React18.useCallback(
8427
+ async (event) => {
8428
+ event.preventDefault();
8429
+ const generated = await submit();
8430
+ if (generated) onGenerated(generated);
8431
+ },
8432
+ [onGenerated, submit]
8433
+ );
8434
+ const handleSwitchToBuild = React18.useCallback(() => {
8435
+ if (currentState && currentState.order.length > 0) {
8436
+ const ok = window.confirm(
8437
+ "D\u1EF1ng m\u1EDBi s\u1EBD thay to\xE0n b\u1ED9 h\xECnh hi\u1EC7n t\u1EA1i b\u1EB1ng h\xECnh m\u1EDBi t\u1EEB AI. Ti\u1EBFp t\u1EE5c?"
8438
+ );
8439
+ if (!ok) return;
8440
+ }
8441
+ setMode("build");
8442
+ }, [currentState, setMode]);
8443
+ const primaryLabel = isLoading ? tokens > 0 ? `\u0110ang d\u1EF1ng ${tokens}tok / ${elapsed}s \u2014 Hu\u1EF7` : `\u0110ang d\u1EF1ng... ${elapsed}s \u2014 Hu\u1EF7` : "D\u1EF1ng b\u1EB1ng AI";
8444
+ const hasContent = currentState != null && currentState.order.length > 0;
8445
+ const examples = mode === "refine" ? REFINE_EXAMPLES : BUILD_EXAMPLES;
8446
+ const refineChipLabel = entityCount.points + entityCount.shapes > 0 ? `Th\xEAm v\xE0o \xB7 ${entityCount.points}\u0111, ${entityCount.shapes}\u0111o\u1EA1n` : "Th\xEAm v\xE0o";
7279
8447
  return /* @__PURE__ */ jsxRuntime.jsxs(
7280
8448
  "form",
7281
8449
  {
@@ -7285,7 +8453,47 @@ function AiFigurePrompt({ generator, onGenerated }) {
7285
8453
  },
7286
8454
  className: "border-b border-slate-200 bg-slate-50 px-3 py-2",
7287
8455
  children: [
7288
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "geometry-ai-prompt", className: "mb-1 block text-xs font-medium text-slate-600", children: "D\u1EF1ng h\xECnh b\u1EB1ng AI" }),
8456
+ /* @__PURE__ */ jsxRuntime.jsx(
8457
+ "label",
8458
+ {
8459
+ htmlFor: "geometry-ai-prompt",
8460
+ className: "mb-1 block text-xs font-medium text-slate-600",
8461
+ children: "D\u1EF1ng h\xECnh b\u1EB1ng AI"
8462
+ }
8463
+ ),
8464
+ hasContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
8465
+ /* @__PURE__ */ jsxRuntime.jsx(
8466
+ "button",
8467
+ {
8468
+ type: "button",
8469
+ "data-testid": "geometry-ai-mode-refine",
8470
+ onClick: () => setMode("refine"),
8471
+ disabled: isLoading || hasUnsupported,
8472
+ className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "refine" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"} ${hasUnsupported ? "cursor-not-allowed opacity-50" : ""}`,
8473
+ title: hasUnsupported ? "H\xECnh hi\u1EC7n t\u1EA1i c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL \u2014 ch\u1EC9 d\u1EF1ng m\u1EDBi \u0111\u01B0\u1EE3c" : refineChipLabel,
8474
+ children: refineChipLabel
8475
+ }
8476
+ ),
8477
+ /* @__PURE__ */ jsxRuntime.jsx(
8478
+ "button",
8479
+ {
8480
+ type: "button",
8481
+ "data-testid": "geometry-ai-mode-build",
8482
+ onClick: handleSwitchToBuild,
8483
+ disabled: isLoading,
8484
+ className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "build" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"}`,
8485
+ children: "D\u1EF1ng m\u1EDBi"
8486
+ }
8487
+ ),
8488
+ hasUnsupported && /* @__PURE__ */ jsxRuntime.jsx(
8489
+ "span",
8490
+ {
8491
+ className: "text-[10px] text-amber-700",
8492
+ "data-testid": "geometry-ai-unsupported-warning",
8493
+ children: "H\xECnh c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL"
8494
+ }
8495
+ )
8496
+ ] }),
7289
8497
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
7290
8498
  /* @__PURE__ */ jsxRuntime.jsx(
7291
8499
  "textarea",
@@ -7296,29 +8504,63 @@ function AiFigurePrompt({ generator, onGenerated }) {
7296
8504
  onChange: (event) => setPrompt(event.target.value),
7297
8505
  disabled: isLoading,
7298
8506
  rows: 2,
7299
- placeholder: "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
8507
+ placeholder: mode === "refine" ? "V\xED d\u1EE5: th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC" : "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
7300
8508
  className: "min-h-12 flex-1 resize-none rounded border border-slate-300 bg-white px-2 py-1.5 text-xs text-slate-800 outline-none focus:border-emerald-500 disabled:opacity-60"
7301
8509
  }
7302
8510
  ),
7303
- /* @__PURE__ */ jsxRuntime.jsx(
8511
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
8512
+ "button",
8513
+ {
8514
+ type: "button",
8515
+ onClick: cancel,
8516
+ className: "rounded bg-amber-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-amber-700",
8517
+ children: primaryLabel
8518
+ }
8519
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
7304
8520
  "button",
7305
8521
  {
7306
8522
  type: "submit",
7307
- disabled: isLoading || !prompt.trim(),
8523
+ disabled: !prompt.trim(),
7308
8524
  className: "rounded bg-emerald-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-emerald-700 disabled:opacity-50",
7309
- children: isLoading ? "\u0110ang d\u1EF1ng..." : "D\u1EF1ng b\u1EB1ng AI"
8525
+ children: primaryLabel
7310
8526
  }
7311
8527
  )
7312
8528
  ] }),
7313
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error })
8529
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error }),
8530
+ !isLoading && !prompt.trim() && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
8531
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-slate-500", children: "G\u1EE3i \xFD:" }),
8532
+ examples.map((ex) => /* @__PURE__ */ jsxRuntime.jsx(
8533
+ "button",
8534
+ {
8535
+ type: "button",
8536
+ onClick: () => setPrompt(ex),
8537
+ className: "rounded-full border border-slate-300 bg-white px-2 py-0.5 text-[10px] text-slate-600 transition hover:border-emerald-400 hover:bg-emerald-50 hover:text-emerald-700",
8538
+ children: ex
8539
+ },
8540
+ ex
8541
+ ))
8542
+ ] })
7314
8543
  ]
7315
8544
  }
7316
8545
  );
7317
8546
  }
8547
+ var BUILD_EXAMPLES, REFINE_EXAMPLES;
7318
8548
  var init_AiFigurePrompt = __esm({
7319
8549
  "src/stamps/geometry-2d/editor/AiFigurePrompt.tsx"() {
7320
8550
  "use client";
7321
8551
  init_useAiFigure();
8552
+ BUILD_EXAMPLES = [
8553
+ "Tam gi\xE1c ABC, d\u1EF1ng trung \u0111i\u1EC3m M c\u1EE7a BC",
8554
+ "Tam gi\xE1c ABC vu\xF4ng t\u1EA1i A, AH l\xE0 \u0111\u01B0\u1EDDng cao xu\u1ED1ng BC",
8555
+ "H\xECnh thoi ABCD, hai \u0111\u01B0\u1EDDng ch\xE9o c\u1EAFt nhau t\u1EA1i O",
8556
+ "T\u1EEB \u0111i\u1EC3m M ngo\xE0i \u0111\u01B0\u1EDDng tr\xF2n (O), k\u1EBB hai ti\u1EBFp tuy\u1EBFn"
8557
+ ];
8558
+ REFINE_EXAMPLES = [
8559
+ "Th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC",
8560
+ "D\u1EF1ng \u0111\u01B0\u1EDDng cao AH xu\u1ED1ng BC",
8561
+ "V\u1EBD \u0111\u01B0\u1EDDng tr\xF2n ngo\u1EA1i ti\u1EBFp",
8562
+ "Th\xEAm ti\u1EBFp tuy\u1EBFn t\u1EA1i A"
8563
+ ];
7322
8564
  }
7323
8565
  });
7324
8566
  var GeometryEditorPanelInner, GeometryEditorPanel;
@@ -7369,6 +8611,11 @@ var init_EditorPanel = __esm({
7369
8611
  onSelectionChangeRef.current = onSelectionChange;
7370
8612
  }, [onSelectionChange]);
7371
8613
  useEditorState({ store, onHistoryChange });
8614
+ const currentSceneState = React18.useSyncExternalStore(
8615
+ (cb) => store.subscribe(cb),
8616
+ () => store.getState(),
8617
+ () => store.getState()
8618
+ );
7372
8619
  React18.useEffect(() => {
7373
8620
  const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
7374
8621
  sync();
@@ -7562,7 +8809,7 @@ var init_EditorPanel = __esm({
7562
8809
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
7563
8810
  ] }) })
7564
8811
  ] }),
7565
- generateGeometryFigure && /* @__PURE__ */ jsxRuntime.jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
8812
+ generateGeometryFigure && /* @__PURE__ */ jsxRuntime.jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure, currentState: currentSceneState }),
7566
8813
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
7567
8814
  MiniBoard2D,
7568
8815
  {
@@ -7853,6 +9100,116 @@ var init_useStampStore = __esm({
7853
9100
  }
7854
9101
  });
7855
9102
 
9103
+ // src/stamps/geometry-2d/dsl/describeDsl.ts
9104
+ function describeEntity(e) {
9105
+ switch (e.kind) {
9106
+ case "free":
9107
+ return `${e.name} = (${e.x}, ${e.y})`;
9108
+ case "midpoint":
9109
+ return `${e.name} = trung \u0111i\u1EC3m ${e.p1}${e.p2}`;
9110
+ case "onSegment":
9111
+ return `${e.name} \u2208 \u0111o\u1EA1n ${e.segmentId} (t = ${e.t})`;
9112
+ case "onLine":
9113
+ return `${e.name} \u2208 \u0111\u01B0\u1EDDng ${e.lineId} (t = ${e.t})`;
9114
+ case "onCircle":
9115
+ return `${e.name} \u2208 \u0111\u01B0\u1EDDng tr\xF2n ${e.circleId} (\u03B8 = ${e.theta})`;
9116
+ case "perpFoot":
9117
+ return `${e.name} = ch\xE2n vu\xF4ng g\xF3c t\u1EEB ${e.from} xu\u1ED1ng ${e.onLine}`;
9118
+ case "circumcenter":
9119
+ return `${e.name} = t\xE2m ngo\u1EA1i ti\u1EBFp ${e.vertices.join("")}`;
9120
+ case "incenter":
9121
+ return `${e.name} = t\xE2m n\u1ED9i ti\u1EBFp ${e.vertices.join("")}`;
9122
+ case "centroid":
9123
+ return `${e.name} = tr\u1ECDng t\xE2m ${e.vertices.join("")}`;
9124
+ case "orthocenter":
9125
+ return `${e.name} = tr\u1EF1c t\xE2m ${e.vertices.join("")}`;
9126
+ case "intersection": {
9127
+ const branch = "branch" in e && e.branch !== void 0 ? ` (nh\xE1nh ${e.branch})` : "";
9128
+ return `${e.name} = ${e.ref1} \u2229 ${e.ref2}${branch}`;
9129
+ }
9130
+ case "segment":
9131
+ return `${e.name} = \u0111o\u1EA1n ${e.p1}${e.p2}`;
9132
+ case "line":
9133
+ return `${e.name} = \u0111\u01B0\u1EDDng th\u1EB3ng ${e.p1}${e.p2}`;
9134
+ case "ray":
9135
+ return `${e.name} = tia ${e.origin}${e.through}`;
9136
+ case "polygon":
9137
+ return `${e.name} = \u0111a gi\xE1c ${e.vertices.join("")}`;
9138
+ case "perpendicular":
9139
+ return `${e.name} \u27C2 ${e.toLine} qua ${e.throughPoint}`;
9140
+ case "parallel":
9141
+ return `${e.name} \u2225 ${e.toLine} qua ${e.throughPoint}`;
9142
+ case "perpBisector":
9143
+ return `${e.name} = trung tr\u1EF1c ${e.p1}${e.p2}`;
9144
+ case "angleBisector":
9145
+ return `${e.name} = ph\xE2n gi\xE1c \u2220${e.p1}${e.vertex}${e.p2}`;
9146
+ case "tangent": {
9147
+ const branch = "branch" in e && e.branch !== void 0 ? ` (nh\xE1nh ${e.branch})` : "";
9148
+ return `${e.name} = ti\u1EBFp tuy\u1EBFn ${e.toCircle} qua ${e.throughPoint}${branch}`;
9149
+ }
9150
+ case "circleCP":
9151
+ return `${e.name} = (${e.center}; ${e.center}${e.surfacePoint})`;
9152
+ case "circle3":
9153
+ return `${e.name} = \u0111\u01B0\u1EDDng tr\xF2n qua ${e.p1}${e.p2}${e.p3}`;
9154
+ default: {
9155
+ return "";
9156
+ }
9157
+ }
9158
+ }
9159
+ function describeDsl(obj, state) {
9160
+ const r = serializeObject(obj, state);
9161
+ if (r.ok) return describeEntity(r.entity);
9162
+ let base;
9163
+ try {
9164
+ base = getKind(obj.kind).describe(obj, state);
9165
+ } catch {
9166
+ base = `${obj.kind} ${obj.label}`;
9167
+ }
9168
+ return `${base} (kh\xF4ng h\u1ED7 tr\u1EE3 DSL)`;
9169
+ }
9170
+ var init_describeDsl = __esm({
9171
+ "src/stamps/geometry-2d/dsl/describeDsl.ts"() {
9172
+ init_registry();
9173
+ init_serialize2();
9174
+ }
9175
+ });
9176
+ function makeDslRenderRow(store) {
9177
+ return function renderDslRow(obj, defaults) {
9178
+ const state = store.getState();
9179
+ const noop = () => {
9180
+ };
9181
+ return /* @__PURE__ */ jsxRuntime.jsx(
9182
+ ObjectRow,
9183
+ {
9184
+ obj,
9185
+ state,
9186
+ selected: defaults.selected,
9187
+ onSelect: defaults.onClick,
9188
+ onToggleVisible: (id) => {
9189
+ const o = state.objects[id];
9190
+ if (!o) return;
9191
+ store.dispatch({ type: "UPDATE", payload: { id, patch: { visible: !o.visible } } });
9192
+ },
9193
+ onToggleLocked: (id) => {
9194
+ const o = state.objects[id];
9195
+ if (!o) return;
9196
+ store.dispatch({ type: "UPDATE", payload: { id, patch: { locked: !o.locked } } });
9197
+ },
9198
+ onRename: noop,
9199
+ onChangeColor: noop,
9200
+ onDelete: (id) => store.dispatch({ type: "DELETE", payload: { id } }),
9201
+ describe: describeDsl
9202
+ }
9203
+ );
9204
+ };
9205
+ }
9206
+ var init_dslRenderRow = __esm({
9207
+ "src/stamps/geometry-2d/editor/dslRenderRow.tsx"() {
9208
+ init_ObjectRow();
9209
+ init_describeDsl();
9210
+ }
9211
+ });
9212
+
7856
9213
  // src/stamps/geometry-2d/host.tsx
7857
9214
  var host_exports = {};
7858
9215
  __export(host_exports, {
@@ -7877,6 +9234,7 @@ var init_host = __esm({
7877
9234
  init_scene();
7878
9235
  init_useIsMobile();
7879
9236
  init_useStampStore();
9237
+ init_dslRenderRow();
7880
9238
  GeometryStampHost = React18.forwardRef(
7881
9239
  function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure }, ref) {
7882
9240
  const panelRef = React18.useRef(null);
@@ -7903,6 +9261,7 @@ var init_host = __esm({
7903
9261
  onSelect: (key) => setSelectedTool(key),
7904
9262
  enabled: !isMobile
7905
9263
  });
9264
+ const renderRow = React18.useMemo(() => makeDslRenderRow(sceneStore), [sceneStore]);
7906
9265
  const handleInsert = React18.useCallback(
7907
9266
  async (jsonState, svgString) => {
7908
9267
  if (!api) return;
@@ -7964,7 +9323,8 @@ var init_host = __esm({
7964
9323
  onObjectSelect: (id) => {
7965
9324
  setSelectedObjectId(id ?? void 0);
7966
9325
  panelRef.current?.selectObject(id);
7967
- }
9326
+ },
9327
+ renderRow
7968
9328
  },
7969
9329
  isMobile,
7970
9330
  drawerOpen,
@@ -8052,7 +9412,7 @@ function isLatexCustomData(data) {
8052
9412
  const d = data;
8053
9413
  return d.kind === "latex" && d.version === 1 && typeof d.src === "string";
8054
9414
  }
8055
- var init_types4 = __esm({
9415
+ var init_types5 = __esm({
8056
9416
  "src/stamps/latex/types.ts"() {
8057
9417
  }
8058
9418
  });
@@ -8461,7 +9821,7 @@ var init_host2 = __esm({
8461
9821
  init_EditorPopover();
8462
9822
  init_insertImage();
8463
9823
  init_useIsMobile();
8464
- init_types4();
9824
+ init_types5();
8465
9825
  LatexStampHost = React18.forwardRef(
8466
9826
  function LatexStampHost2({ api, editingElement, onClose }, ref) {
8467
9827
  const editorRef = React18.useRef(null);
@@ -8557,7 +9917,7 @@ function serializeBoard3D(state, view) {
8557
9917
  function deserializeBoard3D(raw) {
8558
9918
  return deserializeScene("3d", raw);
8559
9919
  }
8560
- var init_serialize2 = __esm({
9920
+ var init_serialize3 = __esm({
8561
9921
  "src/stamps/geometry-3d/serialize.ts"() {
8562
9922
  init_serializeScene();
8563
9923
  }
@@ -8565,7 +9925,7 @@ var init_serialize2 = __esm({
8565
9925
 
8566
9926
  // src/core/scene/render/types.ts
8567
9927
  var DEFAULT_THEME_3D;
8568
- var init_types5 = __esm({
9928
+ var init_types6 = __esm({
8569
9929
  "src/core/scene/render/types.ts"() {
8570
9930
  DEFAULT_THEME_3D = {
8571
9931
  point: { size: 4, color: "#1e40af" },
@@ -8580,7 +9940,7 @@ var JxgRenderer3D;
8580
9940
  var init_JxgRenderer3D = __esm({
8581
9941
  "src/core/scene/render/JxgRenderer3D.ts"() {
8582
9942
  init_registry();
8583
- init_types5();
9943
+ init_types6();
8584
9944
  JxgRenderer3D = class {
8585
9945
  constructor(store, view, options = {}) {
8586
9946
  this.elements = /* @__PURE__ */ new Map();
@@ -8943,7 +10303,7 @@ var OUTPUT_WIDTH, OUTPUT_HEIGHT, BBOX_2D;
8943
10303
  var init_render3 = __esm({
8944
10304
  "src/stamps/geometry-3d/render.ts"() {
8945
10305
  "use client";
8946
- init_serialize2();
10306
+ init_serialize3();
8947
10307
  init_scene();
8948
10308
  init_types();
8949
10309
  init_JxgRenderer3D();
@@ -9074,7 +10434,7 @@ function buildVector(args, store) {
9074
10434
  if (!from || !to || from === to) return null;
9075
10435
  return addDerived(store, "vector3d", "v", { from, to });
9076
10436
  }
9077
- var init_segment2 = __esm({
10437
+ var init_segment3 = __esm({
9078
10438
  "src/stamps/geometry-3d/editor/tools/handlers/segment.ts"() {
9079
10439
  init_scene();
9080
10440
  init_ensurePoint();
@@ -9101,7 +10461,7 @@ function buildPolygon(args, store) {
9101
10461
  store.dispatch({ type: "ADD", payload: { obj } });
9102
10462
  return id;
9103
10463
  }
9104
- var init_polygon3 = __esm({
10464
+ var init_polygon4 = __esm({
9105
10465
  "src/stamps/geometry-3d/editor/tools/handlers/polygon.ts"() {
9106
10466
  init_scene();
9107
10467
  init_ensurePoint();
@@ -9214,8 +10574,8 @@ function constraintToWorld(c, state) {
9214
10574
  const radius = norm(sub(surface, center));
9215
10575
  const x = center[0] + radius * Math.sin(c.phi) * Math.cos(c.theta);
9216
10576
  const y = center[1] + radius * Math.sin(c.phi) * Math.sin(c.theta);
9217
- const z = center[2] + radius * Math.cos(c.phi);
9218
- return [x, y, z];
10577
+ const z25 = center[2] + radius * Math.cos(c.phi);
10578
+ return [x, y, z25];
9219
10579
  }
9220
10580
  }
9221
10581
  }
@@ -9618,8 +10978,8 @@ var stubBuild, ALL_SURFACES, OBJECT_ONLY, NO_SURFACE, TOOLS2;
9618
10978
  var init_spec = __esm({
9619
10979
  "src/stamps/geometry-3d/editor/tools/spec.ts"() {
9620
10980
  init_point3();
9621
- init_segment2();
9622
- init_polygon3();
10981
+ init_segment3();
10982
+ init_polygon4();
9623
10983
  init_plane();
9624
10984
  init_pyramid();
9625
10985
  init_prism();
@@ -10911,7 +12271,7 @@ var init_EditorPanel2 = __esm({
10911
12271
  init_StatusHint();
10912
12272
  init_usePointDrag();
10913
12273
  init_editorHelpers();
10914
- init_serialize2();
12274
+ init_serialize3();
10915
12275
  init_render3();
10916
12276
  init_constants();
10917
12277
  init_Toast2();
@@ -11403,7 +12763,7 @@ var init_host3 = __esm({
11403
12763
  init_insertImage();
11404
12764
  init_useIsMobile();
11405
12765
  init_useStampStore();
11406
- init_serialize2();
12766
+ init_serialize3();
11407
12767
  Geom3DIconHeader = /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
11408
12768
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 9 L4 20 L14 20 L14 9 Z" }),
11409
12769
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 9 L10 4 L20 4 L14 9 Z" }),
@@ -11620,7 +12980,7 @@ function isGraph2DCustomData(data) {
11620
12980
  const d = data;
11621
12981
  return d.kind === "graph2d" && d.version === 2 && typeof d.jsonState === "string";
11622
12982
  }
11623
- var init_types6 = __esm({
12983
+ var init_types7 = __esm({
11624
12984
  "src/stamps/graph-2d/types.ts"() {
11625
12985
  }
11626
12986
  });
@@ -11651,7 +13011,7 @@ function parseSceneState(json) {
11651
13011
  if (!v.objects || typeof v.objects !== "object") return null;
11652
13012
  return raw;
11653
13013
  }
11654
- var init_serialize3 = __esm({
13014
+ var init_serialize4 = __esm({
11655
13015
  "src/stamps/graph-2d/serialize.ts"() {
11656
13016
  init_serializeScene();
11657
13017
  }
@@ -12186,7 +13546,7 @@ var init_EditorPanel3 = __esm({
12186
13546
  void (async () => {
12187
13547
  try {
12188
13548
  const { renderGraphSvgFromState: renderGraphSvgFromState2 } = await Promise.resolve().then(() => (init_render4(), render_exports));
12189
- const { stringifySceneState: stringifySceneState2 } = await Promise.resolve().then(() => (init_serialize3(), serialize_exports));
13549
+ const { stringifySceneState: stringifySceneState2 } = await Promise.resolve().then(() => (init_serialize4(), serialize_exports));
12190
13550
  const jsonState = stringifySceneState2(state);
12191
13551
  const svgString = await renderGraphSvgFromState2(state, !!isDark);
12192
13552
  onInsert(jsonState, svgString);
@@ -12662,8 +14022,8 @@ var init_host4 = __esm({
12662
14022
  init_insertImage();
12663
14023
  init_useIsMobile();
12664
14024
  init_useStampStore();
12665
- init_types6();
12666
- init_serialize3();
14025
+ init_types7();
14026
+ init_serialize4();
12667
14027
  init_tools2();
12668
14028
  init_FunctionRow();
12669
14029
  init_ParameterRow();
@@ -12911,7 +14271,7 @@ var geometryStamp = {
12911
14271
 
12912
14272
  // src/stamps/latex/index.tsx
12913
14273
  init_render2();
12914
- init_types4();
14274
+ init_types5();
12915
14275
  var LatexStampHost3 = React18.lazy(
12916
14276
  () => Promise.resolve().then(() => (init_host2(), host_exports2)).then((m) => ({ default: m.LatexStampHost }))
12917
14277
  );
@@ -12944,7 +14304,7 @@ var latexStamp = {
12944
14304
  };
12945
14305
 
12946
14306
  // src/stamps/geometry-3d/index.tsx
12947
- init_serialize2();
14307
+ init_serialize3();
12948
14308
  init_render3();
12949
14309
  init_svgToStampFile();
12950
14310
  var Geometry3DStampHost3 = React18.lazy(
@@ -13001,8 +14361,8 @@ var geometry3dStamp = {
13001
14361
 
13002
14362
  // src/stamps/graph-2d/index.tsx
13003
14363
  init_render4();
13004
- init_types6();
13005
- init_serialize3();
14364
+ init_types7();
14365
+ init_serialize4();
13006
14366
  init_svgToStampFile();
13007
14367
  var Graph2DStampHost3 = React18.lazy(
13008
14368
  () => Promise.resolve().then(() => (init_host4(), host_exports4)).then((m) => ({ default: m.Graph2DStampHost }))
@@ -14641,7 +16001,7 @@ async function readFiles(storageKey) {
14641
16001
  try {
14642
16002
  return await withStore(
14643
16003
  "readonly",
14644
- (store, setResult, fail) => {
16004
+ (store, setResult, fail2) => {
14645
16005
  const out = {};
14646
16006
  const req = store.index("storageKey").openCursor(IDBKeyRange.only(validKey));
14647
16007
  req.onsuccess = () => {
@@ -14658,7 +16018,7 @@ async function readFiles(storageKey) {
14658
16018
  };
14659
16019
  cursor.continue();
14660
16020
  };
14661
- req.onerror = () => fail(req.error);
16021
+ req.onerror = () => fail2(req.error);
14662
16022
  },
14663
16023
  {}
14664
16024
  );
@@ -14674,7 +16034,7 @@ async function writeFiles(storageKey, files) {
14674
16034
  try {
14675
16035
  await withStore(
14676
16036
  "readwrite",
14677
- (store, setResult, fail) => {
16037
+ (store, setResult, fail2) => {
14678
16038
  let pending = entries.length;
14679
16039
  const finishOne = () => {
14680
16040
  pending -= 1;
@@ -14699,9 +16059,9 @@ async function writeFiles(storageKey, files) {
14699
16059
  };
14700
16060
  const putReq = store.put(rec);
14701
16061
  putReq.onsuccess = finishOne;
14702
- putReq.onerror = () => fail(putReq.error);
16062
+ putReq.onerror = () => fail2(putReq.error);
14703
16063
  };
14704
- getReq.onerror = () => fail(getReq.error);
16064
+ getReq.onerror = () => fail2(getReq.error);
14705
16065
  }
14706
16066
  ;
14707
16067
  },
@@ -14716,7 +16076,7 @@ async function pruneFiles(storageKey, keepIds) {
14716
16076
  try {
14717
16077
  await withStore(
14718
16078
  "readwrite",
14719
- (store, setResult, fail) => {
16079
+ (store, setResult, fail2) => {
14720
16080
  const req = store.index("storageKey").openCursor(IDBKeyRange.only(validKey));
14721
16081
  req.onsuccess = () => {
14722
16082
  const cursor = req.result;
@@ -14731,9 +16091,9 @@ async function pruneFiles(storageKey, keepIds) {
14731
16091
  }
14732
16092
  const deleteReq = cursor.delete();
14733
16093
  deleteReq.onsuccess = () => cursor.continue();
14734
- deleteReq.onerror = () => fail(deleteReq.error);
16094
+ deleteReq.onerror = () => fail2(deleteReq.error);
14735
16095
  };
14736
- req.onerror = () => fail(req.error);
16096
+ req.onerror = () => fail2(req.error);
14737
16097
  },
14738
16098
  void 0
14739
16099
  );