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