@classytic/labs 0.1.0 β†’ 0.2.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 (455) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  2. package/dist/biology/enzyme-rate/preset.mjs +5 -5
  3. package/dist/biology/genetic-cross/core.d.mts +7 -7
  4. package/dist/biology/genetic-cross/core.mjs +4 -4
  5. package/dist/biology/genetic-cross/grid.mjs +132 -123
  6. package/dist/biology/genetic-cross/preset.mjs +4 -4
  7. package/dist/biology/genetic-cross/sex-linked.mjs +7 -7
  8. package/dist/biology/photosynthesis-factors/preset.mjs +8 -8
  9. package/dist/biology/respiration/preset.mjs +4 -4
  10. package/dist/biology/sequence/central-dogma.mjs +5 -5
  11. package/dist/biology/sequence/core.d.mts +6 -6
  12. package/dist/biology/sequence/core.mjs +1 -1
  13. package/dist/biology/sequence/preset.mjs +6 -6
  14. package/dist/blocks/authoring.mjs +5 -5
  15. package/dist/blocks/biology.d.mts +2 -2
  16. package/dist/blocks/biology.mjs +5 -5
  17. package/dist/blocks/chem.d.mts +2 -2
  18. package/dist/blocks/chem.mjs +13 -13
  19. package/dist/blocks/circuits.d.mts +293 -4
  20. package/dist/blocks/circuits.mjs +874 -9
  21. package/dist/blocks/discrete.d.mts +30 -2
  22. package/dist/blocks/discrete.mjs +74 -4
  23. package/dist/blocks/economics.mjs +1 -1
  24. package/dist/blocks/geography.mjs +1 -1
  25. package/dist/blocks/geometry.mjs +3 -3
  26. package/dist/blocks/ict.d.mts +90 -1
  27. package/dist/blocks/ict.mjs +217 -7
  28. package/dist/blocks/index.d.mts +3064 -657
  29. package/dist/blocks/index.mjs +9 -9
  30. package/dist/blocks/lab-block.mjs +5 -5
  31. package/dist/blocks/lab-config.d.mts +1 -1
  32. package/dist/blocks/lab-config.mjs +4 -4
  33. package/dist/blocks/lab-gallery.d.mts +1 -1
  34. package/dist/blocks/lab-gallery.mjs +2 -2
  35. package/dist/blocks/language.d.mts +6 -6
  36. package/dist/blocks/language.mjs +12 -12
  37. package/dist/blocks/lesson.mjs +4 -4
  38. package/dist/blocks/math.d.mts +577 -11
  39. package/dist/blocks/math.mjs +1648 -14
  40. package/dist/blocks/ml.d.mts +45 -1
  41. package/dist/blocks/ml.mjs +80 -6
  42. package/dist/blocks/physics.d.mts +9 -4
  43. package/dist/blocks/physics.mjs +75 -28
  44. package/dist/blocks/statistics.mjs +1 -1
  45. package/dist/build/CircuitEditor.d.mts +14 -0
  46. package/dist/build/CircuitEditor.mjs +787 -0
  47. package/dist/build/CircuitPlayer.d.mts +19 -0
  48. package/dist/build/CircuitPlayer.mjs +53 -0
  49. package/dist/build/CircuitScene.d.mts +61 -0
  50. package/dist/build/CircuitScene.mjs +383 -0
  51. package/dist/build/contract.d.mts +116 -0
  52. package/dist/build/editor-ops.d.mts +65 -0
  53. package/dist/build/editor-ops.mjs +306 -0
  54. package/dist/build/editor-ui.mjs +121 -0
  55. package/dist/build/flow.d.mts +14 -0
  56. package/dist/build/flow.mjs +119 -0
  57. package/dist/build/index.d.mts +10 -0
  58. package/dist/build/index.mjs +10 -0
  59. package/dist/build/parts/ammeter.d.mts +1 -0
  60. package/dist/build/parts/ammeter.mjs +32 -0
  61. package/dist/build/parts/bulb.d.mts +1 -0
  62. package/dist/build/parts/bulb.mjs +50 -0
  63. package/dist/build/parts/capacitor.d.mts +1 -0
  64. package/dist/build/parts/capacitor.mjs +26 -0
  65. package/dist/build/parts/cell.d.mts +1 -0
  66. package/dist/build/parts/cell.mjs +40 -0
  67. package/dist/build/parts/diode.d.mts +1 -0
  68. package/dist/build/parts/diode.mjs +33 -0
  69. package/dist/build/parts/index.d.mts +5 -0
  70. package/dist/build/parts/index.mjs +43 -0
  71. package/dist/build/parts/mosfet.d.mts +1 -0
  72. package/dist/build/parts/mosfet.mjs +95 -0
  73. package/dist/build/parts/node.d.mts +1 -0
  74. package/dist/build/parts/node.mjs +32 -0
  75. package/dist/build/parts/resistor.d.mts +1 -0
  76. package/dist/build/parts/resistor.mjs +49 -0
  77. package/dist/build/parts/shared.mjs +42 -0
  78. package/dist/build/parts/switch.d.mts +1 -0
  79. package/dist/build/parts/switch.mjs +34 -0
  80. package/dist/build/parts.d.mts +1 -0
  81. package/dist/build/registry.d.mts +9 -0
  82. package/dist/build/registry.mjs +15 -0
  83. package/dist/build/solve.d.mts +8 -0
  84. package/dist/build/solve.mjs +0 -0
  85. package/dist/catalog/registry.d.mts +2 -2
  86. package/dist/catalog/templates.d.mts +1 -1
  87. package/dist/catalog/templates.mjs +6 -6
  88. package/dist/chem/battery.mjs +1 -1
  89. package/dist/chem/bohr-atom.mjs +4 -4
  90. package/dist/chem/diffusion/preset.mjs +4 -4
  91. package/dist/chem/electrochem/preset.mjs +5 -5
  92. package/dist/chem/equilibrium/preset.d.mts +1 -1
  93. package/dist/chem/equilibrium/preset.mjs +6 -6
  94. package/dist/chem/gas-box/preset.mjs +6 -6
  95. package/dist/chem/kinetics/preset.mjs +6 -6
  96. package/dist/chem/periodic-trends/preset.mjs +7 -7
  97. package/dist/chem/reaction-lab.mjs +3 -3
  98. package/dist/chem/reaction-profile.mjs +4 -4
  99. package/dist/chem/solution/dilution.mjs +6 -6
  100. package/dist/chem/solution/field.d.mts +2 -2
  101. package/dist/chem/solution/field.mjs +2 -2
  102. package/dist/chem/solution/solution-box.mjs +7 -7
  103. package/dist/chem/stoichiometry/preset.mjs +5 -5
  104. package/dist/chem/titration/preset.mjs +5 -5
  105. package/dist/circuits/ac-dc/asset.mjs +1 -1
  106. package/dist/circuits/ac-dc/preset.mjs +2 -2
  107. package/dist/circuits/brownout/index.d.mts +1 -0
  108. package/dist/circuits/brownout/preset.d.mts +22 -0
  109. package/dist/circuits/brownout/preset.mjs +399 -0
  110. package/dist/circuits/capacitor-leak/preset.mjs +13 -8
  111. package/dist/circuits/circuit/asset.mjs +71 -14
  112. package/dist/circuits/circuit/preset.mjs +23 -5
  113. package/dist/circuits/circuit-builder.mjs +60 -132
  114. package/dist/circuits/circuit-lab.mjs +60 -40
  115. package/dist/circuits/cmos-gate/index.d.mts +1 -0
  116. package/dist/circuits/cmos-gate/preset.d.mts +75 -0
  117. package/dist/circuits/cmos-gate/preset.mjs +1491 -0
  118. package/dist/circuits/diode/index.d.mts +1 -0
  119. package/dist/circuits/diode/preset.d.mts +25 -0
  120. package/dist/circuits/diode/preset.mjs +266 -0
  121. package/dist/circuits/index.d.mts +7 -1
  122. package/dist/circuits/index.mjs +7 -1
  123. package/dist/circuits/rc-charging/index.d.mts +1 -0
  124. package/dist/circuits/rc-charging/preset.d.mts +27 -0
  125. package/dist/circuits/rc-charging/preset.mjs +329 -0
  126. package/dist/circuits/semiconductor/index.d.mts +1 -0
  127. package/dist/circuits/semiconductor/preset.d.mts +102 -0
  128. package/dist/circuits/semiconductor/preset.mjs +1855 -0
  129. package/dist/circuits/transistor/index.d.mts +1 -0
  130. package/dist/circuits/transistor/preset.d.mts +27 -0
  131. package/dist/circuits/transistor/preset.mjs +329 -0
  132. package/dist/commerce/accounting/core.d.mts +1 -1
  133. package/dist/commerce/accounting/equation-balance.mjs +5 -5
  134. package/dist/commerce/accounting/journal-poster.mjs +8 -8
  135. package/dist/commerce/accounting/statement-sorter.mjs +4 -4
  136. package/dist/commerce/economics/core.d.mts +2 -2
  137. package/dist/commerce/economics/core.mjs +1 -1
  138. package/dist/commerce/economics/demand-shift-vs-move.mjs +6 -6
  139. package/dist/commerce/economics/elasticity-revenue.mjs +6 -6
  140. package/dist/commerce/economics/market-equilibrium.mjs +5 -5
  141. package/dist/core/easing.d.mts +3 -3
  142. package/dist/core/easing.mjs +2 -2
  143. package/dist/core/numeric.d.mts +3 -3
  144. package/dist/core/numeric.mjs +2 -2
  145. package/dist/core/reactive.d.mts +1 -1
  146. package/dist/core/reactive.mjs +1 -1
  147. package/dist/core/rng.d.mts +2 -2
  148. package/dist/core/rng.mjs +1 -1
  149. package/dist/core/tex.mjs +2 -2
  150. package/dist/core/timeline.d.mts +1 -1
  151. package/dist/core/timeline.mjs +1 -1
  152. package/dist/core/util.mjs +11 -1
  153. package/dist/discrete/arrangements/preset.mjs +6 -14
  154. package/dist/discrete/bayes/preset.mjs +43 -35
  155. package/dist/discrete/binomial/preset.mjs +2 -2
  156. package/dist/discrete/combination-studio/figure.d.mts +6 -0
  157. package/dist/discrete/combination-studio/figure.mjs +159 -0
  158. package/dist/discrete/combination-studio/index.d.mts +2 -0
  159. package/dist/discrete/combination-studio/preset.d.mts +44 -0
  160. package/dist/discrete/combination-studio/preset.mjs +440 -0
  161. package/dist/discrete/core/combinatorics.d.mts +23 -3
  162. package/dist/discrete/core/combinatorics.mjs +38 -3
  163. package/dist/discrete/core/pigeonhole.d.mts +1 -1
  164. package/dist/discrete/core/pigeonhole.mjs +1 -1
  165. package/dist/discrete/core/probability.d.mts +3 -3
  166. package/dist/discrete/core/probability.mjs +3 -3
  167. package/dist/discrete/core/sets.d.mts +1 -1
  168. package/dist/discrete/counting-slots/preset.mjs +8 -8
  169. package/dist/discrete/counting-tree/preset.mjs +65 -8
  170. package/dist/discrete/expected-value/preset.mjs +13 -13
  171. package/dist/discrete/hypergeometric/preset.mjs +48 -15
  172. package/dist/discrete/index.d.mts +4 -2
  173. package/dist/discrete/index.mjs +4 -2
  174. package/dist/discrete/karnaugh/preset.mjs +26 -20
  175. package/dist/discrete/lln/preset.mjs +44 -3
  176. package/dist/discrete/logic-circuit/preset.mjs +2 -2
  177. package/dist/discrete/monte-carlo/preset.d.mts +1 -1
  178. package/dist/discrete/monte-carlo/preset.mjs +14 -14
  179. package/dist/discrete/monty-hall/preset.mjs +6 -6
  180. package/dist/discrete/outcome-builder/preset.mjs +3 -3
  181. package/dist/discrete/pascal/preset.mjs +37 -7
  182. package/dist/discrete/rules.d.mts +20 -0
  183. package/dist/discrete/rules.mjs +264 -0
  184. package/dist/discrete/sample-space/preset.mjs +4 -4
  185. package/dist/discrete/selection/preset.mjs +7 -13
  186. package/dist/discrete/truth-table/preset.mjs +32 -9
  187. package/dist/discrete/venn/preset.mjs +71 -48
  188. package/dist/geography/cycle-lab/preset.mjs +17 -10
  189. package/dist/geography/cycles.d.mts +3 -3
  190. package/dist/geography/cycles.mjs +3 -3
  191. package/dist/geometry/board/preset.d.mts +2 -0
  192. package/dist/geometry/board/preset.mjs +11 -15
  193. package/dist/geometry/builder.mjs +3 -3
  194. package/dist/ict/number-systems/base-odometer.mjs +4 -4
  195. package/dist/ict/number-systems/bit-grouper.d.mts +1 -1
  196. package/dist/ict/number-systems/bit-grouper.mjs +4 -4
  197. package/dist/ict/number-systems/place-value-dial.d.mts +1 -1
  198. package/dist/ict/number-systems/place-value-dial.mjs +3 -3
  199. package/dist/ict/number-systems/wheel.d.mts +3 -3
  200. package/dist/ict/number-systems/wheel.mjs +4 -4
  201. package/dist/kit/annotate.mjs +3 -3
  202. package/dist/kit/answer-check.d.mts +2 -2
  203. package/dist/kit/answer-check.mjs +34 -6
  204. package/dist/kit/ask.d.mts +19 -0
  205. package/dist/kit/ask.mjs +46 -0
  206. package/dist/kit/bar-strip.mjs +53 -0
  207. package/dist/kit/calc.d.mts +33 -0
  208. package/dist/kit/calc.mjs +27 -0
  209. package/dist/kit/carrier-engine.mjs +147 -0
  210. package/dist/kit/clue-scene.d.mts +86 -0
  211. package/dist/kit/clue-scene.mjs +424 -0
  212. package/dist/kit/cluster.d.mts +30 -0
  213. package/dist/kit/cluster.mjs +81 -0
  214. package/dist/kit/controls.mjs +11 -5
  215. package/dist/kit/coords.d.mts +88 -0
  216. package/dist/kit/coords.mjs +192 -0
  217. package/dist/kit/data-scene.d.mts +27 -0
  218. package/dist/kit/data-scene.mjs +199 -0
  219. package/dist/kit/diagram.mjs +111 -50
  220. package/dist/kit/electronics.mjs +552 -60
  221. package/dist/kit/expr-analysis.d.mts +18 -6
  222. package/dist/kit/expr-analysis.mjs +82 -28
  223. package/dist/kit/frame.d.mts +3 -3
  224. package/dist/kit/frame.mjs +25 -6
  225. package/dist/kit/gameshow.mjs +2 -2
  226. package/dist/kit/index.d.mts +14 -2
  227. package/dist/kit/index.mjs +13 -1
  228. package/dist/kit/logic-gates.mjs +246 -47
  229. package/dist/kit/palette.mjs +26 -0
  230. package/dist/kit/pedagogy.d.mts +4 -4
  231. package/dist/kit/pedagogy.mjs +21 -17
  232. package/dist/kit/play.d.mts +1 -1
  233. package/dist/kit/play.mjs +3 -3
  234. package/dist/kit/predict.d.mts +55 -0
  235. package/dist/kit/predict.mjs +146 -0
  236. package/dist/kit/receipt.d.mts +29 -0
  237. package/dist/kit/receipt.mjs +94 -0
  238. package/dist/kit/rich.mjs +2 -2
  239. package/dist/kit/rule.d.mts +59 -0
  240. package/dist/kit/rule.mjs +215 -0
  241. package/dist/kit/scale.mjs +1 -1
  242. package/dist/kit/scene-library.d.mts +22 -0
  243. package/dist/kit/scene-library.mjs +311 -0
  244. package/dist/kit/scene-studio.d.mts +14 -0
  245. package/dist/kit/scene-studio.mjs +338 -0
  246. package/dist/kit/scenes.d.mts +31 -0
  247. package/dist/kit/scenes.mjs +569 -0
  248. package/dist/kit/slot-fill.d.mts +61 -0
  249. package/dist/kit/slot-fill.mjs +207 -0
  250. package/dist/kit/solve.d.mts +21 -0
  251. package/dist/kit/solve.mjs +75 -0
  252. package/dist/kit/space.mjs +5 -5
  253. package/dist/kit/steps.mjs +2 -2
  254. package/dist/kit/vessel.d.mts +69 -0
  255. package/dist/kit/vessel.mjs +191 -0
  256. package/dist/language/agreement/preset.mjs +2 -2
  257. package/dist/language/article-lens/preset.d.mts +1 -1
  258. package/dist/language/article-lens/preset.mjs +8 -8
  259. package/dist/language/deck.d.mts +3 -3
  260. package/dist/language/deck.mjs +1 -1
  261. package/dist/language/preposition-scene/preset.d.mts +2 -2
  262. package/dist/language/preposition-scene/preset.mjs +5 -5
  263. package/dist/language/sentence-builder/preset.mjs +5 -5
  264. package/dist/language/transform/preset.d.mts +2 -2
  265. package/dist/language/transform/preset.mjs +5 -5
  266. package/dist/language/ui.d.mts +3 -3
  267. package/dist/language/ui.mjs +4 -4
  268. package/dist/language/word-match/preset.mjs +3 -3
  269. package/dist/logic/LogicBuildLab.d.mts +22 -0
  270. package/dist/logic/LogicBuildLab.mjs +170 -0
  271. package/dist/logic/LogicEditScene.d.mts +31 -0
  272. package/dist/logic/LogicEditScene.mjs +276 -0
  273. package/dist/logic/LogicEditor.d.mts +14 -0
  274. package/dist/logic/LogicEditor.mjs +413 -0
  275. package/dist/logic/LogicScene.d.mts +32 -0
  276. package/dist/logic/LogicScene.mjs +277 -0
  277. package/dist/logic/contract.d.mts +72 -0
  278. package/dist/logic/display.d.mts +24 -0
  279. package/dist/logic/display.mjs +127 -0
  280. package/dist/logic/edit-ops.d.mts +44 -0
  281. package/dist/logic/edit-ops.mjs +177 -0
  282. package/dist/logic/evaluate.d.mts +11 -0
  283. package/dist/logic/evaluate.mjs +93 -0
  284. package/dist/logic/gates.d.mts +10 -0
  285. package/dist/logic/gates.mjs +73 -0
  286. package/dist/logic/index.d.mts +14 -0
  287. package/dist/logic/index.mjs +13 -0
  288. package/dist/logic/lab.d.mts +32 -0
  289. package/dist/logic/lab.mjs +160 -0
  290. package/dist/logic/presets.d.mts +12 -0
  291. package/dist/logic/presets.mjs +241 -0
  292. package/dist/logic/registry.d.mts +9 -0
  293. package/dist/logic/registry.mjs +15 -0
  294. package/dist/math/area-model/preset.mjs +70 -44
  295. package/dist/math/balance-algebra/preset.mjs +14 -5
  296. package/dist/math/broken-tree/index.d.mts +1 -0
  297. package/dist/math/broken-tree/preset.d.mts +26 -0
  298. package/dist/math/broken-tree/preset.mjs +435 -0
  299. package/dist/math/circle/index.d.mts +1 -0
  300. package/dist/math/circle/preset.d.mts +44 -0
  301. package/dist/math/circle/preset.mjs +198 -0
  302. package/dist/math/complex/core.d.mts +93 -0
  303. package/dist/math/complex/core.mjs +239 -0
  304. package/dist/math/complex/index.d.mts +3 -0
  305. package/dist/math/complex/preset.d.mts +31 -0
  306. package/dist/math/complex/preset.mjs +377 -0
  307. package/dist/math/complex/rules.d.mts +6 -0
  308. package/dist/math/complex/rules.mjs +121 -0
  309. package/dist/math/conic/index.d.mts +1 -0
  310. package/dist/math/conic/preset.d.mts +30 -0
  311. package/dist/math/conic/preset.mjs +334 -0
  312. package/dist/math/derivation.mjs +5 -5
  313. package/dist/math/derivative-explorer/preset.mjs +5 -5
  314. package/dist/math/domain-range/index.d.mts +1 -0
  315. package/dist/math/domain-range/preset.d.mts +33 -0
  316. package/dist/math/domain-range/preset.mjs +313 -0
  317. package/dist/math/fraction-bar/index.d.mts +1 -0
  318. package/dist/math/fraction-bar/preset.d.mts +27 -0
  319. package/dist/math/fraction-bar/preset.mjs +197 -0
  320. package/dist/math/function-machine/preset.mjs +2 -2
  321. package/dist/math/gradient-descent.mjs +6 -6
  322. package/dist/math/grapher/preset.d.mts +1 -1
  323. package/dist/math/grapher/preset.mjs +4 -4
  324. package/dist/math/harmonic-form/preset.mjs +6 -6
  325. package/dist/math/index.d.mts +27 -2
  326. package/dist/math/index.mjs +27 -2
  327. package/dist/math/integral-explorer/preset.mjs +2 -2
  328. package/dist/math/interactive/preset.mjs +3 -3
  329. package/dist/math/limit-explorer/preset.mjs +4 -4
  330. package/dist/math/linear-model/index.d.mts +1 -0
  331. package/dist/math/linear-model/preset.d.mts +53 -0
  332. package/dist/math/linear-model/preset.mjs +164 -0
  333. package/dist/math/linear-system/preset.mjs +4 -4
  334. package/dist/math/mystery-bucket/preset.mjs +6 -6
  335. package/dist/math/number-line/preset.mjs +3 -2
  336. package/dist/math/parabola/preset.mjs +4 -3
  337. package/dist/math/pattern/preset.mjs +7 -13
  338. package/dist/math/percent-bar/index.d.mts +1 -0
  339. package/dist/math/percent-bar/preset.d.mts +37 -0
  340. package/dist/math/percent-bar/preset.mjs +275 -0
  341. package/dist/math/poly/core.d.mts +50 -0
  342. package/dist/math/poly/core.mjs +268 -0
  343. package/dist/math/poly/index.d.mts +3 -0
  344. package/dist/math/poly/preset.d.mts +23 -0
  345. package/dist/math/poly/preset.mjs +141 -0
  346. package/dist/math/poly/steps.d.mts +10 -0
  347. package/dist/math/poly/steps.mjs +99 -0
  348. package/dist/math/rate-machine/index.d.mts +1 -0
  349. package/dist/math/rate-machine/preset.d.mts +35 -0
  350. package/dist/math/rate-machine/preset.mjs +281 -0
  351. package/dist/math/ratio-share/index.d.mts +1 -0
  352. package/dist/math/ratio-share/preset.d.mts +24 -0
  353. package/dist/math/ratio-share/preset.mjs +204 -0
  354. package/dist/math/receipt/index.d.mts +1 -0
  355. package/dist/math/receipt/preset.d.mts +22 -0
  356. package/dist/math/receipt/preset.mjs +137 -0
  357. package/dist/math/sequence-predict/index.d.mts +1 -0
  358. package/dist/math/sequence-predict/preset.d.mts +34 -0
  359. package/dist/math/sequence-predict/preset.mjs +130 -0
  360. package/dist/math/straight-line/index.d.mts +1 -0
  361. package/dist/math/straight-line/preset.d.mts +37 -0
  362. package/dist/math/straight-line/preset.mjs +374 -0
  363. package/dist/math/system-solve/index.d.mts +1 -0
  364. package/dist/math/system-solve/preset.d.mts +21 -0
  365. package/dist/math/system-solve/preset.mjs +227 -0
  366. package/dist/math/transform/index.d.mts +1 -0
  367. package/dist/math/transform/preset.d.mts +41 -0
  368. package/dist/math/transform/preset.mjs +343 -0
  369. package/dist/math/triangle-trig/preset.mjs +12 -9
  370. package/dist/math/trig/core.d.mts +37 -0
  371. package/dist/math/trig/core.mjs +150 -0
  372. package/dist/math/trig/diagrams.d.mts +1 -0
  373. package/dist/math/trig/diagrams.mjs +321 -0
  374. package/dist/math/trig/index.d.mts +3 -0
  375. package/dist/math/trig/preset.d.mts +25 -0
  376. package/dist/math/trig/preset.mjs +260 -0
  377. package/dist/math/trig/rules.d.mts +6 -0
  378. package/dist/math/trig/rules.mjs +159 -0
  379. package/dist/math/trig-explorer.mjs +4 -4
  380. package/dist/ml/boundary/preset.mjs +8 -3
  381. package/dist/ml/classifier/preset.mjs +31 -6
  382. package/dist/ml/kmeans/preset.mjs +4 -4
  383. package/dist/ml/knn/preset.mjs +47 -12
  384. package/dist/ml/regression/preset.mjs +36 -7
  385. package/dist/physics/atwood/preset.mjs +4 -4
  386. package/dist/physics/bullet-walls/preset.d.mts +1 -1
  387. package/dist/physics/bullet-walls/preset.mjs +7 -7
  388. package/dist/physics/carnot/preset.mjs +6 -6
  389. package/dist/physics/circular-motion/preset.mjs +36 -5
  390. package/dist/physics/collision-track/preset.mjs +35 -5
  391. package/dist/physics/efficiency/preset.d.mts +2 -2
  392. package/dist/physics/efficiency/preset.mjs +5 -5
  393. package/dist/physics/electric-field/preset.mjs +32 -23
  394. package/dist/physics/electric-flux/index.d.mts +1 -0
  395. package/dist/physics/electric-flux/preset.d.mts +29 -0
  396. package/dist/physics/electric-flux/preset.mjs +264 -0
  397. package/dist/physics/energy-skate/preset.mjs +5 -5
  398. package/dist/physics/entropy/preset.mjs +7 -7
  399. package/dist/physics/expansion/preset.mjs +13 -13
  400. package/dist/physics/exponential/asset.mjs +1 -1
  401. package/dist/physics/exponential/preset.mjs +4 -4
  402. package/dist/physics/gas-process/preset.mjs +3 -3
  403. package/dist/physics/gauss-law/index.d.mts +1 -0
  404. package/dist/physics/gauss-law/preset.d.mts +20 -0
  405. package/dist/physics/gauss-law/preset.mjs +286 -0
  406. package/dist/physics/gravitation/preset.mjs +7 -7
  407. package/dist/physics/gravity-drop.mjs +4 -4
  408. package/dist/physics/heat-transfer/preset.d.mts +1 -1
  409. package/dist/physics/heat-transfer/preset.mjs +10 -10
  410. package/dist/physics/impulse/preset.mjs +5 -5
  411. package/dist/physics/index.d.mts +4 -1
  412. package/dist/physics/index.mjs +4 -1
  413. package/dist/physics/kepler/preset.mjs +4 -4
  414. package/dist/physics/lever/preset.mjs +3 -3
  415. package/dist/physics/lorentz/preset.mjs +11 -11
  416. package/dist/physics/magnetism/preset.mjs +3 -3
  417. package/dist/physics/optics/preset.mjs +2 -2
  418. package/dist/physics/orbit-lab.mjs +5 -5
  419. package/dist/physics/projectile-lab.mjs +4 -4
  420. package/dist/physics/rain-relative/preset.mjs +5 -5
  421. package/dist/physics/ramp-forces/preset.mjs +5 -5
  422. package/dist/physics/river-boat.mjs +6 -6
  423. package/dist/physics/shm/preset.mjs +9 -9
  424. package/dist/physics/stopping-distance/preset.mjs +3 -3
  425. package/dist/physics/temperature-scales/preset.mjs +105 -116
  426. package/dist/physics/terminal-velocity/preset.mjs +5 -5
  427. package/dist/physics/thermal/preset.mjs +5 -5
  428. package/dist/physics/vector-board/preset.mjs +7 -6
  429. package/dist/physics/vector-scene.mjs +2 -2
  430. package/dist/physics/vector-types/preset.mjs +37 -3
  431. package/dist/physics/water-density/preset.mjs +12 -12
  432. package/dist/physics/waves/doppler.mjs +2 -2
  433. package/dist/physics/waves/preset.mjs +4 -4
  434. package/dist/physics/waves/ripple.mjs +6 -6
  435. package/dist/physics/waves/string.mjs +5 -5
  436. package/dist/physics/work-energy/preset.mjs +4 -4
  437. package/dist/physics/work-potential/index.d.mts +1 -0
  438. package/dist/physics/work-potential/preset.d.mts +20 -0
  439. package/dist/physics/work-potential/preset.mjs +276 -0
  440. package/dist/schemas/index.d.mts +6 -6
  441. package/dist/schemas/index.mjs +3 -3
  442. package/dist/statistics/center-spread/preset.mjs +3 -3
  443. package/dist/statistics/core/descriptive.d.mts +2 -2
  444. package/dist/statistics/core/descriptive.mjs +2 -2
  445. package/dist/statistics/core/normal.d.mts +3 -3
  446. package/dist/statistics/core/normal.mjs +3 -3
  447. package/dist/statistics/core/sequences.d.mts +1 -1
  448. package/dist/statistics/galton/preset.mjs +2 -2
  449. package/dist/statistics/histogram/preset.mjs +6 -6
  450. package/dist/statistics/normal/preset.mjs +2 -2
  451. package/dist/statistics/sampling/preset.mjs +4 -4
  452. package/dist/statistics/sequence/preset.mjs +58 -15
  453. package/dist/statistics/z-table/preset.mjs +17 -4
  454. package/package.json +11 -3
  455. package/styles.css +4 -1
