@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
@@ -0,0 +1,19 @@
1
+ import { CircuitDoc } from "./contract.mjs";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/build/CircuitPlayer.d.ts
5
+ interface CircuitPlayerProps {
6
+ doc: CircuitDoc;
7
+ flow?: boolean;
8
+ ariaLabel?: string;
9
+ /** notified after every tap with the new doc (e.g. to check a goal). */
10
+ onChange?: (doc: CircuitDoc) => void;
11
+ }
12
+ declare function CircuitPlayer({
13
+ doc: authored,
14
+ flow,
15
+ ariaLabel,
16
+ onChange
17
+ }: CircuitPlayerProps): ReactNode;
18
+ //#endregion
19
+ export { CircuitPlayer, CircuitPlayerProps };
@@ -0,0 +1,53 @@
1
+ 'use client';
2
+
3
+ import { getPart } from "./registry.mjs";
4
+ import { CircuitScene } from "./CircuitScene.mjs";
5
+ import { useMemo, useState } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+
8
+ //#region src/build/CircuitPlayer.tsx
9
+ /**
10
+ * CircuitPlayer — a CircuitScene you can operate. The authored `doc` is the source of truth (so a
11
+ * parent can drive it, e.g. a slider that changes a resistor's ohms), and the learner's taps
12
+ * (close a switch, flip a component) are kept as a small per-part OVERLAY on top. That way an
13
+ * external doc change is adopted live AND the user's taps survive it. The engine re-solves on
14
+ * every change; CircuitScene stays a pure render.
15
+ */
16
+ const applyOverlay = (doc, overlay) => ({
17
+ ...doc,
18
+ parts: doc.parts.map((p) => overlay[p.id] ? {
19
+ ...p,
20
+ props: {
21
+ ...p.props,
22
+ ...overlay[p.id]
23
+ }
24
+ } : p)
25
+ });
26
+ function CircuitPlayer({ doc: authored, flow = true, ariaLabel, onChange }) {
27
+ const [overlay, setOverlay] = useState({});
28
+ const doc = useMemo(() => applyOverlay(authored, overlay), [authored, overlay]);
29
+ const tap = (partId) => {
30
+ const part = doc.parts.find((p) => p.id === partId);
31
+ if (!part) return;
32
+ const patch = getPart(part.kind)?.tap?.(part);
33
+ if (!patch) return;
34
+ const next = {
35
+ ...overlay,
36
+ [partId]: {
37
+ ...overlay[partId] ?? {},
38
+ ...patch
39
+ }
40
+ };
41
+ setOverlay(next);
42
+ onChange?.(applyOverlay(authored, next));
43
+ };
44
+ return /* @__PURE__ */ jsx(CircuitScene, {
45
+ doc,
46
+ flow,
47
+ ariaLabel,
48
+ onPartTap: tap
49
+ });
50
+ }
51
+
52
+ //#endregion
53
+ export { CircuitPlayer };
@@ -0,0 +1,61 @@
1
+ import { CircuitDoc } from "./contract.mjs";
2
+ import { PointerEvent, ReactNode } from "react";
3
+ import { Vec2 } from "@classytic/stage";
4
+
5
+ //#region src/build/CircuitScene.d.ts
6
+ interface CircuitEditorBag {
7
+ /** draw a small handle at every pin terminal (for wiring). */
8
+ showPins?: boolean;
9
+ /** a part body was clicked (select it). */
10
+ onSelect?: (partId: string) => void;
11
+ /** the pin a pending wire starts from (highlighted). */
12
+ wireStart?: {
13
+ partId: string;
14
+ pin: string;
15
+ };
16
+ /** pointer went down on a part body (begin a drag). */
17
+ onPartPointerDown?: (partId: string, e: PointerEvent) => void;
18
+ /** pointer went down on a pin: a click wires it, a drag moves the part (click-vs-drag). */
19
+ onPinPointerDown?: (partId: string, pin: string, e: PointerEvent) => void;
20
+ /** a wire edge was clicked (select / branch / delete — the editor decides). */
21
+ onWireClick?: (wireId: string) => void;
22
+ /** highlight one wire as selected. */
23
+ selectedWireId?: string;
24
+ /** pointer went down on the BODY of the selected wire (grab to bend / reroute it). */
25
+ onWireBodyDown?: (wireId: string, e: PointerEvent) => void;
26
+ /** pointer went down on an existing bend handle (drag to move that bend). */
27
+ onWireWaypointDown?: (wireId: string, index: number, e: PointerEvent) => void;
28
+ /** pointer went down on a wire's endpoint ring (drag to detach / re-target that end). */
29
+ onWireEndDown?: (wireId: string, end: 'a' | 'b', e: PointerEvent) => void;
30
+ /** the empty canvas was pressed (clear selection, or drop a routing bend while drawing). */
31
+ onBackground?: (e: PointerEvent) => void;
32
+ /** live rubber-band while drawing a wire: origin terminal → any dropped bends → the cursor. */
33
+ wirePreview?: {
34
+ from: Vec2;
35
+ mids?: Vec2[];
36
+ to: Vec2;
37
+ valid?: boolean;
38
+ };
39
+ }
40
+ interface CircuitSceneProps {
41
+ doc: CircuitDoc;
42
+ /** show moving charge dots on live wires (default true). */
43
+ flow?: boolean;
44
+ ariaLabel?: string;
45
+ /** when set, tappable parts (e.g. switches) are clickable and call this with the part id. */
46
+ onPartTap?: (partId: string) => void;
47
+ /** highlight one part as selected (authoring). */
48
+ selectedId?: string;
49
+ /** authoring affordances; omit for the read-only / learner view. */
50
+ editor?: CircuitEditorBag;
51
+ }
52
+ declare function CircuitScene({
53
+ doc,
54
+ flow,
55
+ ariaLabel,
56
+ onPartTap,
57
+ selectedId,
58
+ editor
59
+ }: CircuitSceneProps): ReactNode;
60
+ //#endregion
61
+ export { CircuitEditorBag, CircuitScene, CircuitSceneProps };
@@ -0,0 +1,383 @@
1
+ 'use client';
2
+
3
+ import { FlowDots, JunctionDot, Wire } from "../kit/electronics.mjs";
4
+ import { useReducedMotion } from "../kit/anim.mjs";
5
+ import { getPart } from "./registry.mjs";
6
+ import { registerBuiltinParts } from "./parts/index.mjs";
7
+ import { partState, solveCircuit } from "./solve.mjs";
8
+ import { FLOW_EPS, nodeKey, pinKey, wireCurrents } from "./flow.mjs";
9
+ import { wirePolyline } from "./editor-ops.mjs";
10
+ import { useState } from "react";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
12
+ import { useFrameLoop } from "@classytic/stage";
13
+
14
+ //#region src/build/CircuitScene.tsx
15
+ /**
16
+ * CircuitScene — pure render of a CircuitDoc. It solves the doc, draws a wire from
17
+ * every part pin to the node it names, places a junction dot where 3+ pins meet, and
18
+ * lets each PartDef draw its own glyph with the solved state. Live branches carry
19
+ * moving charge dots. No drawing logic lives here: parts own their look.
20
+ *
21
+ * Read-only by default. Pass `onPartTap` for click-to-operate (learner), or an
22
+ * `editor` bag for authoring (selection + pin handles for wiring). A node with no
23
+ * explicit `at` is drawn at the centroid of the terminals wired to it, so the
24
+ * author never has to place junctions by hand.
25
+ */
26
+ registerBuiltinParts();
27
+ /** Manhattan route terminal → node: straight when aligned, else a single elbow (vertical-first). */
28
+ function orthRoute(a, b) {
29
+ if (a.x === b.x || a.y === b.y) return [[a.x, a.y], [b.x, b.y]];
30
+ return [
31
+ [a.x, a.y],
32
+ [a.x, b.y],
33
+ [b.x, b.y]
34
+ ];
35
+ }
36
+ function CircuitScene({ doc, flow = true, ariaLabel = "circuit diagram", onPartTap, selectedId, editor }) {
37
+ const [phase, setPhase] = useState(0);
38
+ const reduce = useReducedMotion();
39
+ const W = doc.size?.w ?? 520;
40
+ const H = doc.size?.h ?? 220;
41
+ const sol = solveCircuit(doc);
42
+ const states = new Map(doc.parts.map((p) => [p.id, partState(p, sol)]));
43
+ const anyLive = [...states.values()].some((s) => s.live);
44
+ const wf = wireCurrents(doc, sol);
45
+ const termOf = (partId, pin) => {
46
+ const p = doc.parts.find((x) => x.id === partId);
47
+ const def = p && getPart(p.kind);
48
+ return def ? def.terminalAt(p, pin) : void 0;
49
+ };
50
+ const rev = (s) => [...s].reverse();
51
+ const termsByNode = /* @__PURE__ */ new Map();
52
+ for (const p of doc.parts) {
53
+ const def = getPart(p.kind);
54
+ if (!def) continue;
55
+ for (const pin of def.pins) {
56
+ const nid = p.pins[pin];
57
+ if (!nid) continue;
58
+ (termsByNode.get(nid) ?? termsByNode.set(nid, []).get(nid)).push(def.terminalAt(p, pin));
59
+ }
60
+ }
61
+ const explicit = new Map(doc.nodes.map((n) => [n.id, n.at]));
62
+ const nodePos = (nid) => {
63
+ const fixed = explicit.get(nid);
64
+ if (fixed) return fixed;
65
+ const ts = termsByNode.get(nid) ?? [];
66
+ return ts.length ? {
67
+ x: ts.reduce((s, t) => s + t.x, 0) / ts.length,
68
+ y: ts.reduce((s, t) => s + t.y, 0) / ts.length
69
+ } : {
70
+ x: W / 2,
71
+ y: H / 2
72
+ };
73
+ };
74
+ const drawnNode = (nid) => explicit.has(nid) || (termsByNode.get(nid)?.length ?? 0) >= 2;
75
+ useFrameLoop((f) => setPhase((p) => (p + f.dtMs / 1400) % 1), { running: flow && anyLive && !reduce });
76
+ const wires = [];
77
+ const live = [];
78
+ const pinHandles = [];
79
+ const wireEndpoints = /* @__PURE__ */ new Map();
80
+ const bump = (k) => {
81
+ wireEndpoints.set(k, (wireEndpoints.get(k) ?? 0) + 1);
82
+ };
83
+ for (const p of doc.parts) {
84
+ const def = getPart(p.kind);
85
+ if (!def) continue;
86
+ for (const pin of def.pins) {
87
+ const nid = p.pins[pin];
88
+ if (!nid || !drawnNode(nid)) continue;
89
+ const seg = orthRoute(def.terminalAt(p, pin), nodePos(nid));
90
+ const I = wf.current(pinKey(p.id, pin), nodeKey(nid));
91
+ const isLive = Math.abs(I) > FLOW_EPS;
92
+ wires.push(/* @__PURE__ */ jsx(Wire, {
93
+ points: seg,
94
+ live: isLive
95
+ }, `stub-${p.id}-${pin}`));
96
+ if (isLive) live.push(I > 0 ? rev(seg) : seg);
97
+ }
98
+ }
99
+ for (const w of doc.wires ?? []) {
100
+ const ta = termOf(w.a.partId, w.a.pin);
101
+ const tb = termOf(w.b.partId, w.b.pin);
102
+ if (!ta || !tb) continue;
103
+ const seg = wirePolyline(ta, w.mid ?? [], tb).map((p) => [p.x, p.y]);
104
+ const ptStr = seg.map((q) => `${q[0]},${q[1]}`).join(" ");
105
+ const isSel = editor?.selectedWireId === w.id;
106
+ const I = wf.current(pinKey(w.a.partId, w.a.pin), pinKey(w.b.partId, w.b.pin));
107
+ const isLive = Math.abs(I) > FLOW_EPS;
108
+ wires.push(/* @__PURE__ */ jsxs("g", {
109
+ style: { cursor: editor?.onWireClick ? "pointer" : "default" },
110
+ onClick: editor?.onWireClick ? (e) => {
111
+ e.stopPropagation();
112
+ editor.onWireClick(w.id);
113
+ } : void 0,
114
+ children: [
115
+ isSel && /* @__PURE__ */ jsx("polyline", {
116
+ points: ptStr,
117
+ fill: "none",
118
+ stroke: "var(--stage-accent)",
119
+ strokeWidth: 6,
120
+ strokeLinecap: "round",
121
+ strokeLinejoin: "round",
122
+ opacity: .4
123
+ }),
124
+ /* @__PURE__ */ jsx(Wire, {
125
+ points: seg,
126
+ live: isLive
127
+ }),
128
+ editor?.onWireClick && /* @__PURE__ */ jsx("polyline", {
129
+ points: ptStr,
130
+ fill: "none",
131
+ stroke: "transparent",
132
+ strokeWidth: isSel ? 20 : 14,
133
+ strokeLinecap: "round",
134
+ strokeLinejoin: "round",
135
+ style: {
136
+ cursor: isSel ? "move" : "pointer",
137
+ pointerEvents: "stroke"
138
+ },
139
+ onPointerDown: isSel && editor.onWireBodyDown ? (e) => {
140
+ e.stopPropagation();
141
+ editor.onWireBodyDown(w.id, e);
142
+ } : void 0
143
+ }),
144
+ isSel && (w.mid ?? []).map((m, i) => /* @__PURE__ */ jsx("rect", {
145
+ x: m.x - 5,
146
+ y: m.y - 5,
147
+ width: 10,
148
+ height: 10,
149
+ rx: 2,
150
+ fill: "var(--stage-bg)",
151
+ stroke: "var(--stage-accent)",
152
+ strokeWidth: 2,
153
+ style: { cursor: "move" },
154
+ onPointerDown: editor.onWireWaypointDown ? (e) => {
155
+ e.stopPropagation();
156
+ editor.onWireWaypointDown(w.id, i, e);
157
+ } : void 0
158
+ }, `wp-${i}`))
159
+ ]
160
+ }, `wire-${w.id}`));
161
+ if (isLive) live.push(I > 0 ? rev(seg) : seg);
162
+ bump(`${w.a.partId} ${w.a.pin}`);
163
+ bump(`${w.b.partId} ${w.b.pin}`);
164
+ }
165
+ if (editor?.showPins) for (const p of doc.parts) {
166
+ const def = getPart(p.kind);
167
+ if (!def) continue;
168
+ for (const pin of def.pins) {
169
+ const t = def.terminalAt(p, pin);
170
+ const armed = editor.wireStart?.partId === p.id && editor.wireStart?.pin === pin;
171
+ pinHandles.push(/* @__PURE__ */ jsx("circle", {
172
+ cx: t.x,
173
+ cy: t.y,
174
+ r: armed ? 7 : 5.5,
175
+ fill: armed ? "var(--stage-accent)" : "var(--stage-bg)",
176
+ stroke: "var(--stage-accent)",
177
+ strokeWidth: 2,
178
+ style: { cursor: "crosshair" },
179
+ role: "button",
180
+ "aria-label": `${pin} of ${def.label}`,
181
+ onPointerDown: (e) => {
182
+ e.stopPropagation();
183
+ editor.onPinPointerDown?.(p.id, pin, e);
184
+ }
185
+ }, `pin-${p.id}-${pin}`));
186
+ }
187
+ }
188
+ const dots = [];
189
+ for (const [nid, ts] of termsByNode) if (drawnNode(nid) && ts.length > 2) {
190
+ const np = nodePos(nid);
191
+ dots.push(/* @__PURE__ */ jsx(JunctionDot, {
192
+ x: np.x,
193
+ y: np.y,
194
+ live: false
195
+ }, `j-${nid}`));
196
+ }
197
+ for (const [key, n] of wireEndpoints) if (n >= 2) {
198
+ const [partId, pin] = key.split(" ");
199
+ const t = partId && pin ? termOf(partId, pin) : void 0;
200
+ if (t) dots.push(/* @__PURE__ */ jsx(JunctionDot, {
201
+ x: t.x,
202
+ y: t.y,
203
+ live: false
204
+ }, `jw-${key}`));
205
+ }
206
+ return /* @__PURE__ */ jsx("div", {
207
+ style: {
208
+ borderRadius: 14,
209
+ overflow: "hidden",
210
+ background: "var(--stage-bg)",
211
+ border: "1px solid var(--stage-grid)"
212
+ },
213
+ children: /* @__PURE__ */ jsxs("svg", {
214
+ viewBox: `0 0 ${W} ${H}`,
215
+ width: "100%",
216
+ role: "img",
217
+ "aria-label": ariaLabel,
218
+ children: [
219
+ editor?.onBackground && /* @__PURE__ */ jsx("rect", {
220
+ x: 0,
221
+ y: 0,
222
+ width: W,
223
+ height: H,
224
+ fill: "transparent",
225
+ onPointerDown: (e) => editor.onBackground(e)
226
+ }),
227
+ wires,
228
+ flow && !reduce && live.map((seg, k) => /* @__PURE__ */ jsx(FlowDots, {
229
+ points: seg,
230
+ phase,
231
+ spacing: 54,
232
+ r: 2.3
233
+ }, `f${k}`)),
234
+ dots,
235
+ editor?.wirePreview && (() => {
236
+ const { from, mids = [], to, valid } = editor.wirePreview;
237
+ const pts = [
238
+ from,
239
+ ...mids,
240
+ to
241
+ ];
242
+ const col = "var(--stage-accent)";
243
+ return /* @__PURE__ */ jsxs("g", {
244
+ style: { pointerEvents: "none" },
245
+ children: [
246
+ /* @__PURE__ */ jsx("polyline", {
247
+ points: pts.map((q) => `${q.x},${q.y}`).join(" "),
248
+ fill: "none",
249
+ stroke: col,
250
+ strokeWidth: 2.5,
251
+ strokeDasharray: "5 4",
252
+ strokeLinecap: "round",
253
+ strokeLinejoin: "round",
254
+ opacity: .9
255
+ }),
256
+ mids.map((m, i) => /* @__PURE__ */ jsx("circle", {
257
+ cx: m.x,
258
+ cy: m.y,
259
+ r: 3.5,
260
+ fill: col
261
+ }, i)),
262
+ /* @__PURE__ */ jsx("circle", {
263
+ cx: to.x,
264
+ cy: to.y,
265
+ r: valid ? 6 : 5,
266
+ fill: valid ? col : "var(--stage-bg)",
267
+ stroke: col,
268
+ strokeWidth: 2
269
+ })
270
+ ]
271
+ });
272
+ })(),
273
+ doc.parts.map((p) => {
274
+ const def = getPart(p.kind);
275
+ if (!def) return null;
276
+ const glyph = def.render(p, states.get(p.id));
277
+ const tappable = !!onPartTap && (def.tap?.(p) ?? null) !== null;
278
+ const selectable = !!editor?.onSelect;
279
+ const selected = selectedId === p.id;
280
+ if (!tappable && !selectable && !selected) return glyph;
281
+ const onActivate = selectable ? () => editor.onSelect(p.id) : tappable ? () => onPartTap(p.id) : void 0;
282
+ const label = !selectable && tappable ? `toggle ${def.label.toLowerCase()}` : `select ${def.label.toLowerCase()}`;
283
+ return /* @__PURE__ */ jsxs("g", {
284
+ role: onActivate ? "button" : void 0,
285
+ tabIndex: onActivate ? 0 : void 0,
286
+ "aria-label": onActivate ? label : void 0,
287
+ style: { cursor: editor?.onPartPointerDown ? "move" : onActivate ? "pointer" : "default" },
288
+ onPointerDown: editor?.onPartPointerDown ? (e) => editor.onPartPointerDown(p.id, e) : void 0,
289
+ onClick: onActivate ? (e) => {
290
+ e.stopPropagation();
291
+ onActivate();
292
+ } : void 0,
293
+ onKeyDown: onActivate ? (e) => {
294
+ if (e.key === "Enter" || e.key === " ") {
295
+ e.preventDefault();
296
+ onActivate();
297
+ }
298
+ } : void 0,
299
+ children: [
300
+ selected && /* @__PURE__ */ jsx("rect", {
301
+ x: p.at.x - 40,
302
+ y: p.at.y - 30,
303
+ width: 80,
304
+ height: 60,
305
+ rx: 8,
306
+ fill: "none",
307
+ stroke: "var(--stage-accent)",
308
+ strokeWidth: 1.5,
309
+ strokeDasharray: "4 3"
310
+ }),
311
+ (tappable || selectable) && /* @__PURE__ */ jsx("rect", {
312
+ x: p.at.x - 38,
313
+ y: p.at.y - 28,
314
+ width: 76,
315
+ height: 56,
316
+ rx: 8,
317
+ fill: "transparent"
318
+ }),
319
+ glyph
320
+ ]
321
+ }, `hit-${p.id}`);
322
+ }),
323
+ doc.parts.map((p) => {
324
+ const dmg = states.get(p.id)?.damage;
325
+ if (!dmg) return null;
326
+ const c = "var(--stage-danger, #e03131)";
327
+ return /* @__PURE__ */ jsxs("g", {
328
+ style: { pointerEvents: "none" },
329
+ children: [/* @__PURE__ */ jsx("rect", {
330
+ x: p.at.x - 34,
331
+ y: p.at.y - 24,
332
+ width: 68,
333
+ height: 48,
334
+ rx: 8,
335
+ fill: "color-mix(in oklab, var(--stage-danger, #e03131) 14%, transparent)",
336
+ stroke: c,
337
+ strokeWidth: 2,
338
+ strokeDasharray: "3 3"
339
+ }), /* @__PURE__ */ jsx("text", {
340
+ x: p.at.x,
341
+ y: p.at.y - 30,
342
+ fill: c,
343
+ fontSize: 14,
344
+ fontWeight: 800,
345
+ textAnchor: "middle",
346
+ dominantBaseline: "auto",
347
+ children: dmg === "overpower" ? "🔥" : "⚡"
348
+ })]
349
+ }, `dmg-${p.id}`);
350
+ }),
351
+ pinHandles,
352
+ editor?.selectedWireId && editor.onWireEndDown && (() => {
353
+ const w = (doc.wires ?? []).find((x) => x.id === editor.selectedWireId);
354
+ if (!w) return null;
355
+ return [{
356
+ end: "a",
357
+ t: termOf(w.a.partId, w.a.pin)
358
+ }, {
359
+ end: "b",
360
+ t: termOf(w.b.partId, w.b.pin)
361
+ }].map(({ end, t }) => t && /* @__PURE__ */ jsx("circle", {
362
+ cx: t.x,
363
+ cy: t.y,
364
+ r: 7.5,
365
+ fill: "var(--stage-bg)",
366
+ stroke: "var(--stage-accent)",
367
+ strokeWidth: 2.5,
368
+ style: { cursor: "grab" },
369
+ role: "button",
370
+ "aria-label": `wire end ${end}`,
371
+ onPointerDown: (e) => {
372
+ e.stopPropagation();
373
+ editor.onWireEndDown(w.id, end, e);
374
+ }
375
+ }, `we-${end}`));
376
+ })()
377
+ ]
378
+ })
379
+ });
380
+ }
381
+
382
+ //#endregion
383
+ export { CircuitScene };
@@ -0,0 +1,116 @@
1
+ import { ReactNode } from "react";
2
+ import { Vec2 } from "@classytic/stage";
3
+ import { Elem } from "@classytic/stage/circuit";
4
+
5
+ //#region src/build/contract.d.ts
6
+ type PartKind = string;
7
+ /** A placed component instance. */
8
+ interface PartInstance {
9
+ id: string;
10
+ kind: PartKind;
11
+ /** centre on the canvas, pixels. */
12
+ at: Vec2;
13
+ /** 'h' = terminals left/right, 'v' = top/bottom (2-terminal parts). */
14
+ orient?: 'h' | 'v';
15
+ /** value / vth / closed / label … (the part's tunables). */
16
+ props?: Record<string, number | string | boolean>;
17
+ /** pin id → node id it connects to. */
18
+ pins: Record<string, string>;
19
+ }
20
+ /** An electrical node (junction) with a canvas position. `id === 'gnd'` is the reference. */
21
+ interface CNode {
22
+ id: string;
23
+ at: Vec2;
24
+ }
25
+ /** One end of a wire: a specific pin of a specific part. */
26
+ interface PinRef {
27
+ partId: string;
28
+ pin: string;
29
+ }
30
+ /**
31
+ * A wire is its OWN edge between two pin terminals. Parts keep their positions; the
32
+ * wire routes between them. Electrical nets are derived by union-find over wires (plus
33
+ * any pins that share a node id), so connecting two pins never drags parts together.
34
+ */
35
+ interface Wire {
36
+ id: string;
37
+ a: PinRef;
38
+ b: PinRef;
39
+ /** optional bend points the wire routes through (drag to position the wire's path). */
40
+ mid?: Vec2[];
41
+ }
42
+ /** A circuit, the serializable source of truth. */
43
+ interface CircuitDoc {
44
+ parts: PartInstance[];
45
+ nodes: CNode[];
46
+ /** explicit wire edges (the editor's connection model). */
47
+ wires?: Wire[];
48
+ size?: {
49
+ w: number;
50
+ h: number;
51
+ };
52
+ }
53
+ interface CircuitSolution {
54
+ /** node voltage by node id (each pin's node id resolves to its net voltage). */
55
+ nodeV: Record<string, number>;
56
+ /** branch current by part id (sources / diodes / mosfets / closed switches). */
57
+ current: Record<string, number>;
58
+ ok: boolean;
59
+ /** part ids whose two terminals collapsed onto the same net (a dead short across a source). */
60
+ shorted: string[];
61
+ /** voltage at a specific pin (net-accurate). */
62
+ pinV: (partId: string, pin: string) => number;
63
+ /** net number a pin belongs to (0 = ground). */
64
+ net: (partId: string, pin: string) => number;
65
+ }
66
+ /** What a part's glyph needs from the solve to draw itself. */
67
+ interface PartState {
68
+ /** current is flowing through this part. */
69
+ live: boolean;
70
+ /** representative current through the part, amps (signed). */
71
+ i: number;
72
+ /** representative voltage across the part, volts. */
73
+ v: number;
74
+ /** power the part dissipates, watts (|v·i|). */
75
+ power: number;
76
+ /** the part is being destroyed: it exceeds a rated limit. `overpower` = dissipating more
77
+ * than its power rating (it overheats / burns out); `overvoltage` = the voltage across it
78
+ * exceeds its breakdown rating. undefined = within ratings. Drives the "you fried it" signal. */
79
+ damage?: 'overpower' | 'overvoltage';
80
+ /** voltage at one of this part's pins. */
81
+ pinV: (pin: string) => number;
82
+ }
83
+ /** A tunable a part exposes to the inspector as a friendly labelled field (vs a raw prop key). */
84
+ interface PartControl {
85
+ /** the prop key it edits. */
86
+ key: string;
87
+ label: string;
88
+ /** unit shown after the value (e.g. 'V', 'Ω'). */
89
+ unit?: string;
90
+ min?: number;
91
+ max?: number;
92
+ step?: number;
93
+ }
94
+ /** The one extension point: register a part once to make it placeable + solvable + drawable. */
95
+ interface PartDef {
96
+ kind: PartKind;
97
+ label: string;
98
+ /** pin ids (e.g. ['a','b'] or ['d','s','g']). */
99
+ pins: string[];
100
+ defaultProps?: Record<string, number | string | boolean>;
101
+ /** the part's tunables, rendered as labelled inspector fields (falls back to defaultProps). */
102
+ controls?: PartControl[];
103
+ /** world position of a pin's terminal, given the instance (handles orientation). */
104
+ terminalAt(inst: PartInstance, pin: string): Vec2;
105
+ /** map this instance to engine elements; nodeNum(pin) resolves a pin to an engine node number. */
106
+ toElems(inst: PartInstance, nodeNum: (pin: string) => number): Elem[];
107
+ /** draw the glyph at the instance centre with its solved state. */
108
+ render(inst: PartInstance, state: PartState): ReactNode;
109
+ /**
110
+ * If the part can be operated by tapping it (e.g. a switch), return the props patch
111
+ * a tap applies; return null for inert parts. Drives click-on-the-circuit interaction.
112
+ */
113
+ tap?(inst: PartInstance): Record<string, number | string | boolean> | null;
114
+ }
115
+ //#endregion
116
+ export { CNode, CircuitDoc, CircuitSolution, PartDef, PartInstance, PartKind, PartState, PinRef, Wire };