@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,201 @@
|
|
|
1
|
+
//#region src/optics/refraction.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Refraction: light crossing a boundary, and everything that follows from it.
|
|
4
|
+
*
|
|
5
|
+
* THE MODEL. One law does the whole of this file:
|
|
6
|
+
*
|
|
7
|
+
* n₁ sin θ₁ = n₂ sin θ₂ (Snell)
|
|
8
|
+
*
|
|
9
|
+
* with n = c/v, the factor by which a medium slows light down. Written that way
|
|
10
|
+
* rather than as a pair of "denser/rarer" rules, because the symmetry is the
|
|
11
|
+
* point: reverse the ray and the same equation describes it, which is why a
|
|
12
|
+
* critical angle exists at all and why it exists only going the other way.
|
|
13
|
+
*
|
|
14
|
+
* WHAT SNELL'S LAW RETURNS WHEN THERE IS NO ANSWER. Solving for θ₂ needs
|
|
15
|
+
* arcsin((n₁/n₂)·sin θ₁), and past the critical angle that argument exceeds 1.
|
|
16
|
+
* That is not a numerical accident to be clamped away: it is TOTAL INTERNAL
|
|
17
|
+
* REFLECTION, the physical statement that no refracted ray exists. So
|
|
18
|
+
* `refractAngleDeg` returns `null` rather than NaN or a clamped 90 degrees, and
|
|
19
|
+
* `refract` returns a result that says which case happened. A clamp here would
|
|
20
|
+
* draw a refracted ray grazing along the surface forever, which is a picture of
|
|
21
|
+
* something that does not happen.
|
|
22
|
+
*
|
|
23
|
+
* ANGLES ARE IN DEGREES at this boundary, because every syllabus, every
|
|
24
|
+
* protractor and every worked answer is, and a kernel that took radians would
|
|
25
|
+
* push a conversion into every single call site. Internally it converts once.
|
|
26
|
+
*
|
|
27
|
+
* SCOPE. Geometric optics: rays, not beams. No amplitude, so nothing here says
|
|
28
|
+
* how MUCH light reflects at a boundary (that is Fresnel, and it is not on
|
|
29
|
+
* either syllabus). Non-dispersive unless a caller passes a per-colour index;
|
|
30
|
+
* `prism.ts` is where dispersion is handled properly.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Refractive indices at roughly 589 nm (the sodium D line), which is the
|
|
34
|
+
* wavelength every table is quoted at.
|
|
35
|
+
*
|
|
36
|
+
* Air is 1.000293 and is almost always taken as 1. Both are here: the exact
|
|
37
|
+
* value so a lesson about why we round it has something to point at, and the
|
|
38
|
+
* rounding left to the caller rather than baked in.
|
|
39
|
+
*/
|
|
40
|
+
declare const MEDIA: Record<string, number>;
|
|
41
|
+
/** Speed of light in a medium, m/s: v = c/n. */
|
|
42
|
+
declare function speedInMedium(n: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Wavelength inside a medium, given the vacuum wavelength: λ = λ₀/n.
|
|
45
|
+
*
|
|
46
|
+
* The FREQUENCY does not change, and that is the whole reason refraction
|
|
47
|
+
* happens: the wave crests arrive at the boundary at a fixed rate, so if they
|
|
48
|
+
* travel more slowly on the far side they must be closer together, and a train
|
|
49
|
+
* of wavefronts meeting the boundary at an angle pivots. Colour is frequency,
|
|
50
|
+
* which is why light does not change colour on entering water.
|
|
51
|
+
*/
|
|
52
|
+
declare function wavelengthInMedium(vacuumWavelength: number, n: number): number;
|
|
53
|
+
/**
|
|
54
|
+
* The refractive index of medium b relative to medium a: ₐn_b = n_b/n_a.
|
|
55
|
+
*
|
|
56
|
+
* The relative index is what Snell's law actually contains, which is why the
|
|
57
|
+
* chain ₐn_b × _bn_c × _cn_a = 1 holds: each factor is a ratio and the ratios
|
|
58
|
+
* telescope. That identity is a standard exam question and it is also the
|
|
59
|
+
* cheapest possible check that a table of indices is self-consistent.
|
|
60
|
+
*/
|
|
61
|
+
declare function relativeIndex(from: number, to: number): number;
|
|
62
|
+
interface Refraction {
|
|
63
|
+
/** The angle of incidence given, degrees from the normal. */
|
|
64
|
+
incidenceDeg: number;
|
|
65
|
+
/** The refracted angle, degrees from the normal, or `null` under total internal reflection. */
|
|
66
|
+
refractionDeg: number | null;
|
|
67
|
+
/** True when no refracted ray exists and all the light reflects back. */
|
|
68
|
+
totalInternalReflection: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The critical angle for this pair, degrees, or `null` when there is none.
|
|
71
|
+
*
|
|
72
|
+
* Only exists going from denser to rarer. Reported even when the ray is below
|
|
73
|
+
* it, because "how much further could I tilt this before the ray vanishes" is
|
|
74
|
+
* the question the number answers.
|
|
75
|
+
*/
|
|
76
|
+
criticalAngleDeg: number | null;
|
|
77
|
+
/** Index of the medium the light starts in. */
|
|
78
|
+
fromIndex: number;
|
|
79
|
+
/** Index of the medium it enters. */
|
|
80
|
+
toIndex: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Refract a ray across a boundary, reporting what happened rather than only the
|
|
84
|
+
* angle.
|
|
85
|
+
*
|
|
86
|
+
* Returns the critical angle alongside, so a caller drawing the boundary does
|
|
87
|
+
* not have to ask a second function to know how close it is to losing the ray.
|
|
88
|
+
*/
|
|
89
|
+
declare function refract(incidenceDeg: number, fromIndex: number, toIndex: number): Refraction;
|
|
90
|
+
/** Just the refracted angle in degrees, or `null` under total internal reflection. */
|
|
91
|
+
declare function refractAngleDeg(incidenceDeg: number, fromIndex: number, toIndex: number): number | null;
|
|
92
|
+
/**
|
|
93
|
+
* The critical angle in degrees: sin C = n_rare/n_dense.
|
|
94
|
+
*
|
|
95
|
+
* Throws when the light is going the easy way, because there is no critical
|
|
96
|
+
* angle from rare to dense and returning one would invent a boundary that is
|
|
97
|
+
* not there. That refusal is the lesson: total internal reflection is a
|
|
98
|
+
* one-way phenomenon, which is why an optical fibre works and why it has to be
|
|
99
|
+
* made of a dense core in a less dense cladding rather than the other way
|
|
100
|
+
* round.
|
|
101
|
+
*/
|
|
102
|
+
declare function criticalAngleDeg(denseIndex: number, rareIndex?: number): number;
|
|
103
|
+
/** One layer of a stack of transparent media, for the apparent-depth sum. */
|
|
104
|
+
interface DepthLayer {
|
|
105
|
+
label?: string;
|
|
106
|
+
/** True thickness of this layer. */
|
|
107
|
+
thickness: number;
|
|
108
|
+
/** Refractive index of this layer. */
|
|
109
|
+
index: number;
|
|
110
|
+
}
|
|
111
|
+
interface ApparentDepth {
|
|
112
|
+
/** The total real depth, the sum of the layers. */
|
|
113
|
+
realDepth: number;
|
|
114
|
+
/** The depth the bottom appears to be at, viewed from directly above. */
|
|
115
|
+
apparentDepth: number;
|
|
116
|
+
/** How much closer the bottom looks: real minus apparent. */
|
|
117
|
+
apparentShift: number;
|
|
118
|
+
/** Each layer's contribution to the apparent depth. */
|
|
119
|
+
layers: {
|
|
120
|
+
label: string;
|
|
121
|
+
thickness: number;
|
|
122
|
+
index: number;
|
|
123
|
+
apparent: number;
|
|
124
|
+
}[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* How deep a stack of transparent layers appears, viewed from straight above.
|
|
128
|
+
*
|
|
129
|
+
* Each layer contributes its own thickness divided by its own index, and the
|
|
130
|
+
* apparent depths simply add:
|
|
131
|
+
*
|
|
132
|
+
* d_apparent = Σ dᵢ / nᵢ
|
|
133
|
+
*
|
|
134
|
+
* That they add is worth pausing on, because the refractions do not: the ray
|
|
135
|
+
* bends at every boundary, and the bends do not sum to anything tidy. It is the
|
|
136
|
+
* near-normal limit that makes this exact, where every sine may be replaced by
|
|
137
|
+
* its angle, and this function is therefore only right for looking STRAIGHT
|
|
138
|
+
* DOWN. A fish watched from a shallow angle is not where this says it is.
|
|
139
|
+
*
|
|
140
|
+
* Handles one layer as easily as five, which is the usual case: a coin under
|
|
141
|
+
* water is `apparentDepth([{ thickness: 0.4, index: 1.333 }])`.
|
|
142
|
+
*/
|
|
143
|
+
declare function apparentDepth(layers: readonly DepthLayer[]): ApparentDepth;
|
|
144
|
+
/**
|
|
145
|
+
* The refractive index measured by the apparent-depth method: n = real/apparent.
|
|
146
|
+
*
|
|
147
|
+
* The simplest quantitative optics experiment there is, and the inverse of the
|
|
148
|
+
* single-layer case above.
|
|
149
|
+
*/
|
|
150
|
+
declare function indexFromDepths(realDepth: number, apparentDepthValue: number): number;
|
|
151
|
+
interface SlabPassage {
|
|
152
|
+
/** The refracted angle inside the slab, degrees. */
|
|
153
|
+
refractionDeg: number;
|
|
154
|
+
/** Sideways displacement of the emerging ray from the original line. */
|
|
155
|
+
lateralShift: number;
|
|
156
|
+
/** Path length travelled inside the slab. */
|
|
157
|
+
pathLength: number;
|
|
158
|
+
/** Time spent inside the slab, seconds, if the thickness is in metres. */
|
|
159
|
+
timeInside: number;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* A ray through a parallel-sided slab: how far it is shifted, and how long it
|
|
163
|
+
* takes.
|
|
164
|
+
*
|
|
165
|
+
* x = d · sin(i − r) / cos r
|
|
166
|
+
*
|
|
167
|
+
* The emerging ray is PARALLEL to the one that went in, never bent overall,
|
|
168
|
+
* because the second boundary undoes exactly what the first did. All a glass
|
|
169
|
+
* block does is move the ray sideways, which is why a window does not distort
|
|
170
|
+
* the view and why a thick one seen at a glancing angle does.
|
|
171
|
+
*
|
|
172
|
+
* `timeInside` uses the slowed speed c/n, so it is longer than the same path in
|
|
173
|
+
* air. Keep the thickness in metres for that to be in seconds.
|
|
174
|
+
*/
|
|
175
|
+
declare function throughSlab(thickness: number, incidenceDeg: number, slabIndex: number, outsideIndex?: number): SlabPassage;
|
|
176
|
+
/**
|
|
177
|
+
* Brewster's angle, degrees: tan θ_p = n₂/n₁.
|
|
178
|
+
*
|
|
179
|
+
* The one angle of incidence at which the reflected light is completely plane
|
|
180
|
+
* polarised. At it, the reflected and refracted rays are exactly 90 degrees
|
|
181
|
+
* apart, which is the reason rather than a coincidence: the reflected ray is
|
|
182
|
+
* driven by the oscillation of charges in the second medium, and a dipole
|
|
183
|
+
* radiates nothing along its own axis.
|
|
184
|
+
*
|
|
185
|
+
* Polaroid sunglasses cut glare off water because that glare is reflected near
|
|
186
|
+
* this angle and is therefore polarised horizontally.
|
|
187
|
+
*/
|
|
188
|
+
declare function brewsterAngleDeg(toIndex: number, fromIndex?: number): number;
|
|
189
|
+
/**
|
|
190
|
+
* The refractive index from the two angles a rod makes at a liquid surface:
|
|
191
|
+
*
|
|
192
|
+
* n = tan θ / tan φ
|
|
193
|
+
*
|
|
194
|
+
* θ is the angle the rod makes with the surface, φ the angle the rod's IMAGE
|
|
195
|
+
* appears to make. This is the "a stick in water looks bent" measurement made
|
|
196
|
+
* quantitative, and it is a tangent rather than a sine because both angles are
|
|
197
|
+
* read off the surface rather than off the normal.
|
|
198
|
+
*/
|
|
199
|
+
declare function indexFromRodAngles(rodDeg: number, imageDeg: number): number;
|
|
200
|
+
//#endregion
|
|
201
|
+
export { ApparentDepth, DepthLayer, MEDIA, Refraction, SlabPassage, apparentDepth, brewsterAngleDeg, criticalAngleDeg, indexFromDepths, indexFromRodAngles, refract, refractAngleDeg, relativeIndex, speedInMedium, throughSlab, wavelengthInMedium };
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { SPEED_OF_LIGHT } from "../core/constants.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/optics/refraction.ts
|
|
4
|
+
/**
|
|
5
|
+
* Refraction: light crossing a boundary, and everything that follows from it.
|
|
6
|
+
*
|
|
7
|
+
* THE MODEL. One law does the whole of this file:
|
|
8
|
+
*
|
|
9
|
+
* n₁ sin θ₁ = n₂ sin θ₂ (Snell)
|
|
10
|
+
*
|
|
11
|
+
* with n = c/v, the factor by which a medium slows light down. Written that way
|
|
12
|
+
* rather than as a pair of "denser/rarer" rules, because the symmetry is the
|
|
13
|
+
* point: reverse the ray and the same equation describes it, which is why a
|
|
14
|
+
* critical angle exists at all and why it exists only going the other way.
|
|
15
|
+
*
|
|
16
|
+
* WHAT SNELL'S LAW RETURNS WHEN THERE IS NO ANSWER. Solving for θ₂ needs
|
|
17
|
+
* arcsin((n₁/n₂)·sin θ₁), and past the critical angle that argument exceeds 1.
|
|
18
|
+
* That is not a numerical accident to be clamped away: it is TOTAL INTERNAL
|
|
19
|
+
* REFLECTION, the physical statement that no refracted ray exists. So
|
|
20
|
+
* `refractAngleDeg` returns `null` rather than NaN or a clamped 90 degrees, and
|
|
21
|
+
* `refract` returns a result that says which case happened. A clamp here would
|
|
22
|
+
* draw a refracted ray grazing along the surface forever, which is a picture of
|
|
23
|
+
* something that does not happen.
|
|
24
|
+
*
|
|
25
|
+
* ANGLES ARE IN DEGREES at this boundary, because every syllabus, every
|
|
26
|
+
* protractor and every worked answer is, and a kernel that took radians would
|
|
27
|
+
* push a conversion into every single call site. Internally it converts once.
|
|
28
|
+
*
|
|
29
|
+
* SCOPE. Geometric optics: rays, not beams. No amplitude, so nothing here says
|
|
30
|
+
* how MUCH light reflects at a boundary (that is Fresnel, and it is not on
|
|
31
|
+
* either syllabus). Non-dispersive unless a caller passes a per-colour index;
|
|
32
|
+
* `prism.ts` is where dispersion is handled properly.
|
|
33
|
+
*/
|
|
34
|
+
const DEG = Math.PI / 180;
|
|
35
|
+
const toRad = (deg) => deg * DEG;
|
|
36
|
+
const toDeg = (rad) => rad / DEG;
|
|
37
|
+
const finite = (value, what) => {
|
|
38
|
+
if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
|
|
39
|
+
return value;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Guard for a refractive index.
|
|
43
|
+
*
|
|
44
|
+
* Refuses anything below 1, because n = c/v and nothing carries light faster
|
|
45
|
+
* than light does. A caller who has passed 0.9 has swapped two media or typed a
|
|
46
|
+
* reciprocal, and both mistakes produce believable angles if allowed through.
|
|
47
|
+
*/
|
|
48
|
+
const index = (value, what = "A refractive index") => {
|
|
49
|
+
if (!Number.isFinite(value) || value < 1) throw new RangeError(`${what} must be at least 1 (got ${value}); n = c/v, and nothing outruns light in vacuum.`);
|
|
50
|
+
return value;
|
|
51
|
+
};
|
|
52
|
+
/** An angle measured from the NORMAL, in degrees, as every optics convention does. */
|
|
53
|
+
const angle = (value, what = "An angle") => {
|
|
54
|
+
if (!Number.isFinite(value) || value < 0 || value > 90) throw new RangeError(`${what} is measured from the normal and lies in [0, 90] degrees (got ${value}).`);
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Refractive indices at roughly 589 nm (the sodium D line), which is the
|
|
59
|
+
* wavelength every table is quoted at.
|
|
60
|
+
*
|
|
61
|
+
* Air is 1.000293 and is almost always taken as 1. Both are here: the exact
|
|
62
|
+
* value so a lesson about why we round it has something to point at, and the
|
|
63
|
+
* rounding left to the caller rather than baked in.
|
|
64
|
+
*/
|
|
65
|
+
const MEDIA = {
|
|
66
|
+
vacuum: 1,
|
|
67
|
+
air: 1.000293,
|
|
68
|
+
ice: 1.31,
|
|
69
|
+
water: 1.333,
|
|
70
|
+
ethanol: 1.361,
|
|
71
|
+
glycerol: 1.473,
|
|
72
|
+
perspex: 1.495,
|
|
73
|
+
crownGlass: 1.52,
|
|
74
|
+
glass: 1.5,
|
|
75
|
+
flintGlass: 1.62,
|
|
76
|
+
sapphire: 1.77,
|
|
77
|
+
diamond: 2.417
|
|
78
|
+
};
|
|
79
|
+
/** Speed of light in a medium, m/s: v = c/n. */
|
|
80
|
+
function speedInMedium(n) {
|
|
81
|
+
return SPEED_OF_LIGHT / index(n);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Wavelength inside a medium, given the vacuum wavelength: λ = λ₀/n.
|
|
85
|
+
*
|
|
86
|
+
* The FREQUENCY does not change, and that is the whole reason refraction
|
|
87
|
+
* happens: the wave crests arrive at the boundary at a fixed rate, so if they
|
|
88
|
+
* travel more slowly on the far side they must be closer together, and a train
|
|
89
|
+
* of wavefronts meeting the boundary at an angle pivots. Colour is frequency,
|
|
90
|
+
* which is why light does not change colour on entering water.
|
|
91
|
+
*/
|
|
92
|
+
function wavelengthInMedium(vacuumWavelength, n) {
|
|
93
|
+
return finite(vacuumWavelength, "A wavelength") / index(n);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The refractive index of medium b relative to medium a: ₐn_b = n_b/n_a.
|
|
97
|
+
*
|
|
98
|
+
* The relative index is what Snell's law actually contains, which is why the
|
|
99
|
+
* chain ₐn_b × _bn_c × _cn_a = 1 holds: each factor is a ratio and the ratios
|
|
100
|
+
* telescope. That identity is a standard exam question and it is also the
|
|
101
|
+
* cheapest possible check that a table of indices is self-consistent.
|
|
102
|
+
*/
|
|
103
|
+
function relativeIndex(from, to) {
|
|
104
|
+
return index(to, "The index of the second medium") / index(from, "The index of the first medium");
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Refract a ray across a boundary, reporting what happened rather than only the
|
|
108
|
+
* angle.
|
|
109
|
+
*
|
|
110
|
+
* Returns the critical angle alongside, so a caller drawing the boundary does
|
|
111
|
+
* not have to ask a second function to know how close it is to losing the ray.
|
|
112
|
+
*/
|
|
113
|
+
function refract(incidenceDeg, fromIndex, toIndex) {
|
|
114
|
+
const i = angle(incidenceDeg, "The angle of incidence");
|
|
115
|
+
const n1 = index(fromIndex, "The index of the first medium");
|
|
116
|
+
const n2 = index(toIndex, "The index of the second medium");
|
|
117
|
+
const critical = n1 > n2 ? toDeg(Math.asin(n2 / n1)) : null;
|
|
118
|
+
const sinR = n1 / n2 * Math.sin(toRad(i));
|
|
119
|
+
if (sinR > 1.000000000001) return {
|
|
120
|
+
incidenceDeg: i,
|
|
121
|
+
refractionDeg: null,
|
|
122
|
+
totalInternalReflection: true,
|
|
123
|
+
criticalAngleDeg: critical,
|
|
124
|
+
fromIndex: n1,
|
|
125
|
+
toIndex: n2
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
incidenceDeg: i,
|
|
129
|
+
refractionDeg: toDeg(Math.asin(Math.min(1, sinR))),
|
|
130
|
+
totalInternalReflection: false,
|
|
131
|
+
criticalAngleDeg: critical,
|
|
132
|
+
fromIndex: n1,
|
|
133
|
+
toIndex: n2
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Just the refracted angle in degrees, or `null` under total internal reflection. */
|
|
137
|
+
function refractAngleDeg(incidenceDeg, fromIndex, toIndex) {
|
|
138
|
+
return refract(incidenceDeg, fromIndex, toIndex).refractionDeg;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The critical angle in degrees: sin C = n_rare/n_dense.
|
|
142
|
+
*
|
|
143
|
+
* Throws when the light is going the easy way, because there is no critical
|
|
144
|
+
* angle from rare to dense and returning one would invent a boundary that is
|
|
145
|
+
* not there. That refusal is the lesson: total internal reflection is a
|
|
146
|
+
* one-way phenomenon, which is why an optical fibre works and why it has to be
|
|
147
|
+
* made of a dense core in a less dense cladding rather than the other way
|
|
148
|
+
* round.
|
|
149
|
+
*/
|
|
150
|
+
function criticalAngleDeg(denseIndex, rareIndex = 1) {
|
|
151
|
+
const dense = index(denseIndex, "The index of the dense medium");
|
|
152
|
+
const rare = index(rareIndex, "The index of the rare medium");
|
|
153
|
+
if (dense <= rare) throw new RangeError(`No critical angle from n = ${dense} into n = ${rare}: total internal reflection only happens going from denser to rarer.`);
|
|
154
|
+
return toDeg(Math.asin(rare / dense));
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* How deep a stack of transparent layers appears, viewed from straight above.
|
|
158
|
+
*
|
|
159
|
+
* Each layer contributes its own thickness divided by its own index, and the
|
|
160
|
+
* apparent depths simply add:
|
|
161
|
+
*
|
|
162
|
+
* d_apparent = Σ dᵢ / nᵢ
|
|
163
|
+
*
|
|
164
|
+
* That they add is worth pausing on, because the refractions do not: the ray
|
|
165
|
+
* bends at every boundary, and the bends do not sum to anything tidy. It is the
|
|
166
|
+
* near-normal limit that makes this exact, where every sine may be replaced by
|
|
167
|
+
* its angle, and this function is therefore only right for looking STRAIGHT
|
|
168
|
+
* DOWN. A fish watched from a shallow angle is not where this says it is.
|
|
169
|
+
*
|
|
170
|
+
* Handles one layer as easily as five, which is the usual case: a coin under
|
|
171
|
+
* water is `apparentDepth([{ thickness: 0.4, index: 1.333 }])`.
|
|
172
|
+
*/
|
|
173
|
+
function apparentDepth(layers) {
|
|
174
|
+
if (layers.length === 0) throw new RangeError("There is nothing to look through.");
|
|
175
|
+
const resolved = layers.map((layer, i) => {
|
|
176
|
+
const thickness = finite(layer.thickness, "A layer thickness");
|
|
177
|
+
if (thickness < 0) throw new RangeError("A layer cannot have a negative thickness.");
|
|
178
|
+
const n = index(layer.index, `Layer ${i + 1}'s refractive index`);
|
|
179
|
+
return {
|
|
180
|
+
label: layer.label ?? `layer ${i + 1}`,
|
|
181
|
+
thickness,
|
|
182
|
+
index: n,
|
|
183
|
+
apparent: thickness / n
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
const realDepth = resolved.reduce((sum, l) => sum + l.thickness, 0);
|
|
187
|
+
const apparent = resolved.reduce((sum, l) => sum + l.apparent, 0);
|
|
188
|
+
return {
|
|
189
|
+
realDepth,
|
|
190
|
+
apparentDepth: apparent,
|
|
191
|
+
apparentShift: realDepth - apparent,
|
|
192
|
+
layers: resolved
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The refractive index measured by the apparent-depth method: n = real/apparent.
|
|
197
|
+
*
|
|
198
|
+
* The simplest quantitative optics experiment there is, and the inverse of the
|
|
199
|
+
* single-layer case above.
|
|
200
|
+
*/
|
|
201
|
+
function indexFromDepths(realDepth, apparentDepthValue) {
|
|
202
|
+
const real = finite(realDepth, "The real depth");
|
|
203
|
+
const apparent = finite(apparentDepthValue, "The apparent depth");
|
|
204
|
+
if (apparent <= 0) throw new RangeError("The apparent depth must be positive.");
|
|
205
|
+
if (real < apparent) throw new RangeError("The bottom always looks CLOSER than it is, so the real depth cannot be the smaller of the two.");
|
|
206
|
+
return real / apparent;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* A ray through a parallel-sided slab: how far it is shifted, and how long it
|
|
210
|
+
* takes.
|
|
211
|
+
*
|
|
212
|
+
* x = d · sin(i − r) / cos r
|
|
213
|
+
*
|
|
214
|
+
* The emerging ray is PARALLEL to the one that went in, never bent overall,
|
|
215
|
+
* because the second boundary undoes exactly what the first did. All a glass
|
|
216
|
+
* block does is move the ray sideways, which is why a window does not distort
|
|
217
|
+
* the view and why a thick one seen at a glancing angle does.
|
|
218
|
+
*
|
|
219
|
+
* `timeInside` uses the slowed speed c/n, so it is longer than the same path in
|
|
220
|
+
* air. Keep the thickness in metres for that to be in seconds.
|
|
221
|
+
*/
|
|
222
|
+
function throughSlab(thickness, incidenceDeg, slabIndex, outsideIndex = 1) {
|
|
223
|
+
const d = finite(thickness, "The slab thickness");
|
|
224
|
+
if (d < 0) throw new RangeError("A slab cannot have a negative thickness.");
|
|
225
|
+
const i = angle(incidenceDeg, "The angle of incidence");
|
|
226
|
+
const result = refract(i, outsideIndex, slabIndex);
|
|
227
|
+
if (result.refractionDeg === null) throw new RangeError("No ray enters the slab, so it has no passage through it.");
|
|
228
|
+
const r = result.refractionDeg;
|
|
229
|
+
const pathLength = d / Math.cos(toRad(r));
|
|
230
|
+
return {
|
|
231
|
+
refractionDeg: r,
|
|
232
|
+
lateralShift: d * Math.sin(toRad(i - r)) / Math.cos(toRad(r)),
|
|
233
|
+
pathLength,
|
|
234
|
+
timeInside: pathLength / speedInMedium(slabIndex)
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Brewster's angle, degrees: tan θ_p = n₂/n₁.
|
|
239
|
+
*
|
|
240
|
+
* The one angle of incidence at which the reflected light is completely plane
|
|
241
|
+
* polarised. At it, the reflected and refracted rays are exactly 90 degrees
|
|
242
|
+
* apart, which is the reason rather than a coincidence: the reflected ray is
|
|
243
|
+
* driven by the oscillation of charges in the second medium, and a dipole
|
|
244
|
+
* radiates nothing along its own axis.
|
|
245
|
+
*
|
|
246
|
+
* Polaroid sunglasses cut glare off water because that glare is reflected near
|
|
247
|
+
* this angle and is therefore polarised horizontally.
|
|
248
|
+
*/
|
|
249
|
+
function brewsterAngleDeg(toIndex, fromIndex = 1) {
|
|
250
|
+
return toDeg(Math.atan(index(toIndex, "The index of the second medium") / index(fromIndex, "The index of the first medium")));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The refractive index from the two angles a rod makes at a liquid surface:
|
|
254
|
+
*
|
|
255
|
+
* n = tan θ / tan φ
|
|
256
|
+
*
|
|
257
|
+
* θ is the angle the rod makes with the surface, φ the angle the rod's IMAGE
|
|
258
|
+
* appears to make. This is the "a stick in water looks bent" measurement made
|
|
259
|
+
* quantitative, and it is a tangent rather than a sine because both angles are
|
|
260
|
+
* read off the surface rather than off the normal.
|
|
261
|
+
*/
|
|
262
|
+
function indexFromRodAngles(rodDeg, imageDeg) {
|
|
263
|
+
const theta = finite(rodDeg, "The rod angle");
|
|
264
|
+
const phi = finite(imageDeg, "The image angle");
|
|
265
|
+
if (theta <= 0 || theta >= 90 || phi <= 0 || phi >= 90) throw new RangeError("Both angles are measured from the liquid surface and lie strictly between 0 and 90 degrees.");
|
|
266
|
+
return Math.tan(toRad(theta)) / Math.tan(toRad(phi));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
export { MEDIA, apparentDepth, brewsterAngleDeg, criticalAngleDeg, indexFromDepths, indexFromRodAngles, refract, refractAngleDeg, relativeIndex, speedInMedium, throughSlab, wavelengthInMedium };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { pathFromPhase, phaseFromPath } from "../waves/wave.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/optics/wave-optics.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Fringe spacing in Young's experiment: w = λD/a.
|
|
6
|
+
*
|
|
7
|
+
* The workhorse, and the reason the experiment is the classic measurement of a
|
|
8
|
+
* wavelength: every quantity on the right is measurable with a ruler, and the
|
|
9
|
+
* left is a few tenths of a millimetre magnified into something you can count.
|
|
10
|
+
*
|
|
11
|
+
* The slit separation `a` is in the DENOMINATOR, which is the counter-intuitive
|
|
12
|
+
* part: pushing the slits closer together spreads the fringes apart.
|
|
13
|
+
*/
|
|
14
|
+
declare function fringeSpacing(wavelength: number, screenDistance: number, slitSeparation: number): number;
|
|
15
|
+
/** Wavelength from a measured fringe spacing, the inverse of `fringeSpacing`. */
|
|
16
|
+
declare function wavelengthFromFringes(fringeWidth: number, screenDistance: number, slitSeparation: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Distance from the centre of the pattern to the nth BRIGHT fringe, metres.
|
|
19
|
+
*
|
|
20
|
+
* `n = 0` is the central maximum, which sits at zero path difference and is
|
|
21
|
+
* therefore in the same place for every wavelength. That is why the centre of a
|
|
22
|
+
* white-light interference pattern is white and everything either side is
|
|
23
|
+
* coloured.
|
|
24
|
+
*/
|
|
25
|
+
declare function brightFringePosition(n: number, wavelength: number, screenDistance: number, slitSeparation: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Distance to the nth DARK fringe, metres, with `n = 0` the first one out from
|
|
28
|
+
* the centre.
|
|
29
|
+
*
|
|
30
|
+
* Half a fringe width further out than the bright one of the same index, which
|
|
31
|
+
* is the (n + ½) in the textbook formula written where it cannot be misread as
|
|
32
|
+
* (2n+1)/2 applied to the wrong thing.
|
|
33
|
+
*/
|
|
34
|
+
declare function darkFringePosition(n: number, wavelength: number, screenDistance: number, slitSeparation: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* The exact angle to the nth bright fringe, degrees, from a sin θ = nλ.
|
|
37
|
+
*
|
|
38
|
+
* No small-angle assumption, so it stays right where `fringeSpacing` starts to
|
|
39
|
+
* drift. Returns `null` when the order does not exist, which happens once
|
|
40
|
+
* nλ exceeds the slit separation.
|
|
41
|
+
*/
|
|
42
|
+
declare function fringeAngleDeg(n: number, wavelength: number, slitSeparation: number): number | null;
|
|
43
|
+
/**
|
|
44
|
+
* Relative intensity of a two-slit pattern at a phase difference φ:
|
|
45
|
+
* I = I₀·cos²(φ/2).
|
|
46
|
+
*
|
|
47
|
+
* Note the pattern's peaks are FOUR times one slit's intensity, not twice, and
|
|
48
|
+
* the average is twice. Energy is conserved by redistribution, not by creation:
|
|
49
|
+
* the light missing from the dark fringes is exactly the excess in the bright
|
|
50
|
+
* ones.
|
|
51
|
+
*/
|
|
52
|
+
declare const twoSlitIntensity: (peakIntensity: number, phase: number) => number;
|
|
53
|
+
/**
|
|
54
|
+
* The single-slit ENVELOPE at an angle, normalised to 1 straight ahead:
|
|
55
|
+
*
|
|
56
|
+
* I/I₀ = (sin α / α)² with α = πa·sinθ/λ
|
|
57
|
+
*
|
|
58
|
+
* The shape every diffraction pattern sits inside. `α = 0` is 0/0 and the limit
|
|
59
|
+
* is 1, handled explicitly rather than left to produce NaN on the axis, which
|
|
60
|
+
* is the one point every plot draws.
|
|
61
|
+
*
|
|
62
|
+
* Note the contrast with the two-slit fringe term: the same algebra
|
|
63
|
+
* `a sinθ = nλ` gives a MINIMUM here and a MAXIMUM there. Confusing the two is
|
|
64
|
+
* the commonest error in the topic.
|
|
65
|
+
*/
|
|
66
|
+
declare function singleSlitEnvelope(thetaDeg: number, wavelength: number, slitWidth: number): number;
|
|
67
|
+
/**
|
|
68
|
+
* The full two-slit pattern at an angle, normalised to 1 straight ahead:
|
|
69
|
+
* the envelope times the fringes.
|
|
70
|
+
*
|
|
71
|
+
* Two independent effects multiplied, and that product is the insight the
|
|
72
|
+
* pattern exists to deliver. The slit WIDTH sets the broad envelope, which
|
|
73
|
+
* decides how bright each fringe is; the slit SEPARATION sets the fine fringes
|
|
74
|
+
* inside it. Students routinely attribute both to one number, and a lab that
|
|
75
|
+
* draws only the fringe term cannot show them otherwise.
|
|
76
|
+
*
|
|
77
|
+
* `interfere: false` drops the fringe term and leaves the envelope, which is
|
|
78
|
+
* what covering one slit looks like, and what a which-path measurement does to
|
|
79
|
+
* the quantum version.
|
|
80
|
+
*/
|
|
81
|
+
declare function doubleSlitPattern(thetaDeg: number, wavelength: number, slitSeparation: number, slitWidth: number, options?: {
|
|
82
|
+
readonly interfere?: boolean;
|
|
83
|
+
}): number;
|
|
84
|
+
/**
|
|
85
|
+
* Angle to the nth diffraction MINIMUM of a single slit, degrees: a sin θ = nλ.
|
|
86
|
+
*
|
|
87
|
+
* `n` starts at 1; there is no n = 0 minimum, because straight ahead every
|
|
88
|
+
* contribution across the slit arrives in phase and that is the central
|
|
89
|
+
* maximum. Returns `null` when the order does not exist.
|
|
90
|
+
*/
|
|
91
|
+
declare function singleSlitMinimumDeg(n: number, wavelength: number, slitWidth: number): number | null;
|
|
92
|
+
/**
|
|
93
|
+
* Angular half-width of the central diffraction maximum, degrees.
|
|
94
|
+
*
|
|
95
|
+
* The central bright band is TWICE this wide, and twice as wide as every other
|
|
96
|
+
* band, which is the single most recognisable feature of a diffraction pattern.
|
|
97
|
+
*/
|
|
98
|
+
declare function centralMaximumHalfWidthDeg(wavelength: number, slitWidth: number): number | null;
|
|
99
|
+
/**
|
|
100
|
+
* Width of the central maximum on a screen, metres, in the small-angle limit:
|
|
101
|
+
* 2λD/a.
|
|
102
|
+
*
|
|
103
|
+
* Narrowing the slit WIDENS the patch. Push it to a slit comparable with the
|
|
104
|
+
* wavelength and the light spreads through most of a hemisphere, which is the
|
|
105
|
+
* observation that rules out light being a stream of particles travelling in
|
|
106
|
+
* straight lines.
|
|
107
|
+
*/
|
|
108
|
+
declare function centralMaximumWidth(wavelength: number, screenDistance: number, slitWidth: number): number;
|
|
109
|
+
/** Slit spacing from a ruling density: d = 1/N, with N lines per metre. */
|
|
110
|
+
declare const gratingSpacing: (linesPerMetre: number) => number;
|
|
111
|
+
/**
|
|
112
|
+
* Angle of the nth order from a grating, degrees: d sin θ = nλ.
|
|
113
|
+
*
|
|
114
|
+
* Returns `null` when that order does not exist, rather than NaN, because
|
|
115
|
+
* "which orders can I see" is the question and a missing order is an answer to
|
|
116
|
+
* it.
|
|
117
|
+
*/
|
|
118
|
+
declare function gratingAngleDeg(n: number, wavelength: number, spacing: number): number | null;
|
|
119
|
+
/**
|
|
120
|
+
* The highest order a grating can show: floor(d/λ).
|
|
121
|
+
*
|
|
122
|
+
* Because sin θ cannot exceed 1. A subtlety worth the comment: the order at
|
|
123
|
+
* exactly d/λ would sit at 90 degrees, grazing along the grating and carrying
|
|
124
|
+
* no light, so when d/λ is a whole number the highest OBSERVABLE order is one
|
|
125
|
+
* less. That edge is handled rather than rounded past.
|
|
126
|
+
*/
|
|
127
|
+
declare function maximumGratingOrder(wavelength: number, spacing: number): number;
|
|
128
|
+
/**
|
|
129
|
+
* Wavelength from a grating measurement: λ = d sin θ / n.
|
|
130
|
+
*
|
|
131
|
+
* The grating's advantage over two slits is that many slits make each maximum
|
|
132
|
+
* very sharp, so the angle can be read precisely, which is why spectrometers
|
|
133
|
+
* use gratings rather than double slits.
|
|
134
|
+
*/
|
|
135
|
+
declare function wavelengthFromGrating(n: number, angleDeg: number, spacing: number): number;
|
|
136
|
+
/**
|
|
137
|
+
* Malus's law: I = I₀·cos²θ, with θ between the analyser and the polarisation.
|
|
138
|
+
*
|
|
139
|
+
* Crossed polarisers pass nothing, and a third one inserted between them at 45
|
|
140
|
+
* degrees lets light through again, which is impossible to explain if
|
|
141
|
+
* polarisers are filters that merely remove things. They do not filter, they
|
|
142
|
+
* PROJECT, and cos² is the projection.
|
|
143
|
+
*/
|
|
144
|
+
declare function malusIntensity(incidentIntensity: number, analyserAngleDeg: number): number;
|
|
145
|
+
/**
|
|
146
|
+
* Intensity after unpolarised light passes one ideal polariser: exactly half.
|
|
147
|
+
*
|
|
148
|
+
* Half rather than cos² of anything, because unpolarised light carries every
|
|
149
|
+
* orientation equally and the average of cos² over all angles is a half. The
|
|
150
|
+
* first polariser is the one that loses half; the second loses by Malus.
|
|
151
|
+
*/
|
|
152
|
+
declare const unpolarisedThroughPolariser: (intensity: number) => number;
|
|
153
|
+
/**
|
|
154
|
+
* Intensity at a distance from a point source: I = P/(4πr²).
|
|
155
|
+
*
|
|
156
|
+
* The inverse square is geometry, not a property of light: the same power
|
|
157
|
+
* spread over a sphere whose area grows as r².
|
|
158
|
+
*/
|
|
159
|
+
declare function pointSourceIntensity(power: number, distance: number): number;
|
|
160
|
+
/**
|
|
161
|
+
* The Rayleigh criterion, radians: θ = 1.22·λ/D.
|
|
162
|
+
*
|
|
163
|
+
* Two point sources are just resolved when the first's diffraction maximum
|
|
164
|
+
* falls on the other's first minimum. The 1.22 is the first zero of a Bessel
|
|
165
|
+
* function, and it is there because the aperture is a CIRCLE; a slit gives
|
|
166
|
+
* exactly 1. This is the hard limit on every telescope and microscope, and the
|
|
167
|
+
* reason bigger mirrors see finer detail quite apart from gathering more light.
|
|
168
|
+
*/
|
|
169
|
+
declare function rayleighResolutionRad(wavelength: number, aperture: number): number;
|
|
170
|
+
//#endregion
|
|
171
|
+
export { brightFringePosition, centralMaximumHalfWidthDeg, centralMaximumWidth, darkFringePosition, doubleSlitPattern, fringeAngleDeg, fringeSpacing, gratingAngleDeg, gratingSpacing, malusIntensity, maximumGratingOrder, pointSourceIntensity, rayleighResolutionRad, singleSlitEnvelope, singleSlitMinimumDeg, twoSlitIntensity, unpolarisedThroughPolariser, wavelengthFromFringes, wavelengthFromGrating };
|