@xom11/whiteboard 0.25.0 → 0.28.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/{ExcalidrawWithMenus-WENZRYYE.mjs → ExcalidrawWithMenus-2QPPTXJM.mjs} +3 -2
  2. package/dist/ExcalidrawWithMenus-2QPPTXJM.mjs.map +1 -0
  3. package/dist/ai.d.mts +3035 -108
  4. package/dist/ai.d.ts +3035 -108
  5. package/dist/ai.js +6780 -788
  6. package/dist/ai.js.map +1 -1
  7. package/dist/ai.mjs +5140 -577
  8. package/dist/ai.mjs.map +1 -1
  9. package/dist/catalog.json +5 -5
  10. package/dist/{chunk-NDEZJKNY.mjs → chunk-5JM35CXV.mjs} +4 -4
  11. package/dist/{chunk-NDEZJKNY.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
  12. package/dist/{chunk-VNCCIV6O.mjs → chunk-AJAHD35N.mjs} +779 -9
  13. package/dist/chunk-AJAHD35N.mjs.map +1 -0
  14. package/dist/{chunk-M42TGYT6.mjs → chunk-BNBOIDO5.mjs} +3 -3
  15. package/dist/{chunk-M42TGYT6.mjs.map → chunk-BNBOIDO5.mjs.map} +1 -1
  16. package/dist/{chunk-ONBCUWVI.mjs → chunk-BU5KLO3P.mjs} +3 -3
  17. package/dist/{chunk-ONBCUWVI.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
  18. package/dist/{chunk-CJBLJUWG.mjs → chunk-CXHNVYMD.mjs} +4 -4
  19. package/dist/{chunk-CJBLJUWG.mjs.map → chunk-CXHNVYMD.mjs.map} +1 -1
  20. package/dist/chunk-H22OZYTW.mjs +265 -0
  21. package/dist/chunk-H22OZYTW.mjs.map +1 -0
  22. package/dist/chunk-J5LGTIGS.mjs +10 -0
  23. package/dist/chunk-J5LGTIGS.mjs.map +1 -0
  24. package/dist/{chunk-TB4CL25L.mjs → chunk-OQIQNKPQ.mjs} +206 -66
  25. package/dist/chunk-OQIQNKPQ.mjs.map +1 -0
  26. package/dist/{chunk-SGFJLHHG.mjs → chunk-PPKHCRRE.mjs} +3 -3
  27. package/dist/{chunk-SGFJLHHG.mjs.map → chunk-PPKHCRRE.mjs.map} +1 -1
  28. package/dist/{chunk-YSJOVBCD.mjs → chunk-QCZVFEN4.mjs} +4 -4
  29. package/dist/{chunk-YSJOVBCD.mjs.map → chunk-QCZVFEN4.mjs.map} +1 -1
  30. package/dist/{chunk-ESVPQWHX.mjs → chunk-QRUAEXLR.mjs} +5 -5
  31. package/dist/{chunk-ESVPQWHX.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
  32. package/dist/{chunk-AYSFWUPK.mjs → chunk-SZDAS7LK.mjs} +79 -2
  33. package/dist/chunk-SZDAS7LK.mjs.map +1 -0
  34. package/dist/chunk-T3SOHYB2.mjs +851 -0
  35. package/dist/chunk-T3SOHYB2.mjs.map +1 -0
  36. package/dist/{chunk-I24QOHPU.mjs → chunk-V3YJ6JFL.mjs} +3 -3
  37. package/dist/{chunk-I24QOHPU.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
  38. package/dist/{chunk-REIJZDVZ.mjs → chunk-ZTQBUKLJ.mjs} +960 -196
  39. package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
  40. package/dist/geometry-2d.d.mts +1 -1
  41. package/dist/geometry-2d.d.ts +1 -1
  42. package/dist/geometry-2d.js +5521 -1384
  43. package/dist/geometry-2d.js.map +1 -1
  44. package/dist/geometry-2d.mjs +5 -4
  45. package/dist/geometry-3d.d.mts +1 -1
  46. package/dist/geometry-3d.d.ts +1 -1
  47. package/dist/geometry-3d.js +1351 -252
  48. package/dist/geometry-3d.js.map +1 -1
  49. package/dist/geometry-3d.mjs +4 -3
  50. package/dist/graph-2d.d.mts +1 -1
  51. package/dist/graph-2d.d.ts +1 -1
  52. package/dist/graph-2d.js +1517 -341
  53. package/dist/graph-2d.js.map +1 -1
  54. package/dist/graph-2d.mjs +7 -6
  55. package/dist/handleExtractProblem-C-U5KluK.d.mts +158 -0
  56. package/dist/handleExtractProblem-C-U5KluK.d.ts +158 -0
  57. package/dist/{host-A64ITWVX.mjs → host-2ISGVO7O.mjs} +6 -5
  58. package/dist/host-2ISGVO7O.mjs.map +1 -0
  59. package/dist/{host-L7FMFZUW.mjs → host-4P766V4J.mjs} +1363 -463
  60. package/dist/host-4P766V4J.mjs.map +1 -0
  61. package/dist/{host-QK53UYMD.mjs → host-HOSJHQ5H.mjs} +10 -9
  62. package/dist/host-HOSJHQ5H.mjs.map +1 -0
  63. package/dist/{host-QS2EOTRJ.mjs → host-ZQCDAT6O.mjs} +3 -2
  64. package/dist/host-ZQCDAT6O.mjs.map +1 -0
  65. package/dist/index.d.mts +10 -4
  66. package/dist/index.d.ts +10 -4
  67. package/dist/index.js +5746 -1603
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +26 -22
  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.mjs +2 -1
  74. package/dist/render-ZX2O2IK7.mjs +10 -0
  75. package/dist/{render-3WTY7NZB.mjs.map → render-ZX2O2IK7.mjs.map} +1 -1
  76. package/dist/serialize-N4G6RFBB.mjs +9 -0
  77. package/dist/{serialize-SRJVKYUG.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
  78. package/dist/{types-DWRyCa2m.d.ts → types-BHYC2Fiw.d.mts} +130 -1
  79. package/dist/{types-DWRyCa2m.d.mts → types-BHYC2Fiw.d.ts} +130 -1
  80. package/package.json +10 -1
  81. package/dist/ExcalidrawWithMenus-WENZRYYE.mjs.map +0 -1
  82. package/dist/chunk-AYSFWUPK.mjs.map +0 -1
  83. package/dist/chunk-REIJZDVZ.mjs.map +0 -1
  84. package/dist/chunk-TB4CL25L.mjs.map +0 -1
  85. package/dist/chunk-VNCCIV6O.mjs.map +0 -1
  86. package/dist/chunk-VRHWDZ66.mjs +0 -96
  87. package/dist/chunk-VRHWDZ66.mjs.map +0 -1
  88. package/dist/host-A64ITWVX.mjs.map +0 -1
  89. package/dist/host-L7FMFZUW.mjs.map +0 -1
  90. package/dist/host-QK53UYMD.mjs.map +0 -1
  91. package/dist/host-QS2EOTRJ.mjs.map +0 -1
  92. package/dist/render-3WTY7NZB.mjs +0 -9
  93. package/dist/serialize-SRJVKYUG.mjs +0 -8
package/dist/latex.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as BaseStampCustomData, S as StampType } from './types-DWRyCa2m.mjs';
1
+ import { B as BaseStampCustomData, S as StampType } from './types-BHYC2Fiw.mjs';
2
2
  import 'zod';
3
3
  import 'react';
4
4
  import '@excalidraw/excalidraw/element/types';
package/dist/latex.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as BaseStampCustomData, S as StampType } from './types-DWRyCa2m.js';
1
+ import { B as BaseStampCustomData, S as StampType } from './types-BHYC2Fiw.js';
2
2
  import 'zod';
3
3
  import 'react';
4
4
  import '@excalidraw/excalidraw/element/types';
package/dist/latex.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  "use client";
2
- export { latexStamp } from './chunk-SGFJLHHG.mjs';
2
+ export { latexStamp } from './chunk-PPKHCRRE.mjs';
3
3
  import './chunk-X5R72SSJ.mjs';
4
+ import './chunk-J5LGTIGS.mjs';
4
5
  //# sourceMappingURL=latex.mjs.map
5
6
  //# sourceMappingURL=latex.mjs.map
@@ -0,0 +1,10 @@
1
+ "use client";
2
+ export { renderGraphSvgFromState } from './chunk-CXHNVYMD.mjs';
3
+ import './chunk-BNBOIDO5.mjs';
4
+ import './chunk-SZDAS7LK.mjs';
5
+ import './chunk-ICR4CVOE.mjs';
6
+ import './chunk-IHUFOV7L.mjs';
7
+ import './chunk-B4NJJZFR.mjs';
8
+ import './chunk-J5LGTIGS.mjs';
9
+ //# sourceMappingURL=render-ZX2O2IK7.mjs.map
10
+ //# sourceMappingURL=render-ZX2O2IK7.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"render-3WTY7NZB.mjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"render-ZX2O2IK7.mjs"}
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ export { parseSceneState, stringifySceneState } from './chunk-V3YJ6JFL.mjs';
3
+ import './chunk-ZTQBUKLJ.mjs';
4
+ import './chunk-IHUFOV7L.mjs';
5
+ import './chunk-73Q7ADVL.mjs';
6
+ import './chunk-B4NJJZFR.mjs';
7
+ import './chunk-J5LGTIGS.mjs';
8
+ //# sourceMappingURL=serialize-N4G6RFBB.mjs.map
9
+ //# sourceMappingURL=serialize-N4G6RFBB.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"serialize-SRJVKYUG.mjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"serialize-N4G6RFBB.mjs"}
@@ -2,9 +2,45 @@ import { z } from 'zod';
2
2
  import { ReactNode, ComponentType, RefAttributes } from 'react';
3
3
  import { ExcalidrawElement } from '@excalidraw/excalidraw/element/types';
4
4
 
5
+ /**
6
+ * Snapshot tiến trình dựng hình geometry-2d, phát ra trong lúc GV thao tác
7
+ * (trước khi chèn ảnh thật). Consumer broadcast cho học sinh để vẽ ghost preview.
8
+ * Toạ độ + kích thước tính theo board-units của Excalidraw.
9
+ */
10
+ interface GeometryDraftPreview {
11
+ /** SVG markup của hình đang dựng (đã render từ state hiện tại). */
12
+ svg: string;
13
+ /** Board-units width (= intrinsic px của SVG ở zoom 1). */
14
+ width: number;
15
+ /** Board-units height. */
16
+ height: number;
17
+ /** Board-coord góc trên-trái nơi ảnh sẽ được chèn. */
18
+ x: number;
19
+ y: number;
20
+ /** Counter tăng dần để consumer bỏ khung cũ khi kênh lossy reorder. */
21
+ seq: number;
22
+ }
23
+
5
24
  declare const NameZ: z.ZodString;
6
25
 
7
26
  type Name = z.infer<typeof NameZ>;
27
+ type DslDistanceSpec = {
28
+ kind: 'circleRadius';
29
+ circle: Name;
30
+ scale?: number;
31
+ offset?: number;
32
+ } | {
33
+ kind: 'segmentLength';
34
+ p1: Name;
35
+ p2: Name;
36
+ scale?: number;
37
+ offset?: number;
38
+ } | {
39
+ kind: 'literal';
40
+ value: number;
41
+ scale?: number;
42
+ offset?: number;
43
+ };
8
44
  type DslPointT = {
9
45
  name: Name;
10
46
  kind: 'free';
@@ -15,6 +51,7 @@ type DslPointT = {
15
51
  kind: 'midpoint';
16
52
  p1: Name;
17
53
  p2: Name;
54
+ visible?: boolean;
18
55
  } | {
19
56
  name: Name;
20
57
  kind: 'onSegment';
@@ -57,6 +94,63 @@ type DslPointT = {
57
94
  ref1: Name;
58
95
  ref2: Name;
59
96
  branch?: 0 | 1;
97
+ } | {
98
+ name: Name;
99
+ kind: 'secondIntersection';
100
+ line: Name;
101
+ circle: Name;
102
+ other: Name;
103
+ } | {
104
+ name: Name;
105
+ kind: 'circleIntersection';
106
+ c1: Name;
107
+ c2: Name;
108
+ which: 0 | 1;
109
+ } | {
110
+ name: Name;
111
+ kind: 'circleSecondIntersection';
112
+ c1: Name;
113
+ c2: Name;
114
+ exclude: Name;
115
+ } | {
116
+ name: Name;
117
+ kind: 'tangencyPoint';
118
+ circle: Name;
119
+ onLine: Name;
120
+ } | {
121
+ name: Name;
122
+ kind: 'tangentPointExt';
123
+ from: Name;
124
+ circle: Name;
125
+ which: 0 | 1;
126
+ } | {
127
+ name: Name;
128
+ kind: 'arcMidpoint';
129
+ circle: Name;
130
+ a: Name;
131
+ b: Name;
132
+ notContaining: Name;
133
+ } | {
134
+ name: Name;
135
+ kind: 'excenter';
136
+ vertices: [Name, Name, Name];
137
+ opposite: Name;
138
+ } | {
139
+ name: Name;
140
+ kind: 'reflectPoint';
141
+ of: Name;
142
+ through: Name;
143
+ } | {
144
+ name: Name;
145
+ kind: 'reflectLine';
146
+ of: Name;
147
+ through: Name;
148
+ } | {
149
+ name: Name;
150
+ kind: 'pointAtDistance';
151
+ from: Name;
152
+ through: Name;
153
+ distance: DslDistanceSpec;
60
154
  };
61
155
  type DslShapeT = {
62
156
  name: Name;
@@ -98,6 +192,15 @@ type DslShapeT = {
98
192
  p1: Name;
99
193
  vertex: Name;
100
194
  p2: Name;
195
+ } | {
196
+ name: Name;
197
+ kind: 'lineThrough';
198
+ points: Name[];
199
+ } | {
200
+ name: Name;
201
+ kind: 'radicalAxis';
202
+ circle1: Name;
203
+ circle2: Name;
101
204
  } | {
102
205
  name: Name;
103
206
  kind: 'tangent';
@@ -109,12 +212,33 @@ type DslShapeT = {
109
212
  kind: 'circleCP';
110
213
  center: Name;
111
214
  surfacePoint: Name;
215
+ visible?: boolean;
112
216
  } | {
113
217
  name: Name;
114
218
  kind: 'circle3';
115
219
  p1: Name;
116
220
  p2: Name;
117
221
  p3: Name;
222
+ } | {
223
+ name: Name;
224
+ kind: 'circleDiameter';
225
+ p1: Name;
226
+ p2: Name;
227
+ visible?: boolean;
228
+ } | {
229
+ name: Name;
230
+ kind: 'circleCR';
231
+ center: Name;
232
+ radius: number;
233
+ } | {
234
+ name: Name;
235
+ kind: 'incircle';
236
+ vertices: [Name, Name, Name];
237
+ } | {
238
+ name: Name;
239
+ kind: 'excircle';
240
+ vertices: [Name, Name, Name];
241
+ opposite: Name;
118
242
  };
119
243
  type DslInputT = {
120
244
  version: 1;
@@ -240,6 +364,11 @@ interface StampHostProps {
240
364
  isDark: boolean;
241
365
  /** Optional client-safe bridge for the geometry-2d AI prompt editor. */
242
366
  generateGeometryFigure?: GenerateGeometryFigure;
367
+ /**
368
+ * Chỉ geometry-2d dùng: phát snapshot hình đang dựng (debounced) để consumer
369
+ * broadcast cho học sinh xem live. `null` = clear ghost (đã chèn / huỷ / rỗng).
370
+ */
371
+ onGeometryDraft?: (draft: GeometryDraftPreview | null) => void;
243
372
  }
244
373
  /**
245
374
  * Imperative API mà main view truy cập qua ref:
@@ -310,4 +439,4 @@ interface StampType<TCustomData extends BaseStampCustomData = BaseStampCustomDat
310
439
  experimental?: boolean;
311
440
  }
312
441
 
313
- export type { AiFigureProgress as A, BaseStampCustomData as B, DslInputT as D, GenerateGeometryFigure as G, StampType as S, AiFigureUiResult as a, State as b };
442
+ export type { AiFigureProgress as A, BaseStampCustomData as B, DslInputT as D, GenerateGeometryFigure as G, StampType as S, GeometryDraftPreview as a, AiFigureUiResult as b, State as c };
@@ -2,9 +2,45 @@ import { z } from 'zod';
2
2
  import { ReactNode, ComponentType, RefAttributes } from 'react';
3
3
  import { ExcalidrawElement } from '@excalidraw/excalidraw/element/types';
4
4
 
5
+ /**
6
+ * Snapshot tiến trình dựng hình geometry-2d, phát ra trong lúc GV thao tác
7
+ * (trước khi chèn ảnh thật). Consumer broadcast cho học sinh để vẽ ghost preview.
8
+ * Toạ độ + kích thước tính theo board-units của Excalidraw.
9
+ */
10
+ interface GeometryDraftPreview {
11
+ /** SVG markup của hình đang dựng (đã render từ state hiện tại). */
12
+ svg: string;
13
+ /** Board-units width (= intrinsic px của SVG ở zoom 1). */
14
+ width: number;
15
+ /** Board-units height. */
16
+ height: number;
17
+ /** Board-coord góc trên-trái nơi ảnh sẽ được chèn. */
18
+ x: number;
19
+ y: number;
20
+ /** Counter tăng dần để consumer bỏ khung cũ khi kênh lossy reorder. */
21
+ seq: number;
22
+ }
23
+
5
24
  declare const NameZ: z.ZodString;
6
25
 
7
26
  type Name = z.infer<typeof NameZ>;
27
+ type DslDistanceSpec = {
28
+ kind: 'circleRadius';
29
+ circle: Name;
30
+ scale?: number;
31
+ offset?: number;
32
+ } | {
33
+ kind: 'segmentLength';
34
+ p1: Name;
35
+ p2: Name;
36
+ scale?: number;
37
+ offset?: number;
38
+ } | {
39
+ kind: 'literal';
40
+ value: number;
41
+ scale?: number;
42
+ offset?: number;
43
+ };
8
44
  type DslPointT = {
9
45
  name: Name;
10
46
  kind: 'free';
@@ -15,6 +51,7 @@ type DslPointT = {
15
51
  kind: 'midpoint';
16
52
  p1: Name;
17
53
  p2: Name;
54
+ visible?: boolean;
18
55
  } | {
19
56
  name: Name;
20
57
  kind: 'onSegment';
@@ -57,6 +94,63 @@ type DslPointT = {
57
94
  ref1: Name;
58
95
  ref2: Name;
59
96
  branch?: 0 | 1;
97
+ } | {
98
+ name: Name;
99
+ kind: 'secondIntersection';
100
+ line: Name;
101
+ circle: Name;
102
+ other: Name;
103
+ } | {
104
+ name: Name;
105
+ kind: 'circleIntersection';
106
+ c1: Name;
107
+ c2: Name;
108
+ which: 0 | 1;
109
+ } | {
110
+ name: Name;
111
+ kind: 'circleSecondIntersection';
112
+ c1: Name;
113
+ c2: Name;
114
+ exclude: Name;
115
+ } | {
116
+ name: Name;
117
+ kind: 'tangencyPoint';
118
+ circle: Name;
119
+ onLine: Name;
120
+ } | {
121
+ name: Name;
122
+ kind: 'tangentPointExt';
123
+ from: Name;
124
+ circle: Name;
125
+ which: 0 | 1;
126
+ } | {
127
+ name: Name;
128
+ kind: 'arcMidpoint';
129
+ circle: Name;
130
+ a: Name;
131
+ b: Name;
132
+ notContaining: Name;
133
+ } | {
134
+ name: Name;
135
+ kind: 'excenter';
136
+ vertices: [Name, Name, Name];
137
+ opposite: Name;
138
+ } | {
139
+ name: Name;
140
+ kind: 'reflectPoint';
141
+ of: Name;
142
+ through: Name;
143
+ } | {
144
+ name: Name;
145
+ kind: 'reflectLine';
146
+ of: Name;
147
+ through: Name;
148
+ } | {
149
+ name: Name;
150
+ kind: 'pointAtDistance';
151
+ from: Name;
152
+ through: Name;
153
+ distance: DslDistanceSpec;
60
154
  };
61
155
  type DslShapeT = {
62
156
  name: Name;
@@ -98,6 +192,15 @@ type DslShapeT = {
98
192
  p1: Name;
99
193
  vertex: Name;
100
194
  p2: Name;
195
+ } | {
196
+ name: Name;
197
+ kind: 'lineThrough';
198
+ points: Name[];
199
+ } | {
200
+ name: Name;
201
+ kind: 'radicalAxis';
202
+ circle1: Name;
203
+ circle2: Name;
101
204
  } | {
102
205
  name: Name;
103
206
  kind: 'tangent';
@@ -109,12 +212,33 @@ type DslShapeT = {
109
212
  kind: 'circleCP';
110
213
  center: Name;
111
214
  surfacePoint: Name;
215
+ visible?: boolean;
112
216
  } | {
113
217
  name: Name;
114
218
  kind: 'circle3';
115
219
  p1: Name;
116
220
  p2: Name;
117
221
  p3: Name;
222
+ } | {
223
+ name: Name;
224
+ kind: 'circleDiameter';
225
+ p1: Name;
226
+ p2: Name;
227
+ visible?: boolean;
228
+ } | {
229
+ name: Name;
230
+ kind: 'circleCR';
231
+ center: Name;
232
+ radius: number;
233
+ } | {
234
+ name: Name;
235
+ kind: 'incircle';
236
+ vertices: [Name, Name, Name];
237
+ } | {
238
+ name: Name;
239
+ kind: 'excircle';
240
+ vertices: [Name, Name, Name];
241
+ opposite: Name;
118
242
  };
119
243
  type DslInputT = {
120
244
  version: 1;
@@ -240,6 +364,11 @@ interface StampHostProps {
240
364
  isDark: boolean;
241
365
  /** Optional client-safe bridge for the geometry-2d AI prompt editor. */
242
366
  generateGeometryFigure?: GenerateGeometryFigure;
367
+ /**
368
+ * Chỉ geometry-2d dùng: phát snapshot hình đang dựng (debounced) để consumer
369
+ * broadcast cho học sinh xem live. `null` = clear ghost (đã chèn / huỷ / rỗng).
370
+ */
371
+ onGeometryDraft?: (draft: GeometryDraftPreview | null) => void;
243
372
  }
244
373
  /**
245
374
  * Imperative API mà main view truy cập qua ref:
@@ -310,4 +439,4 @@ interface StampType<TCustomData extends BaseStampCustomData = BaseStampCustomDat
310
439
  experimental?: boolean;
311
440
  }
312
441
 
313
- export type { AiFigureProgress as A, BaseStampCustomData as B, DslInputT as D, GenerateGeometryFigure as G, StampType as S, AiFigureUiResult as a, State as b };
442
+ export type { AiFigureProgress as A, BaseStampCustomData as B, DslInputT as D, GenerateGeometryFigure as G, StampType as S, GeometryDraftPreview as a, AiFigureUiResult as b, State as c };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xom11/whiteboard",
3
- "version": "0.25.0",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "description": "Excalidraw + JSXGraph + KaTeX whiteboard component (drawing, geometry stamps, LaTeX stamps).",
6
6
  "repository": {
@@ -73,6 +73,7 @@
73
73
  "demo": "vite --config scripts/demo/vite.config.ts",
74
74
  "ai:eval": "tsx scripts/eval-ai.ts",
75
75
  "ai:smoke": "tsx scripts/smoke-ai.ts",
76
+ "check:matrix": "tsx scripts/check-construct-matrix.ts",
76
77
  "prepublishOnly": "npm run clean && npm run build"
77
78
  },
78
79
  "peerDependencies": {
@@ -97,6 +98,7 @@
97
98
  "@typescript-eslint/eslint-plugin": "^8.59.4",
98
99
  "@typescript-eslint/parser": "^8.59.4",
99
100
  "@vitejs/plugin-react": "^6.0.2",
101
+ "dotenv": "^17.4.2",
100
102
  "eslint": "^9.39.4",
101
103
  "eslint-plugin-react": "^7.37.5",
102
104
  "eslint-plugin-react-hooks": "^5.2.0",
@@ -116,10 +118,17 @@
116
118
  "vite": "^8.0.13"
117
119
  },
118
120
  "dependencies": {
121
+ "@anthropic-ai/claude-agent-sdk": "^0.3.161",
119
122
  "@anthropic-ai/sdk": "^0.98.0",
120
123
  "immer": "^10.2.0",
121
124
  "pdfjs-dist": "^5.7.284",
125
+ "tesseract.js": "^7.0.0",
122
126
  "zod": "^3.23.8",
123
127
  "zod-to-json-schema": "^3.25.2"
128
+ },
129
+ "overrides": {
130
+ "@anthropic-ai/claude-agent-sdk": {
131
+ "zod": "$zod"
132
+ }
124
133
  }
125
134
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ExcalidrawWithMenus.tsx"],"names":[],"mappings":";;;AAiBO,SAAS,oBAAoB,KAAA,EAAwB;AAC1D,EAAA,MAAM,EAAE,QAAA,EAAU,GAAG,IAAA,EAAK,GAAI,KAAA;AAC9B,EAAA,uBACE,IAAA,CAAC,UAAA,EAAA,EAAY,GAAG,IAAA,EAEd,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,QAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,SAAA,EAAtB,EAAgC,CAAA;AAAA,sBACjC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC,CAAA;AAAA,sBACnC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC,CAAA;AAAA,sBACnC,GAAA,CAAC,QAAA,CAAS,YAAA,CAAa,WAAA,EAAtB,EAAkC;AAAA,KAAA,EACrC,CAAA;AAAA,oBAEA,GAAA,CAAC,MAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EACR,CAAA;AAAA,oBAGA,GAAA,CAAC,aAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EACR,CAAA;AAAA,IACC;AAAA,GAAA,EACH,CAAA;AAEJ","file":"ExcalidrawWithMenus-WENZRYYE.mjs","sourcesContent":["'use client';\n\n// Client-only wrapper around Excalidraw that lets us reach for static helpers\n// like `MainMenu.DefaultItems.*`. Whiteboard dynamic-imports this\n// file so SSR never evaluates @excalidraw/excalidraw, while inside this file we\n// can use plain static imports (the entire module loads on the client).\n\nimport React from 'react';\nimport {\n Excalidraw,\n MainMenu,\n Footer,\n WelcomeScreen,\n} from '@excalidraw/excalidraw';\n \ntype ExcalidrawProps = any;\n\nexport function ExcalidrawWithMenus(props: ExcalidrawProps) {\n const { children, ...rest } = props;\n return (\n <Excalidraw {...rest}>\n {/* Replace default menu with curated items — no socials/help/branding */}\n <MainMenu>\n <MainMenu.DefaultItems.LoadScene />\n <MainMenu.DefaultItems.SaveAsImage />\n <MainMenu.DefaultItems.ClearCanvas />\n <MainMenu.DefaultItems.ToggleTheme />\n </MainMenu>\n {/* Footer slot with no content suppresses default \"Made with Excalidraw\" link */}\n <Footer>\n <span />\n </Footer>\n {/* WelcomeScreen slot (empty) prevents the default Excalidraw welcome panel\n * (which includes the Excalidraw logo and social links) from appearing. */}\n <WelcomeScreen>\n <span />\n </WelcomeScreen>\n {children}\n </Excalidraw>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/scene/render/types2d.ts","../src/core/scene/render/JxgRenderer.ts"],"names":[],"mappings":"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","file":"chunk-AYSFWUPK.mjs","sourcesContent":["// src/core/scene/render/types2d.ts\nimport type { RenderCtx } from '../types';\n\nexport type Theme2D = {\n stroke: string;\n fill: string;\n label: string;\n axis: string;\n grid: string;\n pointFill: string;\n};\n\nexport const DEFAULT_THEME_2D: Theme2D = {\n stroke: '#0f172a',\n fill: '#60a5fa',\n label: '#0f172a',\n axis: '#94a3b8',\n grid: '#e2e8f0',\n pointFill: '#1e40af',\n};\n\nexport type RenderCtx2D = RenderCtx & {\n theme: Theme2D;\n};\n","// src/core/scene/render/JxgRenderer.ts\nimport type { Store } from '../store';\nimport type { State, SceneObject, RenderCtx } from '../types';\nimport { getKind } from '../registry';\nimport { DEFAULT_THEME_2D, type Theme2D } from './types2d';\nimport { collectFreeVars } from '../expressions/parser';\n\nexport type JxgRendererOptions = { theme?: Theme2D };\n\nexport class JxgRenderer {\n private board: unknown;\n private store: Store;\n private theme: Theme2D;\n private elements = new Map<string, unknown>();\n private unsubscribe: () => void;\n private disposed = false;\n\n /** Chỉ dùng cho domain='graph2d': parameter.label → parameter.value */\n private paramMap: Record<string, number> = {};\n /** Chỉ dùng cho domain='graph2d': function2d.id → expression string */\n private functionExpr: Record<string, string> = {};\n\n constructor(store: Store, board: unknown, options: JxgRendererOptions = {}) {\n this.store = store;\n this.board = board;\n this.theme = options.theme ?? DEFAULT_THEME_2D;\n this.unsubscribe = store.subscribe((next, prev) => this.applyDiff(prev, next));\n // Render state hiện tại (vd LOAD chạy trước khi subscribe).\n this.applyDiff(undefined, store.getState());\n }\n\n private ctx(): RenderCtx {\n return {\n jxg: this.board,\n resolveRef: (id: string) => {\n // Synthetic \"<polyId>:border:<N>\" → polygon.borders[N]. Polygon edges\n // là sub-segment do JSXGraph auto-tạo bên trong polygon; chúng không\n // có scene id riêng. Synthetic id cho phép construct tools (vd\n // perpendicular qua một cạnh đa giác) tham chiếu cạnh như một line.\n const m = /^(.+):border:(\\d+)$/.exec(id);\n if (m) {\n const poly = this.elements.get(m[1]) as { borders?: unknown[] } | undefined;\n if (!poly) throw new Error(`[scene/2d] resolveRef: chưa render polygon id=\"${m[1]}\"`);\n const borders = poly.borders;\n const idx = parseInt(m[2], 10);\n if (!Array.isArray(borders) || !borders[idx]) {\n throw new Error(`[scene/2d] resolveRef: polygon \"${m[1]}\" không có border[${idx}]`);\n }\n return borders[idx];\n }\n const el = this.elements.get(id);\n if (!el) throw new Error(`[scene/2d] resolveRef: chưa render id=\"${id}\"`);\n return el;\n },\n defaults: { theme: this.theme, _functionExpr: this.functionExpr },\n paramMap: this.paramMap,\n };\n }\n\n /**\n * Rebuild `paramMap` và `functionExpr` từ state hiện tại.\n * Chỉ chạy khi domain='graph2d'. Chi phí thấp vì parameters thường ≤ 8.\n */\n private rebuildGraphMaps(state: State): void {\n if (state.meta.domain !== 'graph2d') return;\n const params: Record<string, number> = {};\n const fns: Record<string, string> = {};\n for (const id of state.order) {\n const obj = state.objects[id];\n if (obj.kind === 'parameter') {\n params[obj.label] = (obj.attrs as { value: number }).value;\n } else if (obj.kind === 'function2d') {\n fns[obj.id] = (obj.attrs as { expression: string }).expression;\n }\n }\n this.paramMap = params;\n this.functionExpr = fns;\n }\n\n private create(obj: SceneObject): void {\n try {\n const def = getKind(obj.kind);\n const el = def.render(obj, this.ctx());\n this.elements.set(obj.id, el);\n this.attachFreePointDragSync(obj, el);\n } catch (err) {\n console.warn(`[scene/render/2d] không render được ${obj.kind} id=\"${obj.id}\":`, err);\n }\n }\n\n /**\n * Đồng bộ toạ độ live của free point về scene.constraint khi user kéo bằng\n * tay (Move tool / mobile drag). JSXGraph mutate obj.X()/Y() ngay nhưng\n * constraint vẫn giữ giá trị lúc tạo → serialize sẽ ra SVG y hệt cũ →\n * fileId SHA-256 trùng → Excalidraw bỏ qua refresh. (Regression từ\n * commit f41f366 sau scene v2 port.)\n *\n * Chỉ áp dụng cho free point — glider/intersection/midpoint không drag được\n * trực tiếp (toạ độ derived từ ref khác).\n */\n private attachFreePointDragSync(obj: SceneObject, el: unknown): void {\n if (obj.kind !== 'point') return;\n const c = (obj.attrs as { constraint?: { kind?: string } }).constraint;\n if (!c || c.kind !== 'free') return;\n \n const point = el as any;\n if (typeof point.on !== 'function') return;\n const sceneId = obj.id;\n point.on('up', () => {\n if (this.disposed) return;\n if (typeof point.X !== 'function' || typeof point.Y !== 'function') return;\n const x = point.X();\n const y = point.Y();\n if (!Number.isFinite(x) || !Number.isFinite(y)) return;\n const cur = this.store.getState().objects[sceneId];\n if (!cur) return;\n const curC = (cur.attrs as { constraint?: { kind?: string; x?: number; y?: number } }).constraint;\n if (!curC || curC.kind !== 'free') return;\n if (curC.x === x && curC.y === y) return;\n this.store.dispatch({\n type: 'UPDATE_ATTRS',\n payload: { id: sceneId, patch: { constraint: { kind: 'free', x, y } } },\n });\n });\n }\n\n private remove(id: string): void {\n // Selection halo (nếu có) phải bị xoá TRƯỚC element gốc — halo tham chiếu\n // tới point1/point2/center/vertices của element gốc qua lambda; xoá element\n // gốc trước sẽ làm halo dangling.\n this.removeHalo(id);\n this.selectedIds.delete(id);\n const el = this.elements.get(id);\n if (!el) return;\n try {\n const helpers = (el as Record<string, unknown>)._helpers;\n // Element chính bị remove trước, sau đó helpers (glider phụ trợ cho\n // tangent ...). Helpers thường là parent của element chính — nếu xoá\n // parent trước, JSXGraph có thể phàn nàn dangling reference.\n (this.board as { removeObject?: (e: unknown) => void }).removeObject?.(el);\n if (Array.isArray(helpers)) {\n for (const h of helpers) {\n try {\n (this.board as { removeObject?: (e: unknown) => void }).removeObject?.(h);\n } catch { /* ignore */ }\n }\n }\n } catch (err) {\n console.warn(`[scene/render/2d] không remove được id=\"${id}\":`, err);\n }\n this.elements.delete(id);\n }\n\n private applyDiff(prev: State | undefined, next: State): void {\n if (this.disposed) return;\n\n // Rebuild paramMap + functionExpr TRƯỚC khi diff, để ctx() có đúng\n // paramMap khi render lần đầu tiên.\n this.rebuildGraphMaps(next);\n\n const prevObjs = prev?.objects ?? {};\n const nextObjs = next.objects;\n\n // Xoá ids biến mất.\n for (const id of Object.keys(prevObjs)) {\n if (!(id in nextObjs)) this.remove(id);\n }\n\n // Thêm/cập nhật theo state.order — đảm bảo refs có trước.\n for (const id of next.order) {\n const cur = nextObjs[id];\n const old = prevObjs[id] as SceneObject | undefined;\n if (!old) {\n this.create(cur);\n continue;\n }\n if (Object.is(old, cur)) continue;\n const def = getKind(cur.kind);\n const existing = this.elements.get(id);\n if (def.update && existing) {\n try { def.update(cur, old, this.ctx(), existing); continue; }\n catch (err) { console.warn(`[scene/render/2d] update fail, recreate:`, err); }\n }\n this.remove(id);\n this.create(cur);\n }\n\n // Sau diff bình thường: nếu domain='graph2d', detect parameter value changes\n // và force re-render các function2d phụ thuộc.\n if (next.meta.domain === 'graph2d' && prev) {\n const changedParams = new Set<string>();\n for (const id of next.order) {\n const cur = next.objects[id];\n const old = prev.objects[id] as SceneObject | undefined;\n if (cur.kind !== 'parameter' || old?.kind !== 'parameter') continue;\n if ((cur.attrs as { value: number }).value !== (old.attrs as { value: number }).value) {\n changedParams.add(cur.label);\n }\n }\n if (changedParams.size > 0) {\n for (const id of next.order) {\n const obj = next.objects[id];\n if (obj.kind !== 'function2d') continue;\n const expr = (obj.attrs as { expression: string }).expression;\n const refs = collectFreeVars(expr);\n if (refs.some((r) => changedParams.has(r))) {\n this.remove(id);\n this.create(obj);\n }\n }\n }\n }\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.unsubscribe();\n for (const id of Array.from(this.elements.keys())) this.remove(id);\n this.disposed = true;\n }\n\n /** Return the rendered JSXGraph element for a scene id, or null if not found. */\n getElement(id: string): unknown {\n return this.elements.get(id) ?? null;\n }\n\n /** Return a read-only view of the scene id → JSXGraph element map (for hit-test). */\n listElements(): Map<string, unknown> {\n return this.elements;\n }\n\n // Selection halo overlay model: thay vì đổi màu element gốc thành đỏ, tạo\n // một halo element gray phía sau (lower layer) → giữ nguyên màu gốc. Hỗ\n // trợ multi-select cho cả canvas click-selection lẫn ObjectListPanel.\n private selectedIds: Set<string> = new Set();\n private haloMap: Map<string, unknown[]> = new Map();\n\n highlight(ids: string | string[] | null): void {\n if (this.disposed) return;\n const newIds = new Set<string>(\n ids == null ? [] : Array.isArray(ids) ? ids : [ids],\n );\n // Remove halos cho ids đã bị bỏ chọn.\n for (const id of this.selectedIds) {\n if (!newIds.has(id)) this.removeHalo(id);\n }\n // Add halos cho ids mới chọn.\n for (const id of newIds) {\n if (!this.selectedIds.has(id) && this.elements.has(id)) this.addHalo(id);\n }\n this.selectedIds = newIds;\n try {\n (this.board as { update?: () => void }).update?.();\n } catch { /* ignore */ }\n }\n\n private removeHalo(id: string): void {\n const halos = this.haloMap.get(id);\n if (!halos) return;\n const board = this.board as { removeObject?: (e: unknown) => void };\n for (const h of halos) {\n try { board.removeObject?.(h); } catch { /* ignore */ }\n }\n this.haloMap.delete(id);\n }\n\n private addHalo(id: string): void {\n const el = this.elements.get(id) as\n | {\n elType?: string;\n getAttribute?: (k: string) => unknown;\n X?: () => number;\n Y?: () => number;\n point1?: unknown;\n point2?: unknown;\n center?: unknown;\n Radius?: () => number;\n vertices?: unknown[];\n }\n | undefined;\n if (!el) return;\n const board = this.board as {\n create?: (kind: string, parents: unknown[], attrs?: unknown) => unknown;\n };\n if (!board.create) return;\n\n // Selection palette — gray fill + darker gray border (xem\n // tham chiếu /tmp/ss.png).\n const SEL_STROKE = '#475569'; // slate-600\n const SEL_FILL = '#cbd5e1'; // slate-300\n const haloBase = {\n strokeColor: SEL_STROKE,\n strokeOpacity: 0.55,\n fillColor: SEL_FILL,\n fillOpacity: 0.3,\n fixed: true,\n withLabel: false,\n name: '',\n highlight: false,\n layer: 4,\n needsRegularUpdate: true,\n };\n const halos: unknown[] = [];\n try {\n switch (el.elType) {\n case 'point':\n case 'glider':\n case 'intersection': {\n const baseSize = (el.getAttribute?.('size') as number | undefined) ?? 4;\n const halo = board.create('point', [\n () => el.X?.() ?? 0,\n () => el.Y?.() ?? 0,\n ], {\n ...haloBase,\n size: baseSize + 6,\n face: 'o',\n strokeWidth: 2,\n strokeOpacity: 0.75,\n fillOpacity: 0.25,\n });\n halos.push(halo);\n break;\n }\n case 'segment': {\n if (el.point1 && el.point2) {\n const halo = board.create('segment', [el.point1, el.point2], {\n ...haloBase,\n strokeWidth: 9,\n straightFirst: false,\n straightLast: false,\n });\n halos.push(halo);\n }\n break;\n }\n case 'line':\n case 'arrow':\n case 'ray':\n case 'vector':\n case 'tangent':\n case 'normal':\n case 'parallel':\n case 'perpendicular':\n case 'bisector': {\n if (el.point1 && el.point2) {\n const halo = board.create('line', [el.point1, el.point2], {\n ...haloBase,\n strokeWidth: 9,\n });\n halos.push(halo);\n }\n break;\n }\n case 'circle': {\n if (el.center && typeof el.Radius === 'function') {\n const halo = board.create('circle', [el.center, () => el.Radius?.() ?? 0], {\n ...haloBase,\n strokeWidth: 9,\n fillOpacity: 0,\n });\n halos.push(halo);\n }\n break;\n }\n case 'polygon': {\n if (Array.isArray(el.vertices) && el.vertices.length >= 3) {\n // JSXGraph polygon.vertices có thể append vertex đầu lặp lại ở\n // cuối để đóng path — trim cho an toàn.\n const last = el.vertices.length - 1;\n const verts = el.vertices[last] === el.vertices[0]\n ? el.vertices.slice(0, last)\n : el.vertices.slice();\n const halo = board.create('polygon', verts, {\n ...haloBase,\n fillOpacity: 0.2,\n borders: {\n strokeColor: SEL_STROKE,\n strokeWidth: 7,\n strokeOpacity: 0.55,\n highlight: false,\n },\n });\n halos.push(halo);\n }\n break;\n }\n default:\n // Các kind khác (curve, arc, sector, angle, ...) — chưa hỗ trợ halo.\n break;\n }\n } catch (err) {\n console.warn('[scene/render/2d] halo create fail:', err);\n }\n if (halos.length) this.haloMap.set(id, halos);\n }\n}\n"]}