@classytic/labs 0.1.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/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/biology/enzyme-rate/index.d.mts +1 -0
- package/dist/biology/enzyme-rate/preset.d.mts +25 -0
- package/dist/biology/enzyme-rate/preset.mjs +256 -0
- package/dist/biology/genetic-cross/core.d.mts +64 -0
- package/dist/biology/genetic-cross/core.mjs +147 -0
- package/dist/biology/genetic-cross/grid.mjs +239 -0
- package/dist/biology/genetic-cross/index.d.mts +3 -0
- package/dist/biology/genetic-cross/preset.d.mts +26 -0
- package/dist/biology/genetic-cross/preset.mjs +184 -0
- package/dist/biology/genetic-cross/sex-linked.d.mts +27 -0
- package/dist/biology/genetic-cross/sex-linked.mjs +226 -0
- package/dist/biology/index.d.mts +11 -0
- package/dist/biology/index.mjs +12 -0
- package/dist/biology/photosynthesis-factors/index.d.mts +1 -0
- package/dist/biology/photosynthesis-factors/preset.d.mts +25 -0
- package/dist/biology/photosynthesis-factors/preset.mjs +270 -0
- package/dist/biology/punnett-cross/index.d.mts +1 -0
- package/dist/biology/punnett-cross/preset.d.mts +27 -0
- package/dist/biology/punnett-cross/preset.mjs +21 -0
- package/dist/biology/respiration/index.d.mts +1 -0
- package/dist/biology/respiration/preset.d.mts +17 -0
- package/dist/biology/respiration/preset.mjs +179 -0
- package/dist/biology/sequence/central-dogma.d.mts +17 -0
- package/dist/biology/sequence/central-dogma.mjs +339 -0
- package/dist/biology/sequence/core.d.mts +38 -0
- package/dist/biology/sequence/core.mjs +178 -0
- package/dist/biology/sequence/index.d.mts +3 -0
- package/dist/biology/sequence/preset.d.mts +20 -0
- package/dist/biology/sequence/preset.mjs +235 -0
- package/dist/blocks/accounting.d.mts +142 -0
- package/dist/blocks/accounting.mjs +446 -0
- package/dist/blocks/authoring.d.mts +12 -0
- package/dist/blocks/authoring.mjs +705 -0
- package/dist/blocks/biology.d.mts +197 -0
- package/dist/blocks/biology.mjs +513 -0
- package/dist/blocks/chem.d.mts +128 -0
- package/dist/blocks/chem.mjs +486 -0
- package/dist/blocks/circuits.d.mts +86 -0
- package/dist/blocks/circuits.mjs +348 -0
- package/dist/blocks/discrete.d.mts +62 -0
- package/dist/blocks/discrete.mjs +314 -0
- package/dist/blocks/economics.d.mts +56 -0
- package/dist/blocks/economics.mjs +203 -0
- package/dist/blocks/geography.d.mts +58 -0
- package/dist/blocks/geography.mjs +115 -0
- package/dist/blocks/geometry.d.mts +28 -0
- package/dist/blocks/geometry.mjs +160 -0
- package/dist/blocks/ict.d.mts +65 -0
- package/dist/blocks/ict.mjs +197 -0
- package/dist/blocks/index.d.mts +4555 -0
- package/dist/blocks/index.mjs +120 -0
- package/dist/blocks/lab-block.d.mts +16 -0
- package/dist/blocks/lab-block.mjs +74 -0
- package/dist/blocks/lab-config.d.mts +23 -0
- package/dist/blocks/lab-config.mjs +200 -0
- package/dist/blocks/lab-gallery.d.mts +30 -0
- package/dist/blocks/lab-gallery.mjs +208 -0
- package/dist/blocks/language.d.mts +349 -0
- package/dist/blocks/language.mjs +750 -0
- package/dist/blocks/lesson.d.mts +43 -0
- package/dist/blocks/lesson.mjs +140 -0
- package/dist/blocks/math.d.mts +411 -0
- package/dist/blocks/math.mjs +1536 -0
- package/dist/blocks/ml.d.mts +84 -0
- package/dist/blocks/ml.mjs +146 -0
- package/dist/blocks/physics.d.mts +259 -0
- package/dist/blocks/physics.mjs +868 -0
- package/dist/blocks/statistics.d.mts +29 -0
- package/dist/blocks/statistics.mjs +123 -0
- package/dist/catalog/index.d.mts +3 -0
- package/dist/catalog/index.mjs +8 -0
- package/dist/catalog/registry.d.mts +46 -0
- package/dist/catalog/registry.mjs +56 -0
- package/dist/catalog/templates.d.mts +11 -0
- package/dist/catalog/templates.mjs +141 -0
- package/dist/chem/battery.d.mts +16 -0
- package/dist/chem/battery.mjs +311 -0
- package/dist/chem/bohr-atom.d.mts +16 -0
- package/dist/chem/bohr-atom.mjs +212 -0
- package/dist/chem/diffusion/asset.mjs +76 -0
- package/dist/chem/diffusion/index.d.mts +1 -0
- package/dist/chem/diffusion/preset.d.mts +15 -0
- package/dist/chem/diffusion/preset.mjs +188 -0
- package/dist/chem/electrochem/index.d.mts +1 -0
- package/dist/chem/electrochem/preset.d.mts +23 -0
- package/dist/chem/electrochem/preset.mjs +402 -0
- package/dist/chem/equilibrium/index.d.mts +1 -0
- package/dist/chem/equilibrium/preset.d.mts +36 -0
- package/dist/chem/equilibrium/preset.mjs +416 -0
- package/dist/chem/gas-box/index.d.mts +1 -0
- package/dist/chem/gas-box/preset.d.mts +27 -0
- package/dist/chem/gas-box/preset.mjs +395 -0
- package/dist/chem/index.d.mts +16 -0
- package/dist/chem/index.mjs +17 -0
- package/dist/chem/kinetics/index.d.mts +1 -0
- package/dist/chem/kinetics/preset.d.mts +31 -0
- package/dist/chem/kinetics/preset.mjs +478 -0
- package/dist/chem/periodic-trends/index.d.mts +1 -0
- package/dist/chem/periodic-trends/preset.d.mts +21 -0
- package/dist/chem/periodic-trends/preset.mjs +831 -0
- package/dist/chem/reaction-lab.d.mts +18 -0
- package/dist/chem/reaction-lab.mjs +165 -0
- package/dist/chem/reaction-profile.d.mts +21 -0
- package/dist/chem/reaction-profile.mjs +287 -0
- package/dist/chem/solution/dilution.d.mts +27 -0
- package/dist/chem/solution/dilution.mjs +199 -0
- package/dist/chem/solution/field.d.mts +30 -0
- package/dist/chem/solution/field.mjs +145 -0
- package/dist/chem/solution/index.d.mts +3 -0
- package/dist/chem/solution/solution-box.d.mts +28 -0
- package/dist/chem/solution/solution-box.mjs +140 -0
- package/dist/chem/stoichiometry/index.d.mts +1 -0
- package/dist/chem/stoichiometry/preset.d.mts +29 -0
- package/dist/chem/stoichiometry/preset.mjs +392 -0
- package/dist/chem/titration/index.d.mts +1 -0
- package/dist/chem/titration/preset.d.mts +29 -0
- package/dist/chem/titration/preset.mjs +436 -0
- package/dist/circuits/ac-dc/asset.mjs +295 -0
- package/dist/circuits/ac-dc/index.d.mts +1 -0
- package/dist/circuits/ac-dc/preset.d.mts +16 -0
- package/dist/circuits/ac-dc/preset.mjs +134 -0
- package/dist/circuits/capacitor-leak/index.d.mts +1 -0
- package/dist/circuits/capacitor-leak/preset.d.mts +32 -0
- package/dist/circuits/capacitor-leak/preset.mjs +271 -0
- package/dist/circuits/circuit/asset.d.mts +6 -0
- package/dist/circuits/circuit/asset.mjs +367 -0
- package/dist/circuits/circuit/index.d.mts +2 -0
- package/dist/circuits/circuit/preset.d.mts +46 -0
- package/dist/circuits/circuit/preset.mjs +235 -0
- package/dist/circuits/circuit-builder.d.mts +30 -0
- package/dist/circuits/circuit-builder.mjs +412 -0
- package/dist/circuits/circuit-lab.d.mts +20 -0
- package/dist/circuits/circuit-lab.mjs +400 -0
- package/dist/circuits/index.d.mts +7 -0
- package/dist/circuits/index.mjs +8 -0
- package/dist/commerce/accounting/core.d.mts +48 -0
- package/dist/commerce/accounting/core.mjs +57 -0
- package/dist/commerce/accounting/equation-balance.d.mts +35 -0
- package/dist/commerce/accounting/equation-balance.mjs +292 -0
- package/dist/commerce/accounting/index.d.mts +4 -0
- package/dist/commerce/accounting/journal-poster.d.mts +29 -0
- package/dist/commerce/accounting/journal-poster.mjs +472 -0
- package/dist/commerce/accounting/statement-sorter.d.mts +25 -0
- package/dist/commerce/accounting/statement-sorter.mjs +304 -0
- package/dist/commerce/economics/core.d.mts +33 -0
- package/dist/commerce/economics/core.mjs +26 -0
- package/dist/commerce/economics/demand-shift-vs-move.d.mts +35 -0
- package/dist/commerce/economics/demand-shift-vs-move.mjs +324 -0
- package/dist/commerce/economics/elasticity-revenue.d.mts +31 -0
- package/dist/commerce/economics/elasticity-revenue.mjs +253 -0
- package/dist/commerce/economics/index.d.mts +4 -0
- package/dist/commerce/economics/market-equilibrium.d.mts +33 -0
- package/dist/commerce/economics/market-equilibrium.mjs +340 -0
- package/dist/commerce/index.d.mts +9 -0
- package/dist/commerce/index.mjs +10 -0
- package/dist/core/easing.d.mts +28 -0
- package/dist/core/easing.mjs +66 -0
- package/dist/core/index.d.mts +10 -0
- package/dist/core/index.mjs +11 -0
- package/dist/core/numeric.d.mts +37 -0
- package/dist/core/numeric.mjs +75 -0
- package/dist/core/reactive.d.mts +24 -0
- package/dist/core/reactive.mjs +51 -0
- package/dist/core/rng.d.mts +21 -0
- package/dist/core/rng.mjs +39 -0
- package/dist/core/tex.d.mts +14 -0
- package/dist/core/tex.mjs +44 -0
- package/dist/core/timeline.d.mts +34 -0
- package/dist/core/timeline.mjs +77 -0
- package/dist/core/util.d.mts +19 -0
- package/dist/core/util.mjs +31 -0
- package/dist/discrete/arrangements/preset.d.mts +28 -0
- package/dist/discrete/arrangements/preset.mjs +304 -0
- package/dist/discrete/bayes/preset.d.mts +33 -0
- package/dist/discrete/bayes/preset.mjs +476 -0
- package/dist/discrete/binomial/preset.d.mts +25 -0
- package/dist/discrete/binomial/preset.mjs +333 -0
- package/dist/discrete/core/combinatorics.d.mts +23 -0
- package/dist/discrete/core/combinatorics.mjs +57 -0
- package/dist/discrete/core/inclusionExclusion.d.mts +19 -0
- package/dist/discrete/core/inclusionExclusion.mjs +30 -0
- package/dist/discrete/core/pigeonhole.d.mts +15 -0
- package/dist/discrete/core/pigeonhole.mjs +24 -0
- package/dist/discrete/core/probability.d.mts +29 -0
- package/dist/discrete/core/probability.mjs +43 -0
- package/dist/discrete/core/sets.d.mts +21 -0
- package/dist/discrete/core/sets.mjs +45 -0
- package/dist/discrete/counting-slots/preset.d.mts +30 -0
- package/dist/discrete/counting-slots/preset.mjs +553 -0
- package/dist/discrete/counting-tree/index.d.mts +1 -0
- package/dist/discrete/counting-tree/preset.d.mts +44 -0
- package/dist/discrete/counting-tree/preset.mjs +364 -0
- package/dist/discrete/expected-value/preset.d.mts +28 -0
- package/dist/discrete/expected-value/preset.mjs +352 -0
- package/dist/discrete/hypergeometric/preset.d.mts +25 -0
- package/dist/discrete/hypergeometric/preset.mjs +330 -0
- package/dist/discrete/index.d.mts +26 -0
- package/dist/discrete/index.mjs +27 -0
- package/dist/discrete/karnaugh/index.d.mts +1 -0
- package/dist/discrete/karnaugh/preset.d.mts +30 -0
- package/dist/discrete/karnaugh/preset.mjs +452 -0
- package/dist/discrete/lln/asset.mjs +206 -0
- package/dist/discrete/lln/index.d.mts +1 -0
- package/dist/discrete/lln/preset.d.mts +17 -0
- package/dist/discrete/lln/preset.mjs +152 -0
- package/dist/discrete/logic-circuit/index.d.mts +1 -0
- package/dist/discrete/logic-circuit/preset.d.mts +47 -0
- package/dist/discrete/logic-circuit/preset.mjs +307 -0
- package/dist/discrete/monte-carlo/index.d.mts +1 -0
- package/dist/discrete/monte-carlo/preset.d.mts +64 -0
- package/dist/discrete/monte-carlo/preset.mjs +446 -0
- package/dist/discrete/monty-hall/index.d.mts +1 -0
- package/dist/discrete/monty-hall/preset.d.mts +23 -0
- package/dist/discrete/monty-hall/preset.mjs +491 -0
- package/dist/discrete/outcome-builder/preset.d.mts +24 -0
- package/dist/discrete/outcome-builder/preset.mjs +283 -0
- package/dist/discrete/pascal/preset.d.mts +24 -0
- package/dist/discrete/pascal/preset.mjs +372 -0
- package/dist/discrete/sample-space/index.d.mts +1 -0
- package/dist/discrete/sample-space/preset.d.mts +42 -0
- package/dist/discrete/sample-space/preset.mjs +395 -0
- package/dist/discrete/selection/preset.d.mts +33 -0
- package/dist/discrete/selection/preset.mjs +406 -0
- package/dist/discrete/truth-table/index.d.mts +1 -0
- package/dist/discrete/truth-table/preset.d.mts +30 -0
- package/dist/discrete/truth-table/preset.mjs +456 -0
- package/dist/discrete/venn/index.d.mts +1 -0
- package/dist/discrete/venn/preset.d.mts +32 -0
- package/dist/discrete/venn/preset.mjs +461 -0
- package/dist/geography/cycle-lab/index.d.mts +1 -0
- package/dist/geography/cycle-lab/preset.d.mts +25 -0
- package/dist/geography/cycle-lab/preset.mjs +254 -0
- package/dist/geography/cycles.d.mts +21 -0
- package/dist/geography/cycles.mjs +205 -0
- package/dist/geography/index.d.mts +4 -0
- package/dist/geography/index.mjs +5 -0
- package/dist/geometry/board/index.d.mts +1 -0
- package/dist/geometry/board/preset.d.mts +71 -0
- package/dist/geometry/board/preset.mjs +148 -0
- package/dist/geometry/builder.d.mts +18 -0
- package/dist/geometry/builder.mjs +332 -0
- package/dist/geometry/index.d.mts +4 -0
- package/dist/geometry/index.mjs +5 -0
- package/dist/geometry/intersecting-circles.d.mts +17 -0
- package/dist/geometry/intersecting-circles.mjs +104 -0
- package/dist/ict/index.d.mts +5 -0
- package/dist/ict/index.mjs +6 -0
- package/dist/ict/number-systems/base-odometer.d.mts +34 -0
- package/dist/ict/number-systems/base-odometer.mjs +160 -0
- package/dist/ict/number-systems/bit-grouper.d.mts +32 -0
- package/dist/ict/number-systems/bit-grouper.mjs +190 -0
- package/dist/ict/number-systems/index.d.mts +4 -0
- package/dist/ict/number-systems/place-value-dial.d.mts +29 -0
- package/dist/ict/number-systems/place-value-dial.mjs +153 -0
- package/dist/ict/number-systems/wheel.d.mts +73 -0
- package/dist/ict/number-systems/wheel.mjs +279 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +11 -0
- package/dist/kit/anim.mjs +52 -0
- package/dist/kit/annotate.mjs +116 -0
- package/dist/kit/answer-check.d.mts +38 -0
- package/dist/kit/answer-check.mjs +65 -0
- package/dist/kit/asset-util.mjs +15 -0
- package/dist/kit/controls.mjs +77 -0
- package/dist/kit/cycle.d.mts +44 -0
- package/dist/kit/cycle.mjs +188 -0
- package/dist/kit/diagram.mjs +176 -0
- package/dist/kit/electronics.mjs +357 -0
- package/dist/kit/expr-analysis.d.mts +37 -0
- package/dist/kit/expr-analysis.mjs +111 -0
- package/dist/kit/frame.d.mts +70 -0
- package/dist/kit/frame.mjs +205 -0
- package/dist/kit/freq-tree.mjs +99 -0
- package/dist/kit/gameshow.mjs +315 -0
- package/dist/kit/index.d.mts +5 -0
- package/dist/kit/index.mjs +6 -0
- package/dist/kit/logic-gates.d.mts +6 -0
- package/dist/kit/logic-gates.mjs +210 -0
- package/dist/kit/molecules.mjs +178 -0
- package/dist/kit/pedagogy.d.mts +126 -0
- package/dist/kit/pedagogy.mjs +331 -0
- package/dist/kit/play.d.mts +21 -0
- package/dist/kit/play.mjs +52 -0
- package/dist/kit/probability.mjs +141 -0
- package/dist/kit/proportion.mjs +112 -0
- package/dist/kit/reaction.mjs +102 -0
- package/dist/kit/rich.d.mts +10 -0
- package/dist/kit/rich.mjs +21 -0
- package/dist/kit/scale.mjs +230 -0
- package/dist/kit/space.mjs +326 -0
- package/dist/kit/steps.d.mts +24 -0
- package/dist/kit/steps.mjs +57 -0
- package/dist/kit/thermal.mjs +289 -0
- package/dist/language/agreement/index.d.mts +1 -0
- package/dist/language/agreement/preset.d.mts +27 -0
- package/dist/language/agreement/preset.mjs +113 -0
- package/dist/language/article-lens/index.d.mts +1 -0
- package/dist/language/article-lens/preset.d.mts +31 -0
- package/dist/language/article-lens/preset.mjs +125 -0
- package/dist/language/deck.d.mts +45 -0
- package/dist/language/deck.mjs +61 -0
- package/dist/language/icon.d.mts +40 -0
- package/dist/language/icon.mjs +73 -0
- package/dist/language/index.d.mts +10 -0
- package/dist/language/index.mjs +11 -0
- package/dist/language/preposition-scene/index.d.mts +1 -0
- package/dist/language/preposition-scene/preset.d.mts +34 -0
- package/dist/language/preposition-scene/preset.mjs +234 -0
- package/dist/language/sentence-builder/index.d.mts +1 -0
- package/dist/language/sentence-builder/preset.d.mts +32 -0
- package/dist/language/sentence-builder/preset.mjs +122 -0
- package/dist/language/transform/index.d.mts +1 -0
- package/dist/language/transform/preset.d.mts +31 -0
- package/dist/language/transform/preset.mjs +137 -0
- package/dist/language/ui.d.mts +53 -0
- package/dist/language/ui.mjs +88 -0
- package/dist/language/word-match/index.d.mts +1 -0
- package/dist/language/word-match/preset.d.mts +22 -0
- package/dist/language/word-match/preset.mjs +148 -0
- package/dist/math/area-model/asset.d.mts +6 -0
- package/dist/math/area-model/asset.mjs +270 -0
- package/dist/math/area-model/index.d.mts +2 -0
- package/dist/math/area-model/preset.d.mts +29 -0
- package/dist/math/area-model/preset.mjs +243 -0
- package/dist/math/balance-algebra/asset.d.mts +6 -0
- package/dist/math/balance-algebra/asset.mjs +150 -0
- package/dist/math/balance-algebra/index.d.mts +2 -0
- package/dist/math/balance-algebra/preset.d.mts +30 -0
- package/dist/math/balance-algebra/preset.mjs +228 -0
- package/dist/math/derivation.d.mts +22 -0
- package/dist/math/derivation.mjs +113 -0
- package/dist/math/derivative-explorer/index.d.mts +1 -0
- package/dist/math/derivative-explorer/preset.d.mts +19 -0
- package/dist/math/derivative-explorer/preset.mjs +227 -0
- package/dist/math/function-machine/index.d.mts +1 -0
- package/dist/math/function-machine/preset.d.mts +21 -0
- package/dist/math/function-machine/preset.mjs +177 -0
- package/dist/math/gradient-descent.d.mts +23 -0
- package/dist/math/gradient-descent.mjs +473 -0
- package/dist/math/grapher/index.d.mts +1 -0
- package/dist/math/grapher/preset.d.mts +40 -0
- package/dist/math/grapher/preset.mjs +313 -0
- package/dist/math/harmonic-form/index.d.mts +1 -0
- package/dist/math/harmonic-form/preset.d.mts +21 -0
- package/dist/math/harmonic-form/preset.mjs +387 -0
- package/dist/math/index.d.mts +25 -0
- package/dist/math/index.mjs +26 -0
- package/dist/math/integral-explorer/index.d.mts +1 -0
- package/dist/math/integral-explorer/preset.d.mts +23 -0
- package/dist/math/integral-explorer/preset.mjs +217 -0
- package/dist/math/interactive/index.d.mts +1 -0
- package/dist/math/interactive/preset.d.mts +72 -0
- package/dist/math/interactive/preset.mjs +202 -0
- package/dist/math/limit-explorer/index.d.mts +1 -0
- package/dist/math/limit-explorer/preset.d.mts +19 -0
- package/dist/math/limit-explorer/preset.mjs +216 -0
- package/dist/math/linear-system/index.d.mts +1 -0
- package/dist/math/linear-system/preset.d.mts +28 -0
- package/dist/math/linear-system/preset.mjs +164 -0
- package/dist/math/mystery-bucket/asset.d.mts +6 -0
- package/dist/math/mystery-bucket/asset.mjs +145 -0
- package/dist/math/mystery-bucket/index.d.mts +2 -0
- package/dist/math/mystery-bucket/preset.d.mts +36 -0
- package/dist/math/mystery-bucket/preset.mjs +116 -0
- package/dist/math/number-line/index.d.mts +1 -0
- package/dist/math/number-line/preset.d.mts +24 -0
- package/dist/math/number-line/preset.mjs +142 -0
- package/dist/math/parabola/index.d.mts +1 -0
- package/dist/math/parabola/preset.d.mts +13 -0
- package/dist/math/parabola/preset.mjs +79 -0
- package/dist/math/pattern/asset.d.mts +6 -0
- package/dist/math/pattern/asset.mjs +102 -0
- package/dist/math/pattern/index.d.mts +2 -0
- package/dist/math/pattern/preset.d.mts +32 -0
- package/dist/math/pattern/preset.mjs +294 -0
- package/dist/math/triangle-trig/index.d.mts +1 -0
- package/dist/math/triangle-trig/preset.d.mts +47 -0
- package/dist/math/triangle-trig/preset.mjs +245 -0
- package/dist/math/trig-explorer.d.mts +18 -0
- package/dist/math/trig-explorer.mjs +209 -0
- package/dist/ml/boundary/index.d.mts +1 -0
- package/dist/ml/boundary/preset.d.mts +24 -0
- package/dist/ml/boundary/preset.mjs +385 -0
- package/dist/ml/classifier/index.d.mts +1 -0
- package/dist/ml/classifier/preset.d.mts +25 -0
- package/dist/ml/classifier/preset.mjs +315 -0
- package/dist/ml/index.d.mts +6 -0
- package/dist/ml/index.mjs +7 -0
- package/dist/ml/kmeans/index.d.mts +1 -0
- package/dist/ml/kmeans/preset.d.mts +33 -0
- package/dist/ml/kmeans/preset.mjs +236 -0
- package/dist/ml/knn/index.d.mts +1 -0
- package/dist/ml/knn/preset.d.mts +28 -0
- package/dist/ml/knn/preset.mjs +279 -0
- package/dist/ml/regression/index.d.mts +1 -0
- package/dist/ml/regression/preset.d.mts +32 -0
- package/dist/ml/regression/preset.mjs +394 -0
- package/dist/physics/atwood/index.d.mts +1 -0
- package/dist/physics/atwood/preset.d.mts +23 -0
- package/dist/physics/atwood/preset.mjs +312 -0
- package/dist/physics/bullet-walls/index.d.mts +1 -0
- package/dist/physics/bullet-walls/preset.d.mts +28 -0
- package/dist/physics/bullet-walls/preset.mjs +373 -0
- package/dist/physics/carnot/index.d.mts +1 -0
- package/dist/physics/carnot/preset.d.mts +27 -0
- package/dist/physics/carnot/preset.mjs +427 -0
- package/dist/physics/circular-motion/index.d.mts +1 -0
- package/dist/physics/circular-motion/preset.d.mts +25 -0
- package/dist/physics/circular-motion/preset.mjs +293 -0
- package/dist/physics/collision-track/index.d.mts +1 -0
- package/dist/physics/collision-track/preset.d.mts +27 -0
- package/dist/physics/collision-track/preset.mjs +352 -0
- package/dist/physics/efficiency/index.d.mts +1 -0
- package/dist/physics/efficiency/preset.d.mts +33 -0
- package/dist/physics/efficiency/preset.mjs +343 -0
- package/dist/physics/electric-field/index.d.mts +1 -0
- package/dist/physics/electric-field/preset.d.mts +15 -0
- package/dist/physics/electric-field/preset.mjs +306 -0
- package/dist/physics/energy-skate/index.d.mts +1 -0
- package/dist/physics/energy-skate/preset.d.mts +25 -0
- package/dist/physics/energy-skate/preset.mjs +254 -0
- package/dist/physics/entropy/index.d.mts +1 -0
- package/dist/physics/entropy/preset.d.mts +18 -0
- package/dist/physics/entropy/preset.mjs +416 -0
- package/dist/physics/expansion/index.d.mts +1 -0
- package/dist/physics/expansion/preset.d.mts +26 -0
- package/dist/physics/expansion/preset.mjs +609 -0
- package/dist/physics/exponential/asset.mjs +221 -0
- package/dist/physics/exponential/index.d.mts +1 -0
- package/dist/physics/exponential/preset.d.mts +17 -0
- package/dist/physics/exponential/preset.mjs +182 -0
- package/dist/physics/gas-process/index.d.mts +1 -0
- package/dist/physics/gas-process/preset.d.mts +30 -0
- package/dist/physics/gas-process/preset.mjs +384 -0
- package/dist/physics/gravitation/index.d.mts +1 -0
- package/dist/physics/gravitation/preset.d.mts +24 -0
- package/dist/physics/gravitation/preset.mjs +345 -0
- package/dist/physics/gravity-drop.d.mts +9 -0
- package/dist/physics/gravity-drop.mjs +187 -0
- package/dist/physics/heat-transfer/index.d.mts +1 -0
- package/dist/physics/heat-transfer/preset.d.mts +27 -0
- package/dist/physics/heat-transfer/preset.mjs +626 -0
- package/dist/physics/impulse/index.d.mts +1 -0
- package/dist/physics/impulse/preset.d.mts +29 -0
- package/dist/physics/impulse/preset.mjs +453 -0
- package/dist/physics/index.d.mts +43 -0
- package/dist/physics/index.mjs +44 -0
- package/dist/physics/kepler/index.d.mts +1 -0
- package/dist/physics/kepler/preset.d.mts +27 -0
- package/dist/physics/kepler/preset.mjs +257 -0
- package/dist/physics/lever/asset.d.mts +6 -0
- package/dist/physics/lever/asset.mjs +220 -0
- package/dist/physics/lever/index.d.mts +2 -0
- package/dist/physics/lever/preset.d.mts +31 -0
- package/dist/physics/lever/preset.mjs +261 -0
- package/dist/physics/lorentz/index.d.mts +1 -0
- package/dist/physics/lorentz/preset.d.mts +29 -0
- package/dist/physics/lorentz/preset.mjs +367 -0
- package/dist/physics/magnetism/index.d.mts +1 -0
- package/dist/physics/magnetism/preset.d.mts +15 -0
- package/dist/physics/magnetism/preset.mjs +334 -0
- package/dist/physics/optics/asset.d.mts +6 -0
- package/dist/physics/optics/asset.mjs +234 -0
- package/dist/physics/optics/index.d.mts +2 -0
- package/dist/physics/optics/preset.d.mts +14 -0
- package/dist/physics/optics/preset.mjs +202 -0
- package/dist/physics/orbit-lab.d.mts +6 -0
- package/dist/physics/orbit-lab.mjs +222 -0
- package/dist/physics/projectile-lab.d.mts +10 -0
- package/dist/physics/projectile-lab.mjs +354 -0
- package/dist/physics/rain-relative/index.d.mts +1 -0
- package/dist/physics/rain-relative/preset.d.mts +19 -0
- package/dist/physics/rain-relative/preset.mjs +358 -0
- package/dist/physics/ramp-forces/index.d.mts +1 -0
- package/dist/physics/ramp-forces/preset.d.mts +36 -0
- package/dist/physics/ramp-forces/preset.mjs +550 -0
- package/dist/physics/river-boat.d.mts +22 -0
- package/dist/physics/river-boat.mjs +498 -0
- package/dist/physics/shm/index.d.mts +1 -0
- package/dist/physics/shm/preset.d.mts +33 -0
- package/dist/physics/shm/preset.mjs +554 -0
- package/dist/physics/stopping-distance/index.d.mts +1 -0
- package/dist/physics/stopping-distance/preset.d.mts +29 -0
- package/dist/physics/stopping-distance/preset.mjs +662 -0
- package/dist/physics/temperature-scales/index.d.mts +1 -0
- package/dist/physics/temperature-scales/preset.d.mts +15 -0
- package/dist/physics/temperature-scales/preset.mjs +353 -0
- package/dist/physics/terminal-velocity/index.d.mts +1 -0
- package/dist/physics/terminal-velocity/preset.d.mts +26 -0
- package/dist/physics/terminal-velocity/preset.mjs +404 -0
- package/dist/physics/thermal/index.d.mts +1 -0
- package/dist/physics/thermal/preset.d.mts +44 -0
- package/dist/physics/thermal/preset.mjs +373 -0
- package/dist/physics/vector-board/index.d.mts +1 -0
- package/dist/physics/vector-board/preset.d.mts +65 -0
- package/dist/physics/vector-board/preset.mjs +273 -0
- package/dist/physics/vector-board/view.d.mts +49 -0
- package/dist/physics/vector-board/view.mjs +58 -0
- package/dist/physics/vector-scene.d.mts +41 -0
- package/dist/physics/vector-scene.mjs +211 -0
- package/dist/physics/vector-types/index.d.mts +1 -0
- package/dist/physics/vector-types/preset.d.mts +27 -0
- package/dist/physics/vector-types/preset.mjs +192 -0
- package/dist/physics/water-density/index.d.mts +1 -0
- package/dist/physics/water-density/preset.d.mts +18 -0
- package/dist/physics/water-density/preset.mjs +439 -0
- package/dist/physics/waves/core.mjs +33 -0
- package/dist/physics/waves/doppler.d.mts +23 -0
- package/dist/physics/waves/doppler.mjs +260 -0
- package/dist/physics/waves/index.d.mts +4 -0
- package/dist/physics/waves/preset.d.mts +30 -0
- package/dist/physics/waves/preset.mjs +488 -0
- package/dist/physics/waves/ripple.d.mts +26 -0
- package/dist/physics/waves/ripple.mjs +234 -0
- package/dist/physics/waves/string.d.mts +29 -0
- package/dist/physics/waves/string.mjs +289 -0
- package/dist/physics/work-energy/index.d.mts +1 -0
- package/dist/physics/work-energy/preset.d.mts +17 -0
- package/dist/physics/work-energy/preset.mjs +341 -0
- package/dist/schemas/index.d.mts +235 -0
- package/dist/schemas/index.mjs +145 -0
- package/dist/statistics/center-spread/preset.d.mts +34 -0
- package/dist/statistics/center-spread/preset.mjs +323 -0
- package/dist/statistics/core/descriptive.d.mts +35 -0
- package/dist/statistics/core/descriptive.mjs +64 -0
- package/dist/statistics/core/normal.d.mts +21 -0
- package/dist/statistics/core/normal.mjs +37 -0
- package/dist/statistics/core/sequences.d.mts +27 -0
- package/dist/statistics/core/sequences.mjs +35 -0
- package/dist/statistics/galton/preset.d.mts +27 -0
- package/dist/statistics/galton/preset.mjs +331 -0
- package/dist/statistics/histogram/preset.d.mts +27 -0
- package/dist/statistics/histogram/preset.mjs +385 -0
- package/dist/statistics/index.d.mts +11 -0
- package/dist/statistics/index.mjs +12 -0
- package/dist/statistics/normal/preset.d.mts +30 -0
- package/dist/statistics/normal/preset.mjs +400 -0
- package/dist/statistics/sampling/preset.d.mts +32 -0
- package/dist/statistics/sampling/preset.mjs +406 -0
- package/dist/statistics/sequence/preset.d.mts +28 -0
- package/dist/statistics/sequence/preset.mjs +302 -0
- package/dist/statistics/z-table/preset.d.mts +28 -0
- package/dist/statistics/z-table/preset.mjs +348 -0
- package/package.json +266 -0
- package/styles.css +267 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Classytic
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# @classytic/labs
|
|
2
|
+
|
|
3
|
+
**Authorable, domain-organized interactive learning labs — built on the
|
|
4
|
+
[`@classytic/stage`](../stage) engine.** Labs are React components composed from the
|
|
5
|
+
stage primitives — SVG `<Stage>` (accessible, themeable, agent-drivable) plus a zero-dep
|
|
6
|
+
`<CanvasLayer>` for high-element animations — with HTML controls around them, tokenized
|
|
7
|
+
and validated by Zod prop schemas. Some labs are backed by a portable JSON `SceneDoc`
|
|
8
|
+
(typed dependency graph + resolver + command/undo); many are direct primitive
|
|
9
|
+
compositions. Per-domain subpaths so
|
|
10
|
+
you only ship what you import.
|
|
11
|
+
|
|
12
|
+
The product isn't a fixed widget catalogue — it's a small, sharp engine + reusable
|
|
13
|
+
**lab families** (templates) a teacher composes and configures. Adding a "new lab" =
|
|
14
|
+
registering one family, not new plumbing.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i @classytic/labs @classytic/stage
|
|
18
|
+
# required peers: react, react-dom
|
|
19
|
+
# optional peers: katex (pretty math), zod (template params + /blocks), lucide-react,
|
|
20
|
+
# @classytic/cms-ui + @classytic/cms (for /blocks authoring)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
/* in your global CSS, after `@import "tailwindcss";` */
|
|
25
|
+
@import "@classytic/stage/styles.css"; /* engine tokens + asset kit */
|
|
26
|
+
@import "@classytic/labs/styles.css"; /* control-UI kit + lab tokens */
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// once, if you use any lab that renders equations (DerivativeExplorer, Grapher, …)
|
|
31
|
+
import "katex/dist/katex.min.css";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Use a lab
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { Grapher, DerivativeExplorer, BalanceAlgebraLab } from '@classytic/labs/math';
|
|
38
|
+
import { LeverBalanceLab } from '@classytic/labs/physics';
|
|
39
|
+
import { CircuitNetworkLab } from '@classytic/labs/circuits';
|
|
40
|
+
|
|
41
|
+
// type any equation(s) + expose learner-draggable param sliders:
|
|
42
|
+
<Grapher equations={['a*sin(b*x)']} params={[{ name: 'a', min: 0, max: 3, value: 1 }]} />
|
|
43
|
+
|
|
44
|
+
// drag a point; the secant becomes the EXACT tangent (symbolic f′), shown in KaTeX:
|
|
45
|
+
<DerivativeExplorer equation="x^2" />
|
|
46
|
+
|
|
47
|
+
// solve 2x + 1 = 7 by balancing the scale:
|
|
48
|
+
<BalanceAlgebraLab coef={2} addend={1} rhs={7} answer={3} />
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The lab-template registry (`@classytic/labs/catalog`)
|
|
52
|
+
|
|
53
|
+
Families are listable/instantiable units — the basis for a lab "marketplace" and the
|
|
54
|
+
authoring kit. Params are validated against the family's zod schema before a scene is built.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { listLabTemplates, instantiateTemplate } from '@classytic/labs/catalog';
|
|
58
|
+
|
|
59
|
+
listLabTemplates(); // [{ id:'balance-algebra', category:'algebra', … }, …]
|
|
60
|
+
const r = instantiateTemplate('balance-algebra', { coef: 3, addend: 1, rhs: 10, answer: 3 });
|
|
61
|
+
if (r.ok) renderScene(r.doc); // r.doc is a portable SceneDoc
|
|
62
|
+
else console.warn(r.error, r.issues); // typed validation errors — no broken scene
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Built-in families: `balance-algebra`, `area-model`, `growing-pattern`, `balance-lever`,
|
|
66
|
+
`optics`, `circuit` (more as domains migrate).
|
|
67
|
+
|
|
68
|
+
## Authoring
|
|
69
|
+
|
|
70
|
+
Labs are authored with the stage **SceneBuilder** in `authoring` mode (place points,
|
|
71
|
+
sliders, labels; live scalar controls; a pedagogy/`LabMeta` editor) and surfaced in a
|
|
72
|
+
host (e.g. Brihot/Mentora) via the `@classytic/cms-ui` `defineBlock` contract. The lab's
|
|
73
|
+
completion/score events flow to the host's learner seam (xAPI) via `useLearner().report`.
|
|
74
|
+
|
|
75
|
+
## Subpaths
|
|
76
|
+
|
|
77
|
+
Domain packs (lab components): `@classytic/labs/{math, physics, chem, circuits, geometry,
|
|
78
|
+
language, ict, commerce, biology, geography, discrete, statistics, ml}`. Shared:
|
|
79
|
+
`@classytic/labs/{core, catalog, schemas}`. Editor blocks: `@classytic/labs/blocks` (all)
|
|
80
|
+
or per-domain `@classytic/labs/blocks/{math, physics, chem, circuits, geometry, ict,
|
|
81
|
+
language, accounting, economics, biology, geography, ml, discrete, statistics}`. Import
|
|
82
|
+
only what you need (tree-shaken at the subpath boundary).
|
|
83
|
+
|
|
84
|
+
## Rendering model (all on @classytic/stage)
|
|
85
|
+
|
|
86
|
+
**Every lab renders on the stage engine — the legacy canvas engine is gone.** Two backends:
|
|
87
|
+
|
|
88
|
+
- **SVG `<Stage>`** (the default — accessible, themeable, SceneDoc-portable): all of math,
|
|
89
|
+
the physics vector/diagram labs (`VectorScene`, `RiverBoat`, `ProjectileLab`,
|
|
90
|
+
`GravityDrop`), chemistry (`BohrAtom`, `ReactionProfile`, `ReactionLab`, `Battery`),
|
|
91
|
+
circuits (`CircuitLab`, `CircuitBuilder`, `CircuitNetworkLab`), and geometry
|
|
92
|
+
(`GeometryBoard`, `GeometryBuilder`, `IntersectingCircles`).
|
|
93
|
+
- **`<CanvasLayer>`** (stage's zero-dependency raw-Canvas2D escape hatch — HiDPI, shares the
|
|
94
|
+
engine coords + clock) for the genuine high-element-count labs: `GradientDescent` (per-cell
|
|
95
|
+
heatmap) and `OrbitLab` (fading 260-point trail). This is the deliberate alternative to a
|
|
96
|
+
heavy GPU dependency; nothing here needs WebGL.
|
|
97
|
+
|
|
98
|
+
`@classytic/labs/core` is now just a small domain-neutral toolkit on top of stage (lazy-KaTeX
|
|
99
|
+
`<Tex>`, numerical calculus, easing/keyframes, a tiny reactive value, number utils) — the
|
|
100
|
+
coordinate system, primitives, resolver, clock, control surface, and learner seam all live in
|
|
101
|
+
`@classytic/stage`.
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { EnzymeRateLab, EnzymeRateProps } from "./preset.mjs";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/biology/enzyme-rate/preset.d.ts
|
|
4
|
+
interface EnzymeRateProps {
|
|
5
|
+
factor?: 'temperature' | 'pH';
|
|
6
|
+
optimum?: number;
|
|
7
|
+
factorMin?: number;
|
|
8
|
+
factorMax?: number;
|
|
9
|
+
title?: string;
|
|
10
|
+
prompt?: string;
|
|
11
|
+
height?: number;
|
|
12
|
+
objectives?: string[];
|
|
13
|
+
}
|
|
14
|
+
declare function EnzymeRateLab({
|
|
15
|
+
factor,
|
|
16
|
+
optimum,
|
|
17
|
+
factorMin,
|
|
18
|
+
factorMax,
|
|
19
|
+
title,
|
|
20
|
+
prompt,
|
|
21
|
+
height,
|
|
22
|
+
objectives
|
|
23
|
+
}: EnzymeRateProps): ReactNode;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { EnzymeRateLab, EnzymeRateProps };
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { clamp } from "../../core/util.mjs";
|
|
4
|
+
import { Slider, StatusPill } from "../../kit/controls.mjs";
|
|
5
|
+
import { Callout, ControlBar, Field, LabFrame, LiveRegion } from "../../kit/frame.mjs";
|
|
6
|
+
import { useCheckpoint } from "../../kit/pedagogy.mjs";
|
|
7
|
+
import { useRef, useState } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { Axes, Dot, Label, Polygon, Segment, Stage } from "@classytic/stage";
|
|
10
|
+
|
|
11
|
+
//#region src/biology/enzyme-rate/preset.tsx
|
|
12
|
+
/**
|
|
13
|
+
* EnzymeRateLab — the optimum, then the cliff: enzymes denature.
|
|
14
|
+
*
|
|
15
|
+
* Drag temperature: the rate climbs to an optimum (more kinetic energy → more
|
|
16
|
+
* successful enzyme–substrate collisions) then CRASHES as the lock-and-key active
|
|
17
|
+
* site is mangled — and crucially, cooling back down does NOT restore it
|
|
18
|
+
* (thermal denaturation is irreversible). The bell is BUILT from plotted dots as
|
|
19
|
+
* you sweep, never pre-drawn. pH mode shows the same optimum but reversibly; a
|
|
20
|
+
* "fresh enzyme" reset is the only way back from a denatured run.
|
|
21
|
+
*
|
|
22
|
+
* Reuses core/util + kit/controls; tokenized; reduced-motion safe (no autoplay —
|
|
23
|
+
* the learner drags). The collision-theory vs denaturation split → a MathDerivation.
|
|
24
|
+
*/
|
|
25
|
+
const CLIFF = 16;
|
|
26
|
+
/** A lock-and-key enzyme glyph; `denat` 0 (intact) → 1 (mangled active site). */
|
|
27
|
+
function Enzyme({ denat }) {
|
|
28
|
+
const d = clamp(denat, 0, 1);
|
|
29
|
+
const body = d > .05 ? "var(--stage-danger)" : "var(--stage-accent)";
|
|
30
|
+
const edge = `color-mix(in oklab, ${body} 60%, black)`;
|
|
31
|
+
const splay = d * 14;
|
|
32
|
+
const notch = `M ${40 - splay} 26 L 52 ${48 + d * 8} L 64 ${30 - splay * .5} L 76 ${48 + d * 6} L ${88 + splay} 26`;
|
|
33
|
+
const keySeated = d < .25;
|
|
34
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
35
|
+
width: 150,
|
|
36
|
+
height: 120,
|
|
37
|
+
viewBox: "0 0 130 120",
|
|
38
|
+
"aria-hidden": true,
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsx("path", {
|
|
41
|
+
d: "M 18 30 Q 14 70 30 96 Q 64 110 98 96 Q 114 70 110 30 Z",
|
|
42
|
+
fill: `color-mix(in oklab, ${body} 22%, var(--stage-bg))`,
|
|
43
|
+
stroke: edge,
|
|
44
|
+
strokeWidth: 2
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ jsx("path", {
|
|
47
|
+
d: notch,
|
|
48
|
+
fill: "var(--stage-bg)",
|
|
49
|
+
stroke: edge,
|
|
50
|
+
strokeWidth: 2.5,
|
|
51
|
+
strokeLinejoin: "round"
|
|
52
|
+
}),
|
|
53
|
+
/* @__PURE__ */ jsx("g", {
|
|
54
|
+
transform: keySeated ? "translate(52 8)" : `translate(58 -8) rotate(${18 + d * 14} 12 14)`,
|
|
55
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
56
|
+
d: "M 0 18 L 12 0 L 24 18 Z",
|
|
57
|
+
fill: keySeated ? "var(--stage-good)" : "var(--stage-warn)",
|
|
58
|
+
stroke: "color-mix(in oklab, var(--stage-fg) 40%, transparent)",
|
|
59
|
+
strokeWidth: 1
|
|
60
|
+
})
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ jsx("text", {
|
|
63
|
+
x: 64,
|
|
64
|
+
y: 114,
|
|
65
|
+
fill: "var(--stage-muted)",
|
|
66
|
+
fontSize: 10,
|
|
67
|
+
fontWeight: 700,
|
|
68
|
+
textAnchor: "middle",
|
|
69
|
+
children: d > .4 ? "DENATURED" : keySeated ? "substrate fits" : "binding…"
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function EnzymeRateLab({ factor = "temperature", optimum = 40, factorMin = 0, factorMax = 80, title = "The optimum, then the cliff — enzymes denature", prompt = "Drag the temperature. Past the optimum the enzyme denatures — and cooling back down won’t fix it.", height = 240, objectives }) {
|
|
75
|
+
const reversible = factor === "pH";
|
|
76
|
+
const [f, setF] = useState(reversible ? optimum - 2 : factorMin + 5);
|
|
77
|
+
const peak = useRef(f);
|
|
78
|
+
const pts = useRef(/* @__PURE__ */ new Map());
|
|
79
|
+
const [, setTick] = useState(0);
|
|
80
|
+
useCheckpoint({
|
|
81
|
+
solved: Math.abs(f - optimum) < 1.5,
|
|
82
|
+
activity: "enzyme-rate"
|
|
83
|
+
});
|
|
84
|
+
const denatFrom = (x) => clamp((x - optimum) / CLIFF, 0, 1);
|
|
85
|
+
const denat = reversible ? denatFrom(f) : denatFrom(peak.current);
|
|
86
|
+
const rate = clamp(clamp(f / optimum, 0, 1) * (1 - denat), 0, 1);
|
|
87
|
+
pts.current.set(Math.round(f), rate);
|
|
88
|
+
const onF = (v) => {
|
|
89
|
+
setF(v);
|
|
90
|
+
if (!reversible && v > peak.current) peak.current = v;
|
|
91
|
+
setTick((t) => t + 1 & 65535);
|
|
92
|
+
};
|
|
93
|
+
const reset = () => {
|
|
94
|
+
pts.current = /* @__PURE__ */ new Map();
|
|
95
|
+
peak.current = factorMin + 5;
|
|
96
|
+
setF(factorMin + 5);
|
|
97
|
+
setTick((t) => t + 1 & 65535);
|
|
98
|
+
};
|
|
99
|
+
const view = {
|
|
100
|
+
xMin: factorMin - (factorMax - factorMin) * .06,
|
|
101
|
+
xMax: factorMax + 1,
|
|
102
|
+
yMin: -.12,
|
|
103
|
+
yMax: 1.12
|
|
104
|
+
};
|
|
105
|
+
const unit = reversible ? "" : " °C";
|
|
106
|
+
const points = [...pts.current.entries()].sort((a, b) => a[0] - b[0]);
|
|
107
|
+
const state = denat > .5 ? "denatured" : Math.abs(f - optimum) < 2 ? "optimum" : f < optimum ? "climbing" : "falling";
|
|
108
|
+
const figure = /* @__PURE__ */ jsxs("div", {
|
|
109
|
+
style: {
|
|
110
|
+
display: "flex",
|
|
111
|
+
gap: 12,
|
|
112
|
+
flexWrap: "wrap",
|
|
113
|
+
alignItems: "center",
|
|
114
|
+
borderRadius: 14,
|
|
115
|
+
background: "var(--stage-bg)",
|
|
116
|
+
border: "1px solid var(--stage-grid)",
|
|
117
|
+
padding: 12
|
|
118
|
+
},
|
|
119
|
+
children: [/* @__PURE__ */ jsx(Enzyme, { denat }), /* @__PURE__ */ jsx("div", {
|
|
120
|
+
style: {
|
|
121
|
+
flex: 1,
|
|
122
|
+
minWidth: 240
|
|
123
|
+
},
|
|
124
|
+
children: /* @__PURE__ */ jsxs(Stage, {
|
|
125
|
+
view,
|
|
126
|
+
height,
|
|
127
|
+
preserveAspect: false,
|
|
128
|
+
ariaLabel: `Enzyme rate vs ${factor}; ${state}`,
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx(Axes, { ticks: false }),
|
|
131
|
+
/* @__PURE__ */ jsx(Label, {
|
|
132
|
+
x: (factorMin + factorMax) / 2,
|
|
133
|
+
y: -.08,
|
|
134
|
+
text: reversible ? "pH →" : "temperature →",
|
|
135
|
+
color: "var(--stage-muted)",
|
|
136
|
+
size: 11
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ jsx(Label, {
|
|
139
|
+
x: factorMin,
|
|
140
|
+
y: .55,
|
|
141
|
+
text: "rate",
|
|
142
|
+
color: "var(--stage-muted)",
|
|
143
|
+
size: 11,
|
|
144
|
+
dx: -6
|
|
145
|
+
}),
|
|
146
|
+
!reversible && /* @__PURE__ */ jsx(Polygon, {
|
|
147
|
+
points: [
|
|
148
|
+
{
|
|
149
|
+
x: optimum + CLIFF,
|
|
150
|
+
y: 0
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
x: factorMax,
|
|
154
|
+
y: 0
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
x: factorMax,
|
|
158
|
+
y: 1.1
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
x: optimum + CLIFF,
|
|
162
|
+
y: 1.1
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
color: "var(--stage-danger)",
|
|
166
|
+
fill: "var(--stage-danger)",
|
|
167
|
+
fillOpacity: .08,
|
|
168
|
+
weight: 0
|
|
169
|
+
}),
|
|
170
|
+
/* @__PURE__ */ jsx(Segment, {
|
|
171
|
+
from: {
|
|
172
|
+
x: optimum,
|
|
173
|
+
y: 0
|
|
174
|
+
},
|
|
175
|
+
to: {
|
|
176
|
+
x: optimum,
|
|
177
|
+
y: 1.1
|
|
178
|
+
},
|
|
179
|
+
color: "var(--stage-good)",
|
|
180
|
+
weight: 1,
|
|
181
|
+
dashed: true,
|
|
182
|
+
opacity: .5
|
|
183
|
+
}),
|
|
184
|
+
/* @__PURE__ */ jsx(Label, {
|
|
185
|
+
x: optimum,
|
|
186
|
+
y: 1.1,
|
|
187
|
+
text: "optimum",
|
|
188
|
+
color: "var(--stage-good)",
|
|
189
|
+
size: 10,
|
|
190
|
+
dy: -4
|
|
191
|
+
}),
|
|
192
|
+
points.map(([x, y]) => /* @__PURE__ */ jsx(Dot, {
|
|
193
|
+
x,
|
|
194
|
+
y,
|
|
195
|
+
r: 3,
|
|
196
|
+
color: "var(--stage-accent)",
|
|
197
|
+
opacity: .85
|
|
198
|
+
}, x)),
|
|
199
|
+
/* @__PURE__ */ jsx(Dot, {
|
|
200
|
+
x: f,
|
|
201
|
+
y: rate,
|
|
202
|
+
r: 6,
|
|
203
|
+
color: denat > .5 ? "var(--stage-danger)" : "var(--stage-good)"
|
|
204
|
+
})
|
|
205
|
+
]
|
|
206
|
+
})
|
|
207
|
+
})]
|
|
208
|
+
});
|
|
209
|
+
return /* @__PURE__ */ jsx(LabFrame, {
|
|
210
|
+
title,
|
|
211
|
+
prompt,
|
|
212
|
+
objectives,
|
|
213
|
+
aside: /* @__PURE__ */ jsxs(Callout, {
|
|
214
|
+
tone: state === "optimum" ? "result" : "info",
|
|
215
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
216
|
+
style: {
|
|
217
|
+
fontVariantNumeric: "tabular-nums",
|
|
218
|
+
fontWeight: 600
|
|
219
|
+
},
|
|
220
|
+
children: [
|
|
221
|
+
reversible ? "pH" : "temperature",
|
|
222
|
+
" ",
|
|
223
|
+
f.toFixed(0),
|
|
224
|
+
unit,
|
|
225
|
+
" · rate ",
|
|
226
|
+
(rate * 100).toFixed(0)
|
|
227
|
+
]
|
|
228
|
+
}), /* @__PURE__ */ jsx(StatusPill, {
|
|
229
|
+
ok: state === "optimum",
|
|
230
|
+
children: state === "optimum" ? "at the optimum ✓" : state === "denatured" ? "denatured — no recovery" : state === "falling" ? reversible ? "past optimum" : "denaturing…" : "climbing (more collisions)"
|
|
231
|
+
})]
|
|
232
|
+
}),
|
|
233
|
+
controls: /* @__PURE__ */ jsxs(ControlBar, { children: [/* @__PURE__ */ jsx(Field, {
|
|
234
|
+
label: reversible ? "pH" : "temperature",
|
|
235
|
+
value: `${f.toFixed(0)}${unit}`,
|
|
236
|
+
children: /* @__PURE__ */ jsx(Slider, {
|
|
237
|
+
value: f,
|
|
238
|
+
min: factorMin,
|
|
239
|
+
max: factorMax,
|
|
240
|
+
step: 1,
|
|
241
|
+
onChange: onF,
|
|
242
|
+
ariaLabel: reversible ? "pH" : "temperature"
|
|
243
|
+
})
|
|
244
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
245
|
+
type: "button",
|
|
246
|
+
className: "lab-chip",
|
|
247
|
+
onClick: reset,
|
|
248
|
+
children: "↺ fresh enzyme"
|
|
249
|
+
})] }),
|
|
250
|
+
footer: /* @__PURE__ */ jsx(LiveRegion, { children: `${reversible ? "pH" : "Temperature"} ${f.toFixed(0)}, rate ${(rate * 100).toFixed(0)}. ${state}.` }),
|
|
251
|
+
children: figure
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
//#endregion
|
|
256
|
+
export { EnzymeRateLab };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/biology/genetic-cross/core.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Genetics core — a SERIALIZABLE cross model + the rule that turns a genotype into
|
|
4
|
+
* a phenotype. Authored as data (so agents can declare it via JSON), resolved into
|
|
5
|
+
* pure functions for the lab. One model covers simple dominance, multiple alleles,
|
|
6
|
+
* codominance and incomplete dominance:
|
|
7
|
+
*
|
|
8
|
+
* • each allele has a dominance `rank` + the `trait` it expresses
|
|
9
|
+
* • phenotype = the trait(s) of the highest-rank allele(s) present; two equal
|
|
10
|
+
* top-rank alleles with different traits express together (CODOMINANCE → "AB")
|
|
11
|
+
* • an optional `blends` entry overrides a specific heterozygote
|
|
12
|
+
* (INCOMPLETE DOMINANCE → red × white = pink)
|
|
13
|
+
*
|
|
14
|
+
* No reinvented numerics — this is just the genetics rule; UI lives in the preset.
|
|
15
|
+
*/
|
|
16
|
+
interface AlleleSpec {
|
|
17
|
+
symbol: string;
|
|
18
|
+
rank: number;
|
|
19
|
+
trait: string;
|
|
20
|
+
}
|
|
21
|
+
interface BlendSpec {
|
|
22
|
+
pair: [string, string];
|
|
23
|
+
label: string;
|
|
24
|
+
color?: string;
|
|
25
|
+
}
|
|
26
|
+
interface CrossModelSpec {
|
|
27
|
+
trait?: string;
|
|
28
|
+
alleles: AlleleSpec[];
|
|
29
|
+
blends?: BlendSpec[];
|
|
30
|
+
colors?: Record<string, string>;
|
|
31
|
+
}
|
|
32
|
+
interface Phenotype {
|
|
33
|
+
label: string;
|
|
34
|
+
color: string;
|
|
35
|
+
}
|
|
36
|
+
interface ResolvedModel {
|
|
37
|
+
trait: string;
|
|
38
|
+
alleles: AlleleSpec[];
|
|
39
|
+
/** order a genotype's two alleles by their declared position (stable display). */
|
|
40
|
+
norm: (a: string, b: string) => [string, string];
|
|
41
|
+
phenotypeOf: (a: string, b: string) => Phenotype;
|
|
42
|
+
phenotypeColor: (label: string) => string;
|
|
43
|
+
/** every possible genotype as a normalised [a,b] pair (for parent pickers). */
|
|
44
|
+
genotypes: [string, string][];
|
|
45
|
+
/** true if `a` masks `b` here — a dominant over a present lower-rank allele. */
|
|
46
|
+
masks: (a: string, b: string) => boolean;
|
|
47
|
+
}
|
|
48
|
+
declare function resolveModel(spec: CrossModelSpec): ResolvedModel;
|
|
49
|
+
/** Simple dominant/recessive — the classic monohybrid (also backs PunnettCross). */
|
|
50
|
+
declare const monohybridSpec: (letter?: string, dominant?: string, recessive?: string) => CrossModelSpec;
|
|
51
|
+
/** ABO blood groups — multiple alleles + codominance (Aᴬ Aᴮ → AB). */
|
|
52
|
+
declare const BLOOD_TYPE_SPEC: CrossModelSpec;
|
|
53
|
+
/** Incomplete dominance — red × white = pink (a blended heterozygote). */
|
|
54
|
+
declare const INCOMPLETE_SPEC: CrossModelSpec;
|
|
55
|
+
declare const CROSS_PRESETS: {
|
|
56
|
+
readonly monohybrid: CrossModelSpec;
|
|
57
|
+
readonly 'blood-type': CrossModelSpec;
|
|
58
|
+
readonly incomplete: CrossModelSpec;
|
|
59
|
+
};
|
|
60
|
+
type CrossPresetKey = keyof typeof CROSS_PRESETS;
|
|
61
|
+
/** Two independent genes — the classic dihybrid 9:3:3:1 (height × seed colour). */
|
|
62
|
+
declare const DIHYBRID_LOCI: CrossModelSpec[];
|
|
63
|
+
//#endregion
|
|
64
|
+
export { AlleleSpec, BLOOD_TYPE_SPEC, BlendSpec, CROSS_PRESETS, CrossModelSpec, CrossPresetKey, DIHYBRID_LOCI, INCOMPLETE_SPEC, Phenotype, ResolvedModel, monohybridSpec, resolveModel };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//#region src/biology/genetic-cross/core.ts
|
|
2
|
+
const PALETTE = [
|
|
3
|
+
"var(--stage-accent)",
|
|
4
|
+
"var(--stage-accent-2)",
|
|
5
|
+
"var(--stage-good)",
|
|
6
|
+
"var(--stage-warn)",
|
|
7
|
+
"var(--stage-danger)",
|
|
8
|
+
"var(--stage-muted)"
|
|
9
|
+
];
|
|
10
|
+
const blendKey = (x, y) => [x, y].sort().join("|");
|
|
11
|
+
function resolveModel(spec) {
|
|
12
|
+
const order = new Map(spec.alleles.map((a, i) => [a.symbol, i]));
|
|
13
|
+
const rank = new Map(spec.alleles.map((a) => [a.symbol, a.rank]));
|
|
14
|
+
const trait = new Map(spec.alleles.map((a) => [a.symbol, a.trait]));
|
|
15
|
+
const blends = new Map((spec.blends ?? []).map((b) => [blendKey(b.pair[0], b.pair[1]), b]));
|
|
16
|
+
const labelOfPair = (a, b) => {
|
|
17
|
+
const bl = blends.get(blendKey(a, b));
|
|
18
|
+
if (bl) return bl.label;
|
|
19
|
+
const maxR = Math.max(rank.get(a) ?? 0, rank.get(b) ?? 0);
|
|
20
|
+
const tops = [a, b].filter((s) => (rank.get(s) ?? 0) === maxR);
|
|
21
|
+
const traits = [...new Set(tops.map((s) => trait.get(s) ?? s))];
|
|
22
|
+
return traits.length === 1 ? traits[0] : traits.join("");
|
|
23
|
+
};
|
|
24
|
+
const syms = spec.alleles.map((a) => a.symbol);
|
|
25
|
+
const genotypes = [];
|
|
26
|
+
const seen = [];
|
|
27
|
+
for (let i = 0; i < syms.length; i++) for (let j = i; j < syms.length; j++) {
|
|
28
|
+
genotypes.push([syms[i], syms[j]]);
|
|
29
|
+
const l = labelOfPair(syms[i], syms[j]);
|
|
30
|
+
if (!seen.includes(l)) seen.push(l);
|
|
31
|
+
}
|
|
32
|
+
const colorMap = new Map(seen.map((l, idx) => [l, spec.colors?.[l] ?? PALETTE[idx % PALETTE.length]]));
|
|
33
|
+
for (const b of spec.blends ?? []) if (b.color) colorMap.set(b.label, b.color);
|
|
34
|
+
const phenotypeColor = (label) => colorMap.get(label) ?? PALETTE[0];
|
|
35
|
+
return {
|
|
36
|
+
trait: spec.trait ?? "phenotype",
|
|
37
|
+
alleles: spec.alleles,
|
|
38
|
+
norm: (a, b) => (order.get(a) ?? 0) <= (order.get(b) ?? 0) ? [a, b] : [b, a],
|
|
39
|
+
phenotypeOf: (a, b) => ({
|
|
40
|
+
label: labelOfPair(a, b),
|
|
41
|
+
color: phenotypeColor(labelOfPair(a, b))
|
|
42
|
+
}),
|
|
43
|
+
phenotypeColor,
|
|
44
|
+
genotypes,
|
|
45
|
+
masks: (a, b) => !blends.has(blendKey(a, b)) && (rank.get(a) ?? 0) > (rank.get(b) ?? 0)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** Simple dominant/recessive — the classic monohybrid (also backs PunnettCross). */
|
|
49
|
+
const monohybridSpec = (letter = "A", dominant = "tall", recessive = "short") => ({
|
|
50
|
+
trait: "trait",
|
|
51
|
+
alleles: [{
|
|
52
|
+
symbol: letter.toUpperCase(),
|
|
53
|
+
rank: 2,
|
|
54
|
+
trait: dominant
|
|
55
|
+
}, {
|
|
56
|
+
symbol: letter.toLowerCase(),
|
|
57
|
+
rank: 1,
|
|
58
|
+
trait: recessive
|
|
59
|
+
}],
|
|
60
|
+
colors: {
|
|
61
|
+
[dominant]: "var(--stage-accent)",
|
|
62
|
+
[recessive]: "var(--stage-muted)"
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
/** ABO blood groups — multiple alleles + codominance (Aᴬ Aᴮ → AB). */
|
|
66
|
+
const BLOOD_TYPE_SPEC = {
|
|
67
|
+
trait: "blood type",
|
|
68
|
+
alleles: [
|
|
69
|
+
{
|
|
70
|
+
symbol: "A",
|
|
71
|
+
rank: 2,
|
|
72
|
+
trait: "A"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
symbol: "B",
|
|
76
|
+
rank: 2,
|
|
77
|
+
trait: "B"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
symbol: "O",
|
|
81
|
+
rank: 1,
|
|
82
|
+
trait: "O"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
colors: {
|
|
86
|
+
A: "var(--stage-accent)",
|
|
87
|
+
B: "var(--stage-accent-2)",
|
|
88
|
+
AB: "var(--stage-good)",
|
|
89
|
+
O: "var(--stage-muted)"
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
/** Incomplete dominance — red × white = pink (a blended heterozygote). */
|
|
93
|
+
const INCOMPLETE_SPEC = {
|
|
94
|
+
trait: "flower colour",
|
|
95
|
+
alleles: [{
|
|
96
|
+
symbol: "R",
|
|
97
|
+
rank: 1,
|
|
98
|
+
trait: "red"
|
|
99
|
+
}, {
|
|
100
|
+
symbol: "W",
|
|
101
|
+
rank: 1,
|
|
102
|
+
trait: "white"
|
|
103
|
+
}],
|
|
104
|
+
blends: [{
|
|
105
|
+
pair: ["R", "W"],
|
|
106
|
+
label: "pink",
|
|
107
|
+
color: "var(--stage-accent)"
|
|
108
|
+
}],
|
|
109
|
+
colors: {
|
|
110
|
+
red: "var(--stage-danger)",
|
|
111
|
+
white: "color-mix(in oklab, var(--stage-fg) 82%, var(--stage-bg))"
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const CROSS_PRESETS = {
|
|
115
|
+
monohybrid: monohybridSpec(),
|
|
116
|
+
"blood-type": BLOOD_TYPE_SPEC,
|
|
117
|
+
incomplete: INCOMPLETE_SPEC
|
|
118
|
+
};
|
|
119
|
+
/** Two independent genes — the classic dihybrid 9:3:3:1 (height × seed colour). */
|
|
120
|
+
const DIHYBRID_LOCI = [monohybridSpec("A", "tall", "short"), monohybridSpec("B", "yellow", "green")];
|
|
121
|
+
/** every distinct phenotype label a single-locus model can show (stable order). */
|
|
122
|
+
function phenotypeLabels(m) {
|
|
123
|
+
const seen = [];
|
|
124
|
+
for (const [a, b] of m.genotypes) {
|
|
125
|
+
const l = m.phenotypeOf(a, b).label;
|
|
126
|
+
if (!seen.includes(l)) seen.push(l);
|
|
127
|
+
}
|
|
128
|
+
return seen;
|
|
129
|
+
}
|
|
130
|
+
const COMBO_PALETTE = [
|
|
131
|
+
"var(--stage-good)",
|
|
132
|
+
"var(--stage-accent)",
|
|
133
|
+
"var(--stage-accent-2)",
|
|
134
|
+
"var(--stage-warn)",
|
|
135
|
+
"var(--stage-danger)",
|
|
136
|
+
"var(--stage-muted)"
|
|
137
|
+
];
|
|
138
|
+
/** stable colour map for the combined phenotype labels of a multi-locus cross. */
|
|
139
|
+
function comboColorMap(models) {
|
|
140
|
+
const perLocus = models.map(phenotypeLabels);
|
|
141
|
+
let combos = [""];
|
|
142
|
+
for (const labels of perLocus) combos = combos.flatMap((c) => labels.map((l) => c ? `${c} ${l}` : l));
|
|
143
|
+
return new Map(combos.map((c, i) => [c, COMBO_PALETTE[i % COMBO_PALETTE.length]]));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { BLOOD_TYPE_SPEC, CROSS_PRESETS, DIHYBRID_LOCI, INCOMPLETE_SPEC, comboColorMap, monohybridSpec, resolveModel };
|