@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
@@ -3,6 +3,7 @@
3
3
  import { clamp } from "../../core/util.mjs";
4
4
  import { CheckButton, Chip, Slider } from "../../kit/controls.mjs";
5
5
  import { Callout, ControlBar, Field, LabFrame, LiveRegion } from "../../kit/frame.mjs";
6
+ import { ChallengeCard, useChallenge, useCheckpoint } from "../../kit/pedagogy.mjs";
6
7
  import { useFrameTick } from "../../kit/anim.mjs";
7
8
  import { PlayWrap, usePlayGate } from "../../kit/play.mjs";
8
9
  import { useRef, useState } from "react";
@@ -11,24 +12,49 @@ import { Circle, Dot, Label, Segment, Stage, Vector } from "@classytic/stage";
11
12
 
12
13
  //#region src/physics/circular-motion/preset.tsx
13
14
  /**
14
- * CircularMotionLab — "Whirl & cut", where centripetal force points and where the
15
+ * CircularMotionLab, "Whirl & cut", where centripetal force points and where the
15
16
  * ball REALLY goes when you let go.
16
17
  *
17
18
  * A ball on a string whirls at constant speed. The velocity arrow is always
18
- * TANGENT; the tension (centripetal force F = mv²/r) always points to the centre —
19
+ * TANGENT; the tension (centripetal force F = mv²/r) always points to the centre ,
19
20
  * it changes the direction of v, never its size. Then CUT THE STRING: the ball
20
- * flies off along the tangent in a straight line — NOT radially outward, the
21
+ * flies off along the tangent in a straight line, NOT radially outward, the
21
22
  * single most common misconception. Tune v, r, m and read F live (hammer throw,
22
23
  * a car cornering, the spin cycle).
23
24
  *
24
25
  * Uses the ambient PlayWrap gate (pause to study the vectors). Tokenized SVG.
25
26
  */
26
- function CircularMotionLab({ speed = 6, radius = 3, mass = 1, title = "Whirl & cut — where does it really go?", prompt = "The string’s tension is the centripetal force F = mv²/r — always toward the centre, bending the path without changing the speed. Cut the string and the ball leaves along the tangent, not outward.", objectives, controlConfig }) {
27
+ const PREDICT = [{
28
+ id: "release",
29
+ prompt: "You’re whirling a ball on a string in a circle. At the instant you LET GO, which way does the ball fly?",
30
+ choices: [
31
+ {
32
+ value: "tangent",
33
+ label: "straight, along the tangent (the way it was moving)"
34
+ },
35
+ {
36
+ value: "radial",
37
+ label: "straight outward, away from the centre"
38
+ },
39
+ {
40
+ value: "curve",
41
+ label: "it keeps curving for a bit"
42
+ }
43
+ ],
44
+ answer: "tangent",
45
+ explain: "No force acts after release, so by Newton’s first law it travels in a straight line along its velocity — the tangent. It does NOT fly radially outward (that’s the common misconception) and does not keep curving."
46
+ }];
47
+ function CircularMotionLab({ speed = 6, radius = 3, mass = 1, title = "Whirl & cut: where does it really go?", prompt = "The string’s tension is the centripetal force F = mv²/r, always toward the centre, bending the path without changing the speed. Cut the string and the ball leaves along the tangent, not outward.", objectives, controlConfig }) {
27
48
  const [v, setV] = useState(speed);
28
49
  const [r, setR] = useState(radius);
29
50
  const [m, setM] = useState(mass);
30
51
  const [cut, setCut] = useState(false);
31
52
  const gate = usePlayGate();
53
+ const ch = useChallenge(PREDICT);
54
+ useCheckpoint({
55
+ solved: ch.allCorrect,
56
+ activity: "circular-motion-predict"
57
+ });
32
58
  const ang = useRef(0);
33
59
  const fly = useRef(null);
34
60
  const omega = v / r;
@@ -231,7 +257,7 @@ function CircularMotionLab({ speed = 6, radius = 3, mass = 1, title = "Whirl & c
231
257
  " points to the centre. Cut the string → no inward pull → straight-line tangent flight (Newton’s 1st law). Hammer throw, a car cornering, the spin cycle."
232
258
  ]
233
259
  }),
234
- /* @__PURE__ */ jsx(LiveRegion, { children: cut ? "String cut — the ball travels in a straight line along the tangent." : `Centripetal force ${F.toFixed(0)} newtons toward the centre.` })
260
+ /* @__PURE__ */ jsx(LiveRegion, { children: cut ? "String cut, the ball travels in a straight line along the tangent." : `Centripetal force ${F.toFixed(0)} newtons toward the centre.` })
235
261
  ]
