@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
@@ -8,10 +8,10 @@ import { useInView } from "@classytic/stage";
8
8
  //#region src/ict/number-systems/wheel.tsx
9
9
  /**
10
10
  * Shared building blocks for the number-system labs: base digit helpers + the
11
- * DigitWheel glyph (a mechanical odometer wheel). Tokenized SVG only — colours
11
+ * DigitWheel glyph (a mechanical odometer wheel). Tokenized SVG only, colours
12
12
  * are `--stage-*` so the wheels retheme with the host. The roll is DATA: the lab
13
13
  * passes a 0..1 `roll` phase its frame loop decays, so the digit visibly slides
14
- * into place (no fake "press play" — the motion tracks the real value change).
14
+ * into place (no fake "press play", the motion tracks the real value change).
15
15
  */
16
16
  /** Seconds for a wheel to settle after a digit changes. */
17
17
  const ROLL_DUR = .32;
@@ -133,7 +133,7 @@ function DigitWheel({ base, digit, roll = 0, dir = 1, active, onTap, ariaLabel }
133
133
  ]
134
134
  });
135
135
  }
136
- /** A binary ON/OFF cell — the "lightbulb worth 2^n" picture for base-2 mode. */
136
+ /** A binary ON/OFF cell, the "lightbulb worth 2^n" picture for base-2 mode. */
137
137
  function BitCell({ on, onTap, ariaLabel }) {
138
138
  return /* @__PURE__ */ jsxs("svg", {
139
139
  width: CELL_W,
@@ -183,7 +183,7 @@ function BitCell({ on, onTap, ariaLabel }) {
183
183
  }
184
184
  /**
185
185
  * A row of odometer wheels (or bit cells) for `value` in `base`, with the
186
- * carry-ripple roll animation OWNED here — the single reusable place-value
186
+ * carry-ripple roll animation OWNED here, the single reusable place-value
187
187
  * primitive both PlaceValueDial and BaseOdometer compose, so the animation +
188
188
  * weight rendering live in exactly one spot.
189
189
  */
@@ -14,7 +14,7 @@ const charW = 6.4;
14
14
  /** A labelled pointer to (x,y): a dot, a leader line, and a tinted bubble offset by
15
15
  * (dx,dy). Keep dx/dy pointing into open space so the bubble clears the figure.
16
16
  * (Named `Pointer`, not Callout, to avoid clashing with frame.js's prose-box Callout
17
- * and cms-ui's document-level Callout block — this one anchors to FIGURE geometry.) */
17
+ * and cms-ui's document-level Callout block, this one anchors to FIGURE geometry.) */
18
18
  function Pointer({ x, y, text, dx = 30, dy = -26, tone = "info", fontSize = 11 }) {
19
19
  const col = TONE[tone];
20
20
  const w = text.length * (charW * (fontSize / 11)) + 14, h = fontSize + 9;
@@ -59,7 +59,7 @@ function Pointer({ x, y, text, dx = 30, dy = -26, tone = "info", fontSize = 11 }
59
59
  ]
60
60
  });
61
61
  }
62
- /** A pulsing attention ring at (cx,cy) — draws the eye to "look here". */
62
+ /** A pulsing attention ring at (cx,cy), draws the eye to "look here". */
63
63
  function Spotlight({ cx, cy, r = 13, tone = "warn" }) {
64
64
  const col = TONE[tone];
65
65
  return /* @__PURE__ */ jsxs("g", {
@@ -87,7 +87,7 @@ function Spotlight({ cx, cy, r = 13, tone = "warn" }) {
87
87
  })]
88
88
  });
89
89
  }
90
- /** A span bracket from x1→x2 at height y with a centred label — "this range means …".
90
+ /** A span bracket from x1→x2 at height y with a centred label, "this range means …".
91
91
  * `side: 'below'` drops the ticks/label under y; 'above' lifts them over it. */
