@classytic/stage 0.2.0 → 0.4.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 +1 -1
- package/README.md +5 -1
- package/dist/_virtual/_rolldown/runtime.mjs +18 -0
- package/dist/assets/index.mjs +0 -1
- package/dist/atomic/aufbau.d.mts +144 -0
- package/dist/atomic/aufbau.mjs +384 -0
- package/dist/atomic/elements.d.mts +67 -0
- package/dist/atomic/elements.mjs +785 -0
- package/dist/atomic/emission.d.mts +112 -0
- package/dist/atomic/emission.mjs +179 -0
- package/dist/atomic/index.d.mts +8 -0
- package/dist/atomic/index.mjs +9 -0
- package/dist/atomic/periodic.d.mts +82 -0
- package/dist/atomic/periodic.mjs +231 -0
- package/dist/atomic/properties.d.mts +100 -0
- package/dist/atomic/properties.mjs +574 -0
- package/dist/atomic/shells.d.mts +137 -0
- package/dist/atomic/shells.mjs +170 -0
- package/dist/atomic/trends.d.mts +148 -0
- package/dist/atomic/trends.mjs +225 -0
- package/dist/builder/Palette.mjs +50 -89
- package/dist/builder/SceneBuilder.mjs +15 -73
- package/dist/chem/chromatography.d.mts +66 -0
- package/dist/chem/chromatography.mjs +63 -0
- package/dist/chem/complex.d.mts +114 -0
- package/dist/chem/complex.mjs +234 -0
- package/dist/chem/cycle.d.mts +75 -0
- package/dist/chem/cycle.mjs +145 -0
- package/dist/chem/equation.d.mts +86 -0
- package/dist/chem/equation.mjs +168 -0
- package/dist/chem/formula.d.mts +90 -0
- package/dist/chem/formula.mjs +201 -0
- package/dist/chem/functional-groups.d.mts +31 -0
- package/dist/chem/functional-groups.mjs +187 -0
- package/dist/chem/hazard.d.mts +94 -0
- package/dist/chem/hazard.mjs +329 -0
- package/dist/chem/index.d.mts +34 -33
- package/dist/chem/index.mjs +34 -28
- package/dist/chem/ionic.d.mts +98 -0
- package/dist/chem/ionic.mjs +156 -0
- package/dist/chem/layout.d.mts +46 -0
- package/dist/chem/layout.mjs +342 -0
- package/dist/chem/lewis.d.mts +79 -0
- package/dist/chem/lewis.mjs +163 -0
- package/dist/chem/molecular-orbital.d.mts +114 -0
- package/dist/chem/molecular-orbital.mjs +201 -0
- package/dist/chem/molecule.d.mts +154 -0
- package/dist/chem/molecule.mjs +282 -0
- package/dist/chem/nmr.d.mts +153 -0
- package/dist/chem/nmr.mjs +165 -0
- package/dist/chem/polymer.d.mts +65 -0
- package/dist/chem/polymer.mjs +179 -0
- package/dist/chem/redox.d.mts +138 -0
- package/dist/chem/redox.mjs +328 -0
- package/dist/chem/relations.d.mts +183 -0
- package/dist/chem/relations.mjs +299 -0
- package/dist/chem/skeleton.d.mts +51 -0
- package/dist/chem/skeleton.mjs +186 -0
- package/dist/chem/solution.d.mts +116 -0
- package/dist/chem/solution.mjs +186 -0
- package/dist/chem/species.d.mts +47 -0
- package/dist/chem/species.mjs +128 -0
- package/dist/chem/stereo.d.mts +108 -0
- package/dist/chem/stereo.mjs +286 -0
- package/dist/chem/stoichiometry.d.mts +95 -0
- package/dist/chem/stoichiometry.mjs +145 -0
- package/dist/chem/synthesis.d.mts +113 -0
- package/dist/chem/synthesis.mjs +281 -0
- package/dist/chem/vsepr.d.mts +80 -0
- package/dist/chem/vsepr.mjs +247 -0
- package/dist/circuit/ac.d.mts +163 -0
- package/dist/circuit/ac.mjs +452 -0
- package/dist/circuit/dc.d.mts +92 -0
- package/dist/circuit/dc.mjs +333 -0
- package/dist/circuit/index.d.mts +5 -92
- package/dist/circuit/index.mjs +5 -332
- package/dist/circuit/network.d.mts +99 -0
- package/dist/circuit/network.mjs +440 -0
- package/dist/circuit/topology.d.mts +102 -0
- package/dist/circuit/topology.mjs +143 -0
- package/dist/colour/absorption.d.mts +79 -0
- package/dist/colour/absorption.mjs +137 -0
- package/dist/colour/index.d.mts +6 -0
- package/dist/colour/index.mjs +7 -0
- package/dist/colour/name.d.mts +14 -0
- package/dist/colour/name.mjs +76 -0
- package/dist/colour/observer.d.mts +31 -0
- package/dist/colour/observer.mjs +46 -0
- package/dist/colour/spectrum.d.mts +61 -0
- package/dist/colour/spectrum.mjs +108 -0
- package/dist/colour/srgb.d.mts +49 -0
- package/dist/colour/srgb.mjs +108 -0
- package/dist/core/constants.d.mts +138 -0
- package/dist/core/constants.mjs +139 -0
- package/dist/core/index.d.mts +4 -1
- package/dist/core/index.mjs +4 -1
- package/dist/core/math.d.mts +26 -0
- package/dist/core/math.mjs +37 -0
- package/dist/core/vec3.d.mts +94 -0
- package/dist/core/vec3.mjs +123 -0
- package/dist/core/worked.d.mts +35 -0
- package/dist/core/worked.mjs +44 -0
- package/dist/electro/cell.d.mts +102 -0
- package/dist/electro/cell.mjs +170 -0
- package/dist/electro/conductivity.d.mts +157 -0
- package/dist/electro/conductivity.mjs +156 -0
- package/dist/electro/couples.d.mts +114 -0
- package/dist/electro/couples.mjs +334 -0
- package/dist/electro/electrolysis.d.mts +96 -0
- package/dist/electro/electrolysis.mjs +274 -0
- package/dist/electro/faraday.d.mts +150 -0
- package/dist/electro/faraday.mjs +118 -0
- package/dist/electro/index.d.mts +6 -0
- package/dist/electro/index.mjs +7 -0
- package/dist/finance/accounting/adjustments.d.mts +17 -0
- package/dist/finance/accounting/adjustments.mjs +202 -0
- package/dist/finance/accounting/analysis.d.mts +8 -0
- package/dist/finance/accounting/analysis.mjs +205 -0
- package/dist/finance/accounting/clubs.d.mts +21 -0
- package/dist/finance/accounting/clubs.mjs +217 -0
- package/dist/finance/accounting/company-statements.d.mts +7 -0
- package/dist/finance/accounting/company-statements.mjs +150 -0
- package/dist/finance/accounting/harness.d.mts +7 -0
- package/dist/finance/accounting/harness.mjs +45 -0
- package/dist/finance/accounting/index.d.mts +18 -0
- package/dist/finance/accounting/index.mjs +18 -0
- package/dist/finance/accounting/journalize.d.mts +16 -0
- package/dist/finance/accounting/journalize.mjs +128 -0
- package/dist/finance/accounting/manufacturing.d.mts +8 -0
- package/dist/finance/accounting/manufacturing.mjs +236 -0
- package/dist/finance/accounting/partnership.d.mts +7 -0
- package/dist/finance/accounting/partnership.mjs +152 -0
- package/dist/finance/accounting/period-case.d.mts +6 -0
- package/dist/finance/accounting/period-case.mjs +71 -0
- package/dist/finance/accounting/post.d.mts +9 -0
- package/dist/finance/accounting/post.mjs +84 -0
- package/dist/finance/accounting/precision.d.mts +9 -0
- package/dist/finance/accounting/precision.mjs +15 -0
- package/dist/finance/accounting/rules.d.mts +21 -0
- package/dist/finance/accounting/rules.mjs +37 -0
- package/dist/finance/accounting/solve.d.mts +28 -0
- package/dist/finance/accounting/solve.mjs +92 -0
- package/dist/finance/accounting/statements.d.mts +7 -0
- package/dist/finance/accounting/statements.mjs +142 -0
- package/dist/finance/accounting/types.d.mts +649 -0
- package/dist/finance/accounting/validate.d.mts +7 -0
- package/dist/finance/accounting/validate.mjs +67 -0
- package/dist/finance/accounting/verification.d.mts +24 -0
- package/dist/finance/accounting/verification.mjs +386 -0
- package/dist/finance/bizsim.d.mts +75 -0
- package/dist/finance/bizsim.mjs +296 -0
- package/dist/finance/index.d.mts +95 -0
- package/dist/finance/index.mjs +145 -0
- package/dist/finance/investment-math.d.mts +7 -0
- package/dist/finance/investment-math.mjs +18 -0
- package/dist/finance/management-accounting/budgeting.d.mts +7 -0
- package/dist/finance/management-accounting/budgeting.mjs +189 -0
- package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
- package/dist/finance/management-accounting/cash-budget.mjs +154 -0
- package/dist/finance/management-accounting/costing.d.mts +8 -0
- package/dist/finance/management-accounting/costing.mjs +175 -0
- package/dist/finance/management-accounting/decisions.d.mts +8 -0
- package/dist/finance/management-accounting/decisions.mjs +164 -0
- package/dist/finance/management-accounting/index.d.mts +13 -0
- package/dist/finance/management-accounting/index.mjs +13 -0
- package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
- package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
- package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
- package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
- package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
- package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
- package/dist/finance/management-accounting/management-case.d.mts +8 -0
- package/dist/finance/management-accounting/management-case.mjs +91 -0
- package/dist/finance/management-accounting/master-budget.d.mts +7 -0
- package/dist/finance/management-accounting/master-budget.mjs +137 -0
- package/dist/finance/management-accounting/production-costing.d.mts +8 -0
- package/dist/finance/management-accounting/production-costing.mjs +214 -0
- package/dist/finance/management-accounting/types.d.mts +644 -0
- package/dist/finance/management-accounting/variances.d.mts +7 -0
- package/dist/finance/management-accounting/variances.mjs +150 -0
- package/dist/index.d.mts +9 -8
- package/dist/index.mjs +5 -5
- package/dist/interaction/MovableDot.mjs +19 -0
- package/dist/interaction/useDraggable.mjs +24 -4
- package/dist/math/analysis.d.mts +61 -0
- package/dist/math/analysis.mjs +187 -0
- package/dist/math/answer-check.d.mts +50 -0
- package/dist/math/answer-check.mjs +106 -0
- package/dist/math/calculus.d.mts +17 -1
- package/dist/math/calculus.mjs +365 -2
- package/dist/math/complex.d.mts +93 -0
- package/dist/math/complex.mjs +239 -0
- package/dist/math/expr.d.mts +23 -0
- package/dist/math/expr.mjs +36 -0
- package/dist/math/index.d.mts +9 -23
- package/dist/math/index.mjs +9 -38
- package/dist/math/latex.mjs +10 -1
- package/dist/math/parse.mjs +1 -1
- package/dist/math/poly.d.mts +55 -0
- package/dist/math/poly.mjs +273 -0
- package/dist/math/rearrange.d.mts +14 -0
- package/dist/math/rearrange.mjs +125 -0
- package/dist/math/solve.d.mts +21 -0
- package/dist/math/solve.mjs +75 -0
- package/dist/networking/addressing.d.mts +26 -0
- package/dist/networking/addressing.mjs +33 -0
- package/dist/networking/cloud/access.d.mts +36 -0
- package/dist/networking/cloud/access.mjs +95 -0
- package/dist/networking/cloud/containers.d.mts +43 -0
- package/dist/networking/cloud/containers.mjs +54 -0
- package/dist/networking/cloud/edge.d.mts +17 -0
- package/dist/networking/cloud/edge.mjs +31 -0
- package/dist/networking/cloud/failure-domains.d.mts +19 -0
- package/dist/networking/cloud/failure-domains.mjs +22 -0
- package/dist/networking/cloud/geo-routing.d.mts +22 -0
- package/dist/networking/cloud/geo-routing.mjs +64 -0
- package/dist/networking/cloud/index.d.mts +18 -0
- package/dist/networking/cloud/index.mjs +19 -0
- package/dist/networking/cloud/inference-reliability.d.mts +30 -0
- package/dist/networking/cloud/inference-reliability.mjs +76 -0
- package/dist/networking/cloud/inference.d.mts +118 -0
- package/dist/networking/cloud/inference.mjs +179 -0
- package/dist/networking/cloud/infrastructure.d.mts +45 -0
- package/dist/networking/cloud/infrastructure.mjs +96 -0
- package/dist/networking/cloud/observability.d.mts +24 -0
- package/dist/networking/cloud/observability.mjs +34 -0
- package/dist/networking/cloud/orchestration.d.mts +32 -0
- package/dist/networking/cloud/orchestration.mjs +38 -0
- package/dist/networking/cloud/recovery.d.mts +21 -0
- package/dist/networking/cloud/recovery.mjs +27 -0
- package/dist/networking/cloud/releases.d.mts +42 -0
- package/dist/networking/cloud/releases.mjs +135 -0
- package/dist/networking/cloud/scaling.d.mts +25 -0
- package/dist/networking/cloud/scaling.mjs +65 -0
- package/dist/networking/cloud/secrets.d.mts +39 -0
- package/dist/networking/cloud/secrets.mjs +68 -0
- package/dist/networking/cloud/server-deployment.d.mts +29 -0
- package/dist/networking/cloud/server-deployment.mjs +72 -0
- package/dist/networking/cloud/storage.d.mts +16 -0
- package/dist/networking/cloud/storage.mjs +58 -0
- package/dist/networking/cloud/vpc.d.mts +18 -0
- package/dist/networking/cloud/vpc.mjs +100 -0
- package/dist/networking/delivery.d.mts +34 -0
- package/dist/networking/delivery.mjs +52 -0
- package/dist/networking/index.d.mts +47 -0
- package/dist/networking/index.mjs +47 -0
- package/dist/networking/ipv6.d.mts +28 -0
- package/dist/networking/ipv6.mjs +17 -0
- package/dist/networking/journeys.d.mts +83 -0
- package/dist/networking/journeys.mjs +161 -0
- package/dist/networking/models/airtime.d.mts +87 -0
- package/dist/networking/models/airtime.mjs +130 -0
- package/dist/networking/models/cellular.d.mts +157 -0
- package/dist/networking/models/cellular.mjs +252 -0
- package/dist/networking/models/encapsulation.d.mts +98 -0
- package/dist/networking/models/encapsulation.mjs +132 -0
- package/dist/networking/models/handover.d.mts +116 -0
- package/dist/networking/models/handover.mjs +209 -0
- package/dist/networking/models/handshake.d.mts +90 -0
- package/dist/networking/models/handshake.mjs +122 -0
- package/dist/networking/models/index.d.mts +14 -0
- package/dist/networking/models/index.mjs +15 -0
- package/dist/networking/models/media.d.mts +82 -0
- package/dist/networking/models/media.mjs +188 -0
- package/dist/networking/models/satellite.d.mts +86 -0
- package/dist/networking/models/satellite.mjs +121 -0
- package/dist/networking/models/spectrum.d.mts +83 -0
- package/dist/networking/models/spectrum.mjs +235 -0
- package/dist/networking/models/switch.d.mts +80 -0
- package/dist/networking/models/switch.mjs +155 -0
- package/dist/networking/models/vlan.d.mts +62 -0
- package/dist/networking/models/vlan.mjs +100 -0
- package/dist/networking/models/vpn.d.mts +66 -0
- package/dist/networking/models/vpn.mjs +125 -0
- package/dist/networking/models/wifi-privacy.d.mts +82 -0
- package/dist/networking/models/wifi-privacy.mjs +130 -0
- package/dist/networking/models/wifi.d.mts +240 -0
- package/dist/networking/models/wifi.mjs +562 -0
- package/dist/networking/nat-traversal.d.mts +24 -0
- package/dist/networking/nat-traversal.mjs +38 -0
- package/dist/networking/protocols.d.mts +17 -0
- package/dist/networking/protocols.mjs +57 -0
- package/dist/networking/queue.d.mts +12 -0
- package/dist/networking/queue.mjs +18 -0
- package/dist/networking/route-learning.d.mts +23 -0
- package/dist/networking/route-learning.mjs +43 -0
- package/dist/networking/routing.d.mts +11 -0
- package/dist/networking/routing.mjs +25 -0
- package/dist/networking/signals.d.mts +26 -0
- package/dist/networking/signals.mjs +35 -0
- package/dist/networking/subnet.d.mts +49 -0
- package/dist/networking/subnet.mjs +89 -0
- package/dist/networking/tcp-reliability.d.mts +24 -0
- package/dist/networking/tcp-reliability.mjs +38 -0
- package/dist/networking/topology/contract.d.mts +123 -0
- package/dist/networking/topology/index.d.mts +4 -0
- package/dist/networking/topology/index.mjs +4 -0
- package/dist/networking/topology/presets.d.mts +7 -0
- package/dist/networking/topology/presets.mjs +302 -0
- package/dist/networking/topology/simulation.d.mts +8 -0
- package/dist/networking/topology/simulation.mjs +179 -0
- package/dist/networking/wireless.d.mts +11 -0
- package/dist/networking/wireless.mjs +17 -0
- package/dist/optics/imaging.d.mts +218 -0
- package/dist/optics/imaging.mjs +276 -0
- package/dist/optics/index.d.mts +7 -0
- package/dist/optics/index.mjs +8 -0
- package/dist/optics/laws.d.mts +70 -0
- package/dist/optics/laws.mjs +195 -0
- package/dist/optics/prism.d.mts +148 -0
- package/dist/optics/prism.mjs +197 -0
- package/dist/optics/refraction.d.mts +201 -0
- package/dist/optics/refraction.mjs +270 -0
- package/dist/optics/wave-optics.d.mts +171 -0
- package/dist/optics/wave-optics.mjs +259 -0
- package/dist/physics/ac/index.d.mts +183 -0
- package/dist/physics/ac/index.mjs +203 -0
- package/dist/physics/dynamics/forces.d.mts +98 -0
- package/dist/physics/dynamics/forces.mjs +153 -0
- package/dist/physics/dynamics/friction.d.mts +76 -0
- package/dist/physics/dynamics/friction.mjs +119 -0
- package/dist/physics/dynamics/system.d.mts +68 -0
- package/dist/physics/dynamics/system.mjs +125 -0
- package/dist/physics/electrostatics/index.d.mts +169 -0
- package/dist/physics/electrostatics/index.mjs +249 -0
- package/dist/physics/energy/centre-of-mass.d.mts +115 -0
- package/dist/physics/energy/centre-of-mass.mjs +180 -0
- package/dist/physics/energy/conservation.d.mts +81 -0
- package/dist/physics/energy/conservation.mjs +129 -0
- package/dist/physics/energy/power.d.mts +90 -0
- package/dist/physics/energy/power.mjs +167 -0
- package/dist/physics/energy/spring.d.mts +73 -0
- package/dist/physics/energy/spring.mjs +129 -0
- package/dist/physics/energy/store.d.mts +63 -0
- package/dist/physics/energy/store.mjs +108 -0
- package/dist/physics/energy/theorem.d.mts +65 -0
- package/dist/physics/energy/theorem.mjs +113 -0
- package/dist/physics/energy/work.d.mts +114 -0
- package/dist/physics/energy/work.mjs +219 -0
- package/dist/physics/gravitation/body.d.mts +85 -0
- package/dist/physics/gravitation/body.mjs +168 -0
- package/dist/physics/gravitation/kepler.d.mts +127 -0
- package/dist/physics/gravitation/kepler.mjs +216 -0
- package/dist/physics/gravitation/law.d.mts +117 -0
- package/dist/physics/gravitation/law.mjs +175 -0
- package/dist/physics/gravitation/orbit.d.mts +119 -0
- package/dist/physics/gravitation/orbit.mjs +202 -0
- package/dist/physics/gravitation/potential.d.mts +114 -0
- package/dist/physics/gravitation/potential.mjs +202 -0
- package/dist/physics/gravitation/variation.d.mts +97 -0
- package/dist/physics/gravitation/variation.mjs +175 -0
- package/dist/physics/index.d.mts +35 -0
- package/dist/physics/index.mjs +36 -0
- package/dist/physics/integral-sweep.d.mts +63 -0
- package/dist/physics/integral-sweep.mjs +126 -0
- package/dist/physics/kinematics/equations.d.mts +47 -0
- package/dist/physics/kinematics/equations.mjs +126 -0
- package/dist/physics/kinematics/free-fall.d.mts +53 -0
- package/dist/physics/kinematics/free-fall.mjs +71 -0
- package/dist/physics/kinematics/given.d.mts +16 -0
- package/dist/physics/kinematics/given.mjs +55 -0
- package/dist/physics/kinematics/roots.d.mts +41 -0
- package/dist/physics/kinematics/roots.mjs +72 -0
- package/dist/physics/kinematics/solve.d.mts +52 -0
- package/dist/physics/kinematics/solve.mjs +172 -0
- package/dist/physics/magnetism/biot-savart.d.mts +161 -0
- package/dist/physics/magnetism/biot-savart.mjs +353 -0
- package/dist/physics/magnetism/flux.d.mts +94 -0
- package/dist/physics/magnetism/flux.mjs +313 -0
- package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
- package/dist/physics/magnetism/geomagnetism.mjs +184 -0
- package/dist/physics/magnetism/index.d.mts +12 -0
- package/dist/physics/magnetism/index.mjs +74 -0
- package/dist/physics/magnetism/lorentz.d.mts +28 -0
- package/dist/physics/magnetism/lorentz.mjs +88 -0
- package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
- package/dist/physics/magnetism/magnetic-force.mjs +169 -0
- package/dist/physics/momentum/collide.d.mts +77 -0
- package/dist/physics/momentum/collide.mjs +115 -0
- package/dist/physics/momentum/impulse.d.mts +89 -0
- package/dist/physics/momentum/impulse.mjs +159 -0
- package/dist/physics/momentum/planar.d.mts +60 -0
- package/dist/physics/momentum/planar.mjs +110 -0
- package/dist/physics/projectile.d.mts +107 -0
- package/dist/physics/projectile.mjs +185 -0
- package/dist/physics/rotation/angular.d.mts +85 -0
- package/dist/physics/rotation/angular.mjs +130 -0
- package/dist/physics/rotation/circular.d.mts +79 -0
- package/dist/physics/rotation/circular.mjs +131 -0
- package/dist/physics/rotation/inertia.d.mts +164 -0
- package/dist/physics/rotation/inertia.mjs +332 -0
- package/dist/physics/rotation/torque.d.mts +65 -0
- package/dist/physics/rotation/torque.mjs +134 -0
- package/dist/physics/vectors.d.mts +64 -0
- package/dist/physics/vectors.mjs +114 -0
- package/dist/primitives/Dot.d.mts +2 -15
- package/dist/primitives/Dot.mjs +6 -4
- package/dist/primitives/Grid.d.mts +33 -17
- package/dist/primitives/Grid.mjs +89 -17
- package/dist/primitives/Label.d.mts +1 -14
- package/dist/primitives/Label.mjs +3 -2
- package/dist/primitives/Lines.d.mts +4 -32
- package/dist/primitives/Lines.mjs +10 -8
- package/dist/primitives/Shapes.d.mts +5 -43
- package/dist/primitives/Shapes.mjs +12 -10
- package/dist/primitives/index.d.mts +2 -2
- package/dist/primitives/index.mjs +2 -2
- package/dist/primitives/props.mjs +31 -0
- package/dist/quantity/index.d.mts +119 -0
- package/dist/quantity/index.mjs +417 -0
- package/dist/relation/derive.d.mts +74 -0
- package/dist/relation/derive.mjs +73 -0
- package/dist/relation/index.d.mts +56 -0
- package/dist/relation/index.mjs +234 -0
- package/dist/scene/Scene.d.mts +6 -1
- package/dist/scene/Scene.mjs +15 -40
- package/dist/scene/evaluators.mjs +1 -1
- package/dist/sim/thermal.mjs +45 -20
- package/dist/thermo/calorimetry.d.mts +207 -0
- package/dist/thermo/calorimetry.mjs +345 -0
- package/dist/thermo/cycles.d.mts +142 -0
- package/dist/thermo/cycles.mjs +256 -0
- package/dist/thermo/entropy.d.mts +87 -0
- package/dist/thermo/entropy.mjs +140 -0
- package/dist/thermo/expansion.d.mts +130 -0
- package/dist/thermo/expansion.mjs +178 -0
- package/dist/thermo/gas.d.mts +197 -0
- package/dist/thermo/gas.mjs +279 -0
- package/dist/thermo/heat-transfer.d.mts +164 -0
- package/dist/thermo/heat-transfer.mjs +217 -0
- package/dist/thermo/index.d.mts +9 -82
- package/dist/thermo/index.mjs +9 -132
- package/dist/thermo/processes.d.mts +95 -0
- package/dist/thermo/processes.mjs +154 -0
- package/dist/thermo/temperature.d.mts +174 -0
- package/dist/thermo/temperature.mjs +236 -0
- package/dist/view/Stage.mjs +4 -11
- package/dist/waves/damping.d.mts +224 -0
- package/dist/waves/damping.mjs +317 -0
- package/dist/waves/doppler.d.mts +72 -0
- package/dist/waves/doppler.mjs +125 -0
- package/dist/waves/index.d.mts +10 -0
- package/dist/waves/index.mjs +10 -0
- package/dist/waves/pendulum.d.mts +130 -0
- package/dist/waves/pendulum.mjs +211 -0
- package/dist/waves/pitch.d.mts +125 -0
- package/dist/waves/pitch.mjs +158 -0
- package/dist/waves/shm.d.mts +170 -0
- package/dist/waves/shm.mjs +279 -0
- package/dist/waves/springs.d.mts +103 -0
- package/dist/waves/springs.mjs +176 -0
- package/dist/waves/superposition.d.mts +124 -0
- package/dist/waves/superposition.mjs +196 -0
- package/dist/waves/wave.d.mts +154 -0
- package/dist/waves/wave.mjs +178 -0
- package/package.json +103 -23
- package/styles.css +125 -8
- package/dist/assets/kit/index.mjs +0 -4
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//#region src/core/vec3.ts
|
|
2
|
+
const v3 = (x, y, z) => ({
|
|
3
|
+
x,
|
|
4
|
+
y,
|
|
5
|
+
z
|
|
6
|
+
});
|
|
7
|
+
const ZERO3 = {
|
|
8
|
+
x: 0,
|
|
9
|
+
y: 0,
|
|
10
|
+
z: 0
|
|
11
|
+
};
|
|
12
|
+
const add3 = (a, b) => ({
|
|
13
|
+
x: a.x + b.x,
|
|
14
|
+
y: a.y + b.y,
|
|
15
|
+
z: a.z + b.z
|
|
16
|
+
});
|
|
17
|
+
const sub3 = (a, b) => ({
|
|
18
|
+
x: a.x - b.x,
|
|
19
|
+
y: a.y - b.y,
|
|
20
|
+
z: a.z - b.z
|
|
21
|
+
});
|
|
22
|
+
const scale3 = (a, k) => ({
|
|
23
|
+
x: a.x * k,
|
|
24
|
+
y: a.y * k,
|
|
25
|
+
z: a.z * k
|
|
26
|
+
});
|
|
27
|
+
const dot3 = (a, b) => a.x * b.x + a.y * b.y + a.z * b.z;
|
|
28
|
+
/**
|
|
29
|
+
* Right-handed cross product: a × b.
|
|
30
|
+
*
|
|
31
|
+
* The handedness is the whole content of this function. x̂ × ŷ = ẑ, which is
|
|
32
|
+
* what makes the right-hand rule come out right everywhere downstream, from a
|
|
33
|
+
* magnetic force to a torque to a surface normal.
|
|
34
|
+
*/
|
|
35
|
+
const cross3 = (a, b) => ({
|
|
36
|
+
x: a.y * b.z - a.z * b.y,
|
|
37
|
+
y: a.z * b.x - a.x * b.z,
|
|
38
|
+
z: a.x * b.y - a.y * b.x
|
|
39
|
+
});
|
|
40
|
+
const mag3 = (a) => Math.sqrt(dot3(a, a));
|
|
41
|
+
const dist3 = (a, b) => mag3(sub3(a, b));
|
|
42
|
+
/**
|
|
43
|
+
* Unit vector, which THROWS on a zero vector rather than returning one.
|
|
44
|
+
*
|
|
45
|
+
* A zero-length direction is always a caller's mistake: a segment with no
|
|
46
|
+
* length, a field point exactly on a source, an axis nobody set. Returning
|
|
47
|
+
* `{0,0,0}` or dividing by a `|| 1` guard lets that mistake travel silently
|
|
48
|
+
* into a picture, which is how a diagram ends up subtly wrong with every test
|
|
49
|
+
* still green.
|
|
50
|
+
*/
|
|
51
|
+
const unit3 = (a) => {
|
|
52
|
+
const m = mag3(a);
|
|
53
|
+
if (m === 0) throw new RangeError("A zero-length vector has no direction.");
|
|
54
|
+
return scale3(a, 1 / m);
|
|
55
|
+
};
|
|
56
|
+
/** Linear interpolation, with t = 0 at `a` and t = 1 at `b`. */
|
|
57
|
+
const lerp3 = (a, b, t) => add3(a, scale3(sub3(b, a), t));
|
|
58
|
+
const midpoint3 = (a, b) => lerp3(a, b, .5);
|
|
59
|
+
/** Angle between two vectors, in radians, clamped against floating-point drift. */
|
|
60
|
+
const angleBetween3 = (a, b) => {
|
|
61
|
+
const denominator = mag3(a) * mag3(b);
|
|
62
|
+
if (denominator === 0) throw new RangeError("A zero-length vector has no angle.");
|
|
63
|
+
return Math.acos(Math.min(1, Math.max(-1, dot3(a, b) / denominator)));
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* The component of `a` perpendicular to `onto`, with the parallel part removed.
|
|
67
|
+
*
|
|
68
|
+
* The workhorse of anything that needs an in-plane direction: a flux loop's
|
|
69
|
+
* axes, a force resolved across a field, a distance from a line.
|
|
70
|
+
*/
|
|
71
|
+
const reject3 = (a, onto) => {
|
|
72
|
+
const n = unit3(onto);
|
|
73
|
+
return sub3(a, scale3(n, dot3(a, n)));
|
|
74
|
+
};
|
|
75
|
+
/** Shortest distance from a point to the segment ab, not to the infinite line. */
|
|
76
|
+
const distToSegment3 = (p, a, b) => {
|
|
77
|
+
const ab = sub3(b, a);
|
|
78
|
+
const lengthSq = dot3(ab, ab);
|
|
79
|
+
if (lengthSq === 0) return dist3(p, a);
|
|
80
|
+
return dist3(p, add3(a, scale3(ab, Math.max(0, Math.min(1, dot3(sub3(p, a), ab) / lengthSq)))));
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Two perpendicular unit vectors spanning the plane with this normal.
|
|
84
|
+
*
|
|
85
|
+
* A `preferred` direction becomes the FIRST axis, projected into the plane.
|
|
86
|
+
* Note that it must be projected and not merely passed to a cross product:
|
|
87
|
+
* `cross(preferred, n)` returns something perpendicular to `preferred`, which
|
|
88
|
+
* silently swaps the two axes and hands back a frame the caller did not ask
|
|
89
|
+
* for. That bug cost real time in the flux integrator.
|
|
90
|
+
*/
|
|
91
|
+
const basisFor3 = (normal, preferred) => {
|
|
92
|
+
const n = unit3(normal);
|
|
93
|
+
if (preferred) {
|
|
94
|
+
const inPlane = sub3(preferred, scale3(n, dot3(preferred, n)));
|
|
95
|
+
if (mag3(inPlane) > 1e-9) {
|
|
96
|
+
const u = unit3(inPlane);
|
|
97
|
+
return [u, cross3(n, u)];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const u = unit3(cross3(Math.abs(n.z) < .9 ? v3(0, 0, 1) : v3(1, 0, 0), n));
|
|
101
|
+
return [u, cross3(n, u)];
|
|
102
|
+
};
|
|
103
|
+
const vec3 = {
|
|
104
|
+
v: v3,
|
|
105
|
+
add: add3,
|
|
106
|
+
sub: sub3,
|
|
107
|
+
scale: scale3,
|
|
108
|
+
dot: dot3,
|
|
109
|
+
cross: cross3,
|
|
110
|
+
mag: mag3,
|
|
111
|
+
dist: dist3,
|
|
112
|
+
unit: unit3,
|
|
113
|
+
lerp: lerp3,
|
|
114
|
+
midpoint: midpoint3,
|
|
115
|
+
angleBetween: angleBetween3,
|
|
116
|
+
reject: reject3,
|
|
117
|
+
distToSegment: distToSegment3,
|
|
118
|
+
basisFor: basisFor3,
|
|
119
|
+
ZERO: ZERO3
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
export { ZERO3, add3, angleBetween3, basisFor3, cross3, dist3, distToSegment3, dot3, lerp3, mag3, midpoint3, reject3, scale3, sub3, unit3, v3, vec3 };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/core/worked.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Worked calculations: the shape a kernel uses to SHOW ITS WORKING.
|
|
4
|
+
*
|
|
5
|
+
* A kernel that returns only an answer cannot teach. This is the data a kernel emits instead: the
|
|
6
|
+
* value plus every substitution and simplification that produced it, each as a LaTeX line with an
|
|
7
|
+
* optional note saying why that step follows. Pure and dependency-free; rendering is somebody
|
|
8
|
+
* else's job (in labs, `kit/rule`'s RuleCard and WorkedSteps).
|
|
9
|
+
*
|
|
10
|
+
* It lives in stage rather than in labs because the kernels are what produce it. A relation solver
|
|
11
|
+
* or a redox balancer that emits worked steps cannot describe its own return type if the type
|
|
12
|
+
* lives in a consumer. The renderer can stay downstream; the shape cannot.
|
|
13
|
+
*/
|
|
14
|
+
/** One line of a worked calculation: a LaTeX expression + an optional plain note. */
|
|
15
|
+
interface CalcStep {
|
|
16
|
+
tex: string;
|
|
17
|
+
/** Why this step follows ("substitute n = 5", "the falling product"). */
|
|
18
|
+
note?: string;
|
|
19
|
+
}
|
|
20
|
+
/** The result of a worked calculation: the final value + the steps that got there. */
|
|
21
|
+
interface Worked {
|
|
22
|
+
value: number;
|
|
23
|
+
steps: CalcStep[];
|
|
24
|
+
}
|
|
25
|
+
/** A tiny fluent builder: calc().step('…','…').step('…').done(value). */
|
|
26
|
+
declare class Calc {
|
|
27
|
+
private readonly _steps;
|
|
28
|
+
step(tex: string, note?: string): this;
|
|
29
|
+
done(value: number): Worked;
|
|
30
|
+
}
|
|
31
|
+
declare const calc: () => Calc;
|
|
32
|
+
/** Format a number for inline LaTeX (thin-space thousands so big counts read). */
|
|
33
|
+
declare function texNum(n: number): string;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { Calc, CalcStep, Worked, calc, texNum };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/core/worked.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
|
+
* A number to `sf` significant figures, in LaTeX, using exponent notation only when the plain
|
|
27
|
+
* decimal would be unreadable.
|
|
28
|
+
*
|
|
29
|
+
* Every kernel that shows working needs this and they must all round the same way, or two
|
|
30
|
+
* derivations of the same quantity disagree in their last digit and a student reasonably concludes
|
|
31
|
+
* one of them is wrong.
|
|
32
|
+
*/
|
|
33
|
+
function texSigFigs(value, sf = 3) {
|
|
34
|
+
if (!Number.isFinite(value)) return "\\text{?}";
|
|
35
|
+
const abs = Math.abs(value);
|
|
36
|
+
if (abs !== 0 && (abs < .001 || abs >= 1e6)) {
|
|
37
|
+
const [mantissa, exponent] = value.toExponential(sf - 1).split("e");
|
|
38
|
+
return `${mantissa} \\times 10^{${Number(exponent)}}`;
|
|
39
|
+
}
|
|
40
|
+
return String(Number(value.toPrecision(sf)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { Calc, calc, texNum, texSigFigs };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Couple } from "./couples.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/electro/cell.d.ts
|
|
4
|
+
/** Standard temperature for electrode potentials, kelvin (25 °C). */
|
|
5
|
+
declare const STANDARD_TEMPERATURE = 298.15;
|
|
6
|
+
interface HalfCellState {
|
|
7
|
+
readonly couple: Couple;
|
|
8
|
+
/**
|
|
9
|
+
* Concentrations and partial pressures for the species in this couple's quotient, keyed as the
|
|
10
|
+
* quotient keys them. Anything omitted is taken as standard, which is 1.
|
|
11
|
+
*/
|
|
12
|
+
readonly activities?: Readonly<Record<string, number>>;
|
|
13
|
+
}
|
|
14
|
+
interface Cell {
|
|
15
|
+
readonly cathode: HalfCellState;
|
|
16
|
+
readonly anode: HalfCellState;
|
|
17
|
+
/** Electrons transferred by the balanced cell reaction. */
|
|
18
|
+
readonly electrons: number;
|
|
19
|
+
/** E°cell in volts, from standard potentials alone. */
|
|
20
|
+
readonly standardPotential: number;
|
|
21
|
+
/** The reaction quotient for the cell reaction as written. */
|
|
22
|
+
readonly quotient: number;
|
|
23
|
+
/** The actual potential under the stated conditions, volts. */
|
|
24
|
+
readonly potential: number;
|
|
25
|
+
/** ΔG under those conditions, joules per mole of reaction. */
|
|
26
|
+
readonly freeEnergy: number;
|
|
27
|
+
/** ΔG° under standard conditions, joules per mole of reaction. */
|
|
28
|
+
readonly standardFreeEnergy: number;
|
|
29
|
+
/** The equilibrium constant for the cell reaction. */
|
|
30
|
+
readonly equilibriumConstant: number;
|
|
31
|
+
/** Does the reaction run as written? */
|
|
32
|
+
readonly spontaneous: boolean;
|
|
33
|
+
readonly temperature: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build a cell from two half-cells, assigning the electrodes by potential.
|
|
37
|
+
*
|
|
38
|
+
* Which half-cell is the cathode is a consequence of the numbers, not an input. The higher
|
|
39
|
+
* standard potential reduces; on a tie, which is a concentration cell with the same couple on both
|
|
40
|
+
* sides, the more concentrated side reduces, and that is the only case where the electrodes are
|
|
41
|
+
* decided by anything other than E°.
|
|
42
|
+
*/
|
|
43
|
+
declare function galvanicCell(first: HalfCellState, second: HalfCellState, temperature?: number): Cell;
|
|
44
|
+
/**
|
|
45
|
+
* Build the cell exactly as written, cathode on the right, without reassigning the electrodes.
|
|
46
|
+
*
|
|
47
|
+
* For a cell someone has written down and wants checked. A cell notation written the wrong way
|
|
48
|
+
* round has a negative potential, and that is the useful answer: it says the reaction goes the
|
|
49
|
+
* other way. Reordering it silently would answer a question nobody asked.
|
|
50
|
+
*/
|
|
51
|
+
declare const cellAsWritten: (anode: HalfCellState, cathode: HalfCellState, temperature?: number) => Cell;
|
|
52
|
+
/**
|
|
53
|
+
* The cell in the standard notation, anode on the left.
|
|
54
|
+
*
|
|
55
|
+
* Zn(s) | Zn²⁺(aq) || Cu²⁺(aq) | Cu(s)
|
|
56
|
+
*
|
|
57
|
+
* The double bar is the salt bridge and the convention is not decoration: oxidation is written on
|
|
58
|
+
* the left because that is the direction electrons travel through the external wire, so a cell
|
|
59
|
+
* read left to right is a cell read in the direction the electrons move.
|
|
60
|
+
*/
|
|
61
|
+
declare function cellNotation(cell: Cell): string;
|
|
62
|
+
/** The balanced overall reaction, both halves scaled to the same electron count. */
|
|
63
|
+
declare function cellReaction(cell: Cell): string;
|
|
64
|
+
/**
|
|
65
|
+
* The potential of a single electrode against the standard hydrogen electrode, under Nernst.
|
|
66
|
+
*
|
|
67
|
+
* This is what a measurement against the SHE actually reads, and it is the quantity the hydrogen
|
|
68
|
+
* electrode's own definition makes meaningful. Building it as a cell against hydrogen rather than
|
|
69
|
+
* as its own formula keeps one Nernst implementation in the file instead of two.
|
|
70
|
+
*/
|
|
71
|
+
declare const electrodePotential: (state: HalfCellState, temperature?: number) => number;
|
|
72
|
+
/**
|
|
73
|
+
* How a hydrogen electrode's potential reports the pH of the solution it stands in.
|
|
74
|
+
*
|
|
75
|
+
* At 25 °C the Nernst term collapses to 0.0592 volts per pH unit, which is why a pH meter is an
|
|
76
|
+
* electrochemical instrument rather than a chemical one. The coefficient is computed from the
|
|
77
|
+
* constants rather than typed in, so it stays right at any temperature.
|
|
78
|
+
*/
|
|
79
|
+
declare const hydrogenElectrodePotential: (pH: number, temperature?: number) => number;
|
|
80
|
+
/** The volts-per-pH-unit slope, 0.0592 V at 25 °C. */
|
|
81
|
+
declare const nernstSlope: (temperature?: number) => number;
|
|
82
|
+
/**
|
|
83
|
+
* Free energy from a cell potential, and back.
|
|
84
|
+
*
|
|
85
|
+
* Separate from {@link Cell} on purpose: a learner is regularly given E and asked for ΔG with no
|
|
86
|
+
* cell in hand, and the conversion is the point of the question.
|
|
87
|
+
*/
|
|
88
|
+
declare const freeEnergyFromPotential: (electrons: number, potential: number) => number;
|
|
89
|
+
declare const potentialFromFreeEnergy: (electrons: number, freeEnergy: number) => number;
|
|
90
|
+
/**
|
|
91
|
+
* The EMF a cell presents to a circuit.
|
|
92
|
+
*
|
|
93
|
+
* The seam to the circuit kernel. A chemical cell driving a lamp is a voltage source in series
|
|
94
|
+
* with an internal resistance, and the chemistry decides only the source value; everything after
|
|
95
|
+
* that is Kirchhoff and belongs to the circuit solver rather than here. Terminal voltage is
|
|
96
|
+
* deliberately NOT computed in this file, because a cell under load is a circuit question.
|
|
97
|
+
*/
|
|
98
|
+
declare const electromotiveForce: (cell: Cell) => number;
|
|
99
|
+
/** Oxidation potential of a half-cell's couple, for the convention that prefers it. */
|
|
100
|
+
declare const anodeOxidationPotential: (cell: Cell) => number;
|
|
101
|
+
//#endregion
|
|
102
|
+
export { Cell, HalfCellState, STANDARD_TEMPERATURE, anodeOxidationPotential, cellAsWritten, cellNotation, cellReaction, electrodePotential, electromotiveForce, freeEnergyFromPotential, galvanicCell, hydrogenElectrodePotential, nernstSlope, potentialFromFreeEnergy };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { FARADAY, GAS_CONSTANT } from "../core/constants.mjs";
|
|
2
|
+
import { coupleById, oxidationPotential } from "./couples.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/electro/cell.ts
|
|
5
|
+
/**
|
|
6
|
+
* A galvanic cell: which way it runs, how hard, and what that says about the reaction.
|
|
7
|
+
*
|
|
8
|
+
* ## The three statements that are the same statement
|
|
9
|
+
*
|
|
10
|
+
* A learner meets cell potential, free energy and the equilibrium constant as three topics. They
|
|
11
|
+
* are one quantity written three ways:
|
|
12
|
+
*
|
|
13
|
+
* ΔG° = −nFE°cell and ΔG° = −RT ln K
|
|
14
|
+
*
|
|
15
|
+
* so E°cell and K carry exactly the same information, and "will it react" has one answer in three
|
|
16
|
+
* currencies. This file computes all three from the same cell rather than offering three formulas,
|
|
17
|
+
* because a learner who can convert between them has understood something and one who has three
|
|
18
|
+
* formulas has three things to forget.
|
|
19
|
+
*
|
|
20
|
+
* ## Sign, which is where this topic actually goes wrong
|
|
21
|
+
*
|
|
22
|
+
* E°cell = E°(cathode) − E°(anode) both as REDUCTION potentials
|
|
23
|
+
*
|
|
24
|
+
* The cathode is where reduction happens, and it is the half-cell with the higher reduction
|
|
25
|
+
* potential. That single rule fixes every sign in the file. Textbooks that write
|
|
26
|
+
* "E°cell = E°(anode, oxidation) + E°(cathode, reduction)" are saying the same thing, since an
|
|
27
|
+
* oxidation potential is a reduction potential negated.
|
|
28
|
+
*
|
|
29
|
+
* A cell written down the WRONG way round is not an error to hide. Its potential comes out
|
|
30
|
+
* negative, which is the cell telling you it runs the other way, and {@link cellFromNotation}
|
|
31
|
+
* keeps that answer rather than quietly swapping the electrodes.
|
|
32
|
+
*
|
|
33
|
+
* ## Faraday's constant is derived, not 96500
|
|
34
|
+
*
|
|
35
|
+
* F = N_A · e exactly, which is 96485.3 C/mol. Books round it to 96500, a shift of 0.015%, and
|
|
36
|
+
* that is invisible in a two-significant-figure answer. This file uses the exact value: rounding a
|
|
37
|
+
* constant to make a worked answer land is how a kernel starts lying.
|
|
38
|
+
*
|
|
39
|
+
* Pure: no React, no pixels.
|
|
40
|
+
*/
|
|
41
|
+
/** Standard temperature for electrode potentials, kelvin (25 °C). */
|
|
42
|
+
const STANDARD_TEMPERATURE = 298.15;
|
|
43
|
+
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
44
|
+
const lcm = (a, b) => a * b / gcd(a, b);
|
|
45
|
+
/**
|
|
46
|
+
* The activity of one species, defaulting to standard.
|
|
47
|
+
*
|
|
48
|
+
* A missing entry means "standard", never zero. Zero would send a logarithm to infinity and hand
|
|
49
|
+
* back a potential of ±Infinity, which looks like a physical answer and is not one.
|
|
50
|
+
*/
|
|
51
|
+
const activityOf = (state, species) => state.activities?.[species] ?? 1;
|
|
52
|
+
/**
|
|
53
|
+
* The reaction quotient for the whole cell, built from both half-cells.
|
|
54
|
+
*
|
|
55
|
+
* The cathode half runs as reduction and the anode half runs backwards, so the anode's quotient
|
|
56
|
+
* contributions are inverted. Each is also raised to the factor that scales its half-equation up
|
|
57
|
+
* to the cell's electron count, which is the step most hand-worked answers drop when the two
|
|
58
|
+
* half-cells transfer different numbers of electrons.
|
|
59
|
+
*/
|
|
60
|
+
function quotientOf(cathode, anode, electrons) {
|
|
61
|
+
let q = 1;
|
|
62
|
+
const cathodeScale = electrons / cathode.couple.electrons;
|
|
63
|
+
for (const [species, power] of Object.entries(cathode.couple.quotient)) q *= activityOf(cathode, species) ** (-power * cathodeScale);
|
|
64
|
+
const anodeScale = electrons / anode.couple.electrons;
|
|
65
|
+
for (const [species, power] of Object.entries(anode.couple.quotient)) q *= activityOf(anode, species) ** (power * anodeScale);
|
|
66
|
+
return q;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a cell from two half-cells, assigning the electrodes by potential.
|
|
70
|
+
*
|
|
71
|
+
* Which half-cell is the cathode is a consequence of the numbers, not an input. The higher
|
|
72
|
+
* standard potential reduces; on a tie, which is a concentration cell with the same couple on both
|
|
73
|
+
* sides, the more concentrated side reduces, and that is the only case where the electrodes are
|
|
74
|
+
* decided by anything other than E°.
|
|
75
|
+
*/
|
|
76
|
+
function galvanicCell(first, second, temperature = STANDARD_TEMPERATURE) {
|
|
77
|
+
const firstIsCathode = first.couple.standardPotential === second.couple.standardPotential ? concentrationOf(first) >= concentrationOf(second) : first.couple.standardPotential > second.couple.standardPotential;
|
|
78
|
+
return assemble(firstIsCathode ? first : second, firstIsCathode ? second : first, temperature);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build the cell exactly as written, cathode on the right, without reassigning the electrodes.
|
|
82
|
+
*
|
|
83
|
+
* For a cell someone has written down and wants checked. A cell notation written the wrong way
|
|
84
|
+
* round has a negative potential, and that is the useful answer: it says the reaction goes the
|
|
85
|
+
* other way. Reordering it silently would answer a question nobody asked.
|
|
86
|
+
*/
|
|
87
|
+
const cellAsWritten = (anode, cathode, temperature = STANDARD_TEMPERATURE) => assemble(cathode, anode, temperature);
|
|
88
|
+
function assemble(cathode, anode, temperature) {
|
|
89
|
+
const electrons = lcm(cathode.couple.electrons, anode.couple.electrons);
|
|
90
|
+
const standardPotential = cathode.couple.standardPotential - anode.couple.standardPotential;
|
|
91
|
+
const quotient = quotientOf(cathode, anode, electrons);
|
|
92
|
+
const potential = standardPotential - GAS_CONSTANT * temperature / (electrons * FARADAY) * Math.log(quotient);
|
|
93
|
+
return {
|
|
94
|
+
cathode,
|
|
95
|
+
anode,
|
|
96
|
+
electrons,
|
|
97
|
+
standardPotential,
|
|
98
|
+
quotient,
|
|
99
|
+
potential,
|
|
100
|
+
freeEnergy: -electrons * FARADAY * potential,
|
|
101
|
+
standardFreeEnergy: -electrons * FARADAY * standardPotential,
|
|
102
|
+
equilibriumConstant: Math.exp(electrons * FARADAY * standardPotential / (GAS_CONSTANT * temperature)),
|
|
103
|
+
spontaneous: potential > 0,
|
|
104
|
+
temperature
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** The ion concentration a half-cell is at, for the concentration-cell tie-break. */
|
|
108
|
+
function concentrationOf(state) {
|
|
109
|
+
const [species] = Object.keys(state.couple.quotient);
|
|
110
|
+
return species === void 0 ? 1 : activityOf(state, species);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The cell in the standard notation, anode on the left.
|
|
114
|
+
*
|
|
115
|
+
* Zn(s) | Zn²⁺(aq) || Cu²⁺(aq) | Cu(s)
|
|
116
|
+
*
|
|
117
|
+
* The double bar is the salt bridge and the convention is not decoration: oxidation is written on
|
|
118
|
+
* the left because that is the direction electrons travel through the external wire, so a cell
|
|
119
|
+
* read left to right is a cell read in the direction the electrons move.
|
|
120
|
+
*/
|
|
121
|
+
function cellNotation(cell) {
|
|
122
|
+
return `${`${cell.anode.couple.reduced} | ${cell.anode.couple.oxidised}`} || ${`${cell.cathode.couple.oxidised} | ${cell.cathode.couple.reduced}`}`;
|
|
123
|
+
}
|
|
124
|
+
/** The balanced overall reaction, both halves scaled to the same electron count. */
|
|
125
|
+
function cellReaction(cell) {
|
|
126
|
+
const anodeScale = cell.electrons / cell.anode.couple.electrons;
|
|
127
|
+
const cathodeScale = cell.electrons / cell.cathode.couple.electrons;
|
|
128
|
+
const term = (n, species) => n === 1 ? species : `${n}${species}`;
|
|
129
|
+
return `${term(anodeScale, cell.anode.couple.reduced)} + ${term(cathodeScale, cell.cathode.couple.oxidised)} → ${term(anodeScale, cell.anode.couple.oxidised)} + ${term(cathodeScale, cell.cathode.couple.reduced)}`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The potential of a single electrode against the standard hydrogen electrode, under Nernst.
|
|
133
|
+
*
|
|
134
|
+
* This is what a measurement against the SHE actually reads, and it is the quantity the hydrogen
|
|
135
|
+
* electrode's own definition makes meaningful. Building it as a cell against hydrogen rather than
|
|
136
|
+
* as its own formula keeps one Nernst implementation in the file instead of two.
|
|
137
|
+
*/
|
|
138
|
+
const electrodePotential = (state, temperature = STANDARD_TEMPERATURE) => assemble(state, { couple: coupleById("H+/H2") }, temperature).potential;
|
|
139
|
+
/**
|
|
140
|
+
* How a hydrogen electrode's potential reports the pH of the solution it stands in.
|
|
141
|
+
*
|
|
142
|
+
* At 25 °C the Nernst term collapses to 0.0592 volts per pH unit, which is why a pH meter is an
|
|
143
|
+
* electrochemical instrument rather than a chemical one. The coefficient is computed from the
|
|
144
|
+
* constants rather than typed in, so it stays right at any temperature.
|
|
145
|
+
*/
|
|
146
|
+
const hydrogenElectrodePotential = (pH, temperature = STANDARD_TEMPERATURE) => -(GAS_CONSTANT * temperature * Math.LN10 / FARADAY) * pH;
|
|
147
|
+
/** The volts-per-pH-unit slope, 0.0592 V at 25 °C. */
|
|
148
|
+
const nernstSlope = (temperature = STANDARD_TEMPERATURE) => GAS_CONSTANT * temperature * Math.LN10 / FARADAY;
|
|
149
|
+
/**
|
|
150
|
+
* Free energy from a cell potential, and back.
|
|
151
|
+
*
|
|
152
|
+
* Separate from {@link Cell} on purpose: a learner is regularly given E and asked for ΔG with no
|
|
153
|
+
* cell in hand, and the conversion is the point of the question.
|
|
154
|
+
*/
|
|
155
|
+
const freeEnergyFromPotential = (electrons, potential) => -electrons * FARADAY * potential;
|
|
156
|
+
const potentialFromFreeEnergy = (electrons, freeEnergy) => -freeEnergy / (electrons * FARADAY);
|
|
157
|
+
/**
|
|
158
|
+
* The EMF a cell presents to a circuit.
|
|
159
|
+
*
|
|
160
|
+
* The seam to the circuit kernel. A chemical cell driving a lamp is a voltage source in series
|
|
161
|
+
* with an internal resistance, and the chemistry decides only the source value; everything after
|
|
162
|
+
* that is Kirchhoff and belongs to the circuit solver rather than here. Terminal voltage is
|
|
163
|
+
* deliberately NOT computed in this file, because a cell under load is a circuit question.
|
|
164
|
+
*/
|
|
165
|
+
const electromotiveForce = (cell) => cell.potential;
|
|
166
|
+
/** Oxidation potential of a half-cell's couple, for the convention that prefers it. */
|
|
167
|
+
const anodeOxidationPotential = (cell) => oxidationPotential(cell.anode.couple);
|
|
168
|
+
|
|
169
|
+
//#endregion
|
|
170
|
+
export { STANDARD_TEMPERATURE, anodeOxidationPotential, cellAsWritten, cellNotation, cellReaction, electrodePotential, electromotiveForce, freeEnergyFromPotential, galvanicCell, hydrogenElectrodePotential, nernstSlope, potentialFromFreeEnergy };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region src/electro/conductivity.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* How well a solution conducts, and the three quantities that all get called "conductivity".
|
|
4
|
+
*
|
|
5
|
+
* ## Three quantities, three different questions
|
|
6
|
+
*
|
|
7
|
+
* conductance G = 1/R this SAMPLE, in this cell. siemens
|
|
8
|
+
* conductivity κ = G · (l/A) this SOLUTION, cell removed. S/cm
|
|
9
|
+
* molar conductivity Λm = κ / c one MOLE of it, dilution removed. S·cm²/mol
|
|
10
|
+
*
|
|
11
|
+
* Each strips away one thing the one before it still depends on. Conductance depends on the
|
|
12
|
+
* electrodes' spacing and area, so two labs measuring the same solution disagree. Conductivity
|
|
13
|
+
* removes the cell through its geometry (l/A, the cell constant) and is a property of the
|
|
14
|
+
* solution, but it still falls as the solution is diluted, simply because there are fewer ions.
|
|
15
|
+
* Molar conductivity divides that out and asks what one mole contributes wherever it is.
|
|
16
|
+
*
|
|
17
|
+
* The payoff is the last one. Molar conductivity RISES on dilution, which sounds backwards until
|
|
18
|
+
* you see it is measuring per mole while conductivity measures per volume. For a strong
|
|
19
|
+
* electrolyte it rises a little and levels off, because the ions were already fully separated and
|
|
20
|
+
* only get out of each other's way. For a weak one it climbs steeply without ever levelling,
|
|
21
|
+
* because dilution is pushing its dissociation equilibrium further over: at ordinary
|
|
22
|
+
* concentrations most of the acetic acid in a beaker is not ionised at all.
|
|
23
|
+
*
|
|
24
|
+
* That difference is the measurement's whole diagnostic value. It tells strong from weak
|
|
25
|
+
* electrolytes without any chemistry beyond a resistance reading.
|
|
26
|
+
*
|
|
27
|
+
* ## Units, and the trap in them
|
|
28
|
+
*
|
|
29
|
+
* Everything here is in the CENTIMETRE units this topic is universally taught and examined in:
|
|
30
|
+
* cm for the electrode spacing, cm² for the area, cm³ for volume, mol/dm³ for concentration. That
|
|
31
|
+
* last one is the trap, because a concentration in mol/dm³ and a volume in cm³ differ by the
|
|
32
|
+
* factor of 1000 that {@link molarConductivity} carries. Mixing the two is the commonest wrong
|
|
33
|
+
* answer in the topic, and it is wrong by exactly a thousand, which is large enough to spot and
|
|
34
|
+
* quiet enough to miss.
|
|
35
|
+
*
|
|
36
|
+
* Pure: no React, no pixels.
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Cell constant l/A, in cm⁻¹: the geometry that turns a measured conductance into a property.
|
|
40
|
+
*
|
|
41
|
+
* Measured in practice rather than calculated, by putting a solution of known conductivity
|
|
42
|
+
* (standard KCl) in the cell and reading what it gives. The electrodes are never quite the flat
|
|
43
|
+
* parallel plates the formula assumes.
|
|
44
|
+
*/
|
|
45
|
+
declare const cellConstant: (separationCm: number, areaCm2: number) => number;
|
|
46
|
+
/** Conductance in siemens, the reciprocal of the measured resistance. */
|
|
47
|
+
declare const conductance: (resistanceOhm: number) => number;
|
|
48
|
+
/**
|
|
49
|
+
* Conductivity κ in S/cm: the solution's own property, with the cell divided out.
|
|
50
|
+
*
|
|
51
|
+
* Also called specific conductance. It is the conductance a centimetre cube of the solution would
|
|
52
|
+
* show between opposite faces, which is why the units carry a length.
|
|
53
|
+
*/
|
|
54
|
+
declare const conductivity: (resistanceOhm: number, cellConstantPerCm: number) => number;
|
|
55
|
+
/**
|
|
56
|
+
* Molar conductivity Λm in S·cm²/mol, from conductivity and concentration in mol/dm³.
|
|
57
|
+
*
|
|
58
|
+
* The 1000 converts dm³ to cm³. It is not a fudge factor: κ is per cubic centimetre and c is per
|
|
59
|
+
* cubic decimetre, and the conversion has to appear somewhere. Here, once, rather than in every
|
|
60
|
+
* caller.
|
|
61
|
+
*/
|
|
62
|
+
declare const molarConductivity: (conductivityScm: number, concentrationMolPerDm3: number) => number;
|
|
63
|
+
/**
|
|
64
|
+
* Equivalent conductivity in S·cm²/equivalent, for the older papers that ask for it.
|
|
65
|
+
*
|
|
66
|
+
* Same quantity per EQUIVALENT rather than per mole, so it differs by the number of charges the
|
|
67
|
+
* formula unit carries. Sulfuric acid supplies two hydrogen ions per molecule, so a solution
|
|
68
|
+
* 0.5 mol/dm³ in H₂SO₄ is 1 equivalent per cubic decimetre, and its equivalent conductivity is
|
|
69
|
+
* half its molar conductivity. Worth keeping, because the two are quoted interchangeably in older
|
|
70
|
+
* sources and differ by a factor nobody signposts.
|
|
71
|
+
*/
|
|
72
|
+
declare const equivalentConductivity: (conductivityScm: number, concentrationMolPerDm3: number, chargesPerFormulaUnit: number) => number;
|
|
73
|
+
/**
|
|
74
|
+
* Volume in cm³ holding one mole, from a concentration in mol/dm³.
|
|
75
|
+
*
|
|
76
|
+
* The form older texts state the relation in: Λm = κ · V. Same content as dividing by
|
|
77
|
+
* concentration, and worth exposing because a question phrased with V is asking for this.
|
|
78
|
+
*/
|
|
79
|
+
declare const molarVolumeOfSolution: (concentrationMolPerDm3: number) => number;
|
|
80
|
+
/**
|
|
81
|
+
* Degree of dissociation from molar conductivity, against its value at infinite dilution.
|
|
82
|
+
*
|
|
83
|
+
* Arrhenius's ratio: at infinite dilution a weak electrolyte is fully dissociated, so how far
|
|
84
|
+
* short of that a real solution falls is how far short of fully dissociated it is. This is the
|
|
85
|
+
* measurement that makes "weak acid" a number rather than a word.
|
|
86
|
+
*
|
|
87
|
+
* Λ°m cannot be reached by extrapolating a weak electrolyte's own curve, because it is still
|
|
88
|
+
* climbing steeply where the data runs out. It is assembled from ion conductivities instead, which
|
|
89
|
+
* is what Kohlrausch's law is for.
|
|
90
|
+
*/
|
|
91
|
+
declare const degreeOfDissociation: (molar: number, atInfiniteDilution: number) => number;
|
|
92
|
+
/**
|
|
93
|
+
* Λ°m for an electrolyte from its separate ions (Kohlrausch's law of independent migration).
|
|
94
|
+
*
|
|
95
|
+
* At infinite dilution the ions are far enough apart to ignore each other entirely, so each
|
|
96
|
+
* contributes the same amount whatever it arrived with. That independence is the claim, and it is
|
|
97
|
+
* what lets a weak acid's Λ°m be assembled from strong-electrolyte measurements it could never be
|
|
98
|
+
* extrapolated from directly.
|
|
99
|
+
*/
|
|
100
|
+
declare const limitingMolarConductivity: (cation: {
|
|
101
|
+
conductivity: number;
|
|
102
|
+
count: number;
|
|
103
|
+
}, anion: {
|
|
104
|
+
conductivity: number;
|
|
105
|
+
count: number;
|
|
106
|
+
}) => number;
|
|
107
|
+
/**
|
|
108
|
+
* The dissociation constant of a weak electrolyte from its conductivity (Ostwald's dilution law).
|
|
109
|
+
*
|
|
110
|
+
* K = c α² / (1 − α)
|
|
111
|
+
*
|
|
112
|
+
* The bridge between an electrical measurement and an equilibrium constant, and the reason this
|
|
113
|
+
* technique mattered historically: it gives Ka for an acid too weak to titrate accurately.
|
|
114
|
+
*/
|
|
115
|
+
declare const ostwaldConstant: (concentrationMolPerDm3: number, dissociation: number) => number;
|
|
116
|
+
/**
|
|
117
|
+
* How far a weak electrolyte dissociates at a given concentration, from its constant.
|
|
118
|
+
*
|
|
119
|
+
* Ostwald's law run the other way, and the direction that actually gets used: the constant is the
|
|
120
|
+
* fixed property and the concentration is what a learner changes. Solving cα² + Kα − K = 0 for the
|
|
121
|
+
* positive root,
|
|
122
|
+
*
|
|
123
|
+
* α = (−K + √(K² + 4cK)) / 2c
|
|
124
|
+
*
|
|
125
|
+
* written that way rather than as the textbook quadratic because the other arrangement subtracts
|
|
126
|
+
* two nearly equal numbers when K is small, which is exactly the case here: cancellation would eat
|
|
127
|
+
* most of the significant figures for an acid with a K of 10⁻⁵.
|
|
128
|
+
*
|
|
129
|
+
* This is what makes dilution visible. Acetic acid is about 1.3% ionised at 0.1 mol/dm³ and about
|
|
130
|
+
* 13% at 0.001, so its molar conductivity climbs steeply on dilution while a strong electrolyte's
|
|
131
|
+
* barely moves.
|
|
132
|
+
*/
|
|
133
|
+
declare function dissociationFromConstant(concentrationMolPerDm3: number, dissociationConstant: number): number;
|
|
134
|
+
/**
|
|
135
|
+
* Molar conductivity of a STRONG electrolyte at a real concentration (Kohlrausch's √c law).
|
|
136
|
+
*
|
|
137
|
+
* Λm = Λ°m − A√c
|
|
138
|
+
*
|
|
139
|
+
* A strong electrolyte is fully dissociated at every concentration, so its molar conductivity has
|
|
140
|
+
* no dissociation to change. What little it loses on concentrating is the ions getting in each
|
|
141
|
+
* other's way: an ion drags an oppositely charged atmosphere behind it, and the closer they are
|
|
142
|
+
* packed the more it drags.
|
|
143
|
+
*
|
|
144
|
+
* That is the whole diagnostic. The square-root fall is gentle and levels off; a weak
|
|
145
|
+
* electrolyte's rise does not level off at all, because its dissociation is still moving. Told
|
|
146
|
+
* apart by the SHAPE of the curve, without knowing anything else about either substance.
|
|
147
|
+
*/
|
|
148
|
+
declare const strongMolarConductivity: (limiting: number, slope: number, concentrationMolPerDm3: number) => number;
|
|
149
|
+
/**
|
|
150
|
+
* Molar conductivity of a WEAK electrolyte, which is its limit scaled by how far it has gone.
|
|
151
|
+
*
|
|
152
|
+
* Λm = α Λ°m, with α from the dissociation constant. The same statement as
|
|
153
|
+
* {@link degreeOfDissociation} solved for the conductivity instead of the ratio.
|
|
154
|
+
*/
|
|
155
|
+
declare const weakMolarConductivity: (limiting: number, dissociationConstant: number, concentrationMolPerDm3: number) => number;
|
|
156
|
+
//#endregion
|
|
157
|
+
export { cellConstant, conductance, conductivity, degreeOfDissociation, dissociationFromConstant, equivalentConductivity, limitingMolarConductivity, molarConductivity, molarVolumeOfSolution, ostwaldConstant, strongMolarConductivity, weakMolarConductivity };
|