236
262
  }),
237
263
  controls: /* @__PURE__ */ jsxs(ControlBar, { children: [
@@ -284,6 +310,11 @@ function CircularMotionLab({ speed = 6, radius = 3, mass = 1, title = "Whirl & c
284
310
  })
285
311
  })
286
312
  ] }),
313
+ footer: /* @__PURE__ */ jsx(ChallengeCard, {
314
+ questions: PREDICT,
315
+ state: ch,
316
+ title: "Predict first"
317
+ }),
287
318
  controlConfig,
288
319
  children: figure
289
320
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { CheckButton, Slider, StatusPill } from "../../kit/controls.mjs";
4
4
  import { ControlBar, Field, LabFrame, LiveRegion, MeterBar } from "../../kit/frame.mjs";
5
- import { useCheckpoint } from "../../kit/pedagogy.mjs";
5
+ import { ChallengeCard, useChallenge, useCheckpoint } from "../../kit/pedagogy.mjs";
6
6
  import { useFrameTick, useReducedMotion } from "../../kit/anim.mjs";
7
7
  import { useRef, useState } from "react";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -10,19 +10,43 @@ import { Dot, Label, Polygon, Segment, Stage, Vector, useInView } from "@classyt
10
10
 
11
11
  //#region src/physics/collision-track/preset.tsx
12
12
  /**
13
- * CollisionTrackLab — "Sticky or Bouncy?", momentum always survives, KE doesn't.
13
+ * CollisionTrackLab, "Sticky or Bouncy?", momentum always survives, KE doesn't.
14
14
  *
15
15
  * Two carts collide on a frictionless track. ONE elasticity slider morphs
16
16
  * continuously from perfectly inelastic (e=0, stick + KE drops) to perfectly
17
17
  * elastic (e=1, bounce, KE held). A momentum bar stays FULL through the collision
18
18
  * while the KE bar visibly leaks when e<1, and a constant-velocity centre-of-mass
19
- * marker sails dead-straight through the impact — the single-image proof that
19
+ * marker sails dead-straight through the impact, the single-image proof that
20
20
  * momentum is conserved no matter what. Kills the "momentum is lost" misconception.
21
21
  *
22
22
  * Tokenized SVG; time-dependent so the integrator lives here; honours reduced-motion.
23
23
  */
24
24
  const CART_W = 1.8, X0 = -9, X1 = 9;