92
92
  function Bracket({ x1, x2, y, text, tone = "info", side = "below", fontSize = 11 }) {
93
93
  const col = TONE[tone];
@@ -1,10 +1,10 @@
1
1
  //#region src/kit/answer-check.d.ts
2
2
  /**
3
- * answer-check — the "is the student right?" layer of the interactive-problem
3
+ * answer-check, the "is the student right?" layer of the interactive-problem
4
4
  * engine. Pure, built on @classytic/stage's expr engine. Two real modes (the ones
5
5
  * exams need): a NUMBER (value within tolerance, parsed so `pi/2` or `2*sqrt(5)`
6
6
  * count) and an EXPRESSION (any algebraically-EQUIVALENT form accepted, checked
7
- * BOTH symbolically — simplify(student − answer) → 0 — AND numerically by sampling,
7
+ * BOTH symbolically, simplify(student − answer) → 0, AND numerically by sampling,
8
8
  * so `(x+1)(x+2)` ≡ `x^2+3x+2`). No hand-marking, no "exact-string" brittleness.
9
9
  */
10
10
  /** Evaluate a numeric answer string (`3.14`, `pi/2`, `2*sqrt(5)`) → number (NaN if invalid). */
@@ -2,11 +2,11 @@ import { compileExpr, parseExpr, simplify } from "@classytic/stage";
2
2
 
3
3
  //#region src/kit/answer-check.ts
4
4
  /**
5
- * answer-check — the "is the student right?" layer of the interactive-problem
5
+ * answer-check, the "is the student right?" layer of the interactive-problem
6
6
  * engine. Pure, built on @classytic/stage's expr engine. Two real modes (the ones
7
7
  * exams need): a NUMBER (value within tolerance, parsed so `pi/2` or `2*sqrt(5)`
8
8
  * count) and an EXPRESSION (any algebraically-EQUIVALENT form accepted, checked
9
- * BOTH symbolically — simplify(student − answer) → 0 — AND numerically by sampling,
9
+ * BOTH symbolically, simplify(student − answer) → 0, AND numerically by sampling,
10
10
  * so `(x+1)(x+2)` ≡ `x^2+3x+2`). No hand-marking, no "exact-string" brittleness.
11
11
  */
12
12
  /** Compile, returning the usable form or null (never the error union). */
@@ -17,9 +17,37 @@ function tryCompile(src) {
17
17
  }
18
18
  /** Evaluate a numeric answer string (`3.14`, `pi/2`, `2*sqrt(5)`) → number (NaN if invalid). */
19
19
  function parseValue(raw) {
20
- const c = tryCompile(raw);
20
+ const c = tryCompile(normalizeMathInput(raw));
21
21
  return c ? c.fn({}) : NaN;
22
22
  }
23
+ /**
24
+ * Make exam-natural input parse: accept implicit multiplication (`2x` → `2*x`,
25
+ * `)(` → `)*(`) and a leading `y =` (`y = 2x − 3` → `2*x - 3`). Conservative ,
26
+ * never inserts `*` before `(` after a letter, so function calls like `sin(x)`
27
+ * survive. Unicode minus → ascii.
28
+ */
29
+ const SUPERSCRIPT = {
30
+ "⁰": "0",
31
+ "¹": "1",
32
+ "²": "2",
33
+ "³": "3",
34
+ "⁴": "4",
35
+ "⁵": "5",
36
+ "⁶": "6",
37
+ "⁷": "7",
38
+ "⁸": "8",
39
+ "⁹": "9"
40
+ };
41
+ function normalizeMathInput(raw) {
42
+ let s = raw.trim().replace(/−/g, "-").replace(/×/g, "*").replace(/÷/g, "/");
43
+ s = s.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹]+/g, (m) => "^" + [...m].map((ch) => SUPERSCRIPT[ch]).join(""));
44
+ s = s.replace(/\*\*/g, "^");
45
+ s = s.replace(/\s+/g, "");
46
+ s = s.replace(/^y=/i, "");
47
+ s = s.replace(/(\d)([a-zA-Z(])/g, "$1*$2");
48
+ s = s.replace(/\)([a-zA-Z0-9(])/g, ")*$1");
49
+ return s;
50
+ }
23
51
  /** Numeric match with a relative-ish tolerance (default ~1% of scale). */
