@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.
- package/dist/_virtual/_rolldown/runtime.mjs +18 -0
- package/dist/biology/enzyme-rate/preset.mjs +5 -5
- package/dist/biology/genetic-cross/core.d.mts +7 -7
- package/dist/biology/genetic-cross/core.mjs +4 -4
- package/dist/biology/genetic-cross/grid.mjs +132 -123
- package/dist/biology/genetic-cross/preset.mjs +4 -4
- package/dist/biology/genetic-cross/sex-linked.mjs +7 -7
- package/dist/biology/photosynthesis-factors/preset.mjs +8 -8
- package/dist/biology/respiration/preset.mjs +4 -4
- package/dist/biology/sequence/central-dogma.mjs +5 -5
- package/dist/biology/sequence/core.d.mts +6 -6
- package/dist/biology/sequence/core.mjs +1 -1
- package/dist/biology/sequence/preset.mjs +6 -6
- package/dist/blocks/authoring.mjs +5 -5
- package/dist/blocks/biology.d.mts +2 -2
- package/dist/blocks/biology.mjs +5 -5
- package/dist/blocks/chem.d.mts +2 -2
- package/dist/blocks/chem.mjs +13 -13
- package/dist/blocks/circuits.d.mts +293 -4
- package/dist/blocks/circuits.mjs +874 -9
- package/dist/blocks/discrete.d.mts +30 -2
- package/dist/blocks/discrete.mjs +74 -4
- package/dist/blocks/economics.mjs +1 -1
- package/dist/blocks/geography.mjs +1 -1
- package/dist/blocks/geometry.mjs +3 -3
- package/dist/blocks/ict.d.mts +90 -1
- package/dist/blocks/ict.mjs +217 -7
- package/dist/blocks/index.d.mts +3064 -657
- package/dist/blocks/index.mjs +9 -9
- package/dist/blocks/lab-block.mjs +5 -5
- package/dist/blocks/lab-config.d.mts +1 -1
- package/dist/blocks/lab-config.mjs +4 -4
- package/dist/blocks/lab-gallery.d.mts +1 -1
- package/dist/blocks/lab-gallery.mjs +2 -2
- package/dist/blocks/language.d.mts +6 -6
- package/dist/blocks/language.mjs +12 -12
- package/dist/blocks/lesson.mjs +4 -4
- package/dist/blocks/math.d.mts +577 -11
- package/dist/blocks/math.mjs +1648 -14
- package/dist/blocks/ml.d.mts +45 -1
- package/dist/blocks/ml.mjs +80 -6
- package/dist/blocks/physics.d.mts +9 -4
- package/dist/blocks/physics.mjs +75 -28
- package/dist/blocks/statistics.mjs +1 -1
- package/dist/build/CircuitEditor.d.mts +14 -0
- package/dist/build/CircuitEditor.mjs +787 -0
- package/dist/build/CircuitPlayer.d.mts +19 -0
- package/dist/build/CircuitPlayer.mjs +53 -0
- package/dist/build/CircuitScene.d.mts +61 -0
- package/dist/build/CircuitScene.mjs +383 -0
- package/dist/build/contract.d.mts +116 -0
- package/dist/build/editor-ops.d.mts +65 -0
- package/dist/build/editor-ops.mjs +306 -0
- package/dist/build/editor-ui.mjs +121 -0
- package/dist/build/flow.d.mts +14 -0
- package/dist/build/flow.mjs +119 -0
- package/dist/build/index.d.mts +10 -0
- package/dist/build/index.mjs +10 -0
- package/dist/build/parts/ammeter.d.mts +1 -0
- package/dist/build/parts/ammeter.mjs +32 -0
- package/dist/build/parts/bulb.d.mts +1 -0
- package/dist/build/parts/bulb.mjs +50 -0
- package/dist/build/parts/capacitor.d.mts +1 -0
- package/dist/build/parts/capacitor.mjs +26 -0
- package/dist/build/parts/cell.d.mts +1 -0
- package/dist/build/parts/cell.mjs +40 -0
- package/dist/build/parts/diode.d.mts +1 -0
- package/dist/build/parts/diode.mjs +33 -0
- package/dist/build/parts/index.d.mts +5 -0
- package/dist/build/parts/index.mjs +43 -0
- package/dist/build/parts/mosfet.d.mts +1 -0
- package/dist/build/parts/mosfet.mjs +95 -0
- package/dist/build/parts/node.d.mts +1 -0
- package/dist/build/parts/node.mjs +32 -0
- package/dist/build/parts/resistor.d.mts +1 -0
- package/dist/build/parts/resistor.mjs +49 -0
- package/dist/build/parts/shared.mjs +42 -0
- package/dist/build/parts/switch.d.mts +1 -0
- package/dist/build/parts/switch.mjs +34 -0
- package/dist/build/parts.d.mts +1 -0
- package/dist/build/registry.d.mts +9 -0
- package/dist/build/registry.mjs +15 -0
- package/dist/build/solve.d.mts +8 -0
- package/dist/build/solve.mjs +0 -0
- package/dist/catalog/registry.d.mts +2 -2
- package/dist/catalog/templates.d.mts +1 -1
- package/dist/catalog/templates.mjs +6 -6
- package/dist/chem/battery.mjs +1 -1
- package/dist/chem/bohr-atom.mjs +4 -4
- package/dist/chem/diffusion/preset.mjs +4 -4
- package/dist/chem/electrochem/preset.mjs +5 -5
- package/dist/chem/equilibrium/preset.d.mts +1 -1
- package/dist/chem/equilibrium/preset.mjs +6 -6
- package/dist/chem/gas-box/preset.mjs +6 -6
- package/dist/chem/kinetics/preset.mjs +6 -6
- package/dist/chem/periodic-trends/preset.mjs +7 -7
- package/dist/chem/reaction-lab.mjs +3 -3
- package/dist/chem/reaction-profile.mjs +4 -4
- package/dist/chem/solution/dilution.mjs +6 -6
- package/dist/chem/solution/field.d.mts +2 -2
- package/dist/chem/solution/field.mjs +2 -2
- package/dist/chem/solution/solution-box.mjs +7 -7
- package/dist/chem/stoichiometry/preset.mjs +5 -5
- package/dist/chem/titration/preset.mjs +5 -5
- package/dist/circuits/ac-dc/asset.mjs +1 -1
- package/dist/circuits/ac-dc/preset.mjs +2 -2
- package/dist/circuits/brownout/index.d.mts +1 -0
- package/dist/circuits/brownout/preset.d.mts +22 -0
- package/dist/circuits/brownout/preset.mjs +399 -0
- package/dist/circuits/capacitor-leak/preset.mjs +13 -8
- package/dist/circuits/circuit/asset.mjs +71 -14
- package/dist/circuits/circuit/preset.mjs +23 -5
- package/dist/circuits/circuit-builder.mjs +60 -132
- package/dist/circuits/circuit-lab.mjs +60 -40
- package/dist/circuits/cmos-gate/index.d.mts +1 -0
- package/dist/circuits/cmos-gate/preset.d.mts +75 -0
- package/dist/circuits/cmos-gate/preset.mjs +1491 -0
- package/dist/circuits/diode/index.d.mts +1 -0
- package/dist/circuits/diode/preset.d.mts +25 -0
- package/dist/circuits/diode/preset.mjs +266 -0
- package/dist/circuits/index.d.mts +7 -1
- package/dist/circuits/index.mjs +7 -1
- package/dist/circuits/rc-charging/index.d.mts +1 -0
- package/dist/circuits/rc-charging/preset.d.mts +27 -0
- package/dist/circuits/rc-charging/preset.mjs +329 -0
- package/dist/circuits/semiconductor/index.d.mts +1 -0
- package/dist/circuits/semiconductor/preset.d.mts +102 -0
- package/dist/circuits/semiconductor/preset.mjs +1855 -0
- package/dist/circuits/transistor/index.d.mts +1 -0
- package/dist/circuits/transistor/preset.d.mts +27 -0
- package/dist/circuits/transistor/preset.mjs +329 -0
- package/dist/commerce/accounting/core.d.mts +1 -1
- package/dist/commerce/accounting/equation-balance.mjs +5 -5
- package/dist/commerce/accounting/journal-poster.mjs +8 -8
- package/dist/commerce/accounting/statement-sorter.mjs +4 -4
- package/dist/commerce/economics/core.d.mts +2 -2
- package/dist/commerce/economics/core.mjs +1 -1
- package/dist/commerce/economics/demand-shift-vs-move.mjs +6 -6
- package/dist/commerce/economics/elasticity-revenue.mjs +6 -6
- package/dist/commerce/economics/market-equilibrium.mjs +5 -5
- package/dist/core/easing.d.mts +3 -3
- package/dist/core/easing.mjs +2 -2
- package/dist/core/numeric.d.mts +3 -3
- package/dist/core/numeric.mjs +2 -2
- package/dist/core/reactive.d.mts +1 -1
- package/dist/core/reactive.mjs +1 -1
- package/dist/core/rng.d.mts +2 -2
- package/dist/core/rng.mjs +1 -1
- package/dist/core/tex.mjs +2 -2
- package/dist/core/timeline.d.mts +1 -1
- package/dist/core/timeline.mjs +1 -1
- package/dist/core/util.mjs +11 -1
- package/dist/discrete/arrangements/preset.mjs +6 -14
- package/dist/discrete/bayes/preset.mjs +43 -35
- package/dist/discrete/binomial/preset.mjs +2 -2
- package/dist/discrete/combination-studio/figure.d.mts +6 -0
- package/dist/discrete/combination-studio/figure.mjs +159 -0
- package/dist/discrete/combination-studio/index.d.mts +2 -0
- package/dist/discrete/combination-studio/preset.d.mts +44 -0
- package/dist/discrete/combination-studio/preset.mjs +440 -0
- package/dist/discrete/core/combinatorics.d.mts +23 -3
- package/dist/discrete/core/combinatorics.mjs +38 -3
- package/dist/discrete/core/pigeonhole.d.mts +1 -1
- package/dist/discrete/core/pigeonhole.mjs +1 -1
- package/dist/discrete/core/probability.d.mts +3 -3
- package/dist/discrete/core/probability.mjs +3 -3
- package/dist/discrete/core/sets.d.mts +1 -1
- package/dist/discrete/counting-slots/preset.mjs +8 -8
- package/dist/discrete/counting-tree/preset.mjs +65 -8
- package/dist/discrete/expected-value/preset.mjs +13 -13
- package/dist/discrete/hypergeometric/preset.mjs +48 -15
- package/dist/discrete/index.d.mts +4 -2
- package/dist/discrete/index.mjs +4 -2
- package/dist/discrete/karnaugh/preset.mjs +26 -20
- package/dist/discrete/lln/preset.mjs +44 -3
- package/dist/discrete/logic-circuit/preset.mjs +2 -2
- package/dist/discrete/monte-carlo/preset.d.mts +1 -1
- package/dist/discrete/monte-carlo/preset.mjs +14 -14
- package/dist/discrete/monty-hall/preset.mjs +6 -6
- package/dist/discrete/outcome-builder/preset.mjs +3 -3
- package/dist/discrete/pascal/preset.mjs +37 -7
- package/dist/discrete/rules.d.mts +20 -0
- package/dist/discrete/rules.mjs +264 -0
- package/dist/discrete/sample-space/preset.mjs +4 -4
- package/dist/discrete/selection/preset.mjs +7 -13
- package/dist/discrete/truth-table/preset.mjs +32 -9
- package/dist/discrete/venn/preset.mjs +71 -48
- package/dist/geography/cycle-lab/preset.mjs +17 -10
- package/dist/geography/cycles.d.mts +3 -3
- package/dist/geography/cycles.mjs +3 -3
- package/dist/geometry/board/preset.d.mts +2 -0
- package/dist/geometry/board/preset.mjs +11 -15
- package/dist/geometry/builder.mjs +3 -3
- package/dist/ict/number-systems/base-odometer.mjs +4 -4
- package/dist/ict/number-systems/bit-grouper.d.mts +1 -1
- package/dist/ict/number-systems/bit-grouper.mjs +4 -4
- package/dist/ict/number-systems/place-value-dial.d.mts +1 -1
- package/dist/ict/number-systems/place-value-dial.mjs +3 -3
- package/dist/ict/number-systems/wheel.d.mts +3 -3
- package/dist/ict/number-systems/wheel.mjs +4 -4
- package/dist/kit/annotate.mjs +3 -3
- package/dist/kit/answer-check.d.mts +2 -2
- package/dist/kit/answer-check.mjs +34 -6
- package/dist/kit/ask.d.mts +19 -0
- package/dist/kit/ask.mjs +46 -0
- package/dist/kit/bar-strip.mjs +53 -0
- package/dist/kit/calc.d.mts +33 -0
- package/dist/kit/calc.mjs +27 -0
- package/dist/kit/carrier-engine.mjs +147 -0
- package/dist/kit/clue-scene.d.mts +86 -0
- package/dist/kit/clue-scene.mjs +424 -0
- package/dist/kit/cluster.d.mts +30 -0
- package/dist/kit/cluster.mjs +81 -0
- package/dist/kit/controls.mjs +11 -5
- package/dist/kit/coords.d.mts +88 -0
- package/dist/kit/coords.mjs +192 -0
- package/dist/kit/data-scene.d.mts +27 -0
- package/dist/kit/data-scene.mjs +199 -0
- package/dist/kit/diagram.mjs +111 -50
- package/dist/kit/electronics.mjs +552 -60
- package/dist/kit/expr-analysis.d.mts +18 -6
- package/dist/kit/expr-analysis.mjs +82 -28
- package/dist/kit/frame.d.mts +3 -3
- package/dist/kit/frame.mjs +25 -6
- package/dist/kit/gameshow.mjs +2 -2
- package/dist/kit/index.d.mts +14 -2
- package/dist/kit/index.mjs +13 -1
- package/dist/kit/logic-gates.mjs +246 -47
- package/dist/kit/palette.mjs +26 -0
- package/dist/kit/pedagogy.d.mts +4 -4
- package/dist/kit/pedagogy.mjs +21 -17
- package/dist/kit/play.d.mts +1 -1
- package/dist/kit/play.mjs +3 -3
- package/dist/kit/predict.d.mts +55 -0
- package/dist/kit/predict.mjs +146 -0
- package/dist/kit/receipt.d.mts +29 -0
- package/dist/kit/receipt.mjs +94 -0
- package/dist/kit/rich.mjs +2 -2
- package/dist/kit/rule.d.mts +59 -0
- package/dist/kit/rule.mjs +215 -0
- package/dist/kit/scale.mjs +1 -1
- package/dist/kit/scene-library.d.mts +22 -0
- package/dist/kit/scene-library.mjs +311 -0
- package/dist/kit/scene-studio.d.mts +14 -0
- package/dist/kit/scene-studio.mjs +338 -0
- package/dist/kit/scenes.d.mts +31 -0
- package/dist/kit/scenes.mjs +569 -0
- package/dist/kit/slot-fill.d.mts +61 -0
- package/dist/kit/slot-fill.mjs +207 -0
- package/dist/kit/solve.d.mts +21 -0
- package/dist/kit/solve.mjs +75 -0
- package/dist/kit/space.mjs +5 -5
- package/dist/kit/steps.mjs +2 -2
- package/dist/kit/vessel.d.mts +69 -0
- package/dist/kit/vessel.mjs +191 -0
- package/dist/language/agreement/preset.mjs +2 -2
- package/dist/language/article-lens/preset.d.mts +1 -1
- package/dist/language/article-lens/preset.mjs +8 -8
- package/dist/language/deck.d.mts +3 -3
- package/dist/language/deck.mjs +1 -1
- package/dist/language/preposition-scene/preset.d.mts +2 -2
- package/dist/language/preposition-scene/preset.mjs +5 -5
- package/dist/language/sentence-builder/preset.mjs +5 -5
- package/dist/language/transform/preset.d.mts +2 -2
- package/dist/language/transform/preset.mjs +5 -5
- package/dist/language/ui.d.mts +3 -3
- package/dist/language/ui.mjs +4 -4
- package/dist/language/word-match/preset.mjs +3 -3
- package/dist/logic/LogicBuildLab.d.mts +22 -0
- package/dist/logic/LogicBuildLab.mjs +170 -0
- package/dist/logic/LogicEditScene.d.mts +31 -0
- package/dist/logic/LogicEditScene.mjs +276 -0
- package/dist/logic/LogicEditor.d.mts +14 -0
- package/dist/logic/LogicEditor.mjs +413 -0
- package/dist/logic/LogicScene.d.mts +32 -0
- package/dist/logic/LogicScene.mjs +277 -0
- package/dist/logic/contract.d.mts +72 -0
- package/dist/logic/display.d.mts +24 -0
- package/dist/logic/display.mjs +127 -0
- package/dist/logic/edit-ops.d.mts +44 -0
- package/dist/logic/edit-ops.mjs +177 -0
- package/dist/logic/evaluate.d.mts +11 -0
- package/dist/logic/evaluate.mjs +93 -0
- package/dist/logic/gates.d.mts +10 -0
- package/dist/logic/gates.mjs +73 -0
- package/dist/logic/index.d.mts +14 -0
- package/dist/logic/index.mjs +13 -0
- package/dist/logic/lab.d.mts +32 -0
- package/dist/logic/lab.mjs +160 -0
- package/dist/logic/presets.d.mts +12 -0
- package/dist/logic/presets.mjs +241 -0
- package/dist/logic/registry.d.mts +9 -0
- package/dist/logic/registry.mjs +15 -0
- package/dist/math/area-model/preset.mjs +70 -44
- package/dist/math/balance-algebra/preset.mjs +14 -5
- package/dist/math/broken-tree/index.d.mts +1 -0
- package/dist/math/broken-tree/preset.d.mts +26 -0
- package/dist/math/broken-tree/preset.mjs +435 -0
- package/dist/math/circle/index.d.mts +1 -0
- package/dist/math/circle/preset.d.mts +44 -0
- package/dist/math/circle/preset.mjs +198 -0
- package/dist/math/complex/core.d.mts +93 -0
- package/dist/math/complex/core.mjs +239 -0
- package/dist/math/complex/index.d.mts +3 -0
- package/dist/math/complex/preset.d.mts +31 -0
- package/dist/math/complex/preset.mjs +377 -0
- package/dist/math/complex/rules.d.mts +6 -0
- package/dist/math/complex/rules.mjs +121 -0
- package/dist/math/conic/index.d.mts +1 -0
- package/dist/math/conic/preset.d.mts +30 -0
- package/dist/math/conic/preset.mjs +334 -0
- package/dist/math/derivation.mjs +5 -5
- package/dist/math/derivative-explorer/preset.mjs +5 -5
- package/dist/math/domain-range/index.d.mts +1 -0
- package/dist/math/domain-range/preset.d.mts +33 -0
- package/dist/math/domain-range/preset.mjs +313 -0
- package/dist/math/fraction-bar/index.d.mts +1 -0
- package/dist/math/fraction-bar/preset.d.mts +27 -0
- package/dist/math/fraction-bar/preset.mjs +197 -0
- package/dist/math/function-machine/preset.mjs +2 -2
- package/dist/math/gradient-descent.mjs +6 -6
- package/dist/math/grapher/preset.d.mts +1 -1
- package/dist/math/grapher/preset.mjs +4 -4
- package/dist/math/harmonic-form/preset.mjs +6 -6
- package/dist/math/index.d.mts +27 -2
- package/dist/math/index.mjs +27 -2
- package/dist/math/integral-explorer/preset.mjs +2 -2
- package/dist/math/interactive/preset.mjs +3 -3
- package/dist/math/limit-explorer/preset.mjs +4 -4
- package/dist/math/linear-model/index.d.mts +1 -0
- package/dist/math/linear-model/preset.d.mts +53 -0
- package/dist/math/linear-model/preset.mjs +164 -0
- package/dist/math/linear-system/preset.mjs +4 -4
- package/dist/math/mystery-bucket/preset.mjs +6 -6
- package/dist/math/number-line/preset.mjs +3 -2
- package/dist/math/parabola/preset.mjs +4 -3
- package/dist/math/pattern/preset.mjs +7 -13
- package/dist/math/percent-bar/index.d.mts +1 -0
- package/dist/math/percent-bar/preset.d.mts +37 -0
- package/dist/math/percent-bar/preset.mjs +275 -0
- package/dist/math/poly/core.d.mts +50 -0
- package/dist/math/poly/core.mjs +268 -0
- package/dist/math/poly/index.d.mts +3 -0
- package/dist/math/poly/preset.d.mts +23 -0
- package/dist/math/poly/preset.mjs +141 -0
- package/dist/math/poly/steps.d.mts +10 -0
- package/dist/math/poly/steps.mjs +99 -0
- package/dist/math/rate-machine/index.d.mts +1 -0
- package/dist/math/rate-machine/preset.d.mts +35 -0
- package/dist/math/rate-machine/preset.mjs +281 -0
- package/dist/math/ratio-share/index.d.mts +1 -0
- package/dist/math/ratio-share/preset.d.mts +24 -0
- package/dist/math/ratio-share/preset.mjs +204 -0
- package/dist/math/receipt/index.d.mts +1 -0
- package/dist/math/receipt/preset.d.mts +22 -0
- package/dist/math/receipt/preset.mjs +137 -0
- package/dist/math/sequence-predict/index.d.mts +1 -0
- package/dist/math/sequence-predict/preset.d.mts +34 -0
- package/dist/math/sequence-predict/preset.mjs +130 -0
- package/dist/math/straight-line/index.d.mts +1 -0
- package/dist/math/straight-line/preset.d.mts +37 -0
- package/dist/math/straight-line/preset.mjs +374 -0
- package/dist/math/system-solve/index.d.mts +1 -0
- package/dist/math/system-solve/preset.d.mts +21 -0
- package/dist/math/system-solve/preset.mjs +227 -0
- package/dist/math/transform/index.d.mts +1 -0
- package/dist/math/transform/preset.d.mts +41 -0
- package/dist/math/transform/preset.mjs +343 -0
- package/dist/math/triangle-trig/preset.mjs +12 -9
- package/dist/math/trig/core.d.mts +37 -0
- package/dist/math/trig/core.mjs +150 -0
- package/dist/math/trig/diagrams.d.mts +1 -0
- package/dist/math/trig/diagrams.mjs +321 -0
- package/dist/math/trig/index.d.mts +3 -0
- package/dist/math/trig/preset.d.mts +25 -0
- package/dist/math/trig/preset.mjs +260 -0
- package/dist/math/trig/rules.d.mts +6 -0
- package/dist/math/trig/rules.mjs +159 -0
- package/dist/math/trig-explorer.mjs +4 -4
- package/dist/ml/boundary/preset.mjs +8 -3
- package/dist/ml/classifier/preset.mjs +31 -6
- package/dist/ml/kmeans/preset.mjs +4 -4
- package/dist/ml/knn/preset.mjs +47 -12
- package/dist/ml/regression/preset.mjs +36 -7
- package/dist/physics/atwood/preset.mjs +4 -4
- package/dist/physics/bullet-walls/preset.d.mts +1 -1
- package/dist/physics/bullet-walls/preset.mjs +7 -7
- package/dist/physics/carnot/preset.mjs +6 -6
- package/dist/physics/circular-motion/preset.mjs +36 -5
- package/dist/physics/collision-track/preset.mjs +35 -5
- package/dist/physics/efficiency/preset.d.mts +2 -2
- package/dist/physics/efficiency/preset.mjs +5 -5
- package/dist/physics/electric-field/preset.mjs +32 -23
- package/dist/physics/electric-flux/index.d.mts +1 -0
- package/dist/physics/electric-flux/preset.d.mts +29 -0
- package/dist/physics/electric-flux/preset.mjs +264 -0
- package/dist/physics/energy-skate/preset.mjs +5 -5
- package/dist/physics/entropy/preset.mjs +7 -7
- package/dist/physics/expansion/preset.mjs +13 -13
- package/dist/physics/exponential/asset.mjs +1 -1
- package/dist/physics/exponential/preset.mjs +4 -4
- package/dist/physics/gas-process/preset.mjs +3 -3
- package/dist/physics/gauss-law/index.d.mts +1 -0
- package/dist/physics/gauss-law/preset.d.mts +20 -0
- package/dist/physics/gauss-law/preset.mjs +286 -0
- package/dist/physics/gravitation/preset.mjs +7 -7
- package/dist/physics/gravity-drop.mjs +4 -4
- package/dist/physics/heat-transfer/preset.d.mts +1 -1
- package/dist/physics/heat-transfer/preset.mjs +10 -10
- package/dist/physics/impulse/preset.mjs +5 -5
- package/dist/physics/index.d.mts +4 -1
- package/dist/physics/index.mjs +4 -1
- package/dist/physics/kepler/preset.mjs +4 -4
- package/dist/physics/lever/preset.mjs +3 -3
- package/dist/physics/lorentz/preset.mjs +11 -11
- package/dist/physics/magnetism/preset.mjs +3 -3
- package/dist/physics/optics/preset.mjs +2 -2
- package/dist/physics/orbit-lab.mjs +5 -5
- package/dist/physics/projectile-lab.mjs +4 -4
- package/dist/physics/rain-relative/preset.mjs +5 -5
- package/dist/physics/ramp-forces/preset.mjs +5 -5
- package/dist/physics/river-boat.mjs +6 -6
- package/dist/physics/shm/preset.mjs +9 -9
- package/dist/physics/stopping-distance/preset.mjs +3 -3
- package/dist/physics/temperature-scales/preset.mjs +105 -116
- package/dist/physics/terminal-velocity/preset.mjs +5 -5
- package/dist/physics/thermal/preset.mjs +5 -5
- package/dist/physics/vector-board/preset.mjs +7 -6
- package/dist/physics/vector-scene.mjs +2 -2
- package/dist/physics/vector-types/preset.mjs +37 -3
- package/dist/physics/water-density/preset.mjs +12 -12
- package/dist/physics/waves/doppler.mjs +2 -2
- package/dist/physics/waves/preset.mjs +4 -4
- package/dist/physics/waves/ripple.mjs +6 -6
- package/dist/physics/waves/string.mjs +5 -5
- package/dist/physics/work-energy/preset.mjs +4 -4
- package/dist/physics/work-potential/index.d.mts +1 -0
- package/dist/physics/work-potential/preset.d.mts +20 -0
- package/dist/physics/work-potential/preset.mjs +276 -0
- package/dist/schemas/index.d.mts +6 -6
- package/dist/schemas/index.mjs +3 -3
- package/dist/statistics/center-spread/preset.mjs +3 -3
- package/dist/statistics/core/descriptive.d.mts +2 -2
- package/dist/statistics/core/descriptive.mjs +2 -2
- package/dist/statistics/core/normal.d.mts +3 -3
- package/dist/statistics/core/normal.mjs +3 -3
- package/dist/statistics/core/sequences.d.mts +1 -1
- package/dist/statistics/galton/preset.mjs +2 -2
- package/dist/statistics/histogram/preset.mjs +6 -6
- package/dist/statistics/normal/preset.mjs +2 -2
- package/dist/statistics/sampling/preset.mjs +4 -4
- package/dist/statistics/sequence/preset.mjs +58 -15
- package/dist/statistics/z-table/preset.mjs +17 -4
- package/package.json +11 -3
- 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 };
|