25
- function CollisionTrackLab({ m1 = 1, m2 = 1, u1 = 4, u2 = -2, elasticity = 1, showCenterOfMass = true, title = "Sticky or Bouncy? — momentum always survives", prompt = "Set the elasticity, launch, and watch: the momentum bar stays full; the KE bar leaks when sticky.", objectives }) {
25
+ const PREDICT_Q = [{
26
+ id: "collision-track-conserved",
27
+ prompt: "These carts collide and BOUNCE apart (elastic, e = 1). After the crash, which is conserved — total momentum, total kinetic energy, both, or neither?",
28
+ choices: [
29
+ {
30
+ value: "momentum",
31
+ label: "momentum only"
32
+ },
33
+ {
34
+ value: "both",
35
+ label: "both"
36
+ },
37
+ {
38
+ value: "ke",
39
+ label: "kinetic energy only"
40
+ },
41
+ {
42
+ value: "neither",
43
+ label: "neither"
44
+ }
45
+ ],
46
+ answer: "both",
47
+ explain: "Momentum is always conserved in a collision (no external force). In a perfectly elastic collision (e = 1) the carts bounce with no energy lost to heat or deformation, so kinetic energy is conserved too — hence both. Slide elasticity below 1 and the KE bar will start to leak."
48
+ }];
49
+ function CollisionTrackLab({ m1 = 1, m2 = 1, u1 = 4, u2 = -2, elasticity = 1, showCenterOfMass = true, title = "Sticky or Bouncy?: momentum always survives", prompt = "Set the elasticity, launch, and watch: the momentum bar stays full; the KE bar leaks when sticky.", objectives }) {
26
50
  const [ma, setMa] = useState(m1);
27
51
  const [mb, setMb] = useState(m2);
28
52
  const [ua, setUa] = useState(u1);
@@ -36,8 +60,9 @@ function CollisionTrackLab({ m1 = 1, m2 = 1, u1 = 4, u2 = -2, elasticity = 1, sh
36
60
  const startedRef = useRef(false);
37
61
  const reduce = useReducedMotion();
38
62
  const { ref: viewRef, inView } = useInView();
63
+ const ch = useChallenge(PREDICT_Q);
39
64
  useCheckpoint({
40
- solved: stopped,
65
+ solved: ch.allCorrect && stopped,
41
66
  activity: "collision-track"
42
67
  });
43
68
  const M = ma + mb;
@@ -344,6 +369,11 @@ function CollisionTrackLab({ m1 = 1, m2 = 1, u1 = 4, u2 = -2, elasticity = 1, sh
344
369
  })
345
370
  })
346
371
  ] }),
372
+ footer: /* @__PURE__ */ jsx(ChallengeCard, {
373
+ questions: PREDICT_Q,
374
+ state: ch,
375
+ title: "Predict first"
376
+ }),
347
377
  children: figure
348
378
  });
349
379
  }
