@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.
Files changed (458) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -1
  3. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  4. package/dist/assets/index.mjs +0 -1
  5. package/dist/atomic/aufbau.d.mts +144 -0
  6. package/dist/atomic/aufbau.mjs +384 -0
  7. package/dist/atomic/elements.d.mts +67 -0
  8. package/dist/atomic/elements.mjs +785 -0
  9. package/dist/atomic/emission.d.mts +112 -0
  10. package/dist/atomic/emission.mjs +179 -0
  11. package/dist/atomic/index.d.mts +8 -0
  12. package/dist/atomic/index.mjs +9 -0
  13. package/dist/atomic/periodic.d.mts +82 -0
  14. package/dist/atomic/periodic.mjs +231 -0
  15. package/dist/atomic/properties.d.mts +100 -0
  16. package/dist/atomic/properties.mjs +574 -0
  17. package/dist/atomic/shells.d.mts +137 -0
  18. package/dist/atomic/shells.mjs +170 -0
  19. package/dist/atomic/trends.d.mts +148 -0
  20. package/dist/atomic/trends.mjs +225 -0
  21. package/dist/builder/Palette.mjs +50 -89
  22. package/dist/builder/SceneBuilder.mjs +15 -73
  23. package/dist/chem/chromatography.d.mts +66 -0
  24. package/dist/chem/chromatography.mjs +63 -0
  25. package/dist/chem/complex.d.mts +114 -0
  26. package/dist/chem/complex.mjs +234 -0
  27. package/dist/chem/cycle.d.mts +75 -0
  28. package/dist/chem/cycle.mjs +145 -0
  29. package/dist/chem/equation.d.mts +86 -0
  30. package/dist/chem/equation.mjs +168 -0
  31. package/dist/chem/formula.d.mts +90 -0
  32. package/dist/chem/formula.mjs +201 -0
  33. package/dist/chem/functional-groups.d.mts +31 -0
  34. package/dist/chem/functional-groups.mjs +187 -0
  35. package/dist/chem/hazard.d.mts +94 -0
  36. package/dist/chem/hazard.mjs +329 -0
  37. package/dist/chem/index.d.mts +34 -33
  38. package/dist/chem/index.mjs +34 -28
  39. package/dist/chem/ionic.d.mts +98 -0
  40. package/dist/chem/ionic.mjs +156 -0
  41. package/dist/chem/layout.d.mts +46 -0
  42. package/dist/chem/layout.mjs +342 -0
  43. package/dist/chem/lewis.d.mts +79 -0
  44. package/dist/chem/lewis.mjs +163 -0
  45. package/dist/chem/molecular-orbital.d.mts +114 -0
  46. package/dist/chem/molecular-orbital.mjs +201 -0
  47. package/dist/chem/molecule.d.mts +154 -0
  48. package/dist/chem/molecule.mjs +282 -0
  49. package/dist/chem/nmr.d.mts +153 -0
  50. package/dist/chem/nmr.mjs +165 -0
  51. package/dist/chem/polymer.d.mts +65 -0
  52. package/dist/chem/polymer.mjs +179 -0
  53. package/dist/chem/redox.d.mts +138 -0
  54. package/dist/chem/redox.mjs +328 -0
  55. package/dist/chem/relations.d.mts +183 -0
  56. package/dist/chem/relations.mjs +299 -0
  57. package/dist/chem/skeleton.d.mts +51 -0
  58. package/dist/chem/skeleton.mjs +186 -0
  59. package/dist/chem/solution.d.mts +116 -0
  60. package/dist/chem/solution.mjs +186 -0
  61. package/dist/chem/species.d.mts +47 -0
  62. package/dist/chem/species.mjs +128 -0
  63. package/dist/chem/stereo.d.mts +108 -0
  64. package/dist/chem/stereo.mjs +286 -0
  65. package/dist/chem/stoichiometry.d.mts +95 -0
  66. package/dist/chem/stoichiometry.mjs +145 -0
  67. package/dist/chem/synthesis.d.mts +113 -0
  68. package/dist/chem/synthesis.mjs +281 -0
  69. package/dist/chem/vsepr.d.mts +80 -0
  70. package/dist/chem/vsepr.mjs +247 -0
  71. package/dist/circuit/ac.d.mts +163 -0
  72. package/dist/circuit/ac.mjs +452 -0
  73. package/dist/circuit/dc.d.mts +92 -0
  74. package/dist/circuit/dc.mjs +333 -0
  75. package/dist/circuit/index.d.mts +5 -92
  76. package/dist/circuit/index.mjs +5 -332
  77. package/dist/circuit/network.d.mts +99 -0
  78. package/dist/circuit/network.mjs +440 -0
  79. package/dist/circuit/topology.d.mts +102 -0
  80. package/dist/circuit/topology.mjs +143 -0
  81. package/dist/colour/absorption.d.mts +79 -0
  82. package/dist/colour/absorption.mjs +137 -0
  83. package/dist/colour/index.d.mts +6 -0
  84. package/dist/colour/index.mjs +7 -0
  85. package/dist/colour/name.d.mts +14 -0
  86. package/dist/colour/name.mjs +76 -0
  87. package/dist/colour/observer.d.mts +31 -0
  88. package/dist/colour/observer.mjs +46 -0
  89. package/dist/colour/spectrum.d.mts +61 -0
  90. package/dist/colour/spectrum.mjs +108 -0
  91. package/dist/colour/srgb.d.mts +49 -0
  92. package/dist/colour/srgb.mjs +108 -0
  93. package/dist/core/constants.d.mts +138 -0
  94. package/dist/core/constants.mjs +139 -0
  95. package/dist/core/index.d.mts +4 -1
  96. package/dist/core/index.mjs +4 -1
  97. package/dist/core/math.d.mts +26 -0
  98. package/dist/core/math.mjs +37 -0
  99. package/dist/core/vec3.d.mts +94 -0
  100. package/dist/core/vec3.mjs +123 -0
  101. package/dist/core/worked.d.mts +35 -0
  102. package/dist/core/worked.mjs +44 -0
  103. package/dist/electro/cell.d.mts +102 -0
  104. package/dist/electro/cell.mjs +170 -0
  105. package/dist/electro/conductivity.d.mts +157 -0
  106. package/dist/electro/conductivity.mjs +156 -0
  107. package/dist/electro/couples.d.mts +114 -0
  108. package/dist/electro/couples.mjs +334 -0
  109. package/dist/electro/electrolysis.d.mts +96 -0
  110. package/dist/electro/electrolysis.mjs +274 -0
  111. package/dist/electro/faraday.d.mts +150 -0
  112. package/dist/electro/faraday.mjs +118 -0
  113. package/dist/electro/index.d.mts +6 -0
  114. package/dist/electro/index.mjs +7 -0
  115. package/dist/finance/accounting/adjustments.d.mts +17 -0
  116. package/dist/finance/accounting/adjustments.mjs +202 -0
  117. package/dist/finance/accounting/analysis.d.mts +8 -0
  118. package/dist/finance/accounting/analysis.mjs +205 -0
  119. package/dist/finance/accounting/clubs.d.mts +21 -0
  120. package/dist/finance/accounting/clubs.mjs +217 -0
  121. package/dist/finance/accounting/company-statements.d.mts +7 -0
  122. package/dist/finance/accounting/company-statements.mjs +150 -0
  123. package/dist/finance/accounting/harness.d.mts +7 -0
  124. package/dist/finance/accounting/harness.mjs +45 -0
  125. package/dist/finance/accounting/index.d.mts +18 -0
  126. package/dist/finance/accounting/index.mjs +18 -0
  127. package/dist/finance/accounting/journalize.d.mts +16 -0
  128. package/dist/finance/accounting/journalize.mjs +128 -0
  129. package/dist/finance/accounting/manufacturing.d.mts +8 -0
  130. package/dist/finance/accounting/manufacturing.mjs +236 -0
  131. package/dist/finance/accounting/partnership.d.mts +7 -0
  132. package/dist/finance/accounting/partnership.mjs +152 -0
  133. package/dist/finance/accounting/period-case.d.mts +6 -0
  134. package/dist/finance/accounting/period-case.mjs +71 -0
  135. package/dist/finance/accounting/post.d.mts +9 -0
  136. package/dist/finance/accounting/post.mjs +84 -0
  137. package/dist/finance/accounting/precision.d.mts +9 -0
  138. package/dist/finance/accounting/precision.mjs +15 -0
  139. package/dist/finance/accounting/rules.d.mts +21 -0
  140. package/dist/finance/accounting/rules.mjs +37 -0
  141. package/dist/finance/accounting/solve.d.mts +28 -0
  142. package/dist/finance/accounting/solve.mjs +92 -0
  143. package/dist/finance/accounting/statements.d.mts +7 -0
  144. package/dist/finance/accounting/statements.mjs +142 -0
  145. package/dist/finance/accounting/types.d.mts +649 -0
  146. package/dist/finance/accounting/validate.d.mts +7 -0
  147. package/dist/finance/accounting/validate.mjs +67 -0
  148. package/dist/finance/accounting/verification.d.mts +24 -0
  149. package/dist/finance/accounting/verification.mjs +386 -0
  150. package/dist/finance/bizsim.d.mts +75 -0
  151. package/dist/finance/bizsim.mjs +296 -0
  152. package/dist/finance/index.d.mts +95 -0
  153. package/dist/finance/index.mjs +145 -0
  154. package/dist/finance/investment-math.d.mts +7 -0
  155. package/dist/finance/investment-math.mjs +18 -0
  156. package/dist/finance/management-accounting/budgeting.d.mts +7 -0
  157. package/dist/finance/management-accounting/budgeting.mjs +189 -0
  158. package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
  159. package/dist/finance/management-accounting/cash-budget.mjs +154 -0
  160. package/dist/finance/management-accounting/costing.d.mts +8 -0
  161. package/dist/finance/management-accounting/costing.mjs +175 -0
  162. package/dist/finance/management-accounting/decisions.d.mts +8 -0
  163. package/dist/finance/management-accounting/decisions.mjs +164 -0
  164. package/dist/finance/management-accounting/index.d.mts +13 -0
  165. package/dist/finance/management-accounting/index.mjs +13 -0
  166. package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
  167. package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
  168. package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
  169. package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
  170. package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
  171. package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
  172. package/dist/finance/management-accounting/management-case.d.mts +8 -0
  173. package/dist/finance/management-accounting/management-case.mjs +91 -0
  174. package/dist/finance/management-accounting/master-budget.d.mts +7 -0
  175. package/dist/finance/management-accounting/master-budget.mjs +137 -0
  176. package/dist/finance/management-accounting/production-costing.d.mts +8 -0
  177. package/dist/finance/management-accounting/production-costing.mjs +214 -0
  178. package/dist/finance/management-accounting/types.d.mts +644 -0
  179. package/dist/finance/management-accounting/variances.d.mts +7 -0
  180. package/dist/finance/management-accounting/variances.mjs +150 -0
  181. package/dist/index.d.mts +9 -8
  182. package/dist/index.mjs +5 -5
  183. package/dist/interaction/MovableDot.mjs +19 -0
  184. package/dist/interaction/useDraggable.mjs +24 -4
  185. package/dist/math/analysis.d.mts +61 -0
  186. package/dist/math/analysis.mjs +187 -0
  187. package/dist/math/answer-check.d.mts +50 -0
  188. package/dist/math/answer-check.mjs +106 -0
  189. package/dist/math/calculus.d.mts +17 -1
  190. package/dist/math/calculus.mjs +365 -2
  191. package/dist/math/complex.d.mts +93 -0
  192. package/dist/math/complex.mjs +239 -0
  193. package/dist/math/expr.d.mts +23 -0
  194. package/dist/math/expr.mjs +36 -0
  195. package/dist/math/index.d.mts +9 -23
  196. package/dist/math/index.mjs +9 -38
  197. package/dist/math/latex.mjs +10 -1
  198. package/dist/math/parse.mjs +1 -1
  199. package/dist/math/poly.d.mts +55 -0
  200. package/dist/math/poly.mjs +273 -0
  201. package/dist/math/rearrange.d.mts +14 -0
  202. package/dist/math/rearrange.mjs +125 -0
  203. package/dist/math/solve.d.mts +21 -0
  204. package/dist/math/solve.mjs +75 -0
  205. package/dist/networking/addressing.d.mts +26 -0
  206. package/dist/networking/addressing.mjs +33 -0
  207. package/dist/networking/cloud/access.d.mts +36 -0
  208. package/dist/networking/cloud/access.mjs +95 -0
  209. package/dist/networking/cloud/containers.d.mts +43 -0
  210. package/dist/networking/cloud/containers.mjs +54 -0
  211. package/dist/networking/cloud/edge.d.mts +17 -0
  212. package/dist/networking/cloud/edge.mjs +31 -0
  213. package/dist/networking/cloud/failure-domains.d.mts +19 -0
  214. package/dist/networking/cloud/failure-domains.mjs +22 -0
  215. package/dist/networking/cloud/geo-routing.d.mts +22 -0
  216. package/dist/networking/cloud/geo-routing.mjs +64 -0
  217. package/dist/networking/cloud/index.d.mts +18 -0
  218. package/dist/networking/cloud/index.mjs +19 -0
  219. package/dist/networking/cloud/inference-reliability.d.mts +30 -0
  220. package/dist/networking/cloud/inference-reliability.mjs +76 -0
  221. package/dist/networking/cloud/inference.d.mts +118 -0
  222. package/dist/networking/cloud/inference.mjs +179 -0
  223. package/dist/networking/cloud/infrastructure.d.mts +45 -0
  224. package/dist/networking/cloud/infrastructure.mjs +96 -0
  225. package/dist/networking/cloud/observability.d.mts +24 -0
  226. package/dist/networking/cloud/observability.mjs +34 -0
  227. package/dist/networking/cloud/orchestration.d.mts +32 -0
  228. package/dist/networking/cloud/orchestration.mjs +38 -0
  229. package/dist/networking/cloud/recovery.d.mts +21 -0
  230. package/dist/networking/cloud/recovery.mjs +27 -0
  231. package/dist/networking/cloud/releases.d.mts +42 -0
  232. package/dist/networking/cloud/releases.mjs +135 -0
  233. package/dist/networking/cloud/scaling.d.mts +25 -0
  234. package/dist/networking/cloud/scaling.mjs +65 -0
  235. package/dist/networking/cloud/secrets.d.mts +39 -0
  236. package/dist/networking/cloud/secrets.mjs +68 -0
  237. package/dist/networking/cloud/server-deployment.d.mts +29 -0
  238. package/dist/networking/cloud/server-deployment.mjs +72 -0
  239. package/dist/networking/cloud/storage.d.mts +16 -0
  240. package/dist/networking/cloud/storage.mjs +58 -0
  241. package/dist/networking/cloud/vpc.d.mts +18 -0
  242. package/dist/networking/cloud/vpc.mjs +100 -0
  243. package/dist/networking/delivery.d.mts +34 -0
  244. package/dist/networking/delivery.mjs +52 -0
  245. package/dist/networking/index.d.mts +47 -0
  246. package/dist/networking/index.mjs +47 -0
  247. package/dist/networking/ipv6.d.mts +28 -0
  248. package/dist/networking/ipv6.mjs +17 -0
  249. package/dist/networking/journeys.d.mts +83 -0
  250. package/dist/networking/journeys.mjs +161 -0
  251. package/dist/networking/models/airtime.d.mts +87 -0
  252. package/dist/networking/models/airtime.mjs +130 -0
  253. package/dist/networking/models/cellular.d.mts +157 -0
  254. package/dist/networking/models/cellular.mjs +252 -0
  255. package/dist/networking/models/encapsulation.d.mts +98 -0
  256. package/dist/networking/models/encapsulation.mjs +132 -0
  257. package/dist/networking/models/handover.d.mts +116 -0
  258. package/dist/networking/models/handover.mjs +209 -0
  259. package/dist/networking/models/handshake.d.mts +90 -0
  260. package/dist/networking/models/handshake.mjs +122 -0
  261. package/dist/networking/models/index.d.mts +14 -0
  262. package/dist/networking/models/index.mjs +15 -0
  263. package/dist/networking/models/media.d.mts +82 -0
  264. package/dist/networking/models/media.mjs +188 -0
  265. package/dist/networking/models/satellite.d.mts +86 -0
  266. package/dist/networking/models/satellite.mjs +121 -0
  267. package/dist/networking/models/spectrum.d.mts +83 -0
  268. package/dist/networking/models/spectrum.mjs +235 -0
  269. package/dist/networking/models/switch.d.mts +80 -0
  270. package/dist/networking/models/switch.mjs +155 -0
  271. package/dist/networking/models/vlan.d.mts +62 -0
  272. package/dist/networking/models/vlan.mjs +100 -0
  273. package/dist/networking/models/vpn.d.mts +66 -0
  274. package/dist/networking/models/vpn.mjs +125 -0
  275. package/dist/networking/models/wifi-privacy.d.mts +82 -0
  276. package/dist/networking/models/wifi-privacy.mjs +130 -0
  277. package/dist/networking/models/wifi.d.mts +240 -0
  278. package/dist/networking/models/wifi.mjs +562 -0
  279. package/dist/networking/nat-traversal.d.mts +24 -0
  280. package/dist/networking/nat-traversal.mjs +38 -0
  281. package/dist/networking/protocols.d.mts +17 -0
  282. package/dist/networking/protocols.mjs +57 -0
  283. package/dist/networking/queue.d.mts +12 -0
  284. package/dist/networking/queue.mjs +18 -0
  285. package/dist/networking/route-learning.d.mts +23 -0
  286. package/dist/networking/route-learning.mjs +43 -0
  287. package/dist/networking/routing.d.mts +11 -0
  288. package/dist/networking/routing.mjs +25 -0
  289. package/dist/networking/signals.d.mts +26 -0
  290. package/dist/networking/signals.mjs +35 -0
  291. package/dist/networking/subnet.d.mts +49 -0
  292. package/dist/networking/subnet.mjs +89 -0
  293. package/dist/networking/tcp-reliability.d.mts +24 -0
  294. package/dist/networking/tcp-reliability.mjs +38 -0
  295. package/dist/networking/topology/contract.d.mts +123 -0
  296. package/dist/networking/topology/index.d.mts +4 -0
  297. package/dist/networking/topology/index.mjs +4 -0
  298. package/dist/networking/topology/presets.d.mts +7 -0
  299. package/dist/networking/topology/presets.mjs +302 -0
  300. package/dist/networking/topology/simulation.d.mts +8 -0
  301. package/dist/networking/topology/simulation.mjs +179 -0
  302. package/dist/networking/wireless.d.mts +11 -0
  303. package/dist/networking/wireless.mjs +17 -0
  304. package/dist/optics/imaging.d.mts +218 -0
  305. package/dist/optics/imaging.mjs +276 -0
  306. package/dist/optics/index.d.mts +7 -0
  307. package/dist/optics/index.mjs +8 -0
  308. package/dist/optics/laws.d.mts +70 -0
  309. package/dist/optics/laws.mjs +195 -0
  310. package/dist/optics/prism.d.mts +148 -0
  311. package/dist/optics/prism.mjs +197 -0
  312. package/dist/optics/refraction.d.mts +201 -0
  313. package/dist/optics/refraction.mjs +270 -0
  314. package/dist/optics/wave-optics.d.mts +171 -0
  315. package/dist/optics/wave-optics.mjs +259 -0
  316. package/dist/physics/ac/index.d.mts +183 -0
  317. package/dist/physics/ac/index.mjs +203 -0
  318. package/dist/physics/dynamics/forces.d.mts +98 -0
  319. package/dist/physics/dynamics/forces.mjs +153 -0
  320. package/dist/physics/dynamics/friction.d.mts +76 -0
  321. package/dist/physics/dynamics/friction.mjs +119 -0
  322. package/dist/physics/dynamics/system.d.mts +68 -0
  323. package/dist/physics/dynamics/system.mjs +125 -0
  324. package/dist/physics/electrostatics/index.d.mts +169 -0
  325. package/dist/physics/electrostatics/index.mjs +249 -0
  326. package/dist/physics/energy/centre-of-mass.d.mts +115 -0
  327. package/dist/physics/energy/centre-of-mass.mjs +180 -0
  328. package/dist/physics/energy/conservation.d.mts +81 -0
  329. package/dist/physics/energy/conservation.mjs +129 -0
  330. package/dist/physics/energy/power.d.mts +90 -0
  331. package/dist/physics/energy/power.mjs +167 -0
  332. package/dist/physics/energy/spring.d.mts +73 -0
  333. package/dist/physics/energy/spring.mjs +129 -0
  334. package/dist/physics/energy/store.d.mts +63 -0
  335. package/dist/physics/energy/store.mjs +108 -0
  336. package/dist/physics/energy/theorem.d.mts +65 -0
  337. package/dist/physics/energy/theorem.mjs +113 -0
  338. package/dist/physics/energy/work.d.mts +114 -0
  339. package/dist/physics/energy/work.mjs +219 -0
  340. package/dist/physics/gravitation/body.d.mts +85 -0
  341. package/dist/physics/gravitation/body.mjs +168 -0
  342. package/dist/physics/gravitation/kepler.d.mts +127 -0
  343. package/dist/physics/gravitation/kepler.mjs +216 -0
  344. package/dist/physics/gravitation/law.d.mts +117 -0
  345. package/dist/physics/gravitation/law.mjs +175 -0
  346. package/dist/physics/gravitation/orbit.d.mts +119 -0
  347. package/dist/physics/gravitation/orbit.mjs +202 -0
  348. package/dist/physics/gravitation/potential.d.mts +114 -0
  349. package/dist/physics/gravitation/potential.mjs +202 -0
  350. package/dist/physics/gravitation/variation.d.mts +97 -0
  351. package/dist/physics/gravitation/variation.mjs +175 -0
  352. package/dist/physics/index.d.mts +35 -0
  353. package/dist/physics/index.mjs +36 -0
  354. package/dist/physics/integral-sweep.d.mts +63 -0
  355. package/dist/physics/integral-sweep.mjs +126 -0
  356. package/dist/physics/kinematics/equations.d.mts +47 -0
  357. package/dist/physics/kinematics/equations.mjs +126 -0
  358. package/dist/physics/kinematics/free-fall.d.mts +53 -0
  359. package/dist/physics/kinematics/free-fall.mjs +71 -0
  360. package/dist/physics/kinematics/given.d.mts +16 -0
  361. package/dist/physics/kinematics/given.mjs +55 -0
  362. package/dist/physics/kinematics/roots.d.mts +41 -0
  363. package/dist/physics/kinematics/roots.mjs +72 -0
  364. package/dist/physics/kinematics/solve.d.mts +52 -0
  365. package/dist/physics/kinematics/solve.mjs +172 -0
  366. package/dist/physics/magnetism/biot-savart.d.mts +161 -0
  367. package/dist/physics/magnetism/biot-savart.mjs +353 -0
  368. package/dist/physics/magnetism/flux.d.mts +94 -0
  369. package/dist/physics/magnetism/flux.mjs +313 -0
  370. package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
  371. package/dist/physics/magnetism/geomagnetism.mjs +184 -0
  372. package/dist/physics/magnetism/index.d.mts +12 -0
  373. package/dist/physics/magnetism/index.mjs +74 -0
  374. package/dist/physics/magnetism/lorentz.d.mts +28 -0
  375. package/dist/physics/magnetism/lorentz.mjs +88 -0
  376. package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
  377. package/dist/physics/magnetism/magnetic-force.mjs +169 -0
  378. package/dist/physics/momentum/collide.d.mts +77 -0
  379. package/dist/physics/momentum/collide.mjs +115 -0
  380. package/dist/physics/momentum/impulse.d.mts +89 -0
  381. package/dist/physics/momentum/impulse.mjs +159 -0
  382. package/dist/physics/momentum/planar.d.mts +60 -0
  383. package/dist/physics/momentum/planar.mjs +110 -0
  384. package/dist/physics/projectile.d.mts +107 -0
  385. package/dist/physics/projectile.mjs +185 -0
  386. package/dist/physics/rotation/angular.d.mts +85 -0
  387. package/dist/physics/rotation/angular.mjs +130 -0
  388. package/dist/physics/rotation/circular.d.mts +79 -0
  389. package/dist/physics/rotation/circular.mjs +131 -0
  390. package/dist/physics/rotation/inertia.d.mts +164 -0
  391. package/dist/physics/rotation/inertia.mjs +332 -0
  392. package/dist/physics/rotation/torque.d.mts +65 -0
  393. package/dist/physics/rotation/torque.mjs +134 -0
  394. package/dist/physics/vectors.d.mts +64 -0
  395. package/dist/physics/vectors.mjs +114 -0
  396. package/dist/primitives/Dot.d.mts +2 -15
  397. package/dist/primitives/Dot.mjs +6 -4
  398. package/dist/primitives/Grid.d.mts +33 -17
  399. package/dist/primitives/Grid.mjs +89 -17
  400. package/dist/primitives/Label.d.mts +1 -14
  401. package/dist/primitives/Label.mjs +3 -2
  402. package/dist/primitives/Lines.d.mts +4 -32
  403. package/dist/primitives/Lines.mjs +10 -8
  404. package/dist/primitives/Shapes.d.mts +5 -43
  405. package/dist/primitives/Shapes.mjs +12 -10
  406. package/dist/primitives/index.d.mts +2 -2
  407. package/dist/primitives/index.mjs +2 -2
  408. package/dist/primitives/props.mjs +31 -0
  409. package/dist/quantity/index.d.mts +119 -0
  410. package/dist/quantity/index.mjs +417 -0
  411. package/dist/relation/derive.d.mts +74 -0
  412. package/dist/relation/derive.mjs +73 -0
  413. package/dist/relation/index.d.mts +56 -0
  414. package/dist/relation/index.mjs +234 -0
  415. package/dist/scene/Scene.d.mts +6 -1
  416. package/dist/scene/Scene.mjs +15 -40
  417. package/dist/scene/evaluators.mjs +1 -1
  418. package/dist/sim/thermal.mjs +45 -20
  419. package/dist/thermo/calorimetry.d.mts +207 -0
  420. package/dist/thermo/calorimetry.mjs +345 -0
  421. package/dist/thermo/cycles.d.mts +142 -0
  422. package/dist/thermo/cycles.mjs +256 -0
  423. package/dist/thermo/entropy.d.mts +87 -0
  424. package/dist/thermo/entropy.mjs +140 -0
  425. package/dist/thermo/expansion.d.mts +130 -0
  426. package/dist/thermo/expansion.mjs +178 -0
  427. package/dist/thermo/gas.d.mts +197 -0
  428. package/dist/thermo/gas.mjs +279 -0
  429. package/dist/thermo/heat-transfer.d.mts +164 -0
  430. package/dist/thermo/heat-transfer.mjs +217 -0
  431. package/dist/thermo/index.d.mts +9 -82
  432. package/dist/thermo/index.mjs +9 -132
  433. package/dist/thermo/processes.d.mts +95 -0
  434. package/dist/thermo/processes.mjs +154 -0
  435. package/dist/thermo/temperature.d.mts +174 -0
  436. package/dist/thermo/temperature.mjs +236 -0
  437. package/dist/view/Stage.mjs +4 -11
  438. package/dist/waves/damping.d.mts +224 -0
  439. package/dist/waves/damping.mjs +317 -0
  440. package/dist/waves/doppler.d.mts +72 -0
  441. package/dist/waves/doppler.mjs +125 -0
  442. package/dist/waves/index.d.mts +10 -0
  443. package/dist/waves/index.mjs +10 -0
  444. package/dist/waves/pendulum.d.mts +130 -0
  445. package/dist/waves/pendulum.mjs +211 -0
  446. package/dist/waves/pitch.d.mts +125 -0
  447. package/dist/waves/pitch.mjs +158 -0
  448. package/dist/waves/shm.d.mts +170 -0
  449. package/dist/waves/shm.mjs +279 -0
  450. package/dist/waves/springs.d.mts +103 -0
  451. package/dist/waves/springs.mjs +176 -0
  452. package/dist/waves/superposition.d.mts +124 -0
  453. package/dist/waves/superposition.mjs +196 -0
  454. package/dist/waves/wave.d.mts +154 -0
  455. package/dist/waves/wave.mjs +178 -0
  456. package/package.json +103 -23
  457. package/styles.css +125 -8
  458. package/dist/assets/kit/index.mjs +0 -4
