@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,1855 @@
1
+ 'use client';
2
+
3
+ import { Slider } from "../../kit/controls.mjs";
4
+ import { Callout, ControlBar, Field, LabFrame } from "../../kit/frame.mjs";
5
+ import { useCheckpoint } from "../../kit/pedagogy.mjs";
6
+ import { Tag } from "../../kit/electronics.mjs";
7
+ import { LabAsk } from "../../kit/ask.mjs";
8
+ import { inBox, rand, recombine, stepCarriers, tweenOpacity, useCarrierSim } from "../../kit/carrier-engine.mjs";
9
+ import { useState } from "react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { solveDC } from "@classytic/stage/circuit";
12
+
13
+ //#region src/circuits/semiconductor/preset.tsx
14
+ /**
15
+ * MosfetInsideLab — what actually happens INSIDE an NMOS as you turn the gate.
16
+ *
17
+ * A cross-section of the device: a p-type substrate (holes, +), two n+ wells for the
18
+ * source and drain (electrons, −), a metal gate over a thin oxide. Turn the gate
19
+ * voltage: below threshold the gate just pushes holes away and opens a bare depletion
20
+ * region (no path). Past threshold the surface INVERTS, electrons pulled up from the
21
+ * body form a thin n-channel that bridges source to drain, and with a drain voltage
22
+ * those electrons drift across, the conventional current. The channel on/off and the
23
+ * drain current are the real engine solve (the same MOSFET model as the schematic lab),
24
+ * so the inside view and the circuit always agree.
25
+ */
26
+ const W = 560, H = 320;
27
+ const DEV = {
28
+ x: 40,
29
+ y: 86,
30
+ w: 480,
31
+ h: 200
32
+ };
33
+ const WELL_W = 96, WELL_TOP = 110, WELL_BOT = 250;
34
+ const SRC_X = DEV.x + 18, DRN_X = DEV.x + DEV.w - 18 - WELL_W;
35
+ const CHAN_X0 = SRC_X + WELL_W, CHAN_X1 = DRN_X;
36
+ const CHAN_Y = 116;
37
+ const OX_Y = WELL_TOP - 12, OX_H = 8;
38
+ const GATE_Y = OX_Y - 16, GATE_H = 14;
39
+ const GATE_X0 = CHAN_X0 - 12, GATE_X1 = CHAN_X1 + 12;
40
+ const ELEC = "var(--stage-semi-n, oklch(0.62 0.18 250))";
41
+ const HOLE = "var(--stage-semi-p, oklch(0.6 0.19 25))";
42
+ const N_FILL = "color-mix(in oklab, var(--stage-semi-n, oklch(0.62 0.18 250)) 18%, var(--stage-bg))";
43
+ const P_FILL = "color-mix(in oklab, var(--stage-semi-p, oklch(0.6 0.19 25)) 12%, var(--stage-bg))";
44
+ const METAL = "var(--stage-metal)";
45
+ const OXIDE = "color-mix(in oklab, var(--stage-metal) 28%, var(--stage-bg))";
46
+ const MUTED = "var(--stage-muted)";
47
+ const hash = (i, s) => {
48
+ let x = (Math.imul(i + 1, 73856093) ^ Math.imul(s + 1, 19349663)) >>> 0;
49
+ x ^= x >>> 13;
50
+ x = Math.imul(x, 1274126177) >>> 0;
51
+ x ^= x >>> 16;
52
+ return x % 1e5 / 1e5;
53
+ };
54
+ const px = (n) => Math.round(n);
55
+ function Electron({ x, y, o = 1 }) {
56
+ const cx = px(x), cy = px(y);
57
+ return /* @__PURE__ */ jsxs("g", {
58
+ style: { pointerEvents: "none" },
59
+ opacity: o,
60
+ children: [/* @__PURE__ */ jsx("circle", {
61
+ cx,
62
+ cy,
63
+ r: 4.5,
64
+ fill: ELEC
65
+ }), /* @__PURE__ */ jsx("line", {
66
+ x1: cx - 2,
67
+ y1: cy,
68
+ x2: cx + 2,
69
+ y2: cy,
70
+ stroke: "var(--stage-bg)",
71
+ strokeWidth: 1.4,
72
+ strokeLinecap: "round"
73
+ })]
74
+ });
75
+ }
76
+ function Hole({ x, y, o = 1 }) {
77
+ const cx = px(x), cy = px(y);
78
+ return /* @__PURE__ */ jsxs("g", {
79
+ style: { pointerEvents: "none" },
80
+ opacity: o,
81
+ children: [
82
+ /* @__PURE__ */ jsx("circle", {
83
+ cx,
84
+ cy,
85
+ r: 4.5,
86
+ fill: "none",
87
+ stroke: HOLE,
88
+ strokeWidth: 1.6
89
+ }),
90
+ /* @__PURE__ */ jsx("line", {
91
+ x1: cx - 2,
92
+ y1: cy,
93
+ x2: cx + 2,
94
+ y2: cy,
95
+ stroke: HOLE,
96
+ strokeWidth: 1.4,
97
+ strokeLinecap: "round"
98
+ }),
99
+ /* @__PURE__ */ jsx("line", {
100
+ x1: cx,
101
+ y1: cy - 2,
102
+ x2: cx,
103
+ y2: cy + 2,
104
+ stroke: HOLE,
105
+ strokeWidth: 1.4,
106
+ strokeLinecap: "round"
107
+ })
108
+ ]
109
+ });
110
+ }
111
+ /** a spread spawn point that is also the carrier's HOME (so it jiggles there, not wanders off). */
112
+ const sited = (b, seed) => {
113
+ const p = inBox(b, seed);
114
+ return {
115
+ x: p.x,
116
+ y: p.y,
117
+ hx: p.x,
118
+ hy: p.y
119
+ };
120
+ };
121
+ /** draw an engine carrier pool as electron / hole glyphs (positions in-bounds, opacity tweened). */
122
+ const renderCarriers = (cs) => cs.filter((c) => (c.o ?? 1) > .02).map((c) => c.t === "e" ? /* @__PURE__ */ jsx(Electron, {
123
+ x: c.x,
124
+ y: c.y,
125
+ o: c.o ?? 1
126
+ }, c.id) : /* @__PURE__ */ jsx(Hole, {
127
+ x: c.x,
128
+ y: c.y,
129
+ o: c.o ?? 1
130
+ }, c.id));
131
+ function MosfetInsideLab({ pmos = false, vth = 1.5, k = .02, title = pmos ? "Inside the PMOS: the p-channel mirror" : "Inside the transistor: building the channel", prompt = pmos ? "The mirror of the NMOS: an n-type substrate, p+ source and drain, holes as the carriers. Pull the gate BELOW the source and holes are drawn up to invert the surface into a p-channel; the source-drain voltage then drifts them across." : "Turn the gate voltage. Below the threshold it only clears a depletion region, no path. Past it, electrons are pulled up to invert the surface into an n-channel, and the drain voltage drifts them across as current.", ask, activity = pmos ? "pmos-inside" : "mosfet-inside" } = {}) {
132
+ const [Vg, setVg] = useState(0);
133
+ const [Vd, setVd] = useState(2);
134
+ const VDD = 5;
135
+ const sol = solveDC(pmos ? [
136
+ {
137
+ kind: "V",
138
+ n1: 1,
139
+ n2: 0,
140
+ value: VDD
141
+ },
142
+ {
143
+ kind: "V",
144
+ n1: 3,
145
+ n2: 0,
146
+ value: VDD - Vg
147
+ },
148
+ {
149
+ kind: "V",
150
+ n1: 2,
151
+ n2: 0,
152
+ value: VDD - Vd
153
+ },
154
+ {
155
+ kind: "M",
156
+ pmos: true,
157
+ n1: 2,
158
+ n2: 1,
159
+ n3: 3,
160
+ value: 0,
161
+ vth,
162
+ k,
163
+ id: "q"
164
+ }
165
+ ] : [
166
+ {
167
+ kind: "V",
168
+ n1: 3,
169
+ n2: 0,
170
+ value: Vg
171
+ },
172
+ {
173
+ kind: "V",
174
+ n1: 2,
175
+ n2: 0,
176
+ value: Vd
177
+ },
178
+ {
179
+ kind: "M",
180
+ n1: 2,
181
+ n2: 0,
182
+ n3: 3,
183
+ value: 0,
184
+ vth,
185
+ k,
186
+ id: "q"
187
+ }
188
+ ]);
189
+ const Id = Math.abs(sol.current["q"] ?? 0) * 1e3;
190
+ const subFill = pmos ? N_FILL : P_FILL, wellFill = pmos ? P_FILL : N_FILL;
191
+ const wellStroke = pmos ? HOLE : ELEC, chanColor = pmos ? HOLE : ELEC;
192
+ const subLabel = pmos ? "n-type substrate (electrons, −)" : "p-type substrate (holes, +)";
193
+ const wellType = pmos ? "p+" : "n+";
194
+ const carrierWord = pmos ? "holes" : "electrons";
195
+ const chanWord = pmos ? "p-channel" : "n-channel";
196
+ const wcT = pmos ? "h" : "e";
197
+ const scT = pmos ? "e" : "h";
198
+ const on = Vg >= vth && Id > .02;
199
+ const inv = Math.max(0, Math.min(1, (Vg - vth) / 2.5));
200
+ const depl = Math.max(0, Math.min(1, Vg / vth));
201
+ const deplDepth = depl * 40;
202
+ const DEV_BOT = DEV.y + DEV.h;
203
+ const speed = Math.max(.4, Math.min(2.4, Id / 1.2));
204
+ const nChan = on ? Math.max(2, Math.round(inv * 9)) : 0;
205
+ const colBox = () => ({
206
+ x: CHAN_X0 + 12,
207
+ y: 132 + deplDepth,
208
+ w: CHAN_X1 - CHAN_X0 - 24,
209
+ h: Math.max(8, WELL_BOT - CHAN_Y - 26 - deplDepth)
210
+ });
211
+ const resident = useCarrierSim(() => {
212
+ const wL = {
213
+ x: SRC_X + 8,
214
+ y: 122,
215
+ w: WELL_W - 16,
216
+ h: WELL_BOT - WELL_TOP - 40
217
+ };
218
+ const wR = {
219
+ x: DRN_X + 8,
220
+ y: 122,
221
+ w: WELL_W - 16,
222
+ h: WELL_BOT - WELL_TOP - 40
223
+ };
224
+ const sb = {
225
+ x: DEV.x + 16,
226
+ y: 256,
227
+ w: DEV.w - 32,
228
+ h: DEV_BOT - WELL_BOT - 16
229
+ };
230
+ const col = colBox();
231
+ const out = [];
232
+ for (let i = 0; i < 7; i++) out.push({
233
+ id: i,
234
+ t: wcT,
235
+ o: 1,
236
+ box: wL,
237
+ ...sited(wL, i * 7 + 1)
238
+ });
239
+ for (let i = 0; i < 7; i++) out.push({
240
+ id: 10 + i,
241
+ t: wcT,
242
+ o: 1,
243
+ box: wR,
244
+ ...sited(wR, i * 7 + 3)
245
+ });
246
+ for (let i = 0; i < 7; i++) out.push({
247
+ id: 20 + i,
248
+ t: scT,
249
+ o: 1,
250
+ box: sb,
251
+ ...sited(sb, i * 7 + 5)
252
+ });
253
+ for (let i = 0; i < 4; i++) out.push({
254
+ id: 30 + i,
255
+ t: scT,
256
+ o: 1,
257
+ box: col,
258
+ ...sited(col, i * 7 + 9)
259
+ });
260
+ return out;
261
+ }, (cs, step) => {
262
+ const col = colBox();
263
+ return stepCarriers(cs.map((c) => c.id >= 30 && c.id < 40 ? {
264
+ ...c,
265
+ box: col,
266
+ hy: Math.max(col.y + 4, Math.min(col.y + col.h - 4, c.hy ?? col.y + col.h / 2))
267
+ } : c), step, {
268
+ x: DEV.x,
269
+ y: DEV.y,
270
+ w: DEV.w,
271
+ h: DEV.h
272
+ }, {
273
+ jitter: .9,
274
+ speed: .7,
275
+ damp: .85,
276
+ spring: .05
277
+ });
278
+ }, true, `${pmos}`);
279
+ const MAX_CHAN = 9;
280
+ const chanBox = {
281
+ x: CHAN_X0 + 4,
282
+ y: CHAN_Y - 5,
283
+ w: CHAN_X1 - CHAN_X0 - 8,
284
+ h: 12
285
+ };
286
+ const channel = useCarrierSim(() => Array.from({ length: MAX_CHAN }, (_, i) => ({
287
+ id: 200 + i,
288
+ t: wcT,
289
+ slot: i,
290
+ o: 0,
291
+ box: chanBox,
292
+ ...inBox(chanBox, 100 + i)
293
+ })), (cs, step) => tweenOpacity(stepCarriers(cs, step, chanBox, {
294
+ drift: {
295
+ x: .9,
296
+ y: 0
297
+ },
298
+ jitter: .2,
299
+ speed: Math.max(.5, speed),
300
+ signed: false,
301
+ damp: .9
302
+ }), nChan), true, `${pmos}`);
303
+ const scene = /* @__PURE__ */ jsx("div", {
304
+ style: {
305
+ borderRadius: 14,
306
+ overflow: "hidden",
307
+ background: "var(--stage-bg)",
308
+ border: "1px solid var(--stage-grid)"
309
+ },
310
+ children: /* @__PURE__ */ jsxs("svg", {
311
+ viewBox: `0 0 ${W} ${H}`,
312
+ width: "100%",
313
+ role: "img",
314
+ "aria-label": `${pmos ? "PMOS" : "NMOS"} cross-section, gate drive ${Vg.toFixed(1)} volts, channel ${on ? "formed" : "absent"}`,
315
+ children: [
316
+ /* @__PURE__ */ jsx("rect", {
317
+ x: DEV.x,
318
+ y: DEV.y,
319
+ width: DEV.w,
320
+ height: DEV.h,
321
+ rx: 10,
322
+ fill: subFill,
323
+ stroke: METAL,
324
+ strokeWidth: 1
325
+ }),
326
+ /* @__PURE__ */ jsx(Tag, {
327
+ x: DEV.x + DEV.w / 2,
328
+ y: 272,
329
+ text: subLabel,
330
+ color: MUTED,
331
+ size: 11,
332
+ weight: 500
333
+ }),
334
+ /* @__PURE__ */ jsx("rect", {
335
+ x: SRC_X,
336
+ y: WELL_TOP,
337
+ width: WELL_W,
338
+ height: WELL_BOT - WELL_TOP,
339
+ rx: 6,
340
+ fill: wellFill,
341
+ stroke: wellStroke,
342
+ strokeWidth: 1.2
343
+ }),
344
+ /* @__PURE__ */ jsx("rect", {
345
+ x: DRN_X,
346
+ y: WELL_TOP,
347
+ width: WELL_W,
348
+ height: WELL_BOT - WELL_TOP,
349
+ rx: 6,
350
+ fill: wellFill,
351
+ stroke: wellStroke,
352
+ strokeWidth: 1.2
353
+ }),
354
+ /* @__PURE__ */ jsx(Tag, {
355
+ x: SRC_X + WELL_W / 2,
356
+ y: WELL_BOT - 8,
357
+ text: `${wellType} source`,
358
+ color: wellStroke,
359
+ size: 11,
360
+ weight: 700
361
+ }),
362
+ /* @__PURE__ */ jsx(Tag, {
363
+ x: DRN_X + WELL_W / 2,
364
+ y: WELL_BOT - 8,
365
+ text: `${wellType} drain`,
366
+ color: wellStroke,
367
+ size: 11,
368
+ weight: 700
369
+ }),
370
+ depl > .02 && !on && /* @__PURE__ */ jsx("rect", {
371
+ x: GATE_X0,
372
+ y: CHAN_Y,
373
+ width: GATE_X1 - GATE_X0,
374
+ height: 6 + deplDepth,
375
+ fill: "color-mix(in oklab, var(--stage-bg) 70%, transparent)",
376
+ stroke: MUTED,
377
+ strokeWidth: .8,
378
+ strokeDasharray: "3 3"
379
+ }),
380
+ inv > .02 && /* @__PURE__ */ jsx("rect", {
381
+ x: CHAN_X0,
382
+ y: CHAN_Y - 4,
383
+ width: CHAN_X1 - CHAN_X0,
384
+ height: 10,
385
+ rx: 3,
386
+ fill: `color-mix(in oklab, ${chanColor} ${Math.round(20 + inv * 50)}%, transparent)`
387
+ }),
388
+ /* @__PURE__ */ jsx("rect", {
389
+ x: GATE_X0,
390
+ y: OX_Y,
391
+ width: GATE_X1 - GATE_X0,
392
+ height: OX_H,
393
+ fill: OXIDE,
394
+ stroke: METAL,
395
+ strokeWidth: .6
396
+ }),
397
+ /* @__PURE__ */ jsx(Tag, {
398
+ x: GATE_X1 + 6,
399
+ y: 106,
400
+ text: "oxide",
401
+ color: MUTED,
402
+ size: 9.5,
403
+ weight: 500,
404
+ anchor: "start"
405
+ }),
406
+ /* @__PURE__ */ jsx("rect", {
407
+ x: GATE_X0,
408
+ y: GATE_Y,
409
+ width: GATE_X1 - GATE_X0,
410
+ height: GATE_H,
411
+ rx: 2,
412
+ fill: METAL
413
+ }),
414
+ /* @__PURE__ */ jsx(Lead, {
415
+ x: SRC_X + WELL_W / 2,
416
+ y1: WELL_TOP,
417
+ y2: DEV.y - 16,
418
+ label: "S",
419
+ sub: pmos ? `${VDD} V` : "0 V",
420
+ color: MUTED
421
+ }),
422
+ /* @__PURE__ */ jsx(Lead, {
423
+ x: DRN_X + WELL_W / 2,
424
+ y1: WELL_TOP,
425
+ y2: DEV.y - 16,
426
+ label: "D",
427
+ sub: `${(pmos ? VDD - Vd : Vd).toFixed(1)} V`,
428
+ color: on ? wellStroke : MUTED
429
+ }),
430
+ /* @__PURE__ */ jsx(Lead, {
431
+ x: (GATE_X0 + GATE_X1) / 2,
432
+ y1: GATE_Y,
433
+ y2: DEV.y - 16,
434
+ label: "G",
435
+ sub: `${(pmos ? VDD - Vg : Vg).toFixed(1)} V`,
436
+ color: on ? "var(--stage-good)" : wellStroke
437
+ }),
438
+ renderCarriers(resident),
439
+ renderCarriers(channel)
440
+ ]
441
+ })
442
+ });
443
+ const controls = /* @__PURE__ */ jsxs(ControlBar, { children: [/* @__PURE__ */ jsx(Field, {
444
+ label: pmos ? "source-gate drive" : "gate voltage Vg",
445
+ value: `${Vg.toFixed(1)} V`,
446
+ children: /* @__PURE__ */ jsx(Slider, {
447
+ value: Vg,
448
+ min: 0,
449
+ max: 5,
450
+ step: .1,
451
+ onChange: setVg,
452
+ ariaLabel: "gate drive"
453
+ })
454
+ }), /* @__PURE__ */ jsx(Field, {
455
+ label: pmos ? "source-drain drive" : "drain voltage Vd",
456
+ value: `${Vd.toFixed(1)} V`,
457
+ children: /* @__PURE__ */ jsx(Slider, {
458
+ value: Vd,
459
+ min: 0,
460
+ max: 5,
461
+ step: .1,
462
+ onChange: setVd,
463
+ ariaLabel: "drain drive"
464
+ })
465
+ })] });
466
+ const stage = !inv ? "off" : !on ? "depleting" : "on";
467
+ const aside = /* @__PURE__ */ jsxs("div", {
468
+ style: {
469
+ display: "flex",
470
+ flexDirection: "column",
471
+ gap: 10
472
+ },
473
+ children: [/* @__PURE__ */ jsx("div", {
474
+ className: "lab-pill",
475
+ "data-state": on ? "ok" : "no",
476
+ role: "status",
477
+ style: { alignSelf: "flex-start" },
478
+ children: stage === "off" ? "✗ gate not yet past threshold, no channel" : stage === "depleting" ? "… depletion only, still no path" : `✓ channel formed, ${carrierWord} drift S→D`
479
+ }), /* @__PURE__ */ jsx(Callout, {
480
+ tone: "result",
481
+ children: /* @__PURE__ */ jsxs("div", {
482
+ style: {
483
+ display: "grid",
484
+ gap: 6,
485
+ fontVariantNumeric: "tabular-nums",
486
+ fontSize: 13
487
+ },
488
+ children: [
489
+ /* @__PURE__ */ jsxs("span", { children: [
490
+ "gate drive = ",
491
+ /* @__PURE__ */ jsxs("strong", { children: [Vg.toFixed(1), " V"] }),
492
+ " (threshold V",
493
+ /* @__PURE__ */ jsx("sub", { children: "th" }),
494
+ " = ",
495
+ vth,
496
+ " V)"
497
+ ] }),
498
+ /* @__PURE__ */ jsxs("span", { children: [
499
+ "drain current I",
500
+ /* @__PURE__ */ jsx("sub", { children: "d" }),
501
+ " = ",
502
+ /* @__PURE__ */ jsx("strong", { children: Math.abs(Id) < .01 ? "≈ 0" : Id.toFixed(2) + " mA" })
503
+ ] }),
504
+ /* @__PURE__ */ jsx("span", {
505
+ style: { color: MUTED },
506
+ children: on ? `past threshold the surface inverts: a ${chanWord} of ${carrierWord} bridges source and drain` : `below threshold the gate only opens a depletion region: the ${wellType} wells stay isolated`
507
+ })
508
+ ]
509
+ })
510
+ })]
511
+ });
512
+ useCheckpoint({
513
+ solved: on,
514
+ activity: `semiconductor:${activity}`
515
+ });
516
+ return /* @__PURE__ */ jsx(LabFrame, {
517
+ title,
518
+ prompt,
519
+ controls,
520
+ aside,
521
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
522
+ ask,
523
+ activity
524
+ }) : void 0,
525
+ children: scene
526
+ });
527
+ }
528
+ const PJ = {
529
+ x: 44,
530
+ y: 96,
531
+ w: 472,
532
+ h: 150,
533
+ junc: 280
534
+ };
535
+ const PJ_BOT = PJ.y + PJ.h;
536
+ /** A fixed (immobile) ionised dopant core left behind in the depletion region. */
537
+ function Ion({ x, y, sign }) {
538
+ const col = sign === "+" ? ELEC : HOLE;
539
+ const cx = px(x), cy = px(y);
540
+ return /* @__PURE__ */ jsxs("g", {
541
+ style: { pointerEvents: "none" },
542
+ children: [/* @__PURE__ */ jsx("circle", {
543
+ cx,
544
+ cy,
545
+ r: 6,
546
+ fill: "none",
547
+ stroke: col,
548
+ strokeWidth: 1,
549
+ strokeDasharray: "2 1.5"
550
+ }), /* @__PURE__ */ jsx("text", {
551
+ x: cx,
552
+ y: cy,
553
+ fill: col,
554
+ fontSize: 9,
555
+ fontWeight: 700,
556
+ textAnchor: "middle",
557
+ dominantBaseline: "central",
558
+ children: sign
559
+ })]
560
+ });
561
+ }
562
+ function PnJunctionLab({ title = "Inside the diode: the PN junction", prompt = "An n-region (free electrons) meets a p-region (free holes). Where they touch, carriers recombine and leave a depletion region of fixed ions with a built-in field. Bias it: forward narrows the barrier and current floods across; reverse widens it and it blocks.", ask, activity = "pn-junction" } = {}) {
563
+ const [bias, setBias] = useState(0);
564
+ const Id = (solveDC([
565
+ {
566
+ kind: "V",
567
+ n1: 1,
568
+ n2: 0,
569
+ value: bias
570
+ },
571
+ {
572
+ kind: "R",
573
+ n1: 1,
574
+ n2: 2,
575
+ value: 40
576
+ },
577
+ {
578
+ kind: "D",
579
+ n1: 2,
580
+ n2: 0,
581
+ value: 0,
582
+ id: "d"
583
+ }
584
+ ]).current["d"] ?? 0) * 1e3;
585
+ const forward = bias > .05 && Id > .2;
586
+ const reverse = bias < -.02;
587
+ const w = Math.max(7, 24 - (forward ? Math.min(15, Id / 6) : 0) + (reverse ? Math.min(40, -bias * 16) : 0));
588
+ const dL = PJ.junc - w, dR = PJ.junc + w;
589
+ const speed = Math.max(.5, Math.min(2.2, Id / 12));
590
+ const bounds = {
591
+ x: PJ.x,
592
+ y: PJ.y,
593
+ w: PJ.w,
594
+ h: PJ.h
595
+ };
596
+ const nBox = (right) => ({
597
+ x: PJ.x + 8,
598
+ y: PJ.y + 10,
599
+ w: Math.max(10, right - PJ.x - 12),
600
+ h: PJ.h - 20
601
+ });
602
+ const pBox = (left) => ({
603
+ x: left + 4,
604
+ y: PJ.y + 10,
605
+ w: Math.max(10, PJ.x + PJ.w - left - 12),
606
+ h: PJ.h - 20
607
+ });
608
+ const nHome = {
609
+ x: PJ.x + 12,
610
+ y: PJ.y + 12,
611
+ w: PJ.junc - 70 - (PJ.x + 12),
612
+ h: PJ.h - 24
613
+ };
614
+ const pHome = {
615
+ x: PJ.junc + 70,
616
+ y: PJ.y + 12,
617
+ w: PJ.x + PJ.w - (PJ.junc + 70) - 12,
618
+ h: PJ.h - 24
619
+ };
620
+ const carriers = useCarrierSim(() => {
621
+ const out = [];
622
+ for (let i = 0; i < 10; i++) out.push({
623
+ id: i,
624
+ t: "e",
625
+ ...sited(nHome, i * 5 + 1)
626
+ });
627
+ for (let i = 0; i < 10; i++) out.push({
628
+ id: 100 + i,
629
+ t: "h",
630
+ ...sited(pHome, i * 5 + 3)
631
+ });
632
+ return out;
633
+ }, (cs, step) => {
634
+ const eBox = nBox(forward ? PJ.junc + 10 : dL);
635
+ const hBox = pBox(forward ? PJ.junc - 10 : dR);
636
+ const boxed = cs.map((c) => ({
637
+ ...c,
638
+ box: c.t === "e" ? eBox : hBox
639
+ }));
640
+ if (forward) return recombine(stepCarriers(boxed, step, bounds, {
641
+ drift: {
642
+ x: .9,
643
+ y: 0
644
+ },
645
+ jitter: .45,
646
+ speed,
647
+ damp: .9
648
+ }), 12, step, (c) => c.t === "e" ? sited(nHome, c.id * 7 + step) : sited(pHome, c.id * 7 + step));
649
+ return stepCarriers(boxed, step, bounds, {
650
+ jitter: .7,
651
+ speed: .7,
652
+ damp: .85,
653
+ spring: .05
654
+ });
655
+ }, true, "pn");
656
+ const ions = [];
657
+ for (let i = 0; i < 5; i++) {
658
+ const y = PJ.y + 26 + i * (PJ.h - 40) / 4;
659
+ if (dL - 14 > PJ.x) ions.push(/* @__PURE__ */ jsx(Ion, {
660
+ x: (PJ.x + dL) / 2 + (hash(i, 7) - .5) * (dL - PJ.x - 20),
661
+ y,
662
+ sign: "+"
663
+ }, `in${i}`));
664
+ if (dR + 14 < PJ.x + PJ.w) ions.push(/* @__PURE__ */ jsx(Ion, {
665
+ x: (dR + PJ.x + PJ.w) / 2 + (hash(i, 8) - .5) * (PJ.x + PJ.w - dR - 20),
666
+ y,
667
+ sign: "−"
668
+ }, `ip${i}`));
669
+ }
670
+ const scene = /* @__PURE__ */ jsx("div", {
671
+ style: {
672
+ borderRadius: 14,
673
+ overflow: "hidden",
674
+ background: "var(--stage-bg)",
675
+ border: "1px solid var(--stage-grid)"
676
+ },
677
+ children: /* @__PURE__ */ jsxs("svg", {
678
+ viewBox: `0 0 ${W} 300`,
679
+ width: "100%",
680
+ role: "img",
681
+ "aria-label": `PN junction, ${forward ? "forward biased, conducting" : reverse ? "reverse biased, blocking" : "unbiased"}`,
682
+ children: [
683
+ /* @__PURE__ */ jsx("rect", {
684
+ x: PJ.x,
685
+ y: PJ.y,
686
+ width: PJ.junc - PJ.x,
687
+ height: PJ.h,
688
+ fill: N_FILL,
689
+ stroke: ELEC,
690
+ strokeWidth: 1
691
+ }),
692
+ /* @__PURE__ */ jsx("rect", {
693
+ x: PJ.junc,
694
+ y: PJ.y,
695
+ width: PJ.x + PJ.w - PJ.junc,
696
+ height: PJ.h,
697
+ fill: P_FILL,
698
+ stroke: HOLE,
699
+ strokeWidth: 1
700
+ }),
701
+ /* @__PURE__ */ jsx(Tag, {
702
+ x: (PJ.x + dL) / 2,
703
+ y: PJ.y - 8,
704
+ text: "n-type (electrons −)",
705
+ color: ELEC,
706
+ size: 12,
707
+ weight: 700
708
+ }),
709
+ /* @__PURE__ */ jsx(Tag, {
710
+ x: (dR + PJ.x + PJ.w) / 2,
711
+ y: PJ.y - 8,
712
+ text: "p-type (holes +)",
713
+ color: HOLE,
714
+ size: 12,
715
+ weight: 700
716
+ }),
717
+ /* @__PURE__ */ jsx("rect", {
718
+ x: dL,
719
+ y: PJ.y,
720
+ width: 2 * w,
721
+ height: PJ.h,
722
+ fill: "color-mix(in oklab, var(--stage-bg) 66%, transparent)",
723
+ stroke: "var(--stage-muted)",
724
+ strokeWidth: .8,
725
+ strokeDasharray: "3 3"
726
+ }),
727
+ /* @__PURE__ */ jsx(Tag, {
728
+ x: PJ.junc,
729
+ y: PJ_BOT + 16,
730
+ text: "depletion region (fixed ions, built-in field)",
731
+ color: MUTED,
732
+ size: 10,
733
+ weight: 500
734
+ }),
735
+ w > 9 && /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("line", {
736
+ x1: dL + 4,
737
+ y1: PJ.y + PJ.h / 2,
738
+ x2: dR - 4,
739
+ y2: PJ.y + PJ.h / 2,
740
+ stroke: "var(--stage-muted)",
741
+ strokeWidth: 1.4,
742
+ markerEnd: "url(#stage-arrow)"
743
+ }), /* @__PURE__ */ jsx(Tag, {
744
+ x: PJ.junc,
745
+ y: PJ.y + PJ.h / 2 - 6,
746
+ text: "E",
747
+ color: MUTED,
748
+ size: 9,
749
+ weight: 500
750
+ })] }),
751
+ ions,
752
+ renderCarriers(carriers)
753
+ ]
754
+ })
755
+ });
756
+ const controls = /* @__PURE__ */ jsx(ControlBar, { children: /* @__PURE__ */ jsx(Field, {
757
+ label: "bias voltage",
758
+ value: `${bias.toFixed(2)} V`,
759
+ children: /* @__PURE__ */ jsx(Slider, {
760
+ value: bias,
761
+ min: -3,
762
+ max: .9,
763
+ step: .05,
764
+ onChange: setBias,
765
+ ariaLabel: "bias voltage"
766
+ })
767
+ }) });
768
+ const aside = /* @__PURE__ */ jsxs("div", {
769
+ style: {
770
+ display: "flex",
771
+ flexDirection: "column",
772
+ gap: 10
773
+ },
774
+ children: [/* @__PURE__ */ jsx("div", {
775
+ className: "lab-pill",
776
+ "data-state": forward ? "ok" : "no",
777
+ role: "status",
778
+ style: { alignSelf: "flex-start" },
779
+ children: forward ? "✓ forward: barrier thin, carriers flood across" : reverse ? "✗ reverse: barrier wide, it blocks" : "— no bias: equilibrium barrier"
780
+ }), /* @__PURE__ */ jsx(Callout, {
781
+ tone: "result",
782
+ children: /* @__PURE__ */ jsxs("div", {
783
+ style: {
784
+ display: "grid",
785
+ gap: 6,
786
+ fontVariantNumeric: "tabular-nums",
787
+ fontSize: 13
788
+ },
789
+ children: [
790
+ /* @__PURE__ */ jsxs("span", { children: ["bias = ", /* @__PURE__ */ jsxs("strong", { children: [bias.toFixed(2), " V"] })] }),
791
+ /* @__PURE__ */ jsxs("span", { children: ["diode current = ", /* @__PURE__ */ jsx("strong", { children: Math.abs(Id) < .05 ? "≈ 0" : Id.toFixed(1) + " mA" })] }),
792
+ /* @__PURE__ */ jsx("span", {
793
+ style: { color: MUTED },
794
+ children: forward ? "past ~0.6 V the barrier collapses: electrons and holes pour across and recombine" : "the depletion region is a carrier-free barrier; reverse bias only widens it"
795
+ })
796
+ ]
797
+ })
798
+ })]
799
+ });
800
+ useCheckpoint({
801
+ solved: forward,
802
+ activity: `semiconductor:${activity}`
803
+ });
804
+ return /* @__PURE__ */ jsx(LabFrame, {
805
+ title,
806
+ prompt,
807
+ controls,
808
+ aside,
809
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
810
+ ask,
811
+ activity
812
+ }) : void 0,
813
+ children: scene
814
+ });
815
+ }
816
+ const LAT = {
817
+ x0: 96,
818
+ y0: 96,
819
+ dx: 116,
820
+ dy: 78,
821
+ cols: 4,
822
+ rows: 3
823
+ };
824
+ const atomAt = (c, r) => ({
825
+ x: LAT.x0 + c * LAT.dx,
826
+ y: LAT.y0 + r * LAT.dy
827
+ });
828
+ const DOPE_C = 2, DOPE_R = 1;
829
+ const C_DONOR = "var(--stage-good, oklch(0.7 0.15 150))";
830
+ const C_ACCEPTOR = "var(--stage-warn, oklch(0.78 0.15 75))";
831
+ function SiAtom({ x, y, label, fill, stroke }) {
832
+ return /* @__PURE__ */ jsxs("g", {
833
+ style: { pointerEvents: "none" },
834
+ children: [/* @__PURE__ */ jsx("circle", {
835
+ cx: px(x),
836
+ cy: px(y),
837
+ r: 17,
838
+ fill,
839
+ stroke,
840
+ strokeWidth: 1.5
841
+ }), /* @__PURE__ */ jsx("text", {
842
+ x: px(x),
843
+ y: px(y),
844
+ fill: stroke,
845
+ fontSize: 11,
846
+ fontWeight: 700,
847
+ textAnchor: "middle",
848
+ dominantBaseline: "central",
849
+ children: label
850
+ })]
851
+ });
852
+ }
853
+ /** the shared electron pair on a covalent bond (two small dots offset across the bond). */
854
+ function Bond({ a, b, broken }) {
855
+ const mx = (a.x + b.x) / 2, my = (a.y + b.y) / 2;
856
+ const horiz = Math.abs(b.x - a.x) > Math.abs(b.y - a.y);
857
+ const ox = horiz ? 0 : 4, oy = horiz ? 4 : 0;
858
+ const dot = "var(--stage-muted)";
859
+ return /* @__PURE__ */ jsxs("g", {
860
+ style: { pointerEvents: "none" },
861
+ children: [
862
+ /* @__PURE__ */ jsx("line", {
863
+ x1: px(a.x),
864
+ y1: px(a.y),
865
+ x2: px(b.x),
866
+ y2: px(b.y),
867
+ stroke: "var(--stage-grid)",
868
+ strokeWidth: 1.4
869
+ }),
870
+ /* @__PURE__ */ jsx("circle", {
871
+ cx: px(mx - ox),
872
+ cy: px(my - oy),
873
+ r: 2.6,
874
+ fill: dot
875
+ }),
876
+ !broken && /* @__PURE__ */ jsx("circle", {
877
+ cx: px(mx + ox),
878
+ cy: px(my + oy),
879
+ r: 2.6,
880
+ fill: dot
881
+ })
882
+ ]
883
+ });
884
+ }
885
+ function SiliconLatticeLab({ mode: mode0 = "intrinsic", temperature: temp0 = .2, lockDoping = false, showTemperature = true, title = "What is a semiconductor? Silicon and doping", prompt = "Pure silicon: every atom shares its four outer electrons in covalent bonds, so almost none are free, a poor conductor. Dope it: a donor atom brings a spare electron (n-type), an acceptor leaves a hole (p-type). Those carriers are what carry current. Heat also frees pairs.", ask, activity = "silicon-lattice" } = {}) {
886
+ const [mode, setMode] = useState(mode0);
887
+ const [temp, setTemp] = useState(temp0);
888
+ const nPairs = Math.round(temp * 4);
889
+ const dopeAtom = atomAt(DOPE_C, DOPE_R);
890
+ const dopeRight = atomAt(3, DOPE_R);
891
+ const elecStart = {
892
+ x: dopeAtom.x + 22,
893
+ y: dopeAtom.y - 26
894
+ };
895
+ const holeStart = {
896
+ x: (dopeAtom.x + dopeRight.x) / 2,
897
+ y: dopeAtom.y
898
+ };
899
+ const LAT_BOUNDS = {
900
+ x: LAT.x0 - 26,
901
+ y: LAT.y0 - 4,
902
+ w: (LAT.cols - 1) * LAT.dx + 52,
903
+ h: (LAT.rows - 1) * LAT.dy + 30
904
+ };
905
+ const MAX_PAIRS = 4;
906
+ const carriers = useCarrierSim(() => {
907
+ const out = [];
908
+ if (mode === "n") out.push({
909
+ id: 0,
910
+ t: "e",
911
+ o: 1,
912
+ x: elecStart.x,
913
+ y: elecStart.y,
914
+ hx: elecStart.x,
915
+ hy: elecStart.y
916
+ });
917
+ if (mode === "p") out.push({
918
+ id: 1,
919
+ t: "h",
920
+ o: 1,
921
+ x: holeStart.x,
922
+ y: holeStart.y,
923
+ hx: holeStart.x,
924
+ hy: holeStart.y
925
+ });
926
+ for (let i = 0; i < MAX_PAIRS; i++) {
927
+ out.push({
928
+ id: 10 + i,
929
+ t: "e",
930
+ slot: i,
931
+ o: 0,
932
+ ...sited(LAT_BOUNDS, 70 + i)
933
+ });
934
+ out.push({
935
+ id: 30 + i,
936
+ t: "h",
937
+ slot: i,
938
+ o: 0,
939
+ ...sited(LAT_BOUNDS, 90 + i)
940
+ });
941
+ }
942
+ return out;
943
+ }, (cs, step) => tweenOpacity(stepCarriers(cs, step, LAT_BOUNDS, {
944
+ jitter: 1.3,
945
+ speed: .85,
946
+ damp: .85,
947
+ spring: .05
948
+ }), nPairs), true, `${mode}`);
949
+ const atoms = [];
950
+ const bonds = [];
951
+ for (let r = 0; r < LAT.rows; r++) for (let c = 0; c < LAT.cols; c++) {
952
+ const p = atomAt(c, r);
953
+ const isDope = mode !== "intrinsic" && c === DOPE_C && r === DOPE_R;
954
+ const fill = isDope ? mode === "n" ? `color-mix(in oklab, ${C_DONOR} 22%, var(--stage-bg))` : `color-mix(in oklab, ${C_ACCEPTOR} 24%, var(--stage-bg))` : "color-mix(in oklab, var(--stage-semi-n, oklch(0.62 0.18 250)) 14%, var(--stage-bg))";
955
+ const stroke = isDope ? mode === "n" ? C_DONOR : C_ACCEPTOR : ELEC;
956
+ atoms.push(/* @__PURE__ */ jsx(SiAtom, {
957
+ x: p.x,
958
+ y: p.y,
959
+ label: isDope ? mode === "n" ? "+5" : "+3" : "+4",
960
+ fill,
961
+ stroke
962
+ }, `a${c}-${r}`));
963
+ if (c < LAT.cols - 1) {
964
+ const q = atomAt(c + 1, r);
965
+ const acc = mode === "p" && c === DOPE_C && r === DOPE_R;
966
+ bonds.push(/* @__PURE__ */ jsx(Bond, {
967
+ a: p,
968
+ b: q,
969
+ broken: acc
970
+ }, `bh${c}-${r}`));
971
+ }
972
+ if (r < LAT.rows - 1) bonds.push(/* @__PURE__ */ jsx(Bond, {
973
+ a: p,
974
+ b: atomAt(c, r + 1)
975
+ }, `bv${c}-${r}`));
976
+ }
977
+ const scene = /* @__PURE__ */ jsx("div", {
978
+ style: {
979
+ borderRadius: 14,
980
+ overflow: "hidden",
981
+ background: "var(--stage-bg)",
982
+ border: "1px solid var(--stage-grid)"
983
+ },
984
+ children: /* @__PURE__ */ jsxs("svg", {
985
+ viewBox: `0 0 ${W} 320`,
986
+ width: "100%",
987
+ role: "img",
988
+ "aria-label": `silicon lattice, ${mode === "intrinsic" ? "pure" : mode === "n" ? "n-type doped" : "p-type doped"}`,
989
+ children: [
990
+ bonds,
991
+ atoms,
992
+ renderCarriers(carriers)
993
+ ]
994
+ })
995
+ });
996
+ const controls = /* @__PURE__ */ jsxs(ControlBar, { children: [!lockDoping && /* @__PURE__ */ jsx(Field, {
997
+ label: "doping",
998
+ children: /* @__PURE__ */ jsx("div", {
999
+ style: {
1000
+ display: "flex",
1001
+ gap: 6
1002
+ },
1003
+ children: [
1004
+ "intrinsic",
1005
+ "n",
1006
+ "p"
1007
+ ].map((m) => /* @__PURE__ */ jsx("button", {
1008
+ type: "button",
1009
+ onClick: () => setMode(m),
1010
+ className: "lab-chip",
1011
+ "data-active": mode === m,
1012
+ style: {
1013
+ padding: "5px 10px",
1014
+ fontSize: 12,
1015
+ fontWeight: 600,
1016
+ borderRadius: 8,
1017
+ cursor: "pointer",
1018
+ border: "1px solid var(--stage-grid)",
1019
+ background: mode === m ? "var(--stage-accent)" : "transparent",
1020
+ color: mode === m ? "var(--stage-bg)" : "var(--stage-fg)"
1021
+ },
1022
+ children: m === "intrinsic" ? "pure Si" : m === "n" ? "n-type (donor)" : "p-type (acceptor)"
1023
+ }, m))
1024
+ })
1025
+ }), showTemperature && /* @__PURE__ */ jsx(Field, {
1026
+ label: "temperature",
1027
+ value: temp < .33 ? "cool" : temp < .66 ? "warm" : "hot",
1028
+ children: /* @__PURE__ */ jsx(Slider, {
1029
+ value: temp,
1030
+ min: 0,
1031
+ max: 1,
1032
+ step: .05,
1033
+ onChange: setTemp,
1034
+ ariaLabel: "temperature"
1035
+ })
1036
+ })] });
1037
+ const aside = /* @__PURE__ */ jsxs("div", {
1038
+ style: {
1039
+ display: "flex",
1040
+ flexDirection: "column",
1041
+ gap: 10
1042
+ },
1043
+ children: [/* @__PURE__ */ jsx("div", {
1044
+ className: "lab-pill",
1045
+ "data-state": mode === "intrinsic" && nPairs === 0 ? "no" : "ok",
1046
+ role: "status",
1047
+ style: { alignSelf: "flex-start" },
1048
+ children: mode === "intrinsic" ? nPairs > 0 ? "~ weak intrinsic conduction (heat frees pairs)" : "✗ pure Si: bonds full, poor conductor" : mode === "n" ? "✓ n-type: spare electrons carry current" : "✓ p-type: holes carry current"
1049
+ }), /* @__PURE__ */ jsx(Callout, {
1050
+ tone: "result",
1051
+ children: /* @__PURE__ */ jsxs("div", {
1052
+ style: {
1053
+ display: "grid",
1054
+ gap: 6,
1055
+ fontSize: 13
1056
+ },
1057
+ children: [/* @__PURE__ */ jsxs("span", { children: ["majority carriers: ", /* @__PURE__ */ jsx("strong", { children: mode === "n" ? "free electrons (−)" : mode === "p" ? "holes (+)" : nPairs > 0 ? "thermal electron–hole pairs" : "almost none" })] }), /* @__PURE__ */ jsx("span", {
1058
+ style: { color: MUTED },
1059
+ children: mode === "intrinsic" ? "each Si (+4) shares 4 electrons in bonds, so few are free; heating breaks bonds and frees pairs" : mode === "n" ? "the donor (+5) has one electron too many for the bonds: it roams free and carries charge" : "the acceptor (+3) is one electron short, leaving a hole in a bond that moves like a positive carrier"
1060
+ })]
1061
+ })
1062
+ })]
1063
+ });
1064
+ useCheckpoint({
1065
+ solved: mode === "intrinsic" ? nPairs > 0 : true,
1066
+ activity: `semiconductor:${activity}:${mode}`
1067
+ });
1068
+ return /* @__PURE__ */ jsx(LabFrame, {
1069
+ title,
1070
+ prompt,
1071
+ controls,
1072
+ aside,
1073
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
1074
+ ask,
1075
+ activity
1076
+ }) : void 0,
1077
+ children: scene
1078
+ });
1079
+ }
1080
+ const CD = {
1081
+ x: 70,
1082
+ y: 100,
1083
+ w: 420,
1084
+ h: 120
1085
+ };
1086
+ const CD_MID = CD.y + CD.h / 2;
1087
+ function ConductionLab({ title = "Why current flows: electrons drifting in a field", prompt = "A conductor is a sea of free electrons in fixed positive ion cores. With no voltage they only jiggle thermally, fast but going nowhere, so no current. Apply a voltage and the field gives every electron a slow DRIFT on top of that jiggle: that net drift is the current. Double the voltage, double the field, double the drift: current ∝ voltage is Ohm's law, from the inside.", ask, activity = "conduction" } = {}) {
1088
+ const [volts, setVolts] = useState(0);
1089
+ const I = volts / 50 * 1e3;
1090
+ const E = volts / 1;
1091
+ const flowing = volts > .02;
1092
+ const vDriftPx = .34 * E;
1093
+ const barBox = {
1094
+ x: CD.x + 10,
1095
+ y: CD.y + 12,
1096
+ w: CD.w - 20,
1097
+ h: CD.h - 24
1098
+ };
1099
+ const electrons = useCarrierSim(() => Array.from({ length: 14 }, (_, i) => ({
1100
+ id: i,
1101
+ t: "e",
1102
+ o: 1,
1103
+ box: barBox,
1104
+ ...sited(barBox, i * 7 + 1)
1105
+ })), (cs, step) => {
1106
+ return stepCarriers(cs.map((c) => {
1107
+ let hx = (c.hx ?? c.x) + vDriftPx;
1108
+ let x = c.x;
1109
+ if (hx > barBox.x + barBox.w - 4) {
1110
+ hx = barBox.x + 4;
1111
+ x = hx;
1112
+ }
1113
+ return {
1114
+ ...c,
1115
+ hx,
1116
+ x
1117
+ };
1118
+ }), step, barBox, {
1119
+ jitter: 1.1,
1120
+ speed: .9,
1121
+ damp: .82,
1122
+ spring: .06
1123
+ });
1124
+ }, true, "conduction");
1125
+ const ions = [];
1126
+ for (let r = 0; r < 3; r++) for (let c = 0; c < 6; c++) ions.push(/* @__PURE__ */ jsx(Ion, {
1127
+ x: CD.x + 44 + c * 66,
1128
+ y: CD.y + 30 + r * 30,
1129
+ sign: "+"
1130
+ }, `ion${r}-${c}`));
1131
+ const scene = /* @__PURE__ */ jsx("div", {
1132
+ style: {
1133
+ borderRadius: 14,
1134
+ overflow: "hidden",
1135
+ background: "var(--stage-bg)",
1136
+ border: "1px solid var(--stage-grid)"
1137
+ },
1138
+ children: /* @__PURE__ */ jsxs("svg", {
1139
+ viewBox: `0 0 ${W} 300`,
1140
+ width: "100%",
1141
+ role: "img",
1142
+ "aria-label": `conductor, ${flowing ? "voltage applied, electrons drift, current flows" : "no voltage, no current"}`,
1143
+ children: [
1144
+ /* @__PURE__ */ jsx("rect", {
1145
+ x: CD.x,
1146
+ y: CD.y,
1147
+ width: CD.w,
1148
+ height: CD.h,
1149
+ rx: 8,
1150
+ fill: "color-mix(in oklab, var(--stage-metal) 16%, var(--stage-bg))",
1151
+ stroke: "var(--stage-metal)",
1152
+ strokeWidth: 1
1153
+ }),
1154
+ /* @__PURE__ */ jsx(Lead, {
1155
+ x: CD.x,
1156
+ y1: CD_MID,
1157
+ y2: CD.y - 18,
1158
+ label: "−",
1159
+ sub: "0 V",
1160
+ color: MUTED
1161
+ }),
1162
+ /* @__PURE__ */ jsx(Lead, {
1163
+ x: CD.x + CD.w,
1164
+ y1: CD_MID,
1165
+ y2: CD.y - 18,
1166
+ label: "+",
1167
+ sub: `${volts.toFixed(1)} V`,
1168
+ color: flowing ? "var(--stage-good)" : MUTED
1169
+ }),
1170
+ flowing && /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("line", {
1171
+ x1: CD.x + CD.w / 2 + 30,
1172
+ y1: CD.y - 6,
1173
+ x2: CD.x + CD.w / 2 - 30,
1174
+ y2: CD.y - 6,
1175
+ stroke: "var(--stage-muted)",
1176
+ strokeWidth: 1.4,
1177
+ markerEnd: "url(#stage-arrow)"
1178
+ }), /* @__PURE__ */ jsx(Tag, {
1179
+ x: CD.x + CD.w / 2,
1180
+ y: CD.y - 12,
1181
+ text: "field E",
1182
+ color: MUTED,
1183
+ size: 10,
1184
+ weight: 500
1185
+ })] }),
1186
+ /* @__PURE__ */ jsx(Tag, {
1187
+ x: CD.x + CD.w / 2,
1188
+ y: CD.y + CD.h + 18,
1189
+ text: "conductor: free electrons (−) in fixed + ion cores",
1190
+ color: MUTED,
1191
+ size: 11,
1192
+ weight: 500
1193
+ }),
1194
+ ions,
1195
+ renderCarriers(electrons)
1196
+ ]
1197
+ })
1198
+ });
1199
+ const controls = /* @__PURE__ */ jsx(ControlBar, { children: /* @__PURE__ */ jsx(Field, {
1200
+ label: "applied voltage",
1201
+ value: `${volts.toFixed(1)} V`,
1202
+ children: /* @__PURE__ */ jsx(Slider, {
1203
+ value: volts,
1204
+ min: 0,
1205
+ max: 5,
1206
+ step: .1,
1207
+ onChange: setVolts,
1208
+ ariaLabel: "applied voltage"
1209
+ })
1210
+ }) });
1211
+ const aside = /* @__PURE__ */ jsxs("div", {
1212
+ style: {
1213
+ display: "flex",
1214
+ flexDirection: "column",
1215
+ gap: 10
1216
+ },
1217
+ children: [/* @__PURE__ */ jsx("div", {
1218
+ className: "lab-pill",
1219
+ "data-state": flowing ? "ok" : "no",
1220
+ role: "status",
1221
+ style: { alignSelf: "flex-start" },
1222
+ children: flowing ? "✓ electrons drift → current flows" : "✗ no field: electrons jiggle, no net flow"
1223
+ }), /* @__PURE__ */ jsx(Callout, {
1224
+ tone: "result",
1225
+ children: /* @__PURE__ */ jsxs("div", {
1226
+ style: {
1227
+ display: "grid",
1228
+ gap: 6,
1229
+ fontVariantNumeric: "tabular-nums",
1230
+ fontSize: 13
1231
+ },
1232
+ children: [
1233
+ /* @__PURE__ */ jsxs("span", { children: [
1234
+ "field E = V/L = ",
1235
+ /* @__PURE__ */ jsx("strong", { children: E.toFixed(1) }),
1236
+ " (∝ voltage)"
1237
+ ] }),
1238
+ /* @__PURE__ */ jsxs("span", { children: [
1239
+ "drift velocity v = μE = ",
1240
+ /* @__PURE__ */ jsx("strong", { children: vDriftPx.toFixed(2) }),
1241
+ " (a slow bias on fast jiggle)"
1242
+ ] }),
1243
+ /* @__PURE__ */ jsxs("span", { children: ["current I = V/R = ", /* @__PURE__ */ jsx("strong", { children: I < .05 ? "≈ 0" : I.toFixed(1) + " mA" })] }),
1244
+ /* @__PURE__ */ jsx("span", {
1245
+ style: { color: MUTED },
1246
+ children: "current ∝ voltage: that proportionality IS Ohm's law. Collisions with the ion cores limit the drift, that is the resistance R."
1247
+ })
1248
+ ]
1249
+ })
1250
+ })]
1251
+ });
1252
+ useCheckpoint({
1253
+ solved: flowing,
1254
+ activity: `semiconductor:${activity}`
1255
+ });
1256
+ return /* @__PURE__ */ jsx(LabFrame, {
1257
+ title,
1258
+ prompt,
1259
+ controls,
1260
+ aside,
1261
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
1262
+ ask,
1263
+ activity
1264
+ }) : void 0,
1265
+ children: scene
1266
+ });
1267
+ }
1268
+ const HB = {
1269
+ x: 80,
1270
+ y: 100,
1271
+ w: 400,
1272
+ h: 128
1273
+ };
1274
+ const HB_MID = HB.y + HB.h / 2;
1275
+ function HallEffectLab({ title = "The Hall effect: are the carriers electrons or holes?", prompt = "Push a current through a strip in a magnetic field. The field bends the moving carriers sideways, so charge piles up on one edge until a transverse Hall voltage builds. Electrons and holes carrying the SAME current bend to the same edge, but leave OPPOSITE charge there, so the Hall voltage's sign tells you which carrier a material has. This is how carrier type is actually measured.", ask, activity = "hall-effect" } = {}) {
1276
+ const [holes, setHoles] = useState(false);
1277
+ const [bField, setBField] = useState(.6);
1278
+ const reduceB = Math.abs(bField) < .05;
1279
+ const VH = bField * (holes ? 1 : -1);
1280
+ const carrierT = holes ? "h" : "e";
1281
+ const topEdge = bField >= 0;
1282
+ const box = {
1283
+ x: HB.x + 8,
1284
+ y: HB.y + 10,
1285
+ w: HB.w - 16,
1286
+ h: HB.h - 20
1287
+ };
1288
+ const carriers = useCarrierSim(() => Array.from({ length: 16 }, (_, i) => ({
1289
+ id: i,
1290
+ t: carrierT,
1291
+ o: 1,
1292
+ box,
1293
+ ...sited(box, i * 7 + 1)
1294
+ })), (cs, step) => {
1295
+ const driftX = (holes ? 1 : -1) * 1.1;
1296
+ const edgeY = topEdge ? box.y + 14 : box.y + box.h - 14;
1297
+ const defl = Math.min(.85, Math.abs(bField));
1298
+ return stepCarriers(cs.map((c) => {
1299
+ let hx = (c.hx ?? c.x) + driftX;
1300
+ if (hx > box.x + box.w - 4) hx = box.x + 4;
1301
+ if (hx < box.x + 4) hx = box.x + box.w - 4;
1302
+ const hy = inBox(box, c.id * 7 + 1).y + (edgeY - (box.y + box.h / 2)) * defl;
1303
+ return {
1304
+ ...c,
1305
+ hx,
1306
+ hy
1307
+ };
1308
+ }), step, box, {
1309
+ jitter: .9,
1310
+ speed: .9,
1311
+ damp: .82,
1312
+ spring: .06
1313
+ });
1314
+ }, true, `${holes}`);
1315
+ const bSyms = [];
1316
+ for (let r = 0; r < 3; r++) for (let c = 0; c < 7; c++) {
1317
+ const x = HB.x + 34 + c * 56, y = HB.y + 26 + r * 38;
1318
+ bSyms.push(bField >= 0 ? /* @__PURE__ */ jsxs("g", {
1319
+ style: { pointerEvents: "none" },
1320
+ opacity: reduceB ? .12 : .3,
1321
+ children: [/* @__PURE__ */ jsx("line", {
1322
+ x1: x - 3,
1323
+ y1: y - 3,
1324
+ x2: x + 3,
1325
+ y2: y + 3,
1326
+ stroke: "var(--stage-muted)",
1327
+ strokeWidth: 1
1328
+ }), /* @__PURE__ */ jsx("line", {
1329
+ x1: x - 3,
1330
+ y1: y + 3,
1331
+ x2: x + 3,
1332
+ y2: y - 3,
1333
+ stroke: "var(--stage-muted)",
1334
+ strokeWidth: 1
1335
+ })]
1336
+ }, `b${r}-${c}`) : /* @__PURE__ */ jsx("circle", {
1337
+ cx: x,
1338
+ cy: y,
1339
+ r: 1.6,
1340
+ fill: "var(--stage-muted)",
1341
+ opacity: .3
1342
+ }, `b${r}-${c}`));
1343
+ }
1344
+ const edgeCharge = (top) => {
1345
+ if (reduceB) return null;
1346
+ const sign = top === topEdge ? holes ? "+" : "−" : holes ? "−" : "+";
1347
+ const col = sign === "+" ? HOLE : ELEC;
1348
+ const y = top ? HB.y - 4 : HB.y + HB.h + 12;
1349
+ return /* @__PURE__ */ jsx(Tag, {
1350
+ x: HB.x + HB.w / 2,
1351
+ y,
1352
+ text: `${sign} ${sign} ${sign} ${sign} ${sign}`,
1353
+ color: col,
1354
+ size: 13,
1355
+ weight: 700
1356
+ });
1357
+ };
1358
+ const scene = /* @__PURE__ */ jsx("div", {
1359
+ style: {
1360
+ borderRadius: 14,
1361
+ overflow: "hidden",
1362
+ background: "var(--stage-bg)",
1363
+ border: "1px solid var(--stage-grid)"
1364
+ },
1365
+ children: /* @__PURE__ */ jsxs("svg", {
1366
+ viewBox: `0 0 ${W} 300`,
1367
+ width: "100%",
1368
+ role: "img",
1369
+ "aria-label": `Hall bar, ${holes ? "holes" : "electrons"}, field ${bField >= 0 ? "into" : "out of"} page`,
1370
+ children: [
1371
+ /* @__PURE__ */ jsx("rect", {
1372
+ x: HB.x,
1373
+ y: HB.y,
1374
+ width: HB.w,
1375
+ height: HB.h,
1376
+ rx: 8,
1377
+ fill: "color-mix(in oklab, var(--stage-metal) 12%, var(--stage-bg))",
1378
+ stroke: "var(--stage-metal)",
1379
+ strokeWidth: 1
1380
+ }),
1381
+ bSyms,
1382
+ /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("line", {
1383
+ x1: HB.x - 36,
1384
+ y1: HB_MID,
1385
+ x2: HB.x - 6,
1386
+ y2: HB_MID,
1387
+ stroke: "var(--stage-good)",
1388
+ strokeWidth: 2,
1389
+ markerEnd: "url(#stage-arrow)"
1390
+ }), /* @__PURE__ */ jsx(Tag, {
1391
+ x: HB.x - 40,
1392
+ y: HB_MID - 6,
1393
+ text: "I",
1394
+ color: "var(--stage-good)",
1395
+ size: 11,
1396
+ weight: 700,
1397
+ anchor: "end"
1398
+ })] }),
1399
+ /* @__PURE__ */ jsx("line", {
1400
+ x1: HB.x + HB.w + 6,
1401
+ y1: HB_MID,
1402
+ x2: HB.x + HB.w + 30,
1403
+ y2: HB_MID,
1404
+ stroke: "var(--stage-good)",
1405
+ strokeWidth: 2,
1406
+ markerEnd: "url(#stage-arrow)"
1407
+ }),
1408
+ edgeCharge(true),
1409
+ edgeCharge(false),
1410
+ /* @__PURE__ */ jsx(Tag, {
1411
+ x: HB.x + HB.w / 2,
1412
+ y: HB.y + HB.h + 28,
1413
+ text: `B field ${bField >= 0 ? "into the page (×)" : "out of the page (•)"} · carriers: ${holes ? "holes (+)" : "electrons (−)"}`,
1414
+ color: MUTED,
1415
+ size: 10.5,
1416
+ weight: 500
1417
+ }),
1418
+ renderCarriers(carriers)
1419
+ ]
1420
+ })
1421
+ });
1422
+ const controls = /* @__PURE__ */ jsxs(ControlBar, { children: [/* @__PURE__ */ jsx(Field, {
1423
+ label: "carrier type",
1424
+ children: /* @__PURE__ */ jsxs("div", {
1425
+ style: {
1426
+ display: "flex",
1427
+ gap: 6
1428
+ },
1429
+ children: [/* @__PURE__ */ jsx("button", {
1430
+ type: "button",
1431
+ onClick: () => setHoles(false),
1432
+ style: {
1433
+ padding: "5px 10px",
1434
+ fontSize: 12,
1435
+ fontWeight: 600,
1436
+ borderRadius: 8,
1437
+ cursor: "pointer",
1438
+ border: "1px solid var(--stage-grid)",
1439
+ background: !holes ? "var(--stage-accent)" : "transparent",
1440
+ color: !holes ? "var(--stage-bg)" : "var(--stage-fg)"
1441
+ },
1442
+ children: "electrons (n)"
1443
+ }), /* @__PURE__ */ jsx("button", {
1444
+ type: "button",
1445
+ onClick: () => setHoles(true),
1446
+ style: {
1447
+ padding: "5px 10px",
1448
+ fontSize: 12,
1449
+ fontWeight: 600,
1450
+ borderRadius: 8,
1451
+ cursor: "pointer",
1452
+ border: "1px solid var(--stage-grid)",
1453
+ background: holes ? "var(--stage-accent)" : "transparent",
1454
+ color: holes ? "var(--stage-bg)" : "var(--stage-fg)"
1455
+ },
1456
+ children: "holes (p)"
1457
+ })]
1458
+ })
1459
+ }), /* @__PURE__ */ jsx(Field, {
1460
+ label: "magnetic field",
1461
+ value: reduceB ? "off" : bField >= 0 ? "into page" : "out of page",
1462
+ children: /* @__PURE__ */ jsx(Slider, {
1463
+ value: bField,
1464
+ min: -1,
1465
+ max: 1,
1466
+ step: .05,
1467
+ onChange: setBField,
1468
+ ariaLabel: "magnetic field"
1469
+ })
1470
+ })] });
1471
+ const aside = /* @__PURE__ */ jsxs("div", {
1472
+ style: {
1473
+ display: "flex",
1474
+ flexDirection: "column",
1475
+ gap: 10
1476
+ },
1477
+ children: [/* @__PURE__ */ jsx("div", {
1478
+ className: "lab-pill",
1479
+ "data-state": reduceB ? "no" : "ok",
1480
+ role: "status",
1481
+ style: { alignSelf: "flex-start" },
1482
+ children: reduceB ? "— no field: carriers go straight, no Hall voltage" : `✓ carriers bend, ${holes ? "holes" : "electrons"} pile on one edge`
1483
+ }), /* @__PURE__ */ jsx(Callout, {
1484
+ tone: "result",
1485
+ children: /* @__PURE__ */ jsxs("div", {
1486
+ style: {
1487
+ display: "grid",
1488
+ gap: 6,
1489
+ fontVariantNumeric: "tabular-nums",
1490
+ fontSize: 13
1491
+ },
1492
+ children: [/* @__PURE__ */ jsxs("span", { children: [
1493
+ "Hall voltage V",
1494
+ /* @__PURE__ */ jsx("sub", { children: "H" }),
1495
+ " = ",
1496
+ /* @__PURE__ */ jsx("strong", { children: reduceB ? "≈ 0" : VH > 0 ? "+ (positive)" : "− (negative)" })
1497
+ ] }), /* @__PURE__ */ jsxs("span", {
1498
+ style: { color: MUTED },
1499
+ children: [
1500
+ "both carriers bend to the same edge, but electrons leave it negative and holes leave it positive. So V",
1501
+ /* @__PURE__ */ jsx("sub", { children: "H" }),
1502
+ " < 0 ⇒ ",
1503
+ /* @__PURE__ */ jsx("strong", { children: "electrons (n-type)" }),
1504
+ "; V",
1505
+ /* @__PURE__ */ jsx("sub", { children: "H" }),
1506
+ " > 0 ⇒ ",
1507
+ /* @__PURE__ */ jsx("strong", { children: "holes (p-type)" }),
1508
+ ". That sign is how a material's carrier type is measured."
1509
+ ]
1510
+ })]
1511
+ })
1512
+ })]
1513
+ });
1514
+ useCheckpoint({
1515
+ solved: !reduceB,
1516
+ activity: `semiconductor:${activity}`
1517
+ });
1518
+ return /* @__PURE__ */ jsx(LabFrame, {
1519
+ title,
1520
+ prompt,
1521
+ controls,
1522
+ aside,
1523
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
1524
+ ask,
1525
+ activity
1526
+ }) : void 0,
1527
+ children: scene
1528
+ });
1529
+ }
1530
+ const BJ = {
1531
+ y: 100,
1532
+ h: 132
1533
+ };
1534
+ const BJ_EM = {
1535
+ x0: 46,
1536
+ x1: 176
1537
+ };
1538
+ const BJ_BASE = {
1539
+ x0: 176,
1540
+ x1: 232
1541
+ };
1542
+ const BJ_COL = {
1543
+ x0: 232,
1544
+ x1: 516
1545
+ };
1546
+ const BJ_BOT = BJ.y + BJ.h;
1547
+ const BJ_MID = BJ.y + BJ.h / 2;
1548
+ function BjtInsideLab({ pnp = false, beta = 100, title = pnp ? "Inside the PNP: base current steers the rest" : "Inside the NPN: base current steers the rest", prompt = "Forward-bias the base-emitter junction. Carriers pour from the emitter into the THIN base, but only a sliver recombine there (the small base current): the rest are swept across into the collector. A tiny base current controls a much larger collector current.", ask, activity = pnp ? "pnp-bjt" : "npn-bjt" } = {}) {
1549
+ const [vbe, setVbe] = useState(0);
1550
+ const Ic = Math.min(50, (vbe > 0 ? 2e-14 * (Math.exp(Math.min(vbe / .02585, 40)) - 1) : 0) * 1e3);
1551
+ const Ib = Ic / beta;
1552
+ const on = Ic > .05;
1553
+ const speed = Math.max(.5, Math.min(2.6, Ic / 10));
1554
+ const emFill = pnp ? P_FILL : N_FILL, baseFill = pnp ? N_FILL : P_FILL;
1555
+ const emStroke = pnp ? HOLE : ELEC, baseStroke = pnp ? ELEC : HOLE;
1556
+ const emType = pnp ? "p" : "n", baseType = pnp ? "n" : "p";
1557
+ const mT = pnp ? "h" : "e";
1558
+ const bT = pnp ? "e" : "h";
1559
+ const nStream = on ? Math.max(3, Math.round(3 + Math.min(9, Ic / 4))) : 0;
1560
+ const emBox = {
1561
+ x: BJ_EM.x0 + 10,
1562
+ y: BJ.y + 12,
1563
+ w: BJ_EM.x1 - BJ_EM.x0 - 26,
1564
+ h: BJ.h - 24
1565
+ };
1566
+ const colBox = {
1567
+ x: BJ_COL.x0 + 20,
1568
+ y: BJ.y + 12,
1569
+ w: BJ_COL.x1 - BJ_COL.x0 - 40,
1570
+ h: BJ.h - 24
1571
+ };
1572
+ const baseBox = {
1573
+ x: BJ_BASE.x0 + 8,
1574
+ y: BJ.y + 14,
1575
+ w: BJ_BASE.x1 - BJ_BASE.x0 - 16,
1576
+ h: BJ.h - 28
1577
+ };
1578
+ const streamBox = {
1579
+ x: BJ_EM.x1 - 26,
1580
+ y: BJ_MID - BJ.h * .26,
1581
+ w: BJ_COL.x0 + 86 - (BJ_EM.x1 - 26),
1582
+ h: BJ.h * .52
1583
+ };
1584
+ const resident = useCarrierSim(() => {
1585
+ const out = [];
1586
+ for (let i = 0; i < 5; i++) out.push({
1587
+ id: i,
1588
+ t: mT,
1589
+ o: 1,
1590
+ box: emBox,
1591
+ ...sited(emBox, i * 7 + 1)
1592
+ });
1593
+ for (let i = 0; i < 7; i++) out.push({
1594
+ id: 20 + i,
1595
+ t: mT,
1596
+ o: 1,
1597
+ box: colBox,
1598
+ ...sited(colBox, i * 7 + 3)
1599
+ });
1600
+ for (let i = 0; i < 3; i++) out.push({
1601
+ id: 40 + i,
1602
+ t: bT,
1603
+ o: 1,
1604
+ box: baseBox,
1605
+ ...sited(baseBox, i * 7 + 5)
1606
+ });
1607
+ return out;
1608
+ }, (cs, step) => stepCarriers(cs, step, {
1609
+ x: BJ_EM.x0,
1610
+ y: BJ.y,
1611
+ w: BJ_COL.x1 - BJ_EM.x0,
1612
+ h: BJ.h
1613
+ }, {
1614
+ jitter: .85,
1615
+ speed: .65,
1616
+ damp: .85,
1617
+ spring: .05
1618
+ }), true, `${pnp}`);
1619
+ const MAX_STREAM = 12;
1620
+ const stream = useCarrierSim(() => Array.from({ length: MAX_STREAM }, (_, i) => ({
1621
+ id: 300 + i,
1622
+ t: mT,
1623
+ slot: i,
1624
+ o: 0,
1625
+ box: streamBox,
1626
+ ...inBox(streamBox, 200 + i)
1627
+ })), (cs, step) => {
1628
+ return tweenOpacity(stepCarriers(cs, step, streamBox, {
1629
+ drift: {
1630
+ x: 1,
1631
+ y: 0
1632
+ },
1633
+ jitter: .3,
1634
+ speed: Math.max(.6, speed),
1635
+ signed: false,
1636
+ damp: .9
1637
+ }).map((c) => c.x > streamBox.x + streamBox.w - 6 ? {
1638
+ ...c,
1639
+ x: streamBox.x + 4,
1640
+ y: streamBox.y + 4 + rand(c.id, step) * (streamBox.h - 8)
1641
+ } : c), nStream);
1642
+ }, true, `${pnp}`);
1643
+ const scene = /* @__PURE__ */ jsx("div", {
1644
+ style: {
1645
+ borderRadius: 14,
1646
+ overflow: "hidden",
1647
+ background: "var(--stage-bg)",
1648
+ border: "1px solid var(--stage-grid)"
1649
+ },
1650
+ children: /* @__PURE__ */ jsxs("svg", {
1651
+ viewBox: `0 0 ${W} 300`,
1652
+ width: "100%",
1653
+ role: "img",
1654
+ "aria-label": `${pnp ? "PNP" : "NPN"} transistor, ${on ? "forward active, conducting" : "off"}`,
1655
+ children: [
1656
+ /* @__PURE__ */ jsx("rect", {
1657
+ x: BJ_EM.x0,
1658
+ y: BJ.y,
1659
+ width: BJ_EM.x1 - BJ_EM.x0,
1660
+ height: BJ.h,
1661
+ fill: emFill,
1662
+ stroke: emStroke,
1663
+ strokeWidth: 1
1664
+ }),
1665
+ /* @__PURE__ */ jsx("rect", {
1666
+ x: BJ_BASE.x0,
1667
+ y: BJ.y,
1668
+ width: BJ_BASE.x1 - BJ_BASE.x0,
1669
+ height: BJ.h,
1670
+ fill: baseFill,
1671
+ stroke: baseStroke,
1672
+ strokeWidth: 1
1673
+ }),
1674
+ /* @__PURE__ */ jsx("rect", {
1675
+ x: BJ_COL.x0,
1676
+ y: BJ.y,
1677
+ width: BJ_COL.x1 - BJ_COL.x0,
1678
+ height: BJ.h,
1679
+ fill: emFill,
1680
+ stroke: emStroke,
1681
+ strokeWidth: 1
1682
+ }),
1683
+ /* @__PURE__ */ jsx(Tag, {
1684
+ x: (BJ_EM.x0 + BJ_EM.x1) / 2,
1685
+ y: BJ_BOT + 16,
1686
+ text: `emitter (${emType})`,
1687
+ color: emStroke,
1688
+ size: 11,
1689
+ weight: 600
1690
+ }),
1691
+ /* @__PURE__ */ jsx(Tag, {
1692
+ x: (BJ_BASE.x0 + BJ_BASE.x1) / 2,
1693
+ y: BJ.y - 8,
1694
+ text: `base (${baseType}, thin)`,
1695
+ color: baseStroke,
1696
+ size: 10,
1697
+ weight: 700
1698
+ }),
1699
+ /* @__PURE__ */ jsx(Tag, {
1700
+ x: (BJ_COL.x0 + BJ_COL.x1) / 2,
1701
+ y: BJ_BOT + 16,
1702
+ text: `collector (${emType})`,
1703
+ color: emStroke,
1704
+ size: 11,
1705
+ weight: 600
1706
+ }),
1707
+ /* @__PURE__ */ jsx(Lead, {
1708
+ x: (BJ_EM.x0 + BJ_EM.x1) / 2,
1709
+ y1: BJ.y,
1710
+ y2: BJ.y - 18,
1711
+ label: "E",
1712
+ sub: "",
1713
+ color: emStroke
1714
+ }),
1715
+ /* @__PURE__ */ jsx(Lead, {
1716
+ x: (BJ_BASE.x0 + BJ_BASE.x1) / 2,
1717
+ y1: BJ.y,
1718
+ y2: BJ.y - 40,
1719
+ label: "B",
1720
+ sub: `${vbe.toFixed(2)} V`,
1721
+ color: on ? "var(--stage-good)" : baseStroke
1722
+ }),
1723
+ /* @__PURE__ */ jsx(Lead, {
1724
+ x: (BJ_COL.x0 + BJ_COL.x1) / 2,
1725
+ y1: BJ.y,
1726
+ y2: BJ.y - 18,
1727
+ label: "C",
1728
+ sub: "",
1729
+ color: on ? emStroke : "var(--stage-muted)"
1730
+ }),
1731
+ renderCarriers(resident),
1732
+ renderCarriers(stream)
1733
+ ]
1734
+ })
1735
+ });
1736
+ const controls = /* @__PURE__ */ jsx(ControlBar, { children: /* @__PURE__ */ jsx(Field, {
1737
+ label: pnp ? "emitter-base drive" : "base-emitter Vbe",
1738
+ value: `${vbe.toFixed(2)} V`,
1739
+ children: /* @__PURE__ */ jsx(Slider, {
1740
+ value: vbe,
1741
+ min: 0,
1742
+ max: .8,
1743
+ step: .01,
1744
+ onChange: setVbe,
1745
+ ariaLabel: "base emitter voltage"
1746
+ })
1747
+ }) });
1748
+ const aside = /* @__PURE__ */ jsxs("div", {
1749
+ style: {
1750
+ display: "flex",
1751
+ flexDirection: "column",
1752
+ gap: 10
1753
+ },
1754
+ children: [/* @__PURE__ */ jsx("div", {
1755
+ className: "lab-pill",
1756
+ "data-state": on ? "ok" : "no",
1757
+ role: "status",
1758
+ style: { alignSelf: "flex-start" },
1759
+ children: on ? `✓ forward active: ${emType}→base→collector stream` : "✗ off: base junction not yet forward biased"
1760
+ }), /* @__PURE__ */ jsx(Callout, {
1761
+ tone: "result",
1762
+ children: /* @__PURE__ */ jsxs("div", {
1763
+ style: {
1764
+ display: "grid",
1765
+ gap: 6,
1766
+ fontVariantNumeric: "tabular-nums",
1767
+ fontSize: 13
1768
+ },
1769
+ children: [
1770
+ /* @__PURE__ */ jsxs("span", { children: [
1771
+ "base current I",
1772
+ /* @__PURE__ */ jsx("sub", { children: "B" }),
1773
+ " = ",
1774
+ /* @__PURE__ */ jsx("strong", { children: Ib < .001 ? "≈ 0" : (Ib * 1e3).toFixed(1) + " µA" })
1775
+ ] }),
1776
+ /* @__PURE__ */ jsxs("span", { children: [
1777
+ "collector current I",
1778
+ /* @__PURE__ */ jsx("sub", { children: "C" }),
1779
+ " = ",
1780
+ /* @__PURE__ */ jsx("strong", { children: Ic < .05 ? "≈ 0" : Ic.toFixed(1) + " mA" })
1781
+ ] }),
1782
+ /* @__PURE__ */ jsxs("span", { children: [
1783
+ "gain β = I",
1784
+ /* @__PURE__ */ jsx("sub", { children: "C" }),
1785
+ "/I",
1786
+ /* @__PURE__ */ jsx("sub", { children: "B" }),
1787
+ " = ",
1788
+ /* @__PURE__ */ jsx("strong", { children: beta })
1789
+ ] }),
1790
+ /* @__PURE__ */ jsxs("span", {
1791
+ style: { color: MUTED },
1792
+ children: [
1793
+ "the base is so thin that almost every carrier crosses to the collector: a tiny base current commands a ",
1794
+ beta,
1795
+ "× larger collector current"
1796
+ ]
1797
+ })
1798
+ ]
1799
+ })
1800
+ })]
1801
+ });
1802
+ useCheckpoint({
1803
+ solved: on,
1804
+ activity: `semiconductor:${activity}`
1805
+ });
1806
+ return /* @__PURE__ */ jsx(LabFrame, {
1807
+ title,
1808
+ prompt,
1809
+ controls,
1810
+ aside,
1811
+ footer: ask ? /* @__PURE__ */ jsx(LabAsk, {
1812
+ ask,
1813
+ activity
1814
+ }) : void 0,
1815
+ children: scene
1816
+ });
1817
+ }
1818
+ function Lead({ x, y1, y2, label, sub, color }) {
1819
+ return /* @__PURE__ */ jsxs("g", { children: [
1820
+ /* @__PURE__ */ jsx("line", {
1821
+ x1: x,
1822
+ y1,
1823
+ x2: x,
1824
+ y2: y2 + 8,
1825
+ stroke: "var(--stage-wire)",
1826
+ strokeWidth: 2,
1827
+ strokeLinecap: "round"
1828
+ }),
1829
+ /* @__PURE__ */ jsx("circle", {
1830
+ cx: x,
1831
+ cy: y2 + 8,
1832
+ r: 2.6,
1833
+ fill: "var(--stage-metal)"
1834
+ }),
1835
+ /* @__PURE__ */ jsx(Tag, {
1836
+ x,
1837
+ y: y2 + 2,
1838
+ text: label,
1839
+ color,
1840
+ size: 12,
1841
+ weight: 700
1842
+ }),
1843
+ sub ? /* @__PURE__ */ jsx(Tag, {
1844
+ x,
1845
+ y: y2 - 10,
1846
+ text: sub,
1847
+ color,
1848
+ size: 10,
1849
+ weight: 500
1850
+ }) : null
1851
+ ] });
1852
+ }
1853
+
1854
+ //#endregion
1855
+ export { BjtInsideLab, ConductionLab, HallEffectLab, MosfetInsideLab, PnJunctionLab, SiliconLatticeLab };