@@ -12,9 +12,9 @@ interface EfficiencyProps {
12
12
  /** Built-in device preset (ignored if `streams` is given). */
13
13
  device?: 'incandescent' | 'led' | 'petrol-engine' | 'electric-motor' | 'power-station' | 'human';
14
14
  deviceName?: string;
15
- /** Energy supplied, J (default 100 — so shares read as percentages). */
15
+ /** Energy supplied, J (default 100, so shares read as percentages). */
16
16
  inputJoules?: number;
17
- /** Author your own breakdown — overrides the preset entirely. */
17
+ /** Author your own breakdown, overrides the preset entirely. */
18
18
  streams?: EffStream[];
19
19
  title?: string;
20
20
  prompt?: string;
@@ -10,12 +10,12 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
10
10
 
11
11
  //#region src/physics/efficiency/preset.tsx
12
12
  /**
13
- * EfficiencyLab — efficiency as the input→output RATIO you can see. Energy flows in
13
+ * EfficiencyLab, efficiency as the input→output RATIO you can see. Energy flows in
14
14
  * on the left and splits into a USEFUL output stream and WASTED streams (usually
15
15
  * heat), drawn as a Sankey: each ribbon's thickness is its share of the energy, so
16
16
  * efficiency η = useful / input is literally the fraction of the flow that stays
17
17
  * green. Compare an incandescent bulb (≈5%) with an LED (≈45%), a petrol engine
18
- * (≈25%) with an electric motor (≈90%) — and feel why "wasted as heat" matters.
18
+ * (≈25%) with an electric motor (≈90%), and feel why "wasted as heat" matters.
19
19
  *
20
20
  * The device is AUTHORABLE: a creator declares the streams (label, share, useful or
21
21
  * waste) so the same lab draws any energy-flow / efficiency diagram. Interactive
@@ -106,9 +106,9 @@ const ORDER = [
106
106
  "power-station",
107
107
  "human"
108
108
  ];
109
- function EfficiencyLab({ device: device0 = "incandescent", deviceName, inputJoules = 100, streams: streamsProp, title = "Efficiency — how much of the energy is useful?", prompt = "Energy in splits into useful output and wasted energy (mostly heat). Efficiency is the fraction that comes out useful: η = useful ÷ input. Compare the devices.", objectives = [
109
+ function EfficiencyLab({ device: device0 = "incandescent", deviceName, inputJoules = 100, streams: streamsProp, title = "Efficiency: how much of the energy is useful?", prompt = "Energy in splits into useful output and wasted energy (mostly heat). Efficiency is the fraction that comes out useful: η = useful ÷ input. Compare the devices.", objectives = [
110
110
  "Define efficiency as the input→output ratio η = useful energy ÷ total input",
111
- "Read a Sankey diagram — ribbon thickness is energy share",
111
+ "Read a Sankey diagram, ribbon thickness is energy share",
112
112
  "Compare real devices and see where energy is wasted (heat)"
113
113
  ] } = {}) {
114
114
  const [device, setDevice] = useState(device0);
@@ -319,7 +319,7 @@ function EfficiencyLab({ device: device0 = "incandescent", deviceName, inputJoul
319
319
  style: { color: HEAT },
320
320
  children: [(inputJoules - usefulJ).toFixed(0), " J"]
321
321
  }),
322
- " is wasted (mostly heat). Energy is conserved — efficiency is about how much ends up where you want it."
322
+ " is wasted (mostly heat). Energy is conserved, efficiency is about how much ends up where you want it."
323
323
  ]
324
324
  })]
325
325
  })] }),
@@ -10,10 +10,10 @@ import { fieldAt, fieldLines } from "@classytic/stage/field";
10
10
 
11
11
  //#region src/physics/electric-field/preset.tsx
12
12
  /**
13
- * ElectricFieldLab — Coulomb's field you can see and probe, on the same
13
+ * ElectricFieldLab, Coulomb's field you can see and probe, on the same
14
14
  * @classytic/stage `field` kernel that draws magnetism (one kernel → both). Drag
15
15
  * two charges (flip either +/−); field lines retrace live, flowing OUT of + into −.
16
- * Drop the test charge anywhere and a force arrow F = qE appears — toward + or away,
16
+ * Drop the test charge anywhere and a force arrow F = qE appears, toward + or away,
17
17
  * depending on its sign. Interactive (recomputed on drag), not a timed sim.
18
18
  */
19
19
  const VIEW = {
@@ -58,7 +58,7 @@ const POS = "var(--stage-danger, #e03131)";
58
58
  const NEG = "var(--stage-accent, #3b82f6)";
59
59
  const FORCE = "var(--stage-good)";
60
60
  const mag = (v) => Math.hypot(v.x, v.y) || 1;
61
- function ChargeFigure({ sources, lines, charges, test, testSign }) {
61
+ function ChargeFigure({ sources, lines, test, testSign }) {
62
62
  const c = useCoords();
63
63
  const P = (v) => c.toPx(v.x, v.y);
64
64
  const arrow = (a, b, key, color) => {
@@ -118,23 +118,6 @@ function ChargeFigure({ sources, lines, charges, test, testSign }) {
118
118
  ]
119
119
  });
120
120
  })(),
121
- charges.map((ch, i) => {
122
- const [x, y] = P(ch.at);
123
- return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("circle", {
124
- cx: x,
125
- cy: y,
126
- r: 15,
127
- fill: ch.q > 0 ? POS : NEG
128
- }), /* @__PURE__ */ jsx("text", {
129
- x,
130
- y: y + 5,
131
- textAnchor: "middle",
132
- fontSize: 18,
133
- fontWeight: 800,
134
- fill: "white",
135
- children: ch.q > 0 ? "+" : "−"
136
- })] }, `c${i}`);
137
- }),
138
121
  (() => {
139
122
  const [x, y] = P(test);
140
123
  return /* @__PURE__ */ jsxs("g", {
@@ -159,7 +142,33 @@ function ChargeFigure({ sources, lines, charges, test, testSign }) {
159
142
  })()
160
143
  ] });
161
144
  }