24
52
  function checkNumber(student, value, tol = .01) {
25
53
  if (!Number.isFinite(student) || !Number.isFinite(value)) return false;
@@ -28,11 +56,11 @@ function checkNumber(student, value, tol = .01) {
28
56
  const isZeroNode = (n, eps = 1e-9) => n.type === "num" && Math.abs(n.value) < eps;
29
57
  /** True if `student` is algebraically equivalent to `answer` (symbolic OR numeric). */
30
58
  function checkExpression(student, answer, opts = {}) {
31
- const a = tryCompile(student);
32
- const b = tryCompile(answer);
59
+ const a = tryCompile(normalizeMathInput(student));
60
+ const b = tryCompile(normalizeMathInput(answer));
33
61
  if (!a || !b) return false;
34
62
  try {
35
- if (isZeroNode(simplify(parseExpr(`(${student}) - (${answer})`)), opts.tol ?? 1e-9)) return true;
63
+ if (isZeroNode(simplify(parseExpr(`(${normalizeMathInput(student)}) - (${normalizeMathInput(answer)})`)), opts.tol ?? 1e-9)) return true;
36
64
  } catch {}
37
65
  const vars = opts.vars ?? [...new Set([...a.vars, ...b.vars])];
38
66
  const [lo, hi] = opts.domain ?? [-3.3, 3.7];
@@ -0,0 +1,19 @@
1
+ import { ChallengeChoice } from "./pedagogy.mjs";
2
+ import { AnswerSpec } from "./answer-check.mjs";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/kit/ask.d.ts
6
+ /** A serializable question spec an author attaches to a lab. */
7
+ interface LabAskSpec {
8
+ prompt: ReactNode;
9
+ placeholder?: string;
10
+ /** Typed mode: grade the typed answer (a number, or an algebraic expression). */
11
+ answer?: AnswerSpec;
12
+ /** Multiple-choice mode: the options (set `correct` to one option's value). */
13
+ choices?: ChallengeChoice[];
14
+ correct?: string;
15
+ /** Shown when the right choice is picked. */
16
+ explain?: ReactNode;
17
+ }
18
+ //#endregion
19
+ export { LabAskSpec };
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+
3
+ import { AskBox, ChallengeCard, useChallenge, useCheckpoint } from "./pedagogy.mjs";
4
+ import { checkAnswer } from "./answer-check.mjs";
5
+ import { jsx } from "react/jsx-runtime";
6
+
7
+ //#region src/kit/ask.tsx
8
+ function McqAsk({ prompt, choices, answer, explain, activity }) {
9
+ const qs = [{
10
+ id: "q",
11
+ prompt,
12
+ choices,
13
+ answer,
14
+ explain
15
+ }];
16
+ const state = useChallenge(qs);
17
+ useCheckpoint({
18
+ solved: state.allCorrect,
19
+ activity
20
+ });
21
+ return /* @__PURE__ */ jsx(ChallengeCard, {
22
+ questions: qs,
23
+ state,
24
+ title: ""
25
+ });
26
+ }
27
+ /** Render a lab's question, MCQ when `choices` is given, otherwise a typed box. */
28
+ function LabAsk({ ask, activity }) {
29
+ if (ask.choices && ask.choices.length) return /* @__PURE__ */ jsx(McqAsk, {
30
+ prompt: ask.prompt,
31
+ choices: ask.choices,
32
+ answer: ask.correct ?? "",
33
+ explain: ask.explain,
34
+ activity
35
+ });
36
+ if (ask.answer) return /* @__PURE__ */ jsx(AskBox, {
37
+ prompt: ask.prompt,
38
+ placeholder: ask.placeholder,
39
+ check: (r) => checkAnswer(ask.answer, r),
40
+ activity
41
+ });
42
+ return null;
43
+ }
44
+
45
+ //#endregion
46
+ export { LabAsk };
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Segment } from "@classytic/stage";
5
+
6
+ //#region src/kit/bar-strip.tsx
7
+ function BarStrip({ span, cells, shaded, y, color, weight = 32, trackColor = "var(--stage-grid)" }) {
8
+ const cw = span / cells;
9
+ const lines = [];
10
+ for (let i = 1; i < cells; i++) lines.push(/* @__PURE__ */ jsx(Segment, {
11
+ from: {
12
+ x: i * cw,
13
+ y: y - .5
14
+ },
15
+ to: {
16
+ x: i * cw,
17
+ y: y + .5
18
+ },
19
+ color: "var(--stage-bg)",
20
+ weight: 2
21
+ }, i));
22
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
23
+ /* @__PURE__ */ jsx(Segment, {
24
+ from: {
25
+ x: 0,
26
+ y
27
+ },
28
+ to: {
29
+ x: span,
30
+ y
31
+ },
32
+ color: trackColor,
33
+ weight,
34
+ opacity: .55
35
+ }),
36
+ shaded > 0 && /* @__PURE__ */ jsx(Segment, {
37
+ from: {
38
+ x: 0,
39
+ y
40
+ },
41
+ to: {
42
+ x: shaded * cw,
43
+ y
44
+ },
45
+ color,
46
+ weight
47
+ }),
48
+ lines
49
+ ] });
50
+ }
51
+
52
+ //#endregion
53
+ export { BarStrip };
@@ -0,0 +1,33 @@
1
+ //#region src/kit/calc.d.ts
2
+ /**
3
+ * Worked-calculation core. A lab that just prints an answer teaches nothing; this
4
+ * makes a calculation SHOW ITS WORKING — every substitution and simplification as
5
+ * a rendered line — so an author can demonstrate HOW a rule computes, not just
6
+ * what it returns. Pure + dependency-free: the engine produces data (a value plus
7
+ * a list of LaTeX steps); a component renders it.
8
+ *
9
+ * Pair with kit/rule's <RuleCard> (formula + analogy + this calculation +
10
+ * derivation + tricks) to turn a bare formula into a smart, authorable concept.
11
+ */
12
+ /** One line of a worked calculation: a LaTeX expression + an optional plain note. */
13
+ interface CalcStep {
14
+ tex: string;
15
+ /** Why this step follows ("substitute n = 5", "the falling product"). */
16
+ note?: string;
17
+ }
18
+ /** The result of a worked calculation: the final value + the steps that got there. */
19
+ interface Worked {
20
+ value: number;
21
+ steps: CalcStep[];
22
+ }
23
+ /** A tiny fluent builder: calc().step('…','…').step('…').done(value). */
24
+ declare class Calc {
25
+ private readonly _steps;
26
+ step(tex: string, note?: string): this;
27
+ done(value: number): Worked;
28
+ }
29
+ declare const calc: () => Calc;
30
+ /** Format a number for inline LaTeX (thin-space thousands so big counts read). */
31
+ declare function texNum(n: number): string;
32
+ //#endregion
33
+ export { Calc, CalcStep, Worked, calc, texNum };
@@ -0,0 +1,27 @@
1
+ //#region src/kit/calc.ts
2
+ /** A tiny fluent builder: calc().step('…','…').step('…').done(value). */
3
+ var Calc = class {
4
+ _steps = [];
5
+ step(tex, note) {
6
+ this._steps.push(note === void 0 ? { tex } : {
7
+ tex,
8
+ note
9
+ });
10
+ return this;
11
+ }
12
+ done(value) {
13
+ return {
14
+ value,
15
+ steps: this._steps
16
+ };
17
+ }
18
+ };
19
+ const calc = () => new Calc();
20
+ /** Format a number for inline LaTeX (thin-space thousands so big counts read). */
21
+ function texNum(n) {
22
+ if (!Number.isFinite(n)) return "\\text{?}";
23
+ return Math.abs(n) >= 1e4 ? n.toLocaleString("en-US").replace(/,/g, "{,}") : String(n);
24
+ }
25
+
26
+ //#endregion
27
+ export { Calc, calc, texNum };
@@ -0,0 +1,147 @@
1
+ 'use client';
2
+
3
+ import { useReducedMotion } from "./anim.mjs";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { useFrameLoop } from "@classytic/stage";
6
+
7
+ //#region src/kit/carrier-engine.ts
8
+ /**
9
+ * Carrier engine, a small DETERMINISTIC charged-particle core shared by every
10
+ * semiconductor / conduction lab. Carriers (electrons e⁻, holes h⁺) are real
11
+ * entities with a position and a confinement box; each tick they drift under a
12
+ * field (electrons and holes move opposite ways), jitter thermally, and reflect
13
+ * off their region walls so nothing ever floats out of the device. Pairs that
14
+ * meet recombine. Everything is seeded by an integer PRNG advanced by a global
15
+ * step counter, so the simulation is bit-identical on the server and client
16
+ * (no hydration drift) and fully replayable.
17
+ *
18
+ * The engine owns the PHYSICS OF MOTION. Each lab owns the SETUP, where the
19
+ * regions are, which way the field points, how carriers are born and die.
20
+ */
21
+ /** integer-only PRNG (no Math.sin/Math.random) → identical on server + client. */
22
+ const rand = (a, b) => {
23
+ let x = (Math.imul(a + 1, 73856093) ^ Math.imul(b + 1, 19349663)) >>> 0;
24
+ x ^= x >>> 13;
25
+ x = Math.imul(x, 1274126177) >>> 0;
26
+ x ^= x >>> 16;
27
+ return x % 1e5 / 1e5;
28
+ };
29
+ /** A deterministic, EVENLY-spread point inside a box from a seed. Uses the R2 low-
30
+ * discrepancy sequence (plastic constant) so consecutive seeds (0,1,2,…) scatter across
31
+ * the whole box instead of clumping — a plain hash clusters consecutive seeds. */
32
+ const inBox = (b, seed, pad = 8) => {
33
+ const fx = (.5 + .7548776662466927 * seed) % 1;
34
+ const fy = (.5 + .5698402909980532 * seed) % 1;
35
+ return {
36
+ x: b.x + pad + fx * Math.max(1, b.w - 2 * pad),
37
+ y: b.y + pad + fy * Math.max(1, b.h - 2 * pad)
38
+ };
39
+ };
40
+ /**
41
+ * Advance carriers one tick with MOMENTUM: velocity persists and relaxes toward the drift
42
+ * target while taking small random thermal kicks, then position integrates from velocity.
43
+ * The persistent velocity is what makes carriers glide and wander smoothly instead of
44
+ * vibrating in place. Walls bounce (velocity flips); everything stays inside its box. Pure.
45
+ */
46
+ function stepCarriers(cs, step, bounds, f) {
47
+ const sp = f.speed ?? 1, jit = f.jitter ?? 0;
48
+ const dx = f.drift?.x ?? 0, dy = f.drift?.y ?? 0;
49
+ const signed = f.signed ?? true;
50
+ const damp = f.damp ?? .86;
51
+ const spring = f.spring ?? 0;
52
+ return cs.map((c) => {
53
+ if (c.fixed) return c;
54
+ const dir = !signed ? 1 : c.t === "e" ? 1 : -1;
55
+ let vx = (c.vx ?? 0) * damp + (1 - damp) * dx * dir + (rand(c.id, step) - .5) * jit;
56
+ let vy = (c.vy ?? 0) * damp + (1 - damp) * dy * dir + (rand(c.id, step * 2 + 7) - .5) * jit;
57
+ if (spring && c.hx !== void 0) vx += (c.hx - c.x) * spring;
58
+ if (spring && c.hy !== void 0) vy += (c.hy - c.y) * spring;
59
+ let x = c.x + vx * sp, y = c.y + vy * sp;
60
+ const b = c.box ?? bounds;
61
+ if (x < b.x) {
62
+ x = 2 * b.x - x;
63
+ vx = Math.abs(vx);
64
+ } else if (x > b.x + b.w) {
65
+ x = 2 * (b.x + b.w) - x;
66
+ vx = -Math.abs(vx);
67
+ }
68
+ if (y < b.y) {
69
+ y = 2 * b.y - y;
70
+ vy = Math.abs(vy);
71
+ } else if (y > b.y + b.h) {
72
+ y = 2 * (b.y + b.h) - y;
73
+ vy = -Math.abs(vy);
74
+ }
75
+ x = Math.max(b.x, Math.min(b.x + b.w, x));
76
+ y = Math.max(b.y, Math.min(b.y + b.h, y));
77
+ return {
78
+ ...c,
79
+ x,
80
+ y,
81
+ vx,
82
+ vy
83
+ };
84
+ });
85
+ }
86
+ /** Tween every carrier's opacity toward active(1)/inactive(0) so the visible population
87
+ * changes by FADING, not by rebuilding the pool. A carrier is active when it has no slot
88
+ * or its slot < `target`. Call inside advance after stepCarriers. */
89
+ function tweenOpacity(cs, target, rate = .1) {
90
+ return cs.map((c) => {
91
+ const want = c.slot === void 0 || c.slot < target ? 1 : 0;
92
+ return {
93
+ ...c,
94
+ o: (c.o ?? want) + (want - (c.o ?? want)) * rate
95
+ };
96
+ });
97
+ }
98
+ /** Recombine free e⁻/h⁺ pairs within `r` px. With `respawn`, each partner is reborn at a
99
+ * fresh site (steady population, e.g. thermal generation⇄recombination); without it the
100
+ * pair is removed. */
101
+ function recombine(cs, r, step, respawn) {
102
+ if (!r) return cs;
103
+ const r2 = r * r;
104
+ const hit = /* @__PURE__ */ new Set();
105
+ const es = cs.filter((c) => c.t === "e" && !c.fixed);
106
+ const hs = cs.filter((c) => c.t === "h" && !c.fixed);
107
+ for (const e of es) for (const h of hs) {
108
+ if (hit.has(e.id) || hit.has(h.id)) continue;
109
+ if ((e.x - h.x) ** 2 + (e.y - h.y) ** 2 < r2) {
110
+ hit.add(e.id);
111
+ hit.add(h.id);
112
+ }
113
+ }
114
+ if (!hit.size) return cs;
115
+ if (!respawn) return cs.filter((c) => !hit.has(c.id));
116
+ return cs.map((c) => hit.has(c.id) ? {
117
+ ...c,
118
+ ...respawn(c, step)
119
+ } : c);
120
+ }
121
+ /**
122
+ * Drive a carrier simulation: holds the pool, advances it each frame via `advance`, and
123
+ * RESETS to a fresh `init()` whenever `resetKey` changes (mode / dopant / topology). The
124
+ * server and first client render both show step 0 of `init()` (deterministic) → no
125
+ * hydration mismatch.
126
+ */
127
+ function useCarrierSim(init, advance, running, resetKey) {
128
+ const reduce = useReducedMotion();
129
+ const [cs, setCs] = useState(init);
130
+ const stepRef = useRef(0);
131
+ const initRef = useRef(init);
132
+ const advanceRef = useRef(advance);
133
+ initRef.current = init;
134
+ advanceRef.current = advance;
135
+ useEffect(() => {
136
+ stepRef.current = 0;
137
+ setCs(initRef.current());
138
+ }, [resetKey]);
139
+ useFrameLoop(() => {
140
+ stepRef.current += 1;
141
+ setCs((prev) => advanceRef.current(prev, stepRef.current));
142
+ }, { running: running && !reduce });
143
+ return cs;
144
+ }
145
+
146
+ //#endregion
147
+ export { inBox, rand, recombine, stepCarriers, tweenOpacity, useCarrierSim };
@@ -0,0 +1,86 @@
1
+ import { ReactNode } from "react";
2
+
3
+ //#region src/kit/clue-scene.d.ts
4
+ interface Unknown {
5
+ /** symbol shown on chips (an emoji like 🍍 or a letter like x). */
6
+ sym: string;
7
+ label?: string;
8
+ /** token colour for chips / buckets (default accent). */
9
+ color?: string;
10
+ /** the hidden value the learner solves for. */
11
+ answer: number;
12
+ }
13
+ interface Clue {
14
+ /** coefficient per unknown, aligned to the unknowns array (e.g. [2,1] → 2▲ + 1●). */
15
+ coeffs: number[];
16
+ }
17
+ type ClueSceneKind = 'tiles' | 'receipt' | 'balance';
18
+ /** Total a clue evaluates to, given the unknowns' answers (kept consistent by construction). */
19
+ declare function clueTotal(clue: Clue, unknowns: Unknown[]): number;
20
+ /** A coloured token for an unknown (the reusable atom of every scene). */
21
+ declare function UnknownChip({
22
+ u,
23
+ size,
24
+ withLabel
25
+ }: {
26
+ u: Unknown;
27
+ size?: number;
28
+ withLabel?: boolean;
29
+ }): ReactNode;
30
+ interface SceneProps {
31
+ clue: Clue;
32
+ unknowns: Unknown[];
33
+ currency?: string;
34
+ unit?: string;
35
+ store?: string;
36
+ }
37
+ /** Tiles: "2▲ + 1● = 12". Universal, reads as the equation it is. */
38
+ declare function ClueTiles({
39
+ clue,
40
+ unknowns,
41
+ currency,
42
+ unit
43
+ }: SceneProps): ReactNode;
44
+ /** Receipt: a shop bill listing quantities and the total (unit prices unknown). */
45
+ declare function ClueReceipt({
46
+ clue,
47
+ unknowns,
48
+ currency,
49
+ store
50
+ }: SceneProps): ReactNode;
51
+ /** Balance: buckets (one per coeff, coloured by type) on the left pan vs a weight on the right. */
52
+ declare function ClueBalance({
53
+ clue,
54
+ unknowns,
55
+ unit
56
+ }: SceneProps): ReactNode;
57
+ /** Bar model (tape diagram): each clue is one bar of unit cells grouped by unknown = total. */
58
+ declare function ClueBar({
59
+ clue,
60
+ unknowns,
61
+ currency,
62
+ unit
63
+ }: SceneProps): ReactNode;
64
+ /** Coin piles: each unknown is a stack of coins (coloured by type) = a money total. */
65
+ declare function ClueCoins({
66
+ clue,
67
+ unknowns,
68
+ currency
69
+ }: SceneProps): ReactNode;
70
+ interface ClueSceneMeta {
71
+ name: string;
72
+ label: string;
73
+ render: (q: SceneProps) => ReactNode;
74
+ }
75
+ declare function registerClueScene(meta: ClueSceneMeta): void;
76
+ declare function getClueScene(name: string): ClueSceneMeta | undefined;
77
+ declare function listClueScenes(): ClueSceneMeta[];
78
+ /** Render one clue in the chosen scene (registry name). Creators extend via registerClueScene. */
79
+ declare function ClueScene({
80
+ kind,
81
+ ...rest
82
+ }: SceneProps & {
83
+ kind: string;
84
+ }): ReactNode;
85
+ //#endregion
86
+ export { Clue, ClueBalance, ClueBar, ClueCoins, ClueReceipt, ClueScene, ClueSceneKind, ClueSceneMeta, ClueTiles, Unknown, UnknownChip, clueTotal, getClueScene, listClueScenes, registerClueScene };