@@ -15,18 +15,42 @@ import { Derivation } from "../math/derivation.mjs";
15
15
  import { GradientDescent } from "../math/gradient-descent.mjs";
16
16
  import { InteractiveProblem } from "../math/interactive/preset.mjs";
17
17
  import { TriangleTrig } from "../math/triangle-trig/preset.mjs";
18
+ import { StraightLineLab } from "../math/straight-line/preset.mjs";
19
+ import { CircleLab } from "../math/circle/preset.mjs";
20
+ import { ConicLab } from "../math/conic/preset.mjs";
21
+ import { DomainRangeLab } from "../math/domain-range/preset.mjs";
22
+ import { listScenes } from "../kit/scenes.mjs";
23
+ import { LinearModelLab } from "../math/linear-model/preset.mjs";
24
+ import { RateMachineLab } from "../math/rate-machine/preset.mjs";
25
+ import { SequencePredict } from "../math/sequence-predict/preset.mjs";
26
+ import { PercentBarLab } from "../math/percent-bar/preset.mjs";
27
+ import { ComplexPlaneLab } from "../math/complex/preset.mjs";
28
+ import { TrigSignsLab } from "../math/trig/preset.mjs";
29
+ import { FractionBarLab } from "../math/fraction-bar/preset.mjs";
30
+ import { RatioShareLab } from "../math/ratio-share/preset.mjs";
31
+ import { TransformLab } from "../math/transform/preset.mjs";
32
+ import { ReceiptLab } from "../math/receipt/preset.mjs";
33
+ import { listClueScenes } from "../kit/clue-scene.mjs";
34
+ import { SystemSolveLab } from "../math/system-solve/preset.mjs";
35
+ import { PolynomialSolverLab } from "../math/poly/preset.mjs";
36
+ import { registerDataScene } from "../kit/data-scene.mjs";
37
+ import { SceneStudio } from "../kit/scene-studio.mjs";
18
38
  import { ChipToggle, ConfigPanel, ConfigRow, NumField, SelectField, SmallButton, TextField } from "./authoring.mjs";