162
- function ElectricFieldLab({ title = "Electric field — charges & the force you feel", prompt = "Drag the two charges and flip their signs; field lines flow out of + into −. Drop the test charge and watch the force F = qE.", objectives = [
145
+ /** The charge discs with their ± sign, drawn ON TOP so the drag handles never hide them. */
146
+ function ChargeSymbols({ charges }) {
147
+ const c = useCoords();
148
+ return /* @__PURE__ */ jsx("g", {
149
+ style: { pointerEvents: "none" },
150
+ children: charges.map((ch, i) => {
151
+ const [x, y] = c.toPx(ch.at.x, ch.at.y);
152
+ return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("circle", {
153
+ cx: x,
154
+ cy: y,
155
+ r: 15,
156
+ fill: ch.q > 0 ? POS : NEG,
157
+ stroke: "var(--stage-bg)",
158
+ strokeWidth: 2
159
+ }), /* @__PURE__ */ jsx("text", {
160
+ x,
161
+ y: y + 5,
162
+ textAnchor: "middle",
163
+ fontSize: 18,
164
+ fontWeight: 800,
165
+ fill: "white",
166
+ children: ch.q > 0 ? "+" : "−"
167
+ })] }, i);
168
+ })
169
+ });
170
+ }
171
+ function ElectricFieldLab({ title = "Electric field: charges & the force you feel", prompt = "Drag the two charges and flip their signs; field lines flow out of + into −. Drop the test charge and watch the force F = qE.", objectives = [
163
172
  "Read an electric field as field lines (out of +, into −)",
164
173
  "See like charges repel, opposites attract",
165
174
  "Feel the force on a test charge: F = qE"
@@ -215,7 +224,6 @@ function ElectricFieldLab({ title = "Electric field — charges & the force you
215
224
  bounds: VIEW,
216
225
  seed: .35
217
226
  }), [sources]),
218
- charges,
219
227
  test,
220
228
  testSign
221
229
  }),
@@ -239,7 +247,8 @@ function ElectricFieldLab({ title = "Electric field — charges & the force you
239
247
  color: FORCE,
240
248
  ariaLabel: "test charge",
241
249
  r: 8
242
- })
250
+ }),
251
+ /* @__PURE__ */ jsx(ChargeSymbols, { charges })
243
252
  ]
244
253
  });