@@ -0,0 +1,103 @@
1
+ import { Worked } from "../core/worked.mjs";
2
+
3
+ //#region src/waves/springs.d.ts
4
+ /**
5
+ * Hooke's law: the force a spring exerts at a given extension, newtons.
6
+ *
7
+ * SIGNED, and the sign is the point: stretch a spring in the positive
8
+ * direction and it pulls back in the negative one. Returning |kx| would lose
9
+ * exactly the fact that makes the motion periodic.
10
+ *
11
+ * Valid up to the limit of proportionality. Past that a real spring keeps
12
+ * stretching for less force and eventually does not come back, which is
13
+ * `@classytic/stage/physics`'s stress-strain territory rather than this one.
14
+ */
15
+ declare const springForce: (stiffness: number, extension: number) => number;
16
+ /** The extension a given force produces, metres: x = F/k. Takes the magnitude. */
17
+ declare const springExtension: (stiffness: number, force: number) => number;
18
+ /**
19
+ * The stiffness of a spring, from how far a hanging mass stretches it:
20
+ * k = mg/e.
21
+ *
22
+ * This is how k is actually MEASURED, and it is the first line of most spring
23
+ * questions: you are told a 200 g mass stretches the spring by 10 cm, and the
24
+ * 19.6 N/m you need is not given to you.
25
+ *
26
+ * `extension` is the extra length caused by hanging the mass, not the length of
27
+ * the spring.
28
+ */
29
+ declare const stiffnessFromExtension: (mass: number, extension: number, gravity?: number) => number;
30
+ /** How far a hanging mass stretches a spring, metres: e = mg/k. The inverse of the above. */
31
+ declare const staticExtension: (mass: number, stiffness: number, gravity?: number) => number;
32
+ /**
33
+ * The period of a hanging mass, from the extension it causes: T = 2π√(e/g).
34
+ *
35
+ * The MASS HAS CANCELLED, and that is worth stopping on. Substituting k = mg/e
36
+ * into T = 2π√(m/k) removes m entirely, so a spring stretched 10 cm by whatever
37
+ * is hanging on it has a period of 0.63 s whatever that thing weighs. Hang
38
+ * twice the mass: it stretches twice as far, and the period is the same.
39
+ *
40
+ * It is the same cancellation that makes a pendulum period massless, arrived at
41
+ * from the other direction, and it turns a two-step question into one line.
42
+ */
43
+ declare const springPeriodFromExtension: (extension: number, gravity?: number) => number;
44
+ /**
45
+ * Stiffness from the oscillation it produces: k = mω².
46
+ *
47
+ * The bridge back from `shm` to this module, and the reason a differential
48
+ * equation like `4·d²x/dt² + 100x = 0` can be read off directly: it is
49
+ * m·x'' + k·x = 0 with m = 4 and k = 100, so ω = √(k/m) = 5 rad/s. Nothing has
50
+ * to be solved.
51
+ */
52
+ declare const stiffnessFromAngularFrequency: (mass: number, omega: number) => number;
53
+ /**
54
+ * Springs end to end: 1/k = 1/k₁ + 1/k₂ + …
55
+ *
56
+ * The combination is SOFTER than either spring alone, which is the result that
57
+ * surprises people. Both springs carry the whole load, and both stretch, so the
58
+ * extensions add while the force does not: more give for the same pull.
59
+ *
60
+ * Note this is the resistor rule upside down, because stiffness is the
61
+ * spring's opposition to stretching, so it plays the part of conductance.
62
+ * Anyone who has met resistors first tends to import the wrong one of the two
63
+ * formulas, which is precisely why both are named here rather than left to be
64
+ * remembered.
65
+ */
66
+ declare function stiffnessInSeries(...stiffnesses: number[]): number;
67
+ /**
68
+ * Springs side by side: k = k₁ + k₂ + …
69
+ *
70
+ * STIFFER than either alone. They share the load and stretch together, so the
71
+ * forces add at a common extension. A car sits on four of these.
72
+ */
73
+ declare function stiffnessInParallel(...stiffnesses: number[]): number;
74
+ /**
75
+ * The stiffness of a PIECE of a spring, given what fraction of the original
76
+ * length it is: k' = k / fraction.
77
+ *
78
+ * Stiffness goes as 1/length. Half a spring is twice as stiff, a third of a
79
+ * spring three times as stiff. The reason is that every coil stretches by the
80
+ * same amount under a given load, so fewer coils give less total extension for
81
+ * the same force.
82
+ *
83
+ * The check that this is right and not backwards: the pieces put back in series
84
+ * must return the original spring, and `springs.test.ts` asserts exactly that.
85
+ */
86
+ declare function cutSpringStiffness(stiffness: number, lengthFraction: number): number;
87
+ /**
88
+ * Cut a spring into pieces in a given ratio, returning each piece's stiffness.
89
+ *
90
+ * `splitSpringStiffness(60, [1, 2])` cuts a 60 N/m spring in the ratio 1:2 and
91
+ * gives [180, 90]: the short piece is the stiff one. The ratio is taken as
92
+ * lengths, and needs no normalising.
93
+ */
94
+ declare function splitSpringStiffness(stiffness: number, ratio: readonly number[]): number[];
95
+ /**
96
+ * The stiffness question worked: measure the extension, get k, get the period.
97
+ *
98
+ * Both routes to the period are shown, because they must agree and a learner
99
+ * who has only ever seen T = 2π√(m/k) does not expect the mass to drop out.
100
+ */
101
+ declare function stiffnessFromExtensionSteps(mass: number, extension: number, gravity?: number, sf?: number): Worked;
102
+ //#endregion
103
+ export { cutSpringStiffness, splitSpringStiffness, springExtension, springForce, springPeriodFromExtension, staticExtension, stiffnessFromAngularFrequency, stiffnessFromExtension, stiffnessFromExtensionSteps, stiffnessInParallel, stiffnessInSeries };
@@ -0,0 +1,176 @@
1
+ import { calc, texSigFigs } from "../core/worked.mjs";
2
+ import { G_EARTH } from "../physics/kinematics/free-fall.mjs";
3
+
4
+ //#region src/waves/springs.ts
5
+ /**
6
+ * Real springs: stiffness, and where a number for it comes from.
7
+ *
8
+ * ## Why this is separate from `shm`
9
+ *
10
+ * `shm` takes ω as given and describes the motion. This module is about
11
+ * everything that happens BEFORE that: a spring arrives as a coil with a
12
+ * length, and a question gives you a hanging mass, or two springs bolted
13
+ * together, or a spring that has been cut in half. Each of those is an
14
+ * arithmetic step that produces the k which `shm` then uses.
15
+ *
16
+ * Keeping them apart matters because the mistakes live here. A learner who can
17
+ * quote T = 2π√(m/k) still loses the mark by adding two stiffnesses that were
18
+ * in series.
19
+ *
20
+ * ## The one relation everything else follows from
21
+ *
22
+ * F = −kx
23
+ *
24
+ * The minus sign is the physics: the force points BACK towards the natural
25
+ * length, which is what makes the motion oscillate rather than run away. Drop
26
+ * it and you have described a spring that throws things.
27
+ *
28
+ * ## Stiffness is not a property of the material
29
+ *
30
+ * It is a property of the material AND the geometry. Half a spring is twice as
31
+ * stiff, because each coil now carries the same force over half as much give.
32
+ * That is `cutSpringStiffness`, and it is the step that makes the classic
33
+ * "a spring is cut in the ratio 1:2" question tractable rather than magic.
34
+ *
35
+ * ## Units
36
+ *
37
+ * SI. Stiffness in newtons per metre, extension in metres, mass in kilograms,
38
+ * force in newtons.
39
+ */
40
+ const finite = (value, what) => {
41
+ if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
42
+ return value;
43
+ };
44
+ const positive = (value, what) => {
45
+ if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${what} must be positive.`);
46
+ return value;
47
+ };
48
+ const everyPositive = (values, what) => {
49
+ if (values.length === 0) throw new RangeError(`${what} needs at least one spring.`);
50
+ for (const value of values) positive(value, what);
51
+ return values;
52
+ };
53
+ /**
54
+ * Hooke's law: the force a spring exerts at a given extension, newtons.
55
+ *
56
+ * SIGNED, and the sign is the point: stretch a spring in the positive
57
+ * direction and it pulls back in the negative one. Returning |kx| would lose
58
+ * exactly the fact that makes the motion periodic.
59
+ *
60
+ * Valid up to the limit of proportionality. Past that a real spring keeps
61
+ * stretching for less force and eventually does not come back, which is
62
+ * `@classytic/stage/physics`'s stress-strain territory rather than this one.
63
+ */
64
+ const springForce = (stiffness, extension) => -positive(stiffness, "A spring stiffness") * finite(extension, "An extension");
65
+ /** The extension a given force produces, metres: x = F/k. Takes the magnitude. */
66
+ const springExtension = (stiffness, force) => Math.abs(finite(force, "A force")) / positive(stiffness, "A spring stiffness");
67
+ /**
68
+ * The stiffness of a spring, from how far a hanging mass stretches it:
69
+ * k = mg/e.
70
+ *
71
+ * This is how k is actually MEASURED, and it is the first line of most spring
72
+ * questions: you are told a 200 g mass stretches the spring by 10 cm, and the
73
+ * 19.6 N/m you need is not given to you.
74
+ *
75
+ * `extension` is the extra length caused by hanging the mass, not the length of
76
+ * the spring.
77
+ */
78
+ const stiffnessFromExtension = (mass, extension, gravity = G_EARTH) => positive(mass, "A mass") * positive(gravity, "A gravitational field strength") / positive(extension, "An extension");
79
+ /** How far a hanging mass stretches a spring, metres: e = mg/k. The inverse of the above. */
80
+ const staticExtension = (mass, stiffness, gravity = G_EARTH) => positive(mass, "A mass") * positive(gravity, "A gravitational field strength") / positive(stiffness, "A spring stiffness");
81
+ /**
82
+ * The period of a hanging mass, from the extension it causes: T = 2π√(e/g).
83
+ *
84
+ * The MASS HAS CANCELLED, and that is worth stopping on. Substituting k = mg/e
85
+ * into T = 2π√(m/k) removes m entirely, so a spring stretched 10 cm by whatever
86
+ * is hanging on it has a period of 0.63 s whatever that thing weighs. Hang
87
+ * twice the mass: it stretches twice as far, and the period is the same.
88
+ *
89
+ * It is the same cancellation that makes a pendulum period massless, arrived at
90
+ * from the other direction, and it turns a two-step question into one line.
91
+ */
92
+ const springPeriodFromExtension = (extension, gravity = G_EARTH) => 2 * Math.PI * Math.sqrt(positive(extension, "An extension") / positive(gravity, "A gravitational field strength"));
93
+ /**
94
+ * Stiffness from the oscillation it produces: k = mω².
95
+ *
96
+ * The bridge back from `shm` to this module, and the reason a differential
97
+ * equation like `4·d²x/dt² + 100x = 0` can be read off directly: it is
98
+ * m·x'' + k·x = 0 with m = 4 and k = 100, so ω = √(k/m) = 5 rad/s. Nothing has
99
+ * to be solved.
100
+ */
101
+ const stiffnessFromAngularFrequency = (mass, omega) => positive(mass, "A mass") * positive(omega, "An angular frequency") ** 2;
102
+ /**
103
+ * Springs end to end: 1/k = 1/k₁ + 1/k₂ + …
104
+ *
105
+ * The combination is SOFTER than either spring alone, which is the result that
106
+ * surprises people. Both springs carry the whole load, and both stretch, so the
107
+ * extensions add while the force does not: more give for the same pull.
108
+ *
109
+ * Note this is the resistor rule upside down, because stiffness is the
110
+ * spring's opposition to stretching, so it plays the part of conductance.
111
+ * Anyone who has met resistors first tends to import the wrong one of the two
112
+ * formulas, which is precisely why both are named here rather than left to be
113
+ * remembered.
114
+ */
115
+ function stiffnessInSeries(...stiffnesses) {
116
+ everyPositive(stiffnesses, "A spring stiffness");
117
+ return 1 / stiffnesses.reduce((sum, k) => sum + 1 / k, 0);
118
+ }
119
+ /**
120
+ * Springs side by side: k = k₁ + k₂ + …
121
+ *
122
+ * STIFFER than either alone. They share the load and stretch together, so the
123
+ * forces add at a common extension. A car sits on four of these.
124
+ */
125
+ function stiffnessInParallel(...stiffnesses) {
126
+ everyPositive(stiffnesses, "A spring stiffness");
127
+ return stiffnesses.reduce((sum, k) => sum + k, 0);
128
+ }
129
+ /**
130
+ * The stiffness of a PIECE of a spring, given what fraction of the original
131
+ * length it is: k' = k / fraction.
132
+ *
133
+ * Stiffness goes as 1/length. Half a spring is twice as stiff, a third of a
134
+ * spring three times as stiff. The reason is that every coil stretches by the
135
+ * same amount under a given load, so fewer coils give less total extension for
136
+ * the same force.
137
+ *
138
+ * The check that this is right and not backwards: the pieces put back in series
139
+ * must return the original spring, and `springs.test.ts` asserts exactly that.
140
+ */
141
+ function cutSpringStiffness(stiffness, lengthFraction) {
142
+ const k = positive(stiffness, "A spring stiffness");
143
+ const fraction = positive(lengthFraction, "A length fraction");
144
+ if (fraction > 1) throw new RangeError(`A piece cut from a spring cannot be ${fraction} of its length: a fraction is at most 1.`);
145
+ return k / fraction;
146
+ }
147
+ /**
148
+ * Cut a spring into pieces in a given ratio, returning each piece's stiffness.
149
+ *
150
+ * `splitSpringStiffness(60, [1, 2])` cuts a 60 N/m spring in the ratio 1:2 and
151
+ * gives [180, 90]: the short piece is the stiff one. The ratio is taken as
152
+ * lengths, and needs no normalising.
153
+ */
154
+ function splitSpringStiffness(stiffness, ratio) {
155
+ const k = positive(stiffness, "A spring stiffness");
156
+ everyPositive(ratio, "A ratio part");
157
+ const total = ratio.reduce((sum, part) => sum + part, 0);
158
+ return ratio.map((part) => cutSpringStiffness(k, part / total));
159
+ }
160
+ /**
161
+ * The stiffness question worked: measure the extension, get k, get the period.
162
+ *
163
+ * Both routes to the period are shown, because they must agree and a learner
164
+ * who has only ever seen T = 2π√(m/k) does not expect the mass to drop out.
165
+ */
166
+ function stiffnessFromExtensionSteps(mass, extension, gravity = G_EARTH, sf = 3) {
167
+ const m = positive(mass, "A mass");
168
+ const e = positive(extension, "An extension");
169
+ const g = positive(gravity, "A gravitational field strength");
170
+ const k = stiffnessFromExtension(m, e, g);
171
+ const period = 2 * Math.PI * Math.sqrt(m / k);
172
+ return calc().step("kx = mg", "at rest the spring force balances the weight, so the extension measures k").step(`k = \\frac{mg}{e} = \\frac{${texSigFigs(m, sf)} \\times ${texSigFigs(g, sf)}}{${texSigFigs(e, sf)}} = ${texSigFigs(k, sf)}\\ \\mathrm{N\\,m^{-1}}`).step(`T = 2\\pi\\sqrt{\\frac{m}{k}} = ${texSigFigs(period, sf)}\\ \\mathrm{s}`, "the usual route, which needs the k we just found").step(`T = 2\\pi\\sqrt{\\frac{e}{g}} = ${texSigFigs(springPeriodFromExtension(e, g), sf)}\\ \\mathrm{s}`, "substituting k = mg/e cancels the mass entirely: the extension alone fixes the period").done(k);
173
+ }
174
+
175
+ //#endregion
176
+ export { cutSpringStiffness, splitSpringStiffness, springExtension, springForce, springPeriodFromExtension, staticExtension, stiffnessFromAngularFrequency, stiffnessFromExtension, stiffnessFromExtensionSteps, stiffnessInParallel, stiffnessInSeries };
@@ -0,0 +1,124 @@
1
+ import { Wave } from "./wave.mjs";
2
+
3
+ //#region src/waves/superposition.d.ts
4
+ /** The sum of several waves at a point and time, by the principle of superposition. */
5
+ declare function superpose(waves: readonly Wave[], x: number, t: number): number;
6
+ /**
7
+ * Displacement of a standing wave: y = 2A·sin(kx)·cos(ωt).
8
+ *
9
+ * `amplitude` is that of EACH travelling wave, so the antinodes swing to twice
10
+ * it. That doubling is the part worth keeping explicit: a standing wave is
11
+ * built from two waves and its antinodes are louder than either.
12
+ */
13
+ declare function standingWave(amplitude: number, wavelength: number, frequency: number, x: number, t: number): number;
14
+ /**
15
+ * How a string or pipe can vibrate.
16
+ *
17
+ * `both-ends-fixed` is a string, and also a pipe closed at both ends.
18
+ * `both-ends-open` is an open pipe: antinodes at each end, same wavelengths as
19
+ * the string. `one-end-open` is a closed pipe, and it is the odd one out.
20
+ */
21
+ type BoundaryKind = 'both-ends-fixed' | 'both-ends-open' | 'one-end-open';
22
+ /**
23
+ * The wavelength of harmonic n, metres.
24
+ *
25
+ * A string fixed at both ends fits a whole number of HALF wavelengths, so
26
+ * λ = 2L/n. A pipe closed at one end has a node at the closed end and an
27
+ * antinode at the open one, so it fits an ODD number of QUARTER wavelengths:
28
+ * λ = 4L/n with n odd. That is why a closed pipe sounds an octave lower than an
29
+ * open one of the same length and why it is missing its even harmonics, which
30
+ * is most of what makes a clarinet sound like a clarinet.
31
+ */
32
+ declare function harmonicWavelength(length: number, n: number, boundary?: BoundaryKind): number;
33
+ /** The frequency of harmonic n, Hz, for a wave travelling at `speed`. */
34
+ declare function harmonicFrequency(length: number, n: number, speed: number, boundary?: BoundaryKind): number;
35
+ /** The harmonic numbers a boundary admits, in order, up to `count` of them. */
36
+ declare function harmonicSeries(count: number, boundary?: BoundaryKind): number[];
37
+ /**
38
+ * Node positions on [0, L] for harmonic n, metres.
39
+ *
40
+ * Nodes are where the displacement is always zero. A string fixed at both ends
41
+ * has one at each end, so harmonic n has n + 1 of them.
42
+ */
43
+ declare function nodePositions(length: number, n: number, boundary?: BoundaryKind): number[];
44
+ /** Antinode positions on [0, L] for harmonic n, metres: halfway between the nodes. */
45
+ declare function antinodePositions(length: number, n: number, boundary?: BoundaryKind): number[];
46
+ /** The distance between adjacent nodes, metres: half a wavelength, always. */
47
+ declare const nodeSpacing: (wavelength: number) => number;
48
+ /**
49
+ * The speed of a wave on a stretched string: v = √(T/μ).
50
+ *
51
+ * `tension` in newtons, `massPerLength` in kg/m. Tightening a string raises its
52
+ * pitch as the square ROOT of the tension, so an octave needs four times the
53
+ * tension, which is why instruments are strung with different gauges rather
54
+ * than tuned by tension alone.
55
+ */
56
+ declare const stringWaveSpeed: (tension: number, massPerLength: number) => number;
57
+ /**
58
+ * Beat frequency, Hz: |f₁ − f₂|.
59
+ *
60
+ * Heard as a throb rather than as two notes when the difference is small. A
61
+ * piano tuner listens for this going to zero, which is a far more sensitive
62
+ * test than comparing two pitches by ear.
63
+ */
64
+ declare const beatFrequency: (f1: number, f2: number) => number;
65
+ /**
66
+ * The envelope of a beat pattern at time t, as a fraction of the peak.
67
+ *
68
+ * Two equal tones add to 2A·cos(π·Δf·t)·cos(2π·f̄·t): a fast oscillation at the
69
+ * MEAN frequency inside a slow envelope at half the difference. The loudness
70
+ * peaks twice per envelope cycle, once at each extreme, which is why the beat
71
+ * you HEAR is at |f₁ − f₂| and not at half of it.
72
+ */
73
+ declare function beatEnvelope(f1: number, f2: number, t: number): number;
74
+ /** The displacement of two superposed tones of equal amplitude at time t. */
75
+ declare function beatDisplacement(amplitude: number, f1: number, f2: number, t: number): number;
76
+ interface TwoSourcePoint {
77
+ /** Distance from the first source, m. */
78
+ r1: number;
79
+ /** Distance from the second source, m. */
80
+ r2: number;
81
+ /** r1 − r2, m. */
82
+ pathDifference: number;
83
+ /** Combined displacement at this instant, for equal sources. */
84
+ displacement: number;
85
+ /** Standing envelope: 1 on a maximum line, 0 on a minimum line. */
86
+ envelope: number;
87
+ }
88
+ /**
89
+ * Two point sources, in phase, at a point in the plane.
90
+ *
91
+ * The ripple-tank calculation. `envelope` is the part that does not change with
92
+ * time and is therefore what makes the fixed pattern of bright and dark lines:
93
+ * |cos(k·Δr/2)|, one on the constructive lines and zero on the destructive
94
+ * ones. `displacement` is the instantaneous sum, which is what animates.
95
+ *
96
+ * Separating the two is the point. A lab that draws only the instantaneous sum
97
+ * shows a shimmer with no visible structure; the pattern is in the envelope.
98
+ */
99
+ /**
100
+ * The standing ENVELOPE at a point, from the two path lengths: |cos(k·Δr/2)|.
101
+ *
102
+ * 1 on a constructive line, 0 on a destructive one, and it does not depend on
103
+ * time, which is why the pattern of bright and dark lines holds still.
104
+ *
105
+ * Takes the distances rather than the geometry, and returns a bare number
106
+ * rather than a record, because this is the function a canvas render loop calls
107
+ * once per pixel. `twoSourceField` is the readable version for everything else
108
+ * and is built from this one, so there is still a single formula.
109
+ */
110
+ declare function twoSourceEnvelope(r1: number, r2: number, wavelength: number): number;
111
+ /** The instantaneous sum at a point, from the two path lengths. The hot-path twin of the above. */
112
+ declare function twoSourceDisplacement(r1: number, r2: number, wavelength: number, frequency: number, t: number, amplitude?: number): number;
113
+ declare function twoSourceField(source1: {
114
+ x: number;
115
+ y: number;
116
+ }, source2: {
117
+ x: number;
118
+ y: number;
119
+ }, point: {
120
+ x: number;
121
+ y: number;
122
+ }, wavelength: number, frequency: number, t: number, amplitude?: number): TwoSourcePoint;
123
+ //#endregion
124
+ export { BoundaryKind, TwoSourcePoint, antinodePositions, beatDisplacement, beatEnvelope, beatFrequency, harmonicFrequency, harmonicSeries, harmonicWavelength, nodePositions, nodeSpacing, standingWave, stringWaveSpeed, superpose, twoSourceDisplacement, twoSourceEnvelope, twoSourceField };
@@ -0,0 +1,196 @@
1
+ import { angularFrequency, displacement, waveNumber } from "./wave.mjs";
2
+
3
+ //#region src/waves/superposition.ts
4
+ /**
5
+ * Superposition: what happens where waves meet.
6
+ *
7
+ * ## One principle, three consequences
8
+ *
9
+ * The principle is that displacements ADD. Everything below is that statement
10
+ * applied to a different pair of waves:
11
+ *
12
+ * two sources, one medium → an interference pattern, fixed in space
13
+ * two waves, opposite ways → a STANDING wave, with nodes that never move
14
+ * two close frequencies → BEATS, a throb at |f₁ − f₂|
15
+ *
16
+ * No new physics enters at any step, which is worth saying because the three
17
+ * are usually taught as three topics.
18
+ *
19
+ * ## The standing wave, and why it stands
20
+ *
21
+ * y = 2A·sin(kx)·cos(ωt)
22
+ *
23
+ * The x and the t have come apart. That separation IS the difference between a
24
+ * standing wave and a travelling one: the shape sin(kx) is fixed in space and
25
+ * only its scale cos(ωt) changes, so the zeros stay put. In a travelling wave
26
+ * the two are locked together inside one bracket and the zeros move along.
27
+ *
28
+ * A standing wave carries no net energy, because it is two equal waves carrying
29
+ * energy in opposite directions.
30
+ *
31
+ * ## Units
32
+ *
33
+ * SI. Lengths in metres, frequencies in hertz, time in seconds.
34
+ */
35
+ const finite = (value, what) => {
36
+ if (!Number.isFinite(value)) throw new RangeError(`${what} must be a finite number.`);
37
+ return value;
38
+ };
39
+ const positive = (value, what) => {
40
+ if (!Number.isFinite(value) || value <= 0) throw new RangeError(`${what} must be positive.`);
41
+ return value;
42
+ };
43
+ const wholeNumber = (value, what) => {
44
+ if (!Number.isInteger(value) || value < 1) throw new RangeError(`${what} must be a whole number of at least 1.`);
45
+ return value;
46
+ };
47
+ /** The sum of several waves at a point and time, by the principle of superposition. */
48
+ function superpose(waves, x, t) {
49
+ return waves.reduce((sum, wave) => sum + displacement(wave, x, t), 0);
50
+ }
51
+ /**
52
+ * Displacement of a standing wave: y = 2A·sin(kx)·cos(ωt).
53
+ *
54
+ * `amplitude` is that of EACH travelling wave, so the antinodes swing to twice
55
+ * it. That doubling is the part worth keeping explicit: a standing wave is
56
+ * built from two waves and its antinodes are louder than either.
57
+ */
58
+ function standingWave(amplitude, wavelength, frequency, x, t) {
59
+ return 2 * positive(amplitude, "An amplitude") * Math.sin(waveNumber(wavelength) * finite(x, "A position")) * Math.cos(angularFrequency(frequency) * finite(t, "A time"));
60
+ }
61
+ /**
62
+ * The wavelength of harmonic n, metres.
63
+ *
64
+ * A string fixed at both ends fits a whole number of HALF wavelengths, so
65
+ * λ = 2L/n. A pipe closed at one end has a node at the closed end and an
66
+ * antinode at the open one, so it fits an ODD number of QUARTER wavelengths:
67
+ * λ = 4L/n with n odd. That is why a closed pipe sounds an octave lower than an
68
+ * open one of the same length and why it is missing its even harmonics, which
69
+ * is most of what makes a clarinet sound like a clarinet.
70
+ */
71
+ function harmonicWavelength(length, n, boundary = "both-ends-fixed") {
72
+ const L = positive(length, "A length");
73
+ const order = wholeNumber(n, "A harmonic number");
74
+ if (boundary === "one-end-open") {
75
+ if (order % 2 === 0) throw new RangeError(`A pipe closed at one end has no harmonic ${order}: only the odd harmonics fit, which is why it sounds hollow.`);
76
+ return 4 * L / order;
77
+ }
78
+ return 2 * L / order;
79
+ }
80
+ /** The frequency of harmonic n, Hz, for a wave travelling at `speed`. */
81
+ function harmonicFrequency(length, n, speed, boundary = "both-ends-fixed") {
82
+ return positive(speed, "A wave speed") / harmonicWavelength(length, n, boundary);
83
+ }
84
+ /** The harmonic numbers a boundary admits, in order, up to `count` of them. */
85
+ function harmonicSeries(count, boundary = "both-ends-fixed") {
86
+ const howMany = wholeNumber(count, "A count of harmonics");
87
+ const step = boundary === "one-end-open" ? 2 : 1;
88
+ return Array.from({ length: howMany }, (_, i) => 1 + i * step);
89
+ }
90
+ /**
91
+ * Node positions on [0, L] for harmonic n, metres.
92
+ *
93
+ * Nodes are where the displacement is always zero. A string fixed at both ends
94
+ * has one at each end, so harmonic n has n + 1 of them.
95
+ */
96
+ function nodePositions(length, n, boundary = "both-ends-fixed") {
97
+ const L = positive(length, "A length");
98
+ const spacing = harmonicWavelength(L, n, boundary) / 2;
99
+ const start = boundary === "both-ends-open" ? spacing / 2 : 0;
100
+ const out = [];
101
+ for (let x = start; x <= L + 1e-9; x += spacing) out.push(Math.min(x, L));
102
+ return out;
103
+ }
104
+ /** Antinode positions on [0, L] for harmonic n, metres: halfway between the nodes. */
105
+ function antinodePositions(length, n, boundary = "both-ends-fixed") {
106
+ const L = positive(length, "A length");
107
+ const spacing = harmonicWavelength(L, n, boundary) / 2;
108
+ const start = boundary === "both-ends-open" ? 0 : spacing / 2;
109
+ const out = [];
110
+ for (let x = start; x <= L + 1e-9; x += spacing) out.push(Math.min(x, L));
111
+ return out;
112
+ }
113
+ /** The distance between adjacent nodes, metres: half a wavelength, always. */
114
+ const nodeSpacing = (wavelength) => positive(wavelength, "A wavelength") / 2;
115
+ /**
116
+ * The speed of a wave on a stretched string: v = √(T/μ).
117
+ *
118
+ * `tension` in newtons, `massPerLength` in kg/m. Tightening a string raises its
119
+ * pitch as the square ROOT of the tension, so an octave needs four times the
120
+ * tension, which is why instruments are strung with different gauges rather
121
+ * than tuned by tension alone.
122
+ */
123
+ const stringWaveSpeed = (tension, massPerLength) => Math.sqrt(positive(tension, "A tension") / positive(massPerLength, "A mass per unit length"));
124
+ /**
125
+ * Beat frequency, Hz: |f₁ − f₂|.
126
+ *
127
+ * Heard as a throb rather than as two notes when the difference is small. A
128
+ * piano tuner listens for this going to zero, which is a far more sensitive
129
+ * test than comparing two pitches by ear.
130
+ */
131
+ const beatFrequency = (f1, f2) => Math.abs(positive(f1, "A frequency") - positive(f2, "A frequency"));
132
+ /**
133
+ * The envelope of a beat pattern at time t, as a fraction of the peak.
134
+ *
135
+ * Two equal tones add to 2A·cos(π·Δf·t)·cos(2π·f̄·t): a fast oscillation at the
136
+ * MEAN frequency inside a slow envelope at half the difference. The loudness
137
+ * peaks twice per envelope cycle, once at each extreme, which is why the beat
138
+ * you HEAR is at |f₁ − f₂| and not at half of it.
139
+ */
140
+ function beatEnvelope(f1, f2, t) {
141
+ const difference = positive(f1, "A frequency") - positive(f2, "A frequency");
142
+ return Math.abs(Math.cos(Math.PI * difference * finite(t, "A time")));
143
+ }
144
+ /** The displacement of two superposed tones of equal amplitude at time t. */
145
+ function beatDisplacement(amplitude, f1, f2, t) {
146
+ const A = positive(amplitude, "An amplitude");
147
+ const time = finite(t, "A time");
148
+ return A * Math.sin(2 * Math.PI * positive(f1, "A frequency") * time) + A * Math.sin(2 * Math.PI * positive(f2, "A frequency") * time);
149
+ }
150
+ /**
151
+ * Two point sources, in phase, at a point in the plane.
152
+ *
153
+ * The ripple-tank calculation. `envelope` is the part that does not change with
154
+ * time and is therefore what makes the fixed pattern of bright and dark lines:
155
+ * |cos(k·Δr/2)|, one on the constructive lines and zero on the destructive
156
+ * ones. `displacement` is the instantaneous sum, which is what animates.
157
+ *
158
+ * Separating the two is the point. A lab that draws only the instantaneous sum
159
+ * shows a shimmer with no visible structure; the pattern is in the envelope.
160
+ */
161
+ /**
162
+ * The standing ENVELOPE at a point, from the two path lengths: |cos(k·Δr/2)|.
163
+ *
164
+ * 1 on a constructive line, 0 on a destructive one, and it does not depend on
165
+ * time, which is why the pattern of bright and dark lines holds still.
166
+ *
167
+ * Takes the distances rather than the geometry, and returns a bare number
168
+ * rather than a record, because this is the function a canvas render loop calls
169
+ * once per pixel. `twoSourceField` is the readable version for everything else
170
+ * and is built from this one, so there is still a single formula.
171
+ */
172
+ function twoSourceEnvelope(r1, r2, wavelength) {
173
+ return Math.abs(Math.cos(waveNumber(wavelength) * (r1 - r2) / 2));
174
+ }
175
+ /** The instantaneous sum at a point, from the two path lengths. The hot-path twin of the above. */
176
+ function twoSourceDisplacement(r1, r2, wavelength, frequency, t, amplitude = 1) {
177
+ const k = waveNumber(wavelength);
178
+ const phase = angularFrequency(frequency) * t;
179
+ return amplitude * (Math.sin(k * r1 - phase) + Math.sin(k * r2 - phase));
180
+ }
181
+ function twoSourceField(source1, source2, point, wavelength, frequency, t, amplitude = 1) {
182
+ const A = positive(amplitude, "An amplitude");
183
+ const r1 = Math.hypot(point.x - source1.x, point.y - source1.y);
184
+ const r2 = Math.hypot(point.x - source2.x, point.y - source2.y);
185
+ const time = finite(t, "A time");
186
+ return {
187
+ r1,
188
+ r2,
189
+ pathDifference: r1 - r2,
190
+ displacement: twoSourceDisplacement(r1, r2, wavelength, frequency, time, A),
191
+ envelope: twoSourceEnvelope(r1, r2, wavelength)
192
+ };
193
+ }
194
+
195
+ //#endregion
196
+ export { antinodePositions, beatDisplacement, beatEnvelope, beatFrequency, harmonicFrequency, harmonicSeries, harmonicWavelength, nodePositions, nodeSpacing, standingWave, stringWaveSpeed, superpose, twoSourceDisplacement, twoSourceEnvelope, twoSourceField };