39
+ import { labBlock } from "./lab-block.mjs";
19
40
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
20
41
  import { z } from "zod";
21
42
  import { defineBlock } from "@classytic/cms-ui/contract";
22
43
 
23
44
  //#region src/blocks/math.tsx
45
+ const levelSceneOptions = () => ["none", ...listScenes("level").map((s) => s.name)];
46
+ const countSceneOptions = () => listScenes("count").map((s) => s.name);
47
+ const clueSceneOptions = () => listClueScenes().map((s) => s.name);
24
48
  const resolveFns = (raw) => Array.isArray(raw) && raw.length ? raw : ["sin", "cos"];
25
49
  const TrigExplorerBlock = defineBlock({
26
50
  key: "trig-explorer",
27
51
  void: true,
28
52
  label: "Trig explorer",
29
- description: "Unit circle ↔ wave β€” drag the angle; sin & cos trace out. (tan/cot: use Graph)",
53
+ description: "Unit circle ↔ wave, drag the angle; sin & cos trace out. (tan/cot: use Graph)",
30
54
  category: "interactive",
31
55
  schema: z.object({
32
56
  functions: z.array(z.enum(["sin", "cos"])).optional(),
@@ -74,7 +98,7 @@ const GraphBlock = defineBlock({
74
98
  key: "graph",
75
99
  void: true,
76
100
  label: "Graph (equation)",
77
- description: "Plot equations you type β€” y = aΒ·sin(bΒ·x), x^2, … with learner sliders.",
101
+ description: "Plot equations you type, y = aΒ·sin(bΒ·x), x^2, … with learner sliders.",
78
102
  category: "interactive",
79
103
  schema: z.object({
80
104
  equations: z.array(equationSchema).optional(),
@@ -309,7 +333,7 @@ const GradientDescentBlock = defineBlock({
309
333
  key: "gradient-descent",
310
334
  void: true,
311
335
  label: "Gradient descent",
312
- description: "Walk downhill on a loss surface f(x,y) using exact βˆ‚f/βˆ‚x, βˆ‚f/βˆ‚y β€” the calculus behind ML.",
336
+ description: "Walk downhill on a loss surface f(x,y) using exact βˆ‚f/βˆ‚x, βˆ‚f/βˆ‚y, the calculus behind ML.",
313
337
  category: "interactive",
314
338
  schema: z.object({
315
339
  equation: z.string().optional(),
@@ -371,7 +395,7 @@ const IntegralExplorerBlock = defineBlock({
371
395
  key: "integral-explorer",
372
396
  void: true,
373
397
  label: "Integral explorer",
374
- description: "Area under a curve via Riemann rectangles β€” drag endpoints, add n, converge.",
398
+ description: "Area under a curve via Riemann rectangles, drag endpoints, add n, converge.",
375
399
  category: "interactive",
376
400
  schema: z.object({
377
401
  equation: z.string().optional(),
@@ -608,7 +632,7 @@ const LinearSystemBlock = defineBlock({
608
632
  tag: "LinearSystem",
609
633
  void: true,
610
634
  label: "System of equations (x & y)",
611
- description: "Two clue lines on a grid β€” drag to the crossing point that obeys both. The advanced \"find x and y\" lab.",
635
+ description: "Two clue lines on a grid, drag to the crossing point that obeys both. The advanced \"find x and y\" lab.",
612
636
  category: "interactive",
613
637
  schema: z.object({
614
638
  m1: z.number().default(1),
@@ -665,7 +689,7 @@ const NumberLineBlock = defineBlock({
665
689
  tag: "NumberLine",
666
690
  void: true,
667
691
  label: "Number line",
668
- description: "A draggable marker on a number line (incl. below zero) β€” optionally pose a target to land on.",
692
+ description: "A draggable marker on a number line (incl. below zero), optionally pose a target to land on.",
669
693
  category: "interactive",
670
694
  schema: z.object({
671
695
  min: z.number().default(-8),
@@ -719,7 +743,7 @@ const MysteryBucketBlock = defineBlock({
719
743
  tag: "MysteryBucket",
720
744
  void: true,
721
745
  label: "Mystery bucket (weigh the unknown)",
722
- description: "Essentials opener β€” add unit weights until a balance is level to discover the hidden weight. No symbols.",
746
+ description: "Essentials opener, add unit weights until a balance is level to discover the hidden weight. No symbols.",
723
747
  category: "interactive",
724
748
  schema: z.object({
725
749
  bucketWeight: z.number().default(5),
@@ -773,7 +797,7 @@ const BalanceAlgebraBlock = defineBlock({
773
797
  tag: "BalanceAlgebra",
774
798
  void: true,
775
799
  label: "Balance scale (algebra)",
776
- description: "Drag x to balance aΒ·x + b = c β€” learners solve a linear equation by balancing the scale.",
800
+ description: "Drag x to balance aΒ·x + b = c, learners solve a linear equation by balancing the scale.",
777
801
  category: "interactive",
778
802
  schema: z.object({
779
803
  coef: z.number().default(2),
@@ -850,7 +874,7 @@ const AreaModelBlock = defineBlock({
850
874
  tag: "AreaModel",
851
875
  void: true,
852
876
  label: "Area model (algebra tiles)",
853
- description: "(x+a)(x+b) as a partitioned rectangle β€” EXPAND (drag x) or FACTOR (find a, b).",
877
+ description: "(x+a)(x+b) as a partitioned rectangle, EXPAND (drag x) or FACTOR (find a, b).",
854
878
  category: "interactive",
855
879
  schema: z.object({
856
880
  a: z.number().default(3),
@@ -1065,11 +1089,253 @@ function AskEditor({ ask, onChange }) {
1065
1089
  ]
1066
1090
  });
1067
1091
  }
1092
+ const labChoiceSchema = z.object({
1093
+ value: z.string(),
1094
+ label: z.string()
1095
+ });
1096
+ const labAskSchema = z.object({
1097
+ prompt: z.string(),
1098
+ placeholder: z.string().optional(),
1099
+ answer: answerSchema.optional(),
1100
+ choices: z.array(labChoiceSchema).optional(),
1101
+ correct: z.string().optional(),
1102
+ explain: z.string().optional()
1103
+ });
1104
+ const CHOICE_LETTERS = [
1105
+ "a",
1106
+ "b",
1107
+ "c",
1108
+ "d",
1109
+ "e",
1110
+ "f"
1111
+ ];
1112
+ /** Author a graded question as a typed answer (number/expression) OR multiple choice. */
1113
+ function LabAskEditor({ ask, onChange }) {
1114
+ if (!ask) return /* @__PURE__ */ jsxs("div", {
1115
+ className: "flex flex-wrap gap-1.5",
1116
+ children: [/* @__PURE__ */ jsx(SmallButton, {
1117
+ onClick: () => onChange({
1118
+ prompt: "",
1119
+ answer: {
1120
+ kind: "number",
1121
+ value: 0
1122
+ }
1123
+ }),
1124
+ children: "+ typed question"
1125
+ }), /* @__PURE__ */ jsx(SmallButton, {
1126
+ onClick: () => onChange({
1127
+ prompt: "",
1128
+ choices: [{
1129
+ value: "a",
1130
+ label: ""
1131
+ }, {
1132
+ value: "b",
1133
+ label: ""
1134
+ }],
1135
+ correct: "a"
1136
+ }),
1137
+ children: "+ multiple choice"
1138
+ })]
1139
+ });
1140
+ const isMcq = Array.isArray(ask.choices);
1141
+ const isNum = ask.answer?.kind !== "expression";
1142
+ const setAns = (patch) => onChange({
1143
+ ...ask,
1144
+ answer: {
1145
+ ...ask.answer ?? {
1146
+ kind: "number",
1147
+ value: 0
1148
+ },
1149
+ ...patch
1150
+ }
1151
+ });
1152
+ const choices = ask.choices ?? [];
1153
+ const setChoice = (i, patch) => onChange({
1154
+ ...ask,
1155
+ choices: choices.map((c, j) => j === i ? {
1156
+ ...c,
1157
+ ...patch
1158
+ } : c)
1159
+ });
1160
+ return /* @__PURE__ */ jsxs("div", {
1161
+ className: "space-y-1.5",
1162
+ children: [
1163
+ /* @__PURE__ */ jsxs("div", {
1164
+ className: "flex items-center justify-between",
1165
+ children: [/* @__PURE__ */ jsx("span", {
1166
+ className: "font-medium text-muted-foreground",
1167
+ children: "Question (graded)"
1168
+ }), /* @__PURE__ */ jsxs("div", {
1169
+ className: "flex gap-1.5",
1170
+ children: [
1171
+ /* @__PURE__ */ jsx(ChipToggle, {
1172
+ active: !isMcq,
1173
+ onClick: () => onChange({
1174
+ prompt: ask.prompt,
1175
+ placeholder: ask.placeholder,
1176
+ answer: ask.answer ?? {
1177
+ kind: "number",
1178
+ value: 0
1179
+ }
1180
+ }),
1181
+ children: "typed"
1182
+ }),
1183
+ /* @__PURE__ */ jsx(ChipToggle, {
1184
+ active: isMcq,
1185
+ onClick: () => onChange({
1186
+ prompt: ask.prompt,
1187
+ choices: choices.length ? choices : [{
1188
+ value: "a",
1189
+ label: ""
1190
+ }, {
1191
+ value: "b",
1192
+ label: ""
1193
+ }],
1194
+ correct: ask.correct ?? "a"
1195
+ }),
1196
+ children: "multiple choice"
1197
+ }),
1198
+ /* @__PURE__ */ jsx(SmallButton, {
1199
+ tone: "danger",
1200
+ onClick: () => onChange(void 0),
1201
+ children: "remove"
1202
+ })
1203
+ ]
1204
+ })]
1205
+ }),
1206
+ /* @__PURE__ */ jsx(ConfigRow, {
1207
+ label: "Prompt",
1208
+ children: /* @__PURE__ */ jsx(TextField, {
1209
+ value: ask.prompt,
1210
+ onChange: (v) => onChange({
1211
+ ...ask,
1212
+ prompt: v
1213
+ }),
1214
+ className: "flex-1"
1215
+ })
1216
+ }),
1217
+ isMcq ? /* @__PURE__ */ jsxs("div", {
1218
+ className: "space-y-1.5",
1219
+ children: [
1220
+ /* @__PURE__ */ jsx("span", {
1221
+ className: "text-muted-foreground",
1222
+ children: "Options (tap βœ“ to mark the correct one)"
1223
+ }),
1224
+ choices.map((c, i) => /* @__PURE__ */ jsxs("div", {
1225
+ className: "flex items-center gap-1.5",
1226
+ children: [
1227
+ /* @__PURE__ */ jsx(ChipToggle, {
1228
+ active: ask.correct === c.value,
1229
+ onClick: () => onChange({
1230
+ ...ask,
1231
+ correct: c.value
1232
+ }),
1233
+ children: "βœ“"
1234
+ }),
1235
+ /* @__PURE__ */ jsx(TextField, {
1236
+ value: c.label,
1237
+ placeholder: `option ${c.value}`,
1238
+ onChange: (v) => setChoice(i, { label: v }),
1239
+ className: "flex-1"
1240
+ }),
1241
+ choices.length > 2 && /* @__PURE__ */ jsx(SmallButton, {
1242
+ tone: "danger",
1243
+ onClick: () => onChange({
1244
+ ...ask,
1245
+ choices: choices.filter((_, j) => j !== i)
1246
+ }),
1247
+ children: "βœ•"
1248
+ })
1249
+ ]
1250
+ }, i)),
1251
+ /* @__PURE__ */ jsx("div", {
1252
+ className: "flex flex-wrap gap-1.5",
1253
+ children: /* @__PURE__ */ jsx(SmallButton, {
1254
+ onClick: () => {
1255
+ const v = CHOICE_LETTERS[choices.length] ?? String(choices.length);
1256
+ onChange({
1257
+ ...ask,
1258
+ choices: [...choices, {
1259
+ value: v,
1260
+ label: ""
1261
+ }]
1262
+ });
1263
+ },
1264
+ children: "+ option"
1265
+ })
1266
+ }),
1267
+ /* @__PURE__ */ jsx(ConfigRow, {
1268
+ label: "Explain",
1269
+ children: /* @__PURE__ */ jsx(TextField, {
1270
+ value: ask.explain ?? "",
1271
+ placeholder: "shown when correct",
1272
+ onChange: (v) => onChange({
1273
+ ...ask,
1274
+ explain: v
1275
+ }),
1276
+ className: "flex-1"
1277
+ })
1278
+ })
1279
+ ]
1280
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1281
+ /* @__PURE__ */ jsxs(ConfigRow, {
1282
+ label: "Answer is",
1283
+ children: [/* @__PURE__ */ jsx(ChipToggle, {
1284
+ active: isNum,
1285
+ onClick: () => setAns({
1286
+ kind: "number",
1287
+ value: typeof ask.answer?.value === "number" ? ask.answer.value : 0
1288
+ }),
1289
+ children: "a number"
1290
+ }), /* @__PURE__ */ jsx(ChipToggle, {
1291
+ active: !isNum,
1292
+ onClick: () => setAns({
1293
+ kind: "expression",
1294
+ value: String(ask.answer?.value ?? "")
1295
+ }),
1296
+ children: "an expression"
1297
+ })]
1298
+ }),
1299
+ /* @__PURE__ */ jsxs(ConfigRow, {
1300
+ label: "Correct value",
1301
+ children: [isNum ? /* @__PURE__ */ jsx(NumField, {
1302
+ value: Number(ask.answer?.value) || 0,
1303
+ onChange: (v) => setAns({ value: v })
1304
+ }) : /* @__PURE__ */ jsx(TextField, {
1305
+ value: String(ask.answer?.value ?? ""),
1306
+ mono: true,
1307
+ placeholder: "-0.5*x + 5",
1308
+ onChange: (v) => setAns({ value: v }),
1309
+ className: "flex-1"
1310
+ }), isNum && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1311
+ className: "text-muted-foreground",
1312
+ children: "Β± tol"
1313
+ }), /* @__PURE__ */ jsx(NumField, {
1314
+ value: ask.answer?.tol ?? .01,
1315
+ onChange: (v) => setAns({ tol: v })
1316
+ })] })]
1317
+ }),
1318
+ /* @__PURE__ */ jsx(ConfigRow, {
1319
+ label: "Hint",
1320
+ children: /* @__PURE__ */ jsx(TextField, {
1321
+ value: ask.placeholder ?? "",
1322
+ placeholder: "placeholder e.g. y = ...",
1323
+ onChange: (v) => onChange({
1324
+ ...ask,
1325
+ placeholder: v
1326
+ }),
1327
+ className: "flex-1"
1328
+ })
1329
+ })
1330
+ ] })
1331
+ ]
1332
+ });
1333
+ }
1068
1334
  const InteractiveProblemBlock = defineBlock({
1069
1335
  key: "interactive-problem",
1070
1336
  void: true,
1071
1337
  label: "Interactive problem (engine)",
1072
- description: "Author equations + sliders, derive roots/intersections/tangent/normal/area, and grade a typed answer β€” no code.",
1338
+ description: "Author equations + sliders, derive roots/intersections/tangent/normal/area, and grade a typed answer, no code.",
1073
1339
  category: "interactive",
1074
1340
  schema: z.object({
1075
1341
  equations: z.array(equationSchema).optional(),
@@ -1492,10 +1758,1351 @@ const TriangleTrigBlock = defineBlock({
1492
1758
  ] }), widget] });
1493
1759
  }
1494
1760
  });
1495
- /** All math labs blocks β€” spread into a host's `defineBlock` list. */
1761
+ const pointSchema = z.object({
1762
+ x: z.number(),
1763
+ y: z.number()
1764
+ });
1765
+ const StraightLineBlock = defineBlock({
1766
+ key: "straight-line",
1767
+ tag: "StraightLine",
1768
+ void: true,
1769
+ label: "Straight line (y = mx + c, parallel/βŠ₯, intercepts)",
1770
+ description: "Drag points/intercepts to build a line; covers gradient–intercept, two-point, intercept form, and parallel/perpendicular. Optional graded answer.",
1771
+ category: "interactive",
1772
+ schema: z.object({
1773
+ mode: z.enum([
1774
+ "two-point",
1775
+ "gradient-intercept",
1776
+ "intercept-form",
1777
+ "parallel",
1778
+ "perpendicular"
1779
+ ]).optional(),
1780
+ pointA: pointSchema.optional(),
1781
+ pointB: pointSchema.optional(),
1782
+ given: z.object({
1783
+ m: z.number(),
1784
+ c: z.number()
1785
+ }).optional(),
1786
+ through: pointSchema.optional(),
1787
+ showDistance: z.boolean().optional(),
1788
+ snap: z.number().optional(),
1789
+ title: z.string().optional(),
1790
+ prompt: z.string().optional(),
1791
+ ask: labAskSchema.optional(),
1792
+ activity: z.string().optional()
1793
+ }),
1794
+ Component: ({ attributes, mode, updateAttributes }) => {
1795
+ const a = attributes;
1796
+ const ask = attributes.ask;
1797
+ const m = a.mode ?? "two-point";
1798
+ const given = a.given ?? {
1799
+ m: .5,
1800
+ c: 2
1801
+ };
1802
+ const widget = /* @__PURE__ */ jsx(StraightLineLab, { ...a });
1803
+ if (mode !== "editing" || !updateAttributes) return widget;
1804
+ const upd = updateAttributes;
1805
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
1806
+ /* @__PURE__ */ jsx(ConfigRow, {
1807
+ label: "Title",
1808
+ children: /* @__PURE__ */ jsx(TextField, {
1809
+ value: a.title ?? "",
1810
+ placeholder: "The straight line",
1811
+ onChange: (v) => updateAttributes({ title: v }),
1812
+ className: "flex-1"
1813
+ })
1814
+ }),
1815
+ /* @__PURE__ */ jsx(ConfigRow, {
1816
+ label: "Form",
1817
+ children: /* @__PURE__ */ jsx(SelectField, {
1818
+ value: m,
1819
+ options: [
1820
+ "two-point",
1821
+ "gradient-intercept",
1822
+ "intercept-form",
1823
+ "parallel",
1824
+ "perpendicular"
1825
+ ],
1826
+ onChange: (v) => upd({ mode: v })
1827
+ })
1828
+ }),
1829
+ (m === "parallel" || m === "perpendicular") && /* @__PURE__ */ jsxs(ConfigRow, {
1830
+ label: "Given line y =",
1831
+ children: [
1832
+ /* @__PURE__ */ jsx(NumField, {
1833
+ value: given.m,
1834
+ onChange: (v) => upd({ given: {
1835
+ ...given,
1836
+ m: v
1837
+ } })
1838
+ }),
1839
+ /* @__PURE__ */ jsx("span", {
1840
+ className: "text-muted-foreground",
1841
+ children: "x +"
1842
+ }),
1843
+ /* @__PURE__ */ jsx(NumField, {
1844
+ value: given.c,
1845
+ onChange: (v) => upd({ given: {
1846
+ ...given,
1847
+ c: v
1848
+ } })
1849
+ })
1850
+ ]
1851
+ }),
1852
+ m === "two-point" && /* @__PURE__ */ jsx(ConfigRow, {
1853
+ label: "Extras",
1854
+ children: /* @__PURE__ */ jsx(ChipToggle, {
1855
+ active: !!a.showDistance,
1856
+ onClick: () => upd({ showDistance: !a.showDistance }),
1857
+ children: "show |AB| + midpoint"
1858
+ })
1859
+ }),
1860
+ /* @__PURE__ */ jsx(ConfigRow, {
1861
+ label: "Snap",
1862
+ children: /* @__PURE__ */ jsx(NumField, {
1863
+ value: a.snap ?? 1,
1864
+ onChange: (v) => updateAttributes({ snap: v })
1865
+ })
1866
+ }),
1867
+ /* @__PURE__ */ jsx(LabAskEditor, {
1868
+ ask,
1869
+ onChange: (a2) => upd({ ask: a2 })
1870
+ })
1871
+ ] }), widget] });
1872
+ }
1873
+ });
1874
+ const CircleBlock = defineBlock({
1875
+ key: "circle-geometry",
1876
+ tag: "CircleLab",
1877
+ void: true,
1878
+ label: "Circle ((xβˆ’a)Β² + (yβˆ’b)Β² = rΒ², tangent)",
1879
+ description: "Drag the centre and rim; live standard + expanded equation, optional tangent (βŠ₯ to the radius). Optional graded answer.",
1880
+ category: "interactive",
1881
+ schema: z.object({
1882
+ center: pointSchema.optional(),
1883
+ radius: z.number().optional(),
1884
+ showTangent: z.boolean().optional(),
1885
+ showExpanded: z.boolean().optional(),
1886
+ tangentAngleDeg: z.number().optional(),
1887
+ snap: z.number().optional(),
1888
+ title: z.string().optional(),
1889
+ prompt: z.string().optional(),
1890
+ ask: labAskSchema.optional(),
1891
+ activity: z.string().optional()
1892
+ }),
1893
+ Component: ({ attributes, mode, updateAttributes }) => {
1894
+ const a = attributes;
1895
+ const ask = attributes.ask;
1896
+ const widget = /* @__PURE__ */ jsx(CircleLab, { ...a });
1897
+ if (mode !== "editing" || !updateAttributes) return widget;
1898
+ const upd = updateAttributes;
1899
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
1900
+ /* @__PURE__ */ jsx(ConfigRow, {
1901
+ label: "Title",
1902
+ children: /* @__PURE__ */ jsx(TextField, {
1903
+ value: a.title ?? "",
1904
+ placeholder: "The circle",
1905
+ onChange: (v) => updateAttributes({ title: v }),
1906
+ className: "flex-1"
1907
+ })
1908
+ }),
1909
+ /* @__PURE__ */ jsx(ConfigRow, {
1910
+ label: "Radius",
1911
+ children: /* @__PURE__ */ jsx(NumField, {
1912
+ value: a.radius ?? 4,
1913
+ onChange: (v) => updateAttributes({ radius: v })
1914
+ })
1915
+ }),
1916
+ /* @__PURE__ */ jsxs(ConfigRow, {
1917
+ label: "Show",
1918
+ children: [/* @__PURE__ */ jsx(ChipToggle, {
1919
+ active: !!a.showExpanded,
1920
+ onClick: () => upd({ showExpanded: !a.showExpanded }),
1921
+ children: "expanded form"
1922
+ }), /* @__PURE__ */ jsx(ChipToggle, {
1923
+ active: !!a.showTangent,
1924
+ onClick: () => upd({ showTangent: !a.showTangent }),
1925
+ children: "tangent"
1926
+ })]
1927
+ }),
1928
+ /* @__PURE__ */ jsx(ConfigRow, {
1929
+ label: "Snap",
1930
+ children: /* @__PURE__ */ jsx(NumField, {
1931
+ value: a.snap ?? 1,
1932
+ onChange: (v) => updateAttributes({ snap: v })
1933
+ })
1934
+ }),
1935
+ /* @__PURE__ */ jsx(LabAskEditor, {
1936
+ ask,
1937
+ onChange: (a2) => upd({ ask: a2 })
1938
+ })
1939
+ ] }), widget] });
1940
+ }
1941
+ });
1942
+ const ConicBlock = defineBlock({
1943
+ key: "conic",
1944
+ tag: "ConicLab",
1945
+ void: true,
1946
+ label: "Conic (parabola / ellipse / hyperbola / reciprocal)",
1947
+ description: "Drag a parabola (yΒ²=4ax, focus+directrix), an ellipse (xΒ²/aΒ²+yΒ²/bΒ²=1, foci), a hyperbola (xΒ²/aΒ²βˆ’yΒ²/bΒ²=1, asymptotes), or the reciprocal xy=c. Optional graded answer.",
1948
+ category: "interactive",
1949
+ schema: z.object({
1950
+ kind: z.enum([
1951
+ "parabola",
1952
+ "ellipse",
1953
+ "hyperbola",
1954
+ "rectangular"
1955
+ ]).optional(),
1956
+ a: z.number().optional(),
1957
+ b: z.number().optional(),
1958
+ c: z.number().optional(),
1959
+ showFocusDirectrix: z.boolean().optional(),
1960
+ showAsymptotes: z.boolean().optional(),
1961
+ snap: z.number().optional(),
1962
+ title: z.string().optional(),
1963
+ prompt: z.string().optional(),
1964
+ ask: labAskSchema.optional(),
1965
+ activity: z.string().optional()
1966
+ }),
1967
+ Component: ({ attributes, mode, updateAttributes }) => {
1968
+ const a = attributes;
1969
+ const ask = attributes.ask;
1970
+ const k = a.kind ?? "parabola";
1971
+ const widget = /* @__PURE__ */ jsx(ConicLab, { ...a });
1972
+ if (mode !== "editing" || !updateAttributes) return widget;
1973
+ const upd = updateAttributes;
1974
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
1975
+ /* @__PURE__ */ jsx(ConfigRow, {
1976
+ label: "Title",
1977
+ children: /* @__PURE__ */ jsx(TextField, {
1978
+ value: a.title ?? "",
1979
+ placeholder: "The parabola",
1980
+ onChange: (v) => updateAttributes({ title: v }),
1981
+ className: "flex-1"
1982
+ })
1983
+ }),
1984
+ /* @__PURE__ */ jsx(ConfigRow, {
1985
+ label: "Curve",
1986
+ children: /* @__PURE__ */ jsx(SelectField, {
1987
+ value: k,
1988
+ options: [
1989
+ "parabola",
1990
+ "ellipse",
1991
+ "hyperbola",
1992
+ "rectangular"
1993
+ ],
1994
+ onChange: (v) => upd({ kind: v })
1995
+ })
1996
+ }),
1997
+ k === "parabola" && /* @__PURE__ */ jsx(ConfigRow, {
1998
+ label: "a",
1999
+ children: /* @__PURE__ */ jsx(NumField, {
2000
+ value: a.a ?? 1,
2001
+ onChange: (v) => updateAttributes({ a: v })
2002
+ })
2003
+ }),
2004
+ k === "ellipse" && /* @__PURE__ */ jsxs(ConfigRow, {
2005
+ label: "a, b",
2006
+ children: [/* @__PURE__ */ jsx(NumField, {
2007
+ value: a.a ?? 4,
2008
+ onChange: (v) => updateAttributes({ a: v })
2009
+ }), /* @__PURE__ */ jsx(NumField, {
2010
+ value: a.b ?? 2.5,
2011
+ onChange: (v) => updateAttributes({ b: v })
2012
+ })]
2013
+ }),
2014
+ k === "hyperbola" && /* @__PURE__ */ jsxs(ConfigRow, {
2015
+ label: "a, b",
2016
+ children: [/* @__PURE__ */ jsx(NumField, {
2017
+ value: a.a ?? 2,
2018
+ onChange: (v) => updateAttributes({ a: v })
2019
+ }), /* @__PURE__ */ jsx(NumField, {
2020
+ value: a.b ?? 1.5,
2021
+ onChange: (v) => updateAttributes({ b: v })
2022
+ })]
2023
+ }),
2024
+ k === "rectangular" && /* @__PURE__ */ jsx(ConfigRow, {
2025
+ label: "c",
2026
+ children: /* @__PURE__ */ jsx(NumField, {
2027
+ value: a.c ?? 6,
2028
+ onChange: (v) => updateAttributes({ c: v })
2029
+ })
2030
+ }),
2031
+ /* @__PURE__ */ jsx(ConfigRow, {
2032
+ label: "Snap",
2033
+ children: /* @__PURE__ */ jsx(NumField, {
2034
+ value: a.snap ?? 1,
2035
+ onChange: (v) => updateAttributes({ snap: v })
2036
+ })
2037
+ }),
2038
+ /* @__PURE__ */ jsx(LabAskEditor, {
2039
+ ask,
2040
+ onChange: (a2) => upd({ ask: a2 })
2041
+ })
2042
+ ] }), widget] });
2043
+ }
2044
+ });
2045
+ const DomainRangeBlock = defineBlock({
2046
+ key: "domain-range",
2047
+ tag: "DomainRange",
2048
+ void: true,
2049
+ label: "Domain & range (the two shadows)",
2050
+ description: "Type any f(x); the curve casts a domain shadow (x-axis) and range shadow (y-axis). Drag the input probe: green = accepted, red = undefined. Teaches every domain type.",
2051
+ category: "interactive",
2052
+ schema: z.object({
2053
+ equation: z.string().optional(),
2054
+ xRange: z.tuple([z.number(), z.number()]).optional(),
2055
+ restrict: z.tuple([z.number(), z.number()]).optional(),
2056
+ probe: z.number().optional(),
2057
+ title: z.string().optional(),
2058
+ prompt: z.string().optional(),
2059
+ ask: labAskSchema.optional(),
2060
+ activity: z.string().optional()
2061
+ }),
2062
+ Component: ({ attributes, mode, updateAttributes }) => {
2063
+ const a = attributes;
2064
+ const ask = attributes.ask;
2065
+ const xR = a.xRange ?? [-6, 6];
2066
+ const restricted = Array.isArray(a.restrict);
2067
+ const widget = /* @__PURE__ */ jsx(DomainRangeLab, { ...a });
2068
+ if (mode !== "editing" || !updateAttributes) return widget;
2069
+ const upd = updateAttributes;
2070
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2071
+ /* @__PURE__ */ jsx(ConfigRow, {
2072
+ label: "Title",
2073
+ children: /* @__PURE__ */ jsx(TextField, {
2074
+ value: a.title ?? "",
2075
+ placeholder: "Domain & range",
2076
+ onChange: (v) => updateAttributes({ title: v }),
2077
+ className: "flex-1"
2078
+ })
2079
+ }),
2080
+ /* @__PURE__ */ jsx(ConfigRow, {
2081
+ label: "f(x) =",
2082
+ children: /* @__PURE__ */ jsx(TextField, {
2083
+ value: a.equation ?? "",
2084
+ mono: true,
2085
+ placeholder: "sqrt(9 - x^2)",
2086
+ onChange: (v) => updateAttributes({ equation: v }),
2087
+ className: "flex-1"
2088
+ })
2089
+ }),
2090
+ /* @__PURE__ */ jsxs(ConfigRow, {
2091
+ label: "x window",
2092
+ children: [
2093
+ /* @__PURE__ */ jsx(NumField, {
2094
+ value: xR[0],
2095
+ onChange: (v) => updateAttributes({ xRange: [v, xR[1]] })
2096
+ }),
2097
+ /* @__PURE__ */ jsx("span", {
2098
+ className: "text-muted-foreground",
2099
+ children: "to"
2100
+ }),
2101
+ /* @__PURE__ */ jsx(NumField, {
2102
+ value: xR[1],
2103
+ onChange: (v) => updateAttributes({ xRange: [xR[0], v] })
2104
+ })
2105
+ ]
2106
+ }),
2107
+ /* @__PURE__ */ jsxs(ConfigRow, {
2108
+ label: "Restrict domain",
2109
+ children: [
2110
+ /* @__PURE__ */ jsx(ChipToggle, {
2111
+ active: !restricted,
2112
+ onClick: () => upd({ restrict: void 0 }),
2113
+ children: "none"
2114
+ }),
2115
+ /* @__PURE__ */ jsx(ChipToggle, {
2116
+ active: restricted,
2117
+ onClick: () => upd({ restrict: a.restrict ?? [-2, 2] }),
2118
+ children: "interval"
2119
+ }),
2120
+ restricted && /* @__PURE__ */ jsxs(Fragment, { children: [
2121
+ /* @__PURE__ */ jsx(NumField, {
2122
+ value: a.restrict[0],
2123
+ onChange: (v) => upd({ restrict: [v, a.restrict[1]] })
2124
+ }),
2125
+ /* @__PURE__ */ jsx("span", {
2126
+ className: "text-muted-foreground",
2127
+ children: "to"
2128
+ }),
2129
+ /* @__PURE__ */ jsx(NumField, {
2130
+ value: a.restrict[1],
2131
+ onChange: (v) => upd({ restrict: [a.restrict[0], v] })
2132
+ })
2133
+ ] })
2134
+ ]
2135
+ }),
2136
+ /* @__PURE__ */ jsx(LabAskEditor, {
2137
+ ask,
2138
+ onChange: (a2) => upd({ ask: a2 })
2139
+ })
2140
+ ] }), widget] });
2141
+ }
2142
+ });
2143
+ const LinearModelBlock = defineBlock({
2144
+ key: "linear-model",
2145
+ tag: "LinearModel",
2146
+ void: true,
2147
+ label: "Proportion / rate (marbles β†’ volume)",
2148
+ description: "A concrete scene (a beaker filling with marbles) linked to a graph: drag the point to predict the value at the next input. Discover y = rateΒ·x + base from data. Optional graded follow-up.",
2149
+ category: "interactive",
2150
+ schema: z.object({
2151
+ slope: z.number().default(5),
2152
+ intercept: z.number().default(10),
2153
+ predictX: z.number().default(2),
2154
+ xMax: z.number().default(6),
2155
+ yMax: z.number().default(40),
2156
+ yStep: z.number().default(5),
2157
+ xLabel: z.string().default("Marbles"),
2158
+ yLabel: z.string().default("Volume"),
2159
+ unit: z.string().default("mL"),
2160
+ scene: z.string().default("vessel"),
2161
+ vesselObjects: z.boolean().default(true),
2162
+ vesselBinds: z.enum(["guess", "truth"]).default("guess"),
2163
+ objectLabel: z.string().optional(),
2164
+ title: z.string().optional(),
2165
+ prompt: z.string().optional(),
2166
+ ask: labAskSchema.optional(),
2167
+ activity: z.string().optional()
2168
+ }),
2169
+ Component: ({ attributes, mode, updateAttributes }) => {
2170
+ const a = attributes;
2171
+ const ask = attributes.ask;
2172
+ const predictX = a.predictX ?? 2;
2173
+ const given = Array.from({ length: Math.max(1, predictX) }, (_, i) => i);
2174
+ const widget = /* @__PURE__ */ jsx(LinearModelLab, {
2175
+ ...a,
2176
+ predictX,
2177
+ given
2178
+ });
2179
+ if (mode !== "editing" || !updateAttributes) return widget;
2180
+ const upd = updateAttributes;
2181
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2182
+ /* @__PURE__ */ jsx(ConfigRow, {
2183
+ label: "Title",
2184
+ children: /* @__PURE__ */ jsx(TextField, {
2185
+ value: a.title ?? "",
2186
+ placeholder: "Find the volume",
2187
+ onChange: (v) => updateAttributes({ title: v }),
2188
+ className: "flex-1"
2189
+ })
2190
+ }),
2191
+ /* @__PURE__ */ jsxs(ConfigRow, {
2192
+ label: "Rule: y =",
2193
+ children: [
2194
+ /* @__PURE__ */ jsx(NumField, {
2195
+ value: a.slope ?? 5,
2196
+ onChange: (v) => updateAttributes({ slope: v })
2197
+ }),
2198
+ /* @__PURE__ */ jsx("span", {
2199
+ className: "text-muted-foreground",
2200
+ children: "Β· x +"
2201
+ }),
2202
+ /* @__PURE__ */ jsx(NumField, {
2203
+ value: a.intercept ?? 10,
2204
+ onChange: (v) => updateAttributes({ intercept: v })
2205
+ })
2206
+ ]
2207
+ }),
2208
+ /* @__PURE__ */ jsx(ConfigRow, {
2209
+ label: "Predict at x =",
2210
+ children: /* @__PURE__ */ jsx(NumField, {
2211
+ value: predictX,
2212
+ onChange: (v) => updateAttributes({ predictX: v })
2213
+ })
2214
+ }),
2215
+ /* @__PURE__ */ jsxs(ConfigRow, {
2216
+ label: "Axis labels",
2217
+ children: [/* @__PURE__ */ jsx(TextField, {
2218
+ value: a.xLabel ?? "Marbles",
2219
+ onChange: (v) => updateAttributes({ xLabel: v }),
2220
+ className: "w-28"
2221
+ }), /* @__PURE__ */ jsx(TextField, {
2222
+ value: a.yLabel ?? "Volume",
2223
+ onChange: (v) => updateAttributes({ yLabel: v }),
2224
+ className: "w-28"
2225
+ })]
2226
+ }),
2227
+ /* @__PURE__ */ jsxs(ConfigRow, {
2228
+ label: "x / y max",
2229
+ children: [/* @__PURE__ */ jsx(NumField, {
2230
+ value: a.xMax ?? 6,
2231
+ onChange: (v) => updateAttributes({ xMax: v })
2232
+ }), /* @__PURE__ */ jsx(NumField, {
2233
+ value: a.yMax ?? 40,
2234
+ onChange: (v) => updateAttributes({ yMax: v })
2235
+ })]
2236
+ }),
2237
+ /* @__PURE__ */ jsxs(ConfigRow, {
2238
+ label: "y step / unit",
2239
+ children: [/* @__PURE__ */ jsx(NumField, {
2240
+ value: a.yStep ?? 5,
2241
+ onChange: (v) => updateAttributes({ yStep: v })
2242
+ }), /* @__PURE__ */ jsx(TextField, {
2243
+ value: a.unit ?? "mL",
2244
+ onChange: (v) => updateAttributes({ unit: v }),
2245
+ className: "w-20"
2246
+ })]
2247
+ }),
2248
+ /* @__PURE__ */ jsx(ConfigRow, {
2249
+ label: "Concrete scene",
2250
+ children: /* @__PURE__ */ jsx(SelectField, {
2251
+ value: a.scene ?? "vessel",
2252
+ options: levelSceneOptions(),
2253
+ onChange: (v) => upd({ scene: v })
2254
+ })
2255
+ }),
2256
+ (a.scene ?? "vessel") === "vessel" && /* @__PURE__ */ jsxs(ConfigRow, {
2257
+ label: "Drop objects in",
2258
+ children: [/* @__PURE__ */ jsx(ChipToggle, {
2259
+ active: a.vesselObjects !== false,
2260
+ onClick: () => updateAttributes({ vesselObjects: !(a.vesselObjects !== false) }),
2261
+ children: a.vesselObjects !== false ? "objects (marbles)" : "just liquid"
2262
+ }), a.vesselObjects !== false && /* @__PURE__ */ jsx(TextField, {
2263
+ value: a.objectLabel ?? "",
2264
+ placeholder: "object word e.g. marbles",
2265
+ onChange: (v) => updateAttributes({ objectLabel: v }),
2266
+ className: "w-36"
2267
+ })]
2268
+ }),
2269
+ /* @__PURE__ */ jsx(ConfigRow, {
2270
+ label: "Twin level follows",
2271
+ children: /* @__PURE__ */ jsx(ChipToggle, {
2272
+ active: (a.vesselBinds ?? "guess") === "guess",
2273
+ onClick: () => updateAttributes({ vesselBinds: (a.vesselBinds ?? "guess") === "guess" ? "truth" : "guess" }),
2274
+ children: (a.vesselBinds ?? "guess") === "guess" ? "your drag (rises & falls live)" : "the real lab level (you match it)"
2275
+ })
2276
+ }),
2277
+ /* @__PURE__ */ jsx(LabAskEditor, {
2278
+ ask,
2279
+ onChange: (a2) => upd({ ask: a2 })
2280
+ })
2281
+ ] }), widget] });
2282
+ }
2283
+ });
2284
+ const SequencePredictBlock = defineBlock({
2285
+ key: "sequence-predict",
2286
+ tag: "SequencePredict",
2287
+ void: true,
2288
+ label: "Exponential / sequence (watch it grow)",
2289
+ description: "A count shown as a growing crowd of dots (3 β†’ 6 β†’ 12, new ones lit up); the learner tap-fills the hidden terms. Geometric (Γ—ratio) or arithmetic (+difference). The \"joke that doubles\" lesson.",
2290
+ category: "interactive",
2291
+ schema: z.object({
2292
+ start: z.number().default(3),
2293
+ rule: z.enum(["geometric", "arithmetic"]).default("geometric"),
2294
+ factor: z.number().default(2),
2295
+ shown: z.number().default(1),
2296
+ predict: z.number().default(2),
2297
+ stepLabel: z.string().default("Day"),
2298
+ highlightNew: z.boolean().default(true),
2299
+ scene: z.string().default("cluster"),
2300
+ title: z.string().optional(),
2301
+ prompt: z.string().optional(),
2302
+ activity: z.string().optional()
2303
+ }),
2304
+ Component: ({ attributes, mode, updateAttributes }) => {
2305
+ const a = attributes;
2306
+ const r = a.rule ?? "geometric";
2307
+ const widget = /* @__PURE__ */ jsx(SequencePredict, { ...a });
2308
+ if (mode !== "editing" || !updateAttributes) return widget;
2309
+ const upd = updateAttributes;
2310
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2311
+ /* @__PURE__ */ jsx(ConfigRow, {
2312
+ label: "Title",
2313
+ children: /* @__PURE__ */ jsx(TextField, {
2314
+ value: a.title ?? "",
2315
+ placeholder: "How does it grow?",
2316
+ onChange: (v) => updateAttributes({ title: v }),
2317
+ className: "flex-1"
2318
+ })
2319
+ }),
2320
+ /* @__PURE__ */ jsx(ConfigRow, {
2321
+ label: "Story / prompt",
2322
+ children: /* @__PURE__ */ jsx(TextField, {
2323
+ value: a.prompt ?? "",
2324
+ placeholder: "Each day the number doubles.",
2325
+ onChange: (v) => updateAttributes({ prompt: v }),
2326
+ className: "flex-1"
2327
+ })
2328
+ }),
2329
+ /* @__PURE__ */ jsx(ConfigRow, {
2330
+ label: "Start value",
2331
+ children: /* @__PURE__ */ jsx(NumField, {
2332
+ value: a.start ?? 3,
2333
+ onChange: (v) => updateAttributes({ start: v })
2334
+ })
2335
+ }),
2336
+ /* @__PURE__ */ jsxs(ConfigRow, {
2337
+ label: "Rule",
2338
+ children: [
2339
+ /* @__PURE__ */ jsx(SelectField, {
2340
+ value: r,
2341
+ options: ["geometric", "arithmetic"],
2342
+ onChange: (v) => upd({ rule: v })
2343
+ }),
2344
+ /* @__PURE__ */ jsx("span", {
2345
+ className: "text-muted-foreground",
2346
+ children: r === "geometric" ? "Γ— by" : "+ by"
2347
+ }),
2348
+ /* @__PURE__ */ jsx(NumField, {
2349
+ value: a.factor ?? 2,
2350
+ onChange: (v) => updateAttributes({ factor: v })
2351
+ })
2352
+ ]
2353
+ }),
2354
+ /* @__PURE__ */ jsxs(ConfigRow, {
2355
+ label: "Shown / predict",
2356
+ children: [/* @__PURE__ */ jsx(NumField, {
2357
+ value: a.shown ?? 1,
2358
+ onChange: (v) => updateAttributes({ shown: v })
2359
+ }), /* @__PURE__ */ jsx(NumField, {
2360
+ value: a.predict ?? 2,
2361
+ onChange: (v) => updateAttributes({ predict: v })
2362
+ })]
2363
+ }),
2364
+ /* @__PURE__ */ jsx(ConfigRow, {
2365
+ label: "Step label",
2366
+ children: /* @__PURE__ */ jsx(TextField, {
2367
+ value: a.stepLabel ?? "Day",
2368
+ onChange: (v) => updateAttributes({ stepLabel: v }),
2369
+ className: "w-28"
2370
+ })
2371
+ }),
2372
+ /* @__PURE__ */ jsx(ConfigRow, {
2373
+ label: "Count scene",
2374
+ children: /* @__PURE__ */ jsx(SelectField, {
2375
+ value: a.scene ?? "cluster",
2376
+ options: countSceneOptions(),
2377
+ onChange: (v) => upd({ scene: v })
2378
+ })
2379
+ }),
2380
+ /* @__PURE__ */ jsx(ConfigRow, {
2381
+ label: "Highlight new",
2382
+ children: /* @__PURE__ */ jsx(ChipToggle, {
2383
+ active: a.highlightNew !== false,
2384
+ onClick: () => updateAttributes({ highlightNew: !(a.highlightNew !== false) }),
2385
+ children: "light up added"
2386
+ })
2387
+ })
2388
+ ] }), widget] });
2389
+ }
2390
+ });
2391
+ const PercentBarBlock = labBlock({
2392
+ key: "percent-bar",
2393
+ label: "Percentage bar",
2394
+ description: "A bar is the whole (100%); drag the fill to a target percent and read both the percent and the amount (percent Γ— whole). Author any analogy via whole + unit + an optional segment breakdown.",
2395
+ schema: z.object({
2396
+ whole: z.number().default(100),
2397
+ unit: z.string().default(""),
2398
+ target: z.number().optional(),
2399
+ start: z.number().default(0),
2400
+ snapPct: z.number().default(5),
2401
+ showValue: z.boolean().default(true),
2402
+ referenceLabel: z.string().optional(),
2403
+ segments: z.array(z.object({
2404
+ frac: z.number(),
2405
+ label: z.string().optional(),
2406
+ color: z.string().optional()
2407
+ })).optional(),
2408
+ scene: z.enum([
2409
+ "none",
2410
+ "pie",
2411
+ "battery",
2412
+ "jar",
2413
+ "balloon",
2414
+ "thermometer"
2415
+ ]).default("none"),
2416
+ title: z.string().optional(),
2417
+ prompt: z.string().optional()
2418
+ }),
2419
+ Component: (a) => /* @__PURE__ */ jsx(PercentBarLab, { ...a })
2420
+ });
2421
+ const FractionBarBlock = labBlock({
2422
+ key: "fraction-bar",
2423
+ label: "Fraction strip",
2424
+ description: "A strip cut into equal parts; drag to shade k/n. Reads as fraction, decimal, percent and (with a whole) a quantity. An optional compare strip shows the equivalent fraction.",
2425
+ schema: z.object({
2426
+ denom: z.number().default(4),
2427
+ num: z.number().default(0),
2428
+ target: z.number().optional(),
2429
+ whole: z.number().optional(),
2430
+ unit: z.string().default(""),
2431
+ compareDenom: z.number().optional(),
2432
+ showEquiv: z.boolean().default(true),
2433
+ scene: z.enum([
2434
+ "none",
2435
+ "pie",
2436
+ "battery",
2437
+ "jar",
2438
+ "balloon",
2439
+ "thermometer"
2440
+ ]).default("none"),
2441
+ title: z.string().optional(),
2442
+ prompt: z.string().optional()
2443
+ }),
2444
+ Component: (a) => /* @__PURE__ */ jsx(FractionBarLab, { ...a })
2445
+ });
2446
+ const RatioShareBlock = labBlock({
2447
+ key: "ratio-share",
2448
+ label: "Share in a ratio",
2449
+ description: "Split a quantity in the ratio a:b by dragging one divider. Reads back the amounts and the simplified ratio; any equivalent split (40:60 = 2:3) solves it.",
2450
+ schema: z.object({
2451
+ a: z.number().default(2),
2452
+ b: z.number().default(3),
2453
+ total: z.number().default(100),
2454
+ unit: z.string().default(""),
2455
+ labelA: z.string().default("A"),
2456
+ labelB: z.string().default("B"),
2457
+ step: z.number().default(1),
2458
+ scene: z.enum([
2459
+ "none",
2460
+ "pie",
2461
+ "battery",
2462
+ "jar",
2463
+ "balloon",
2464
+ "thermometer"
2465
+ ]).default("none"),
2466
+ title: z.string().optional(),
2467
+ prompt: z.string().optional()
2468
+ }),
2469
+ Component: (a) => /* @__PURE__ */ jsx(RatioShareLab, { ...a })
2470
+ });
2471
+ const ComplexPlaneBlock = labBlock({
2472
+ key: "complex-plane",
2473
+ label: "Complex plane (Argand)",
2474
+ description: "Drag a + bi on the Argand plane: read the modulus and argument (deg & rad). Modes: point, multiply (Γ—i rotates 90Β°), power (De Moivre spiral), or roots (the nth-roots of unity 1, i, βˆ’1, βˆ’i, Ο‰).",
2475
+ schema: z.object({
2476
+ start: z.object({
2477
+ re: z.number(),
2478
+ im: z.number()
2479
+ }).optional(),
2480
+ mode: z.enum([
2481
+ "point",
2482
+ "multiply",
2483
+ "power",
2484
+ "roots"
2485
+ ]).default("point"),
2486
+ rootsN: z.number().default(4),
2487
+ powerN: z.number().default(3),
2488
+ snap: z.number().default(1),
2489
+ range: z.number().default(6),
2490
+ target: z.object({
2491
+ re: z.number(),
2492
+ im: z.number()
2493
+ }).optional(),
2494
+ title: z.string().optional(),
2495
+ prompt: z.string().optional()
2496
+ }),
2497
+ Component: (a) => /* @__PURE__ */ jsx(ComplexPlaneLab, { ...a })
2498
+ });
2499
+ const TrigSignsBlock = labBlock({
2500
+ key: "trig-signs",
2501
+ label: "Unit circle β€” signs (CAST)",
2502
+ description: "Drag the angle on the unit circle: the quadrant lights up with its CAST letter (which of sin/cos/tan are +), cos and sin draw green/red by sign, and special angles show their exact value (Β½, √3⁄2 …).",
2503
+ schema: z.object({
2504
+ startDeg: z.number().default(30),
2505
+ snapDeg: z.number().default(15),
2506
+ targetDeg: z.number().optional(),
2507
+ title: z.string().optional(),
2508
+ prompt: z.string().optional()
2509
+ }),
2510
+ Component: (a) => /* @__PURE__ */ jsx(TrigSignsLab, { ...a })
2511
+ });
2512
+ const PolynomialSolverBlock = labBlock({
2513
+ key: "polynomial-solver",
2514
+ label: "Polynomial solver (factor / solve, step by step)",
2515
+ description: "Type a polynomial in x; the engine factors it or solves =0 and shows the working (split the middle term; factor theorem for higher degree). Any-degree roots incl. complex, client-side.",
2516
+ schema: z.object({
2517
+ expr: z.string().default("x^2 + 5x + 6"),
2518
+ mode: z.enum(["factor", "solve"]).default("factor"),
2519
+ editable: z.boolean().default(true),
2520
+ title: z.string().optional(),
2521
+ prompt: z.string().optional()
2522
+ }),
2523
+ Component: (a) => /* @__PURE__ */ jsx(PolynomialSolverLab, { ...a })
2524
+ });
2525
+ const RateMachineBlock = labBlock({
2526
+ key: "rate-machine",
2527
+ label: "Proportion machine (drag the count, it scales)",
2528
+ description: "Count-driven concrete β†’ graph: drag the input up and down; objects drop into a vessel, the liquid level rises by the same rate each step, and a point rides up the line leaving a dot at every whole step. Proportionality you scrub. Skinnable (battery, jar, savings) and an optional \"set it to N\" goal.",
2529
+ schema: z.object({
2530
+ rate: z.number().default(5),
2531
+ base: z.number().default(0),
2532
+ maxCount: z.number().default(6),
2533
+ startCount: z.number().default(1),
2534
+ yMax: z.number().default(40),
2535
+ yStep: z.number().default(5),
2536
+ xLabel: z.string().default("Items"),
2537
+ yLabel: z.string().default("Cost"),
2538
+ unit: z.string().default("$"),
2539
+ itemLabel: z.string().optional(),
2540
+ scene: z.string().default("vessel"),
2541
+ showObjects: z.boolean().default(true),
2542
+ target: z.number().optional(),
2543
+ title: z.string().optional(),
2544
+ prompt: z.string().optional()
2545
+ }),
2546
+ Component: (a) => /* @__PURE__ */ jsx(RateMachineLab, { ...a })
2547
+ });
2548
+ const GeoTransformBlock = defineBlock({
2549
+ key: "geometry-transform",
2550
+ tag: "GeoTransform",
2551
+ void: true,
2552
+ label: "Transformations (translate / reflect / rotate / enlarge)",
2553
+ description: "Send a shape onto ghost targets by filling the transform from a tile tray; on a correct fill the shape flies to the targets. One lab, four transformation types.",
2554
+ category: "interactive",
2555
+ schema: z.object({
2556
+ kind: z.enum([
2557
+ "translate",
2558
+ "reflect",
2559
+ "rotate",
2560
+ "enlarge"
2561
+ ]).default("translate"),
2562
+ byX: z.number().default(5),
2563
+ byY: z.number().default(1),
2564
+ axis: z.enum([
2565
+ "x",
2566
+ "y",
2567
+ "y=x",
2568
+ "y=-x"
2569
+ ]).default("y"),
2570
+ deg: z.number().default(90),
2571
+ k: z.number().default(2),
2572
+ title: z.string().optional(),
2573
+ prompt: z.string().optional(),
2574
+ activity: z.string().optional()
2575
+ }),
2576
+ Component: ({ attributes, mode, updateAttributes }) => {
2577
+ const a = attributes;
2578
+ const kind = a.kind ?? "translate";
2579
+ const widget = /* @__PURE__ */ jsx(TransformLab, {
2580
+ transform: kind === "translate" ? {
2581
+ kind,
2582
+ by: {
2583
+ x: a.byX ?? 5,
2584
+ y: a.byY ?? 1
2585
+ }
2586
+ } : kind === "reflect" ? {
2587
+ kind,
2588
+ axis: a.axis ?? "y"
2589
+ } : kind === "rotate" ? {
2590
+ kind,
2591
+ deg: a.deg ?? 90,
2592
+ about: {
2593
+ x: 0,
2594
+ y: 0
2595
+ }
2596
+ } : {
2597
+ kind: "enlarge",
2598
+ k: a.k ?? 2,
2599
+ about: {
2600
+ x: 0,
2601
+ y: 0
2602
+ }
2603
+ },
2604
+ title: a.title,
2605
+ prompt: a.prompt,
2606
+ activity: attributes.activity
2607
+ });
2608
+ if (mode !== "editing" || !updateAttributes) return widget;
2609
+ const upd = updateAttributes;
2610
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2611
+ /* @__PURE__ */ jsx(ConfigRow, {
2612
+ label: "Title",
2613
+ children: /* @__PURE__ */ jsx(TextField, {
2614
+ value: a.title ?? "",
2615
+ placeholder: "Transformations",
2616
+ onChange: (v) => updateAttributes({ title: v }),
2617
+ className: "flex-1"
2618
+ })
2619
+ }),
2620
+ /* @__PURE__ */ jsx(ConfigRow, {
2621
+ label: "Type",
2622
+ children: /* @__PURE__ */ jsx(SelectField, {
2623
+ value: kind,
2624
+ options: [
2625
+ "translate",
2626
+ "reflect",
2627
+ "rotate",
2628
+ "enlarge"
2629
+ ],
2630
+ onChange: (v) => upd({ kind: v })
2631
+ })
2632
+ }),
2633
+ kind === "translate" && /* @__PURE__ */ jsxs(ConfigRow, {
2634
+ label: "by (",
2635
+ children: [
2636
+ /* @__PURE__ */ jsx(NumField, {
2637
+ value: a.byX ?? 5,
2638
+ onChange: (v) => updateAttributes({ byX: v })
2639
+ }),
2640
+ /* @__PURE__ */ jsx("span", {
2641
+ className: "text-muted-foreground",
2642
+ children: ","
2643
+ }),
2644
+ /* @__PURE__ */ jsx(NumField, {
2645
+ value: a.byY ?? 1,
2646
+ onChange: (v) => updateAttributes({ byY: v })
2647
+ }),
2648
+ /* @__PURE__ */ jsx("span", {
2649
+ className: "text-muted-foreground",
2650
+ children: ")"
2651
+ })
2652
+ ]
2653
+ }),
2654
+ kind === "reflect" && /* @__PURE__ */ jsx(ConfigRow, {
2655
+ label: "Mirror line",
2656
+ children: /* @__PURE__ */ jsx(SelectField, {
2657
+ value: a.axis ?? "y",
2658
+ options: [
2659
+ "x",
2660
+ "y",
2661
+ "y=x",
2662
+ "y=-x"
2663
+ ],
2664
+ onChange: (v) => upd({ axis: v })
2665
+ })
2666
+ }),
2667
+ kind === "rotate" && /* @__PURE__ */ jsx(ConfigRow, {
2668
+ label: "Angle (Β° anticlockwise)",
2669
+ children: /* @__PURE__ */ jsx(SelectField, {
2670
+ value: String(a.deg ?? 90),
2671
+ options: [
2672
+ "90",
2673
+ "180",
2674
+ "270"
2675
+ ],
2676
+ onChange: (v) => updateAttributes({ deg: Number(v) })
2677
+ })
2678
+ }),
2679
+ kind === "enlarge" && /* @__PURE__ */ jsx(ConfigRow, {
2680
+ label: "Scale factor",
2681
+ children: /* @__PURE__ */ jsx(SelectField, {
2682
+ value: String(a.k ?? 2),
2683
+ options: [
2684
+ "2",
2685
+ "3",
2686
+ "4"
2687
+ ],
2688
+ onChange: (v) => updateAttributes({ k: Number(v) })
2689
+ })
2690
+ })
2691
+ ] }), widget] });
2692
+ }
2693
+ });
2694
+ const receiptItemSchema = z.object({
2695
+ qty: z.number(),
2696
+ name: z.string(),
2697
+ unit: z.number()
2698
+ });
2699
+ const ReceiptBlock = defineBlock({
2700
+ key: "receipt-totals",
2701
+ tag: "ReceiptTotals",
2702
+ void: true,
2703
+ label: "Receipt totals (qty Γ— price)",
2704
+ description: "A shop receipt where the learner tap-fills the total items and total cost; classic \"summed the prices, forgot the quantity\" distractors. Multiplicative + additive reasoning grounded in a real bill.",
2705
+ category: "interactive",
2706
+ schema: z.object({
2707
+ store: z.string().default("Half Foods"),
2708
+ currency: z.string().default("$"),
2709
+ items: z.array(receiptItemSchema).optional(),
2710
+ askItems: z.boolean().default(true),
2711
+ askCost: z.boolean().default(true),
2712
+ title: z.string().optional(),
2713
+ prompt: z.string().optional(),
2714
+ activity: z.string().optional()
2715
+ }),
2716
+ Component: ({ attributes, mode, updateAttributes }) => {
2717
+ const a = attributes;
2718
+ const items = Array.isArray(a.items) && a.items.length ? a.items : void 0;
2719
+ const widget = /* @__PURE__ */ jsx(ReceiptLab, {
2720
+ store: a.store,
2721
+ currency: a.currency,
2722
+ items,
2723
+ ask: {
2724
+ items: a.askItems !== false,
2725
+ cost: a.askCost !== false
2726
+ },
2727
+ title: a.title,
2728
+ prompt: a.prompt,
2729
+ activity: attributes.activity
2730
+ });
2731
+ if (mode !== "editing" || !updateAttributes) return widget;
2732
+ const list = items ?? [{
2733
+ qty: 6,
2734
+ name: "Pineapples",
2735
+ unit: 5
2736
+ }, {
2737
+ qty: 3,
2738
+ name: "Mangoes",
2739
+ unit: 2
2740
+ }];
2741
+ const setItem = (i, patch) => updateAttributes({ items: list.map((it, j) => j === i ? {
2742
+ ...it,
2743
+ ...patch
2744
+ } : it) });
2745
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2746
+ /* @__PURE__ */ jsx(ConfigRow, {
2747
+ label: "Store",
2748
+ children: /* @__PURE__ */ jsx(TextField, {
2749
+ value: a.store ?? "Half Foods",
2750
+ onChange: (v) => updateAttributes({ store: v }),
2751
+ className: "flex-1"
2752
+ })
2753
+ }),
2754
+ /* @__PURE__ */ jsx(ConfigRow, {
2755
+ label: "Currency",
2756
+ children: /* @__PURE__ */ jsx(TextField, {
2757
+ value: a.currency ?? "$",
2758
+ onChange: (v) => updateAttributes({ currency: v }),
2759
+ className: "w-16"
2760
+ })
2761
+ }),
2762
+ /* @__PURE__ */ jsxs("div", {
2763
+ className: "space-y-1.5",
2764
+ children: [
2765
+ /* @__PURE__ */ jsx("span", {
2766
+ className: "font-medium text-muted-foreground",
2767
+ children: "Line items (qty Γ— name @ price)"
2768
+ }),
2769
+ list.map((it, i) => /* @__PURE__ */ jsxs("div", {
2770
+ className: "flex flex-wrap items-center gap-1.5",
2771
+ children: [
2772
+ /* @__PURE__ */ jsx(NumField, {
2773
+ value: it.qty,
2774
+ onChange: (v) => setItem(i, { qty: v })
2775
+ }),
2776
+ /* @__PURE__ */ jsx(TextField, {
2777
+ value: it.name,
2778
+ placeholder: "Pineapples",
2779
+ onChange: (v) => setItem(i, { name: v }),
2780
+ className: "w-32"
2781
+ }),
2782
+ /* @__PURE__ */ jsx("span", {
2783
+ className: "text-muted-foreground",
2784
+ children: "@"
2785
+ }),
2786
+ /* @__PURE__ */ jsx(NumField, {
2787
+ value: it.unit,
2788
+ onChange: (v) => setItem(i, { unit: v })
2789
+ }),
2790
+ list.length > 1 && /* @__PURE__ */ jsx(SmallButton, {
2791
+ tone: "danger",
2792
+ onClick: () => updateAttributes({ items: list.filter((_, j) => j !== i) }),
2793
+ children: "βœ•"
2794
+ })
2795
+ ]
2796
+ }, i)),
2797
+ /* @__PURE__ */ jsx(SmallButton, {
2798
+ onClick: () => updateAttributes({ items: [...list, {
2799
+ qty: 1,
2800
+ name: "",
2801
+ unit: 1
2802
+ }] }),
2803
+ children: "+ item"
2804
+ })
2805
+ ]
2806
+ }),
2807
+ /* @__PURE__ */ jsxs(ConfigRow, {
2808
+ label: "Ask for",
2809
+ children: [/* @__PURE__ */ jsx(ChipToggle, {
2810
+ active: a.askItems !== false,
2811
+ onClick: () => updateAttributes({ askItems: !(a.askItems !== false) }),
2812
+ children: "total items"
2813
+ }), /* @__PURE__ */ jsx(ChipToggle, {
2814
+ active: a.askCost !== false,
2815
+ onClick: () => updateAttributes({ askCost: !(a.askCost !== false) }),
2816
+ children: "total cost"
2817
+ })]
2818
+ })
2819
+ ] }), widget] });
2820
+ }
2821
+ });
2822
+ const SystemSolveBlock = defineBlock({
2823
+ key: "system-solve",
2824
+ tag: "SystemSolve",
2825
+ void: true,
2826
+ label: "System of equations (two clues, by elimination)",
2827
+ description: "Two unknowns, two clues, solved by elimination (not just the graph crossing). Swappable concrete scene: a shop receipt, a bucket balance, or algebra tiles. Creators theme the same maths any way.",
2828
+ category: "interactive",
2829
+ schema: z.object({
2830
+ scene: z.string().default("receipt"),
2831
+ symA: z.string().default("🍍"),
2832
+ labelA: z.string().default("Pineapple"),
2833
+ answerA: z.number().default(5),
2834
+ symB: z.string().default("πŸ₯­"),
2835
+ labelB: z.string().default("Mango"),
2836
+ answerB: z.number().default(2),
2837
+ a0: z.number().default(2),
2838
+ b0: z.number().default(1),
2839
+ a1: z.number().default(1),
2840
+ b1: z.number().default(1),
2841
+ currency: z.string().optional(),
2842
+ unit: z.string().optional(),
2843
+ store: z.string().optional(),
2844
+ title: z.string().optional(),
2845
+ prompt: z.string().optional(),
2846
+ activity: z.string().optional()
2847
+ }),
2848
+ Component: ({ attributes, mode, updateAttributes }) => {
2849
+ const a = attributes;
2850
+ const num = (k, d) => typeof a[k] === "number" ? a[k] : d;
2851
+ const str = (k, d) => typeof a[k] === "string" ? a[k] : d;
2852
+ const scene = str("scene", "receipt");
2853
+ const widget = /* @__PURE__ */ jsx(SystemSolveLab, {
2854
+ scene,
2855
+ unknowns: [{
2856
+ sym: str("symA", "🍍"),
2857
+ label: str("labelA", "Pineapple"),
2858
+ color: "var(--stage-warn)",
2859
+ answer: num("answerA", 5)
2860
+ }, {
2861
+ sym: str("symB", "πŸ₯­"),
2862
+ label: str("labelB", "Mango"),
2863
+ color: "var(--stage-good)",
2864
+ answer: num("answerB", 2)
2865
+ }],
2866
+ clues: [{ coeffs: [num("a0", 2), num("b0", 1)] }, { coeffs: [num("a1", 1), num("b1", 1)] }],
2867
+ currency: a.currency,
2868
+ unit: a.unit,
2869
+ store: a.store,
2870
+ title: a.title,
2871
+ prompt: a.prompt,
2872
+ activity: a.activity
2873
+ });
2874
+ if (mode !== "editing" || !updateAttributes) return widget;
2875
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(ConfigPanel, { children: [
2876
+ /* @__PURE__ */ jsx(ConfigRow, {
2877
+ label: "Title",
2878
+ children: /* @__PURE__ */ jsx(TextField, {
2879
+ value: str("title", ""),
2880
+ placeholder: "Two clues, two unknowns",
2881
+ onChange: (v) => updateAttributes({ title: v }),
2882
+ className: "flex-1"
2883
+ })
2884
+ }),
2885
+ /* @__PURE__ */ jsx(ConfigRow, {
2886
+ label: "Scene",
2887
+ children: /* @__PURE__ */ jsx(SelectField, {
2888
+ value: scene,
2889
+ options: clueSceneOptions(),
2890
+ onChange: (v) => updateAttributes({ scene: v })
2891
+ })
2892
+ }),
2893
+ /* @__PURE__ */ jsxs(ConfigRow, {
2894
+ label: "Item A",
2895
+ children: [
2896
+ /* @__PURE__ */ jsx(TextField, {
2897
+ value: str("symA", "🍍"),
2898
+ onChange: (v) => updateAttributes({ symA: v }),
2899
+ className: "w-16"
2900
+ }),
2901
+ /* @__PURE__ */ jsx(TextField, {
2902
+ value: str("labelA", "Pineapple"),
2903
+ onChange: (v) => updateAttributes({ labelA: v }),
2904
+ className: "w-28"
2905
+ }),
2906
+ /* @__PURE__ */ jsx("span", {
2907
+ className: "text-muted-foreground",
2908
+ children: "="
2909
+ }),
2910
+ /* @__PURE__ */ jsx(NumField, {
2911
+ value: num("answerA", 5),
2912
+ onChange: (v) => updateAttributes({ answerA: v })
2913
+ })
2914
+ ]
2915
+ }),
2916
+ /* @__PURE__ */ jsxs(ConfigRow, {
2917
+ label: "Item B",
2918
+ children: [
2919
+ /* @__PURE__ */ jsx(TextField, {
2920
+ value: str("symB", "πŸ₯­"),
2921
+ onChange: (v) => updateAttributes({ symB: v }),
2922
+ className: "w-16"
2923
+ }),
2924
+ /* @__PURE__ */ jsx(TextField, {
2925
+ value: str("labelB", "Mango"),
2926
+ onChange: (v) => updateAttributes({ labelB: v }),
2927
+ className: "w-28"
2928
+ }),
2929
+ /* @__PURE__ */ jsx("span", {
2930
+ className: "text-muted-foreground",
2931
+ children: "="
2932
+ }),
2933
+ /* @__PURE__ */ jsx(NumField, {
2934
+ value: num("answerB", 2),
2935
+ onChange: (v) => updateAttributes({ answerB: v })
2936
+ })
2937
+ ]
2938
+ }),
2939
+ /* @__PURE__ */ jsxs(ConfigRow, {
2940
+ label: "Clue 1",
2941
+ children: [
2942
+ /* @__PURE__ */ jsx(NumField, {
2943
+ value: num("a0", 2),
2944
+ onChange: (v) => updateAttributes({ a0: v })
2945
+ }),
2946
+ /* @__PURE__ */ jsx("span", {
2947
+ className: "text-muted-foreground",
2948
+ children: "A +"
2949
+ }),
2950
+ /* @__PURE__ */ jsx(NumField, {
2951
+ value: num("b0", 1),
2952
+ onChange: (v) => updateAttributes({ b0: v })
2953
+ }),
2954
+ /* @__PURE__ */ jsx("span", {
2955
+ className: "text-muted-foreground",
2956
+ children: "B"
2957
+ })
2958
+ ]
2959
+ }),
2960
+ /* @__PURE__ */ jsxs(ConfigRow, {
2961
+ label: "Clue 2",
2962
+ children: [
2963
+ /* @__PURE__ */ jsx(NumField, {
2964
+ value: num("a1", 1),
2965
+ onChange: (v) => updateAttributes({ a1: v })
2966
+ }),
2967
+ /* @__PURE__ */ jsx("span", {
2968
+ className: "text-muted-foreground",
2969
+ children: "A +"
2970
+ }),
2971
+ /* @__PURE__ */ jsx(NumField, {
2972
+ value: num("b1", 1),
2973
+ onChange: (v) => updateAttributes({ b1: v })
2974
+ }),
2975
+ /* @__PURE__ */ jsx("span", {
2976
+ className: "text-muted-foreground",
2977
+ children: "B"
2978
+ })
2979
+ ]
2980
+ })
2981
+ ] }), widget] });
2982
+ }
2983
+ });
2984
+ function customSceneSpec(a) {
2985
+ const name = typeof a.name === "string" && a.name.trim() || "custom";
2986
+ const label = typeof a.label === "string" && a.label.trim() ? a.label : void 0;
2987
+ const v = a.variant;
2988
+ if (v === "icons") return {
2989
+ name,
2990
+ label,
2991
+ kind: "level",
2992
+ icon: a.icon || "⭐",
2993
+ slots: Number(a.slots) || 5
2994
+ };
2995
+ if (v === "shape") return {
2996
+ name,
2997
+ label,
2998
+ kind: "level",
2999
+ shape: a.shape || "box",
3000
+ color: a.color || "#7c83ff"
3001
+ };
3002
+ return {
3003
+ name,
3004
+ label,
3005
+ kind: "count",
3006
+ icon: a.icon || "πŸ”΅"
3007
+ };
3008
+ }
3009
+ function customSceneAttrs(s) {
3010
+ if (s.kind === "count") return {
3011
+ name: s.name,
3012
+ label: s.label ?? "",
3013
+ variant: "count",
3014
+ icon: s.icon
3015
+ };
3016
+ if ("icon" in s) return {
3017
+ name: s.name,
3018
+ label: s.label ?? "",
3019
+ variant: "icons",
3020
+ icon: s.icon,
3021
+ slots: s.slots ?? 5
3022
+ };
3023
+ return {
3024
+ name: s.name,
3025
+ label: s.label ?? "",
3026
+ variant: "shape",
3027
+ shape: s.shape,
3028
+ color: s.color ?? "#7c83ff"
3029
+ };
3030
+ }
3031
+ const CustomSceneBlock = defineBlock({
3032
+ key: "custom-scene",
3033
+ tag: "CustomScene",
3034
+ void: true,
3035
+ label: "Custom scene (no-code lab skin)",
3036
+ description: "Invent a new lab skin from a form (an emoji or a shape) β€” no code. Place it ABOVE a lab and pick the new scene by name in that lab.",
3037
+ category: "interactive",
3038
+ schema: z.object({
3039
+ name: z.string().default("custom"),
3040
+ label: z.string().optional(),
3041
+ variant: z.enum([
3042
+ "count",
3043
+ "icons",
3044
+ "shape"
3045
+ ]).default("count"),
3046
+ icon: z.string().default("πŸ”΅"),
3047
+ slots: z.number().default(5),
3048
+ shape: z.enum([
3049
+ "box",
3050
+ "cup",
3051
+ "circle"
3052
+ ]).default("box"),
3053
+ color: z.string().default("#7c83ff")
3054
+ }),
3055
+ Component: ({ attributes, mode, updateAttributes }) => {
3056
+ const spec = customSceneSpec(attributes);
3057
+ registerDataScene(spec);
3058
+ if (mode !== "editing" || !updateAttributes) return /* @__PURE__ */ jsxs("div", {
3059
+ className: "not-prose",
3060
+ style: {
3061
+ padding: "8px 12px",
3062
+ borderRadius: 8,
3063
+ fontSize: 13,
3064
+ color: "var(--stage-good)",
3065
+ border: "1px solid var(--stage-good)"
3066
+ },
3067
+ children: [
3068
+ "βœ“ Scene β€œ",
3069
+ spec.name,
3070
+ "” is ready β€” choose it in a lab’s scene list below."
3071
+ ]
3072
+ });
3073
+ return /* @__PURE__ */ jsxs("div", {
3074
+ style: {
3075
+ display: "grid",
3076
+ gap: 8
3077
+ },
3078
+ children: [/* @__PURE__ */ jsx(SceneStudio, {
3079
+ spec,
3080
+ onChange: (s) => updateAttributes(customSceneAttrs(s))
3081
+ }), /* @__PURE__ */ jsxs("p", {
3082
+ style: {
3083
+ fontSize: 12,
3084
+ color: "var(--stage-muted)",
3085
+ margin: 0
3086
+ },
3087
+ children: [
3088
+ "Tip: put this above a lab, then pick β€œ",
3089
+ spec.name,
3090
+ "” in that lab’s scene dropdown."
3091
+ ]
3092
+ })]
3093
+ });
3094
+ }
3095
+ });
3096
+ /** All math labs blocks, spread into a host's `defineBlock` list. */
1496
3097
  const mathBlocks = [
1497
3098
  TrigExplorerBlock,
1498
3099
  GraphBlock,
3100
+ PercentBarBlock,
3101
+ FractionBarBlock,
3102
+ RatioShareBlock,
3103
+ ComplexPlaneBlock,
3104
+ TrigSignsBlock,
3105
+ PolynomialSolverBlock,
1499
3106
  DerivativeExplorerBlock,
1500
3107
  GradientDescentBlock,
1501
3108
  IntegralExplorerBlock,
@@ -1509,7 +3116,18 @@ const mathBlocks = [
1509
3116
  AreaModelBlock,
1510
3117
  GrowingPatternBlock,
1511
3118
  InteractiveProblemBlock,
1512
- TriangleTrigBlock
3119
+ TriangleTrigBlock,
3120
+ StraightLineBlock,
3121
+ CircleBlock,
3122
+ ConicBlock,
3123
+ DomainRangeBlock,
3124
+ LinearModelBlock,
3125
+ RateMachineBlock,
3126
+ SequencePredictBlock,
3127
+ GeoTransformBlock,
3128
+ ReceiptBlock,
3129
+ SystemSolveBlock,
3130
+ CustomSceneBlock
1513
3131
  ];
1514
3132
  /** The MDX tag β†’ component render map slice for the math domain. */
1515
3133
  const mathComponents = {
@@ -1529,8 +3147,24 @@ const mathComponents = {
1529
3147
  Derivation,
1530
3148
  TrigExplorer,
1531
3149
  InteractiveProblem,
1532
- TriangleTrig
3150
+ TriangleTrig,
3151
+ StraightLine: StraightLineLab,
3152
+ CircleLab,
3153
+ ConicLab,
3154
+ DomainRange: DomainRangeLab,
3155
+ LinearModel: LinearModelLab,
3156
+ RateMachine: RateMachineLab,
3157
+ SequencePredict,
3158
+ PercentBar: PercentBarLab,
3159
+ FractionBar: FractionBarLab,
3160
+ RatioShare: RatioShareLab,
3161
+ ComplexPlane: ComplexPlaneLab,
3162
+ TrigSigns: TrigSignsLab,
3163
+ PolynomialSolver: PolynomialSolverLab,
3164
+ GeoTransform: TransformLab,
3165
+ ReceiptTotals: ReceiptLab,
3166
+ SystemSolve: SystemSolveLab
1533
3167
  };
1534
3168
 
1535
3169
  //#endregion
1536
- export { AreaModelBlock, BalanceAlgebraBlock, DerivationBlock, DerivativeExplorerBlock, GradientDescentBlock, GraphBlock, GrowingPatternBlock, IntegralExplorerBlock, InteractiveProblemBlock, LimitExplorerBlock, LinearSystemBlock, LinearSystemView, MysteryBucketBlock, NumberLineBlock, TriangleTrigBlock, TrigExplorerBlock, VertexParabolaBlock, mathBlocks, mathComponents };
3170
+ export { AreaModelBlock, BalanceAlgebraBlock, CircleBlock, ComplexPlaneBlock, ConicBlock, CustomSceneBlock, DerivationBlock, DerivativeExplorerBlock, DomainRangeBlock, FractionBarBlock, GeoTransformBlock, GradientDescentBlock, GraphBlock, GrowingPatternBlock, IntegralExplorerBlock, InteractiveProblemBlock, LimitExplorerBlock, LinearModelBlock, LinearSystemBlock, LinearSystemView, MysteryBucketBlock, NumberLineBlock, PercentBarBlock, PolynomialSolverBlock, RateMachineBlock, RatioShareBlock, ReceiptBlock, SequencePredictBlock, StraightLineBlock, SystemSolveBlock, TriangleTrigBlock, TrigExplorerBlock, TrigSignsBlock, VertexParabolaBlock, mathBlocks, mathComponents };