245
254
  return /* @__PURE__ */ jsx(LabFrame, {
@@ -0,0 +1 @@
1
+ import { ElectricFluxLab, ElectricFluxProps } from "./preset.mjs";
@@ -0,0 +1,29 @@
1
+ import { LabAskSpec } from "../../kit/ask.mjs";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/physics/electric-flux/preset.d.ts
5
+ interface ElectricFluxProps {
6
+ /** Field strength in vacuum (arbitrary units). */
7
+ field?: number;
8
+ /** Area (length of the flat window, in scene units). */
9
+ area?: number;
10
+ /** Initial angle between the area's normal and the field, in degrees. */
11
+ angleDeg?: number;
12
+ title?: string;
13
+ prompt?: string;
14
+ ask?: LabAskSpec;
15
+ height?: number;
16
+ activity?: string;
17
+ }
18
+ declare function ElectricFluxLab({
19
+ field,
20
+ area,
21
+ angleDeg,
22
+ title,
23
+ prompt,
24
+ ask,
25
+ height,
26
+ activity
27
+ }?: ElectricFluxProps): ReactNode;
28
+ //#endregion
29
+ export { ElectricFluxLab, ElectricFluxProps };
@@ -0,0 +1,264 @@
1
+ 'use client';
2
+
3
+ import { Chip, Slider } from "../../kit/controls.mjs";
4
+ import { Callout, ControlBar, Field, LabFrame } from "../../kit/frame.mjs";
5
+ import { AngleArc } from "../../kit/diagram.mjs";
6
+ import { LabAsk } from "../../kit/ask.mjs";
7
+ import { useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { Label, MovableDot, Segment, Stage, Vector } from "@classytic/stage";
10
+
11
+ //#region src/physics/electric-flux/preset.tsx
12
+ /**
13
+ * ElectricFluxLab, the concept of flux (Φ) made literal: flux is just HOW MANY
14
+ * field lines thread through your area. A uniform field points to the right as a
15
+ * set of evenly spaced lines (denser = stronger E). Drop a flat "area" into it and
16
+ * the lines that actually pass through it light up green; that count IS the flux.
17
+ *
18
+ * • rotate the area: edge-on to the field, nothing threads it (Φ = 0); face-on,
19
+ * the maximum threads it (Φ = E·A). In between, Φ = E·A·cosθ, where θ is the
20
+ * angle between the area's NORMAL and the field.
21
+ * • resize the area A: a bigger window catches more lines.
22
+ * • change the medium (permittivity εr): a dielectric weakens the field to
23
+ * E = E₀/εr, so there are fewer lines to thread, and Φ falls. This is the
24
+ * Gauss-law statement Φ = Q/(ε₀εr) seen as line-counting.
25
+ *
26
+ * Built from stage primitives; the analogy (lines through a hoop) is the point,
27
+ * not a timed simulation. Authorable via props + an optional checked question.
28
+ */
29
+ const VIEW = {
30
+ xMin: -6,
31
+ xMax: 6,
32
+ yMin: -4,
33
+ yMax: 4
34
+ };
35
+ const C_THREAD = "var(--stage-good)";
36
+ const C_FAINT = "color-mix(in oklab, var(--stage-accent) 35%, transparent)";
37
+ const C_AREA = "var(--stage-accent-2)";
38
+ const C_NORMAL = "var(--stage-fg)";
39
+ const MEDIA = [
40
+ {
41
+ name: "vacuum",
42
+ er: 1
43
+ },
44
+ {
45
+ name: "glass",
46
+ er: 5
47
+ },
48
+ {
49
+ name: "water",
50
+ er: 80
51
+ }
52
+ ];
53
+ const fmt$1 = (n) => Math.abs(n) < .05 ? "0" : n.toFixed(1);
54
+ function ElectricFluxLab({ field = 6, area = 3, angleDeg = 0, title = "Electric flux: how many lines thread the area", prompt = "Rotate the area and resize it. The lines that pass through light up: that count is the flux Φ = E·A·cosθ.", ask, height = 420, activity = "electric-flux" } = {}) {
55
+ const [E0, setE0] = useState(field);
56
+ const [A, setA] = useState(area);
57
+ const [theta, setTheta] = useState(angleDeg * Math.PI / 180);
58
+ const [er, setEr] = useState(1);
59
+ const Eeff = E0 / er;
60
+ const cos = Math.cos(theta);
61
+ const phi = Eeff * A * cos;
62
+ const deg = Math.round(theta * 180 / Math.PI);
63
+ const C = {
64
+ x: 0,
65
+ y: 0
66
+ };
67
+ const n = {
68
+ x: Math.cos(theta),
69
+ y: Math.sin(theta)
70
+ };
71
+ const dir = {
72
+ x: -Math.sin(theta),
73
+ y: Math.cos(theta)
74
+ };
75
+ const p1 = {
76
+ x: C.x + dir.x * A / 2,
77
+ y: C.y + dir.y * A / 2
78
+ };
79
+ const p2 = {
80
+ x: C.x - dir.x * A / 2,
81
+ y: C.y - dir.y * A / 2
82
+ };
83
+ const halfSpan = A / 2 * Math.abs(cos);
84
+ const nLines = Math.max(4, Math.min(40, Math.round(Eeff * 3)));
85
+ const y0 = VIEW.yMin + .4, y1 = VIEW.yMax - .4;
86
+ const ys = Array.from({ length: nLines }, (_, i) => y0 + (y1 - y0) * i / Math.max(1, nLines - 1));
87
+ const threads = ys.filter((y) => Math.abs(y - C.y) <= halfSpan + 1e-6).length;
88
+ const rotTip = {
89
+ x: C.x + n.x * 2.2,
90
+ y: C.y + n.y * 2.2
91
+ };
92
+ const figure = /* @__PURE__ */ jsxs(Stage, {
93
+ view: VIEW,
94
+ height,
95
+ ariaLabel: `Uniform field with a flat area at ${deg} degrees; ${threads} field lines thread it`,
96
+ children: [
97
+ ys.map((y, i) => {
98
+ const on = Math.abs(y - C.y) <= halfSpan + 1e-6;
99
+ return /* @__PURE__ */ jsx(Segment, {
100
+ from: {
101
+ x: VIEW.xMin,
102
+ y
103
+ },
104
+ to: {
105
+ x: VIEW.xMax,
106
+ y
107
+ },
108
+ color: on ? C_THREAD : C_FAINT,
109
+ weight: on ? 2.4 : 1.4
110
+ }, i);
111
+ }),
112
+ /* @__PURE__ */ jsx(Vector, {
113
+ tail: {
114
+ x: 3.6,
115
+ y: y1 - .2
116
+ },
117
+ tip: {
118
+ x: 4.7,
119
+ y: y1 - .2
120
+ },
121
+ color: "var(--stage-accent)"
122
+ }),
123
+ /* @__PURE__ */ jsx(Label, {
124
+ x: 4.9,
125
+ y: y1 - .2,
126
+ text: "E",
127
+ color: "var(--stage-accent)",
128
+ size: 13,
129
+ anchor: "start"
130
+ }),
131
+ /* @__PURE__ */ jsx(Segment, {
132
+ from: p1,
133
+ to: p2,
134
+ color: C_AREA,
135
+ weight: 7
136
+ }),
137
+ /* @__PURE__ */ jsx(Label, {
138
+ x: p1.x,
139
+ y: p1.y,
140
+ text: "area A",
141
+ color: C_AREA,
142
+ size: 12,
143
+ weight: 700,
144
+ dx: 8,
145
+ dy: -4,
146
+ anchor: "start"
147
+ }),
148
+ /* @__PURE__ */ jsx(Vector, {
149
+ tail: C,
150
+ tip: {
151
+ x: C.x + n.x * 1.5,
152
+ y: C.y + n.y * 1.5
153
+ },
154
+ color: C_NORMAL
155
+ }),
156
+ /* @__PURE__ */ jsx(AngleArc, {
157
+ at: C,
158
+ from: {
159
+ x: 1,
160
+ y: 0
161
+ },
162
+ to: n,
163
+ rPx: 38,
164
+ label: `θ=${Math.abs(deg)}°`
165
+ }),
166
+ /* @__PURE__ */ jsx(MovableDot, {
167
+ value: rotTip,
168
+ onMove: (p) => setTheta(Math.atan2(p.y - C.y, p.x - C.x)),
169
+ color: "var(--stage-accent)",
170
+ ariaLabel: "rotate the area",
171
+ r: 7
172
+ })
173
+ ]
174
+ });
175
+ return /* @__PURE__ */ jsx(LabFrame, {
176
+ title,
177
+ prompt,
178
+ controls: /* @__PURE__ */ jsxs(ControlBar, { children: [
179
+ /* @__PURE__ */ jsx(Field, {
180
+ label: "field E₀",
181
+ value: fmt$1(E0),
182
+ children: /* @__PURE__ */ jsx(Slider, {
183
+ value: E0,
184
+ min: 1,
185
+ max: 12,
186
+ step: 1,
187
+ onChange: setE0,
188
+ ariaLabel: "field strength"
189
+ })
190
+ }),
191
+ /* @__PURE__ */ jsx(Field, {
192
+ label: "area A",
193
+ value: fmt$1(A),
194
+ children: /* @__PURE__ */ jsx(Slider, {
195
+ value: A,
196
+ min: 1,
197
+ max: 6,
198
+ step: .5,
199
+ onChange: setA,
200
+ ariaLabel: "area size"
201
+ })
202
+ }),
203
+ /* @__PURE__ */ jsx(Field, {
204
+ label: "angle θ",
205
+ value: `${Math.abs(deg)}°`,
206
+ children: /* @__PURE__ */ jsx(Slider, {
207
+ value: deg,
208
+ min: -90,
209
+ max: 90,
210
+ step: 5,
211
+ onChange: (v) => setTheta(v * Math.PI / 180),
212
+ ariaLabel: "angle of the area"
213
+ })
214
+ }),
215
+ /* @__PURE__ */ jsx(Field, {
216
+ label: "medium",
217
+ children: /* @__PURE__ */ jsx("span", {
218
+ className: "lab-field-row",
219
+ children: MEDIA.map((m) => /* @__PURE__ */ jsx(Chip, {
220
+ selected: er === m.er,
221
+ onClick: () => setEr(m.er),
222
+ children: m.name
223
+ }, m.name))
224
+ })
225
+ })
226
+ ] }),
227
+ aside: /* @__PURE__ */ jsx(Callout, {
228
+ tone: "result",
229
+ children: /* @__PURE__ */ jsxs("div", {
230
+ style: {
231
+ display: "grid",
232
+ gap: 6,
233
+ fontVariantNumeric: "tabular-nums",
234
+ fontSize: 13
235
+ },
236
+ children: [
237
+ /* @__PURE__ */ jsxs("span", { children: ["lines threading the area: ", /* @__PURE__ */ jsx("strong", {
238
+ style: { color: C_THREAD },
239
+ children: threads
240
+ })] }),
241
+ /* @__PURE__ */ jsxs("span", { children: [
242
+ "E = E₀/εr = ",
243
+ /* @__PURE__ */ jsx("strong", { children: fmt$1(Eeff) }),
244
+ " ",
245
+ er > 1 ? `(÷${er} in ${MEDIA.find((m) => m.er === er)?.name})` : ""
246
+ ] }),
247
+ /* @__PURE__ */ jsxs("span", { children: ["Φ = E·A·cosθ = ", /* @__PURE__ */ jsx("strong", { children: fmt$1(phi) })] }),
248
+ /* @__PURE__ */ jsx("span", {
249
+ style: { color: "var(--stage-muted)" },
250
+ children: Math.abs(deg) >= 88 ? "edge-on: nothing threads it, Φ = 0" : Math.abs(deg) < 2 ? "face-on: maximum flux, Φ = E·A" : "tilted: Φ falls with cosθ"
251
+ })
252
+ ]
253
+ })
254
+ }),
255
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
256
+ ask,
257
+ activity
258
+ }) : void 0,
259
+ children: figure
260
+ });
261
+ }
262
+
263
+ //#endregion
264
+ export { ElectricFluxLab };
@@ -10,14 +10,14 @@ import { Label, Polyline, Segment, Stage, useInView } from "@classytic/stage";
10
10
 
11
11
  //#region src/physics/energy-skate/preset.tsx
12
12
  /**
13
- * EnergySkateLab — "Where did the energy go?", KE ⇄ PE on a ramp, with friction
13
+ * EnergySkateLab, "Where did the energy go?", KE ⇄ PE on a ramp, with friction
14
14
  * bleeding the total into heat.
15
15
  *
16
- * A skater is released from a height on a parabolic ramp. Three stacked bars —
17
- * potential, kinetic, and thermal — ALWAYS sum to the same total: as the skater
16
+ * A skater is released from a height on a parabolic ramp. Three stacked bars ,
17
+ * potential, kinetic, and thermal, ALWAYS sum to the same total: as the skater
18
18
  * drops, the PE bar empties into the KE bar and back on the way up. Turn friction
19
19
  * on and a THERMAL bar grows each pass, so the skater can never climb as high
20
- * again — mechanical energy isn't destroyed, it's moved to heat. (The "LOL" energy
20
+ * again, mechanical energy isn't destroyed, it's moved to heat. (The "LOL" energy
21
21
  * bar chart, animated.)
22
22
  *
23
23
  * This complements WorkEnergyLab (work = area under F–x): here the spotlight is
@@ -30,7 +30,7 @@ const X = 6;
30
30
  const H = 5;
31
31
  const MU = .08;
32
32
  const yAt = (x) => H * (x / X) * (x / X);
33
- function EnergySkateLab({ startHeight = 4, friction = false, mass = 1, title = "Where did the energy go? — KE ⇄ PE (and heat)", prompt = "Release the skater and watch potential energy pour into kinetic and back. The three bars always add to the same total — unless friction is on, then a heat bar grows and the skater can’t climb as high again.", objectives, controlConfig }) {
33
+ function EnergySkateLab({ startHeight = 4, friction = false, mass = 1, title = "Where did the energy go?: KE ⇄ PE (and heat)", prompt = "Release the skater and watch potential energy pour into kinetic and back. The three bars always add to the same total, unless friction is on, then a heat bar grows and the skater can’t climb as high again.", objectives, controlConfig }) {
34
34
  const [h0, setH0] = useState(clamp(startHeight, 1, H));
35
35
  const [fric, setFric] = useState(friction);
36
36
  const [m] = useState(mass);