@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,89 @@
1
+ import { Worked } from "../../core/worked.mjs";
2
+
3
+ //#region src/physics/momentum/impulse.d.ts
4
+ interface ImpulseResult {
5
+ /** The impulse, N s, which is the same thing as the momentum change in kg m/s. */
6
+ readonly impulse: number;
7
+ /** The average force over the contact, N. */
8
+ readonly averageForce: number;
9
+ readonly duration: number;
10
+ readonly worked: Worked;
11
+ }
12
+ /**
13
+ * The impulse that changes a mass's velocity from `u` to `v`, and the force that delivers it.
14
+ *
15
+ * Both velocities are SIGNED. A ball that arrives at 5 m/s and leaves at −3 m/s has changed its
16
+ * momentum by 8 m/s worth, not 2, and writing `v − u` as `3 − 5` is the single most common way to
17
+ * lose this mark.
18
+ */
19
+ declare function impulseToChange(mass: number, u: number, v: number, duration: number, sf?: number): ImpulseResult;
20
+ /**
21
+ * The force needed to deliver a fixed impulse over a chosen contact time.
22
+ *
23
+ * The airbag calculation, and the reason to have it as its own function is that the question it
24
+ * answers is the interesting one: not "what force" but "how much less force if the stop takes ten
25
+ * times longer". The answer is always exactly ten times less, because `J` did not move.
26
+ */
27
+ declare const forceForContact: (impulse: number, duration: number) => number;
28
+ /**
29
+ * A bounce off a wall, where only the component along the normal reverses.
30
+ *
31
+ * Angles are measured from the WALL, which is how these questions are drawn and stated. The
32
+ * component along the wall is untouched, so the whole impulse is perpendicular and its size is
33
+ * `2mu sin θ`. A learner who works with the full speed rather than the perpendicular component gets
34
+ * an answer that is too big by `1/sin θ`, and at the 90° case, where they usually check their work,
35
+ * the error vanishes.
36
+ */
37
+ declare function bounceOffWall(mass: number, speed: number, angleToWallDeg: number, sf?: number): ImpulseResult & {
38
+ perpendicularSpeed: number;
39
+ };
40
+ interface VariableImpulse {
41
+ readonly impulse: number;
42
+ readonly averageForce: number;
43
+ readonly peakForce: number;
44
+ /** `peakForce / averageForce`. About 1.57 for a half-sine, and never 1 for a real impact. */
45
+ readonly peakRatio: number;
46
+ readonly method: 'symbolic' | 'numeric';
47
+ readonly worked: Worked;
48
+ }
49
+ /**
50
+ * `J = ∫F dt` for a force given as an expression in `t`.
51
+ *
52
+ * Symbolic when `math/calculus` can, quadrature when it cannot, in the same pattern and for the
53
+ * same reason as `integral-sweep`: an impact profile from a real data sheet has no closed form and
54
+ * a refusal would be useless.
55
+ *
56
+ * `peakForce` is reported because it, not the average, is what breaks things. A half-sine pulse
57
+ * peaks at `π/2` times its mean, so a safety margin computed from the average is out by 57%.
58
+ */
59
+ declare function impulseOf(force: string, duration: number, values?: Readonly<Record<string, number>>, sf?: number): VariableImpulse;
60
+ /**
61
+ * Rocket thrust, `F = v_e · (dm/dt)`.
62
+ *
63
+ * A rocket is the cleanest demonstration in the syllabus that momentum, not force, is the primitive
64
+ * idea: it throws mass backwards and the reaction pushes it forwards, and it works in a vacuum
65
+ * precisely because it does not push against anything external.
66
+ *
67
+ * Thrust does not depend on how fast the rocket is going, only on how fast and how quickly it
68
+ * throws mass away. Its ACCELERATION does change, sharply, because the mass being pushed keeps
69
+ * dropping, which is why a rocket accelerates hardest just before burnout.
70
+ */
71
+ declare function rocketThrust(exhaustSpeed: number, burnRate: number, sf?: number): {
72
+ thrust: number;
73
+ worked: Worked;
74
+ };
75
+ /**
76
+ * A rocket's acceleration at an instant, against gravity.
77
+ *
78
+ * `a = (v_e · dm/dt) / m − g`, with `m` the mass RIGHT NOW. Taking off needs the thrust to beat the
79
+ * weight, and a rocket that cannot lift at ignition may be able to a minute later having burned a
80
+ * third of itself, which is a genuinely surprising thing to be able to show.
81
+ */
82
+ declare function rocketAcceleration(exhaustSpeed: number, burnRate: number, currentMass: number, g?: number, sf?: number): {
83
+ acceleration: number;
84
+ thrust: number;
85
+ lifts: boolean;
86
+ worked: Worked;
87
+ };
88
+ //#endregion
89
+ export { ImpulseResult, VariableImpulse, bounceOffWall, forceForContact, impulseOf, impulseToChange, rocketAcceleration, rocketThrust };
@@ -0,0 +1,159 @@
1
+ import { evaluate } from "../../math/ast.mjs";
2
+ import { parse } from "../../math/parse.mjs";
3
+ import { integrate } from "../../math/calculus.mjs";
4
+ import { quadrature } from "../../math/analysis.mjs";
5
+ import { calc, texSigFigs } from "../../core/worked.mjs";
6
+
7
+ //#region src/physics/momentum/impulse.ts
8
+ /**
9
+ * Impulse: what a force does when you multiply it by how long it acts.
10
+ *
11
+ * `J = FΔt = Δp` is one of the few genuinely load-bearing identities at this level, and it is
12
+ * usually presented as two unrelated facts. It is one: Newton's second law says `F = dp/dt`, so
13
+ * integrating both sides over the time the force acts gives `∫F dt = Δp`. The left is the impulse
14
+ * and the right is the change in momentum, and they are equal because that is what integrating an
15
+ * equation does.
16
+ *
17
+ * WHY THIS MATTERS PRACTICALLY, and it is the point most worth teaching: for a given change in
18
+ * momentum, the impulse is FIXED. A car stopping from 30 m/s has to lose all its momentum whether
19
+ * it hits a wall or a crash barrier. Only `Δt` is negotiable, and since `F = J/Δt`, stretching the
20
+ * time is the ONLY way to reduce the force. Airbags, crumple zones, bending your knees on landing,
21
+ * a cricketer drawing the hands back with the ball: all the same sentence.
22
+ *
23
+ * A VARIABLE FORCE is handled by integrating it rather than by pretending it is constant. Real
24
+ * impacts are not rectangles, and `F_max` is roughly twice the average for the half-sine pulse that
25
+ * models a real collision, which is exactly the factor a safety calculation must not lose.
26
+ *
27
+ * Pure: no React, no pixels.
28
+ */
29
+ /**
30
+ * The impulse that changes a mass's velocity from `u` to `v`, and the force that delivers it.
31
+ *
32
+ * Both velocities are SIGNED. A ball that arrives at 5 m/s and leaves at −3 m/s has changed its
33
+ * momentum by 8 m/s worth, not 2, and writing `v − u` as `3 − 5` is the single most common way to
34
+ * lose this mark.
35
+ */
36
+ function impulseToChange(mass, u, v, duration, sf = 3) {
37
+ if (duration <= 0) throw new Error("The contact has to last a positive time.");
38
+ const impulse = mass * (v - u);
39
+ const averageForce = impulse / duration;
40
+ return {
41
+ impulse,
42
+ averageForce,
43
+ duration,
44
+ worked: calc().step("J = \\Delta p = m(v - u)", "impulse IS the change in momentum, not merely equal to it").step(`J = ${texSigFigs(mass, sf)}(${texSigFigs(v, sf)} - ${texSigFigs(u, sf)}) = ${texSigFigs(impulse, sf)}\\ \\mathrm{N\\,s}`, v * u < 0 ? "the velocities have opposite signs, so the two speeds ADD: this is where the mark is usually lost" : void 0).step(`F = \\frac{J}{\\Delta t} = \\frac{${texSigFigs(impulse, sf)}}{${texSigFigs(duration, sf)}} = ${texSigFigs(averageForce, sf)}\\ \\mathrm{N}`, "the impulse was fixed by the momentum change; only the time is negotiable, and the force follows from it").done(impulse)
45
+ };
46
+ }
47
+ /**
48
+ * The force needed to deliver a fixed impulse over a chosen contact time.
49
+ *
50
+ * The airbag calculation, and the reason to have it as its own function is that the question it
51
+ * answers is the interesting one: not "what force" but "how much less force if the stop takes ten
52
+ * times longer". The answer is always exactly ten times less, because `J` did not move.
53
+ */
54
+ const forceForContact = (impulse, duration) => {
55
+ if (duration <= 0) throw new Error("The contact has to last a positive time.");
56
+ return impulse / duration;
57
+ };
58
+ /**
59
+ * A bounce off a wall, where only the component along the normal reverses.
60
+ *
61
+ * Angles are measured from the WALL, which is how these questions are drawn and stated. The
62
+ * component along the wall is untouched, so the whole impulse is perpendicular and its size is
63
+ * `2mu sin θ`. A learner who works with the full speed rather than the perpendicular component gets
64
+ * an answer that is too big by `1/sin θ`, and at the 90° case, where they usually check their work,
65
+ * the error vanishes.
66
+ */
67
+ function bounceOffWall(mass, speed, angleToWallDeg, sf = 3) {
68
+ const theta = angleToWallDeg * Math.PI / 180;
69
+ const perpendicularSpeed = speed * Math.sin(theta);
70
+ const impulse = 2 * mass * perpendicularSpeed;
71
+ return {
72
+ impulse,
73
+ averageForce: NaN,
74
+ duration: NaN,
75
+ perpendicularSpeed,
76
+ worked: calc().step("J = m(v_\\perp - u_\\perp) = 2mu\\sin\\theta", "only the component INTO the wall reverses; the component along it is untouched").step(`u_\\perp = ${texSigFigs(speed, sf)}\\sin ${texSigFigs(angleToWallDeg, sf)}^\\circ = ${texSigFigs(perpendicularSpeed, sf)}\\ \\mathrm{m\\,s^{-1}}`).step(`J = 2 \\times ${texSigFigs(mass, sf)} \\times ${texSigFigs(perpendicularSpeed, sf)} = ${texSigFigs(impulse, sf)}\\ \\mathrm{N\\,s}`, "directed along the normal, because that is the only direction anything changed in").done(impulse)
77
+ };
78
+ }
79
+ /**
80
+ * `J = ∫F dt` for a force given as an expression in `t`.
81
+ *
82
+ * Symbolic when `math/calculus` can, quadrature when it cannot, in the same pattern and for the
83
+ * same reason as `integral-sweep`: an impact profile from a real data sheet has no closed form and
84
+ * a refusal would be useless.
85
+ *
86
+ * `peakForce` is reported because it, not the average, is what breaks things. A half-sine pulse
87
+ * peaks at `π/2` times its mean, so a safety margin computed from the average is out by 57%.
88
+ */
89
+ function impulseOf(force, duration, values = {}, sf = 3) {
90
+ if (duration <= 0) throw new Error("The contact has to last a positive time.");
91
+ const node = parse(force);
92
+ const at = (t) => evaluate(node, {
93
+ ...values,
94
+ t
95
+ });
96
+ const antiderivative = integrate(node, "t");
97
+ const method = antiderivative ? "symbolic" : "numeric";
98
+ const impulse = antiderivative ? evaluate(antiderivative, {
99
+ ...values,
100
+ t: duration
101
+ }) - evaluate(antiderivative, {
102
+ ...values,
103
+ t: 0
104
+ }) : quadrature(at, 0, duration);
105
+ let peakForce = 0;
106
+ const STEPS = 2e3;
107
+ for (let i = 0; i <= STEPS; i++) peakForce = Math.max(peakForce, Math.abs(at(duration * i / STEPS)));
108
+ const averageForce = impulse / duration;
109
+ const worked = calc().step("J = \\int_0^{\\Delta t} F\\,dt", "a real impact is not a rectangle, so it is integrated rather than multiplied").step(`F(t) = ${force}`).step(`J = ${texSigFigs(impulse, sf)}\\ \\mathrm{N\\,s}`, method === "symbolic" ? "integrated exactly" : "no closed form, so integrated numerically").step(`\\bar{F} = ${texSigFigs(averageForce, sf)}\\ \\mathrm{N}, \\quad F_{\\max} = ${texSigFigs(peakForce, sf)}\\ \\mathrm{N}`, "the PEAK is what breaks things, and it is nothing like the average").done(impulse);
110
+ return {
111
+ impulse,
112
+ averageForce,
113
+ peakForce,
114
+ peakRatio: averageForce === 0 ? NaN : peakForce / averageForce,
115
+ method,
116
+ worked
117
+ };
118
+ }
119
+ /**
120
+ * Rocket thrust, `F = v_e · (dm/dt)`.
121
+ *
122
+ * A rocket is the cleanest demonstration in the syllabus that momentum, not force, is the primitive
123
+ * idea: it throws mass backwards and the reaction pushes it forwards, and it works in a vacuum
124
+ * precisely because it does not push against anything external.
125
+ *
126
+ * Thrust does not depend on how fast the rocket is going, only on how fast and how quickly it
127
+ * throws mass away. Its ACCELERATION does change, sharply, because the mass being pushed keeps
128
+ * dropping, which is why a rocket accelerates hardest just before burnout.
129
+ */
130
+ function rocketThrust(exhaustSpeed, burnRate, sf = 3) {
131
+ const thrust = exhaustSpeed * burnRate;
132
+ return {
133
+ thrust,
134
+ worked: calc().step("F = v_e \\frac{dm}{dt}", "the momentum given to the exhaust each second is the momentum the rocket gains each second").step(`F = ${texSigFigs(exhaustSpeed, sf)} \\times ${texSigFigs(burnRate, sf)} = ${texSigFigs(thrust, sf)}\\ \\mathrm{N}`, "independent of the rocket’s own speed, which is why it works in a vacuum").done(thrust)
135
+ };
136
+ }
137
+ /**
138
+ * A rocket's acceleration at an instant, against gravity.
139
+ *
140
+ * `a = (v_e · dm/dt) / m − g`, with `m` the mass RIGHT NOW. Taking off needs the thrust to beat the
141
+ * weight, and a rocket that cannot lift at ignition may be able to a minute later having burned a
142
+ * third of itself, which is a genuinely surprising thing to be able to show.
143
+ */
144
+ function rocketAcceleration(exhaustSpeed, burnRate, currentMass, g = 9.8, sf = 3) {
145
+ if (currentMass <= 0) throw new Error("A rocket has to have some mass left.");
146
+ const thrust = exhaustSpeed * burnRate;
147
+ const weight = currentMass * g;
148
+ const acceleration = thrust / currentMass - g;
149
+ const worked = calc().step("ma = F - mg", "thrust up, weight down, and the mass is whatever is left at this instant").step(`a = \\frac{${texSigFigs(thrust, sf)}}{${texSigFigs(currentMass, sf)}} - ${texSigFigs(g, sf)} = ${texSigFigs(acceleration, sf)}\\ \\mathrm{m\\,s^{-2}}`, thrust > weight ? "thrust beats the weight, so it climbs, and it climbs harder as it gets lighter" : "thrust is less than the weight, so it cannot lift yet").done(acceleration);
150
+ return {
151
+ acceleration,
152
+ thrust,
153
+ lifts: thrust > weight,
154
+ worked
155
+ };
156
+ }
157
+
158
+ //#endregion
159
+ export { bounceOffWall, forceForContact, impulseOf, impulseToChange, rocketAcceleration, rocketThrust };
@@ -0,0 +1,60 @@
1
+ import { Worked } from "../../core/worked.mjs";
2
+ import { Complex } from "../../math/complex.mjs";
3
+ import { Components, Polar } from "../vectors.mjs";
4
+
5
+ //#region src/physics/momentum/planar.d.ts
6
+ /** A body with a velocity in the plane. */
7
+ interface PlanarBody {
8
+ readonly label: string;
9
+ readonly mass: number;
10
+ /** Speed, m/s. */
11
+ readonly speed: number;
12
+ /** Direction, degrees anticlockwise from the x axis. */
13
+ readonly angleDeg: number;
14
+ }
15
+ /** A body's momentum as components, kg m/s. */
16
+ declare function momentumOf(body: PlanarBody): Components;
17
+ /** Total momentum of any number of bodies. */
18
+ declare function totalMomentum(bodies: readonly PlanarBody[]): Components;
19
+ /**
20
+ * A momentum as a complex number, for the polar-arithmetic route.
21
+ *
22
+ * `p_x + i p_y`. Adding momenta is adding complex numbers, and the magnitude and argument of the
23
+ * sum are the size and direction of the resultant, which is why the calculator trick works.
24
+ */
25
+ declare const momentumAsComplex: (body: PlanarBody) => Complex;
26
+ interface PlanarSolution {
27
+ /** The missing velocity, as speed and direction. */
28
+ readonly velocity: Polar;
29
+ /** Its momentum components, for a diagram that draws the vector triangle. */
30
+ readonly momentum: Components;
31
+ readonly worked: Worked;
32
+ }
33
+ /**
34
+ * Find the one velocity that conservation requires, given every other one.
35
+ *
36
+ * This is the whole of oblique collisions: total momentum before, minus every known momentum after,
37
+ * is the momentum of the body you did not measure. Divide by its mass and you have its velocity.
38
+ *
39
+ * ```ts
40
+ * // 5 kg at 2 m/s along x strikes a stationary 3 kg; afterwards the 5 kg moves at 1 m/s, 30° off
41
+ * // the axis. Where does the 3 kg go?
42
+ * conserveMomentum(
43
+ * [{ label: 'A before', mass: 5, speed: 2, angleDeg: 0 },
44
+ * { label: 'B before', mass: 3, speed: 0, angleDeg: 0 }],
45
+ * [{ label: 'A after', mass: 5, speed: 1, angleDeg: 30 }],
46
+ * 3,
47
+ * ); // 2.07 m/s at −23.8°
48
+ * ```
49
+ */
50
+ declare function conserveMomentum(before: readonly PlanarBody[], knownAfter: readonly PlanarBody[], unknownMass: number, sf?: number): PlanarSolution;
51
+ /**
52
+ * Is momentum actually conserved across this collision?
53
+ *
54
+ * For checking a learner's answer, or a lab's own model. The tolerance is relative to the momentum
55
+ * present, because an absolute epsilon is meaningless when the same check has to serve a bullet and
56
+ * a goods train.
57
+ */
58
+ declare function momentumIsConserved(before: readonly PlanarBody[], after: readonly PlanarBody[], tolerance?: number): boolean;
59
+ //#endregion
60
+ export { PlanarBody, PlanarSolution, conserveMomentum, momentumAsComplex, momentumIsConserved, momentumOf, totalMomentum };
@@ -0,0 +1,110 @@
1
+ import { cx } from "../../math/complex.mjs";
2
+ import { calc, texSigFigs } from "../../core/worked.mjs";
3
+ import { compose, resolve } from "../vectors.mjs";
4
+
5
+ //#region src/physics/momentum/planar.ts
6
+ /**
7
+ * Momentum in a plane: the same conservation law, resolved into two directions.
8
+ *
9
+ * There is no new physics here and that is the thing worth saying out loud. Momentum is a vector,
10
+ * vectors add component by component, so conservation in two dimensions is conservation along x AND
11
+ * conservation along y: two equations instead of one, from the same single law.
12
+ *
13
+ * That is the whole method for an oblique collision, and a textbook that presents it as a new
14
+ * "type" with its own worked example has hidden the only idea in it.
15
+ *
16
+ * A NOTE ON THE CALCULATOR TRICK. Competitor material tells students to solve these in complex mode
17
+ * on a calculator, because a 2D vector and a complex number are the same object and the calculator
18
+ * will add them in polar form. That is a real and good insight buried in a keystroke sequence, and
19
+ * `momentumAsComplex` exposes it properly: our complex kernel already does polar arithmetic, so the
20
+ * method can be SHOWN rather than performed blind.
21
+ *
22
+ * Pure: no React, no pixels.
23
+ */
24
+ /** A body's momentum as components, kg m/s. */
25
+ function momentumOf(body) {
26
+ const v = resolve(body.speed, body.angleDeg);
27
+ return {
28
+ x: body.mass * v.x,
29
+ y: body.mass * v.y
30
+ };
31
+ }
32
+ /** Total momentum of any number of bodies. */
33
+ function totalMomentum(bodies) {
34
+ let x = 0;
35
+ let y = 0;
36
+ for (const b of bodies) {
37
+ const p = momentumOf(b);
38
+ x += p.x;
39
+ y += p.y;
40
+ }
41
+ return {
42
+ x,
43
+ y
44
+ };
45
+ }
46
+ /**
47
+ * A momentum as a complex number, for the polar-arithmetic route.
48
+ *
49
+ * `p_x + i p_y`. Adding momenta is adding complex numbers, and the magnitude and argument of the
50
+ * sum are the size and direction of the resultant, which is why the calculator trick works.
51
+ */
52
+ const momentumAsComplex = (body) => {
53
+ const p = momentumOf(body);
54
+ return cx(p.x, p.y);
55
+ };
56
+ /**
57
+ * Find the one velocity that conservation requires, given every other one.
58
+ *
59
+ * This is the whole of oblique collisions: total momentum before, minus every known momentum after,
60
+ * is the momentum of the body you did not measure. Divide by its mass and you have its velocity.
61
+ *
62
+ * ```ts
63
+ * // 5 kg at 2 m/s along x strikes a stationary 3 kg; afterwards the 5 kg moves at 1 m/s, 30° off
64
+ * // the axis. Where does the 3 kg go?
65
+ * conserveMomentum(
66
+ * [{ label: 'A before', mass: 5, speed: 2, angleDeg: 0 },
67
+ * { label: 'B before', mass: 3, speed: 0, angleDeg: 0 }],
68
+ * [{ label: 'A after', mass: 5, speed: 1, angleDeg: 30 }],
69
+ * 3,
70
+ * ); // 2.07 m/s at −23.8°
71
+ * ```
72
+ */
73
+ function conserveMomentum(before, knownAfter, unknownMass, sf = 3) {
74
+ if (unknownMass <= 0) throw new Error("The unknown body must have a positive mass.");
75
+ const total = totalMomentum(before);
76
+ const accounted = totalMomentum(knownAfter);
77
+ const momentum = {
78
+ x: total.x - accounted.x,
79
+ y: total.y - accounted.y
80
+ };
81
+ const velocity = compose(momentum.x / unknownMass, momentum.y / unknownMass);
82
+ const w = calc().step("\\sum p_x \\text{ before} = \\sum p_x \\text{ after}, \\quad \\sum p_y \\text{ before} = \\sum p_y \\text{ after}", "one law, resolved into two directions. That is the entire method for an oblique collision").step(`\\text{before: } (${texSigFigs(total.x, sf)},\\; ${texSigFigs(total.y, sf)})\\ \\mathrm{kg\\,m\\,s^{-1}}`, before.map((b) => b.label).join(" + "));
83
+ for (const b of knownAfter) {
84
+ const p = momentumOf(b);
85
+ w.step(`${b.label}: (${texSigFigs(p.x, sf)},\\; ${texSigFigs(p.y, sf)})\\ \\mathrm{kg\\,m\\,s^{-1}}`, `${texSigFigs(b.mass, sf)} kg at ${texSigFigs(b.speed, sf)} m/s, ${texSigFigs(b.angleDeg, sf)}°`);
86
+ }
87
+ w.step(`\\text{missing: } (${texSigFigs(momentum.x, sf)},\\; ${texSigFigs(momentum.y, sf)})\\ \\mathrm{kg\\,m\\,s^{-1}}`, "whatever is left over is the momentum of the body you did not measure");
88
+ w.step(`v = \\frac{|p|}{m} = ${texSigFigs(velocity.magnitude, sf)}\\ \\mathrm{m\\,s^{-1}} \\text{ at } ${texSigFigs(velocity.angleDeg, sf)}^\\circ`, velocity.angleDeg < 0 ? "below the axis, which the sign of p_y already told you" : void 0);
89
+ return {
90
+ velocity,
91
+ momentum,
92
+ worked: w.done(velocity.magnitude)
93
+ };
94
+ }
95
+ /**
96
+ * Is momentum actually conserved across this collision?
97
+ *
98
+ * For checking a learner's answer, or a lab's own model. The tolerance is relative to the momentum
99
+ * present, because an absolute epsilon is meaningless when the same check has to serve a bullet and
100
+ * a goods train.
101
+ */
102
+ function momentumIsConserved(before, after, tolerance = 1e-6) {
103
+ const a = totalMomentum(before);
104
+ const b = totalMomentum(after);
105
+ const scale = Math.max(Math.hypot(a.x, a.y), Math.hypot(b.x, b.y), 1);
106
+ return Math.hypot(a.x - b.x, a.y - b.y) <= scale * tolerance;
107
+ }
108
+
109
+ //#endregion
110
+ export { conserveMomentum, momentumAsComplex, momentumIsConserved, momentumOf, totalMomentum };
@@ -0,0 +1,107 @@
1
+ import { Worked } from "../core/worked.mjs";
2
+ import { Components, toDegrees, toRadians } from "./vectors.mjs";
3
+ import { Root } from "./kinematics/roots.mjs";
4
+ import { G_EARTH } from "./kinematics/free-fall.mjs";
5
+
6
+ //#region src/physics/projectile.d.ts
7
+ interface Launch {
8
+ /** Launch speed, m/s. */
9
+ readonly speed: number;
10
+ /** Launch angle above the horizontal, degrees. Negative aims below the horizontal. */
11
+ readonly angleDeg: number;
12
+ /**
13
+ * Launch point above the landing level, m. Zero is the level-ground case every textbook does
14
+ * first; a positive value is the cliff, the roof, the gun barrel 1.9 m off the ground.
15
+ */
16
+ readonly height?: number;
17
+ /** Gravitational acceleration, m/s². Positive; the sign is applied here. */
18
+ readonly g?: number;
19
+ }
20
+ interface Flight {
21
+ /** Horizontal and vertical launch velocity components. */
22
+ readonly launchVelocity: Components;
23
+ /** Time from launch until it returns to the landing level, s. */
24
+ readonly timeOfFlight: number;
25
+ /** Horizontal distance covered in that time, m. */
26
+ readonly range: number;
27
+ /** Time to the top of the arc, s. */
28
+ readonly timeToPeak: number;
29
+ /** Rise above the LAUNCH point, m. Zero when the launch aims downwards. */
30
+ readonly peakRise: number;
31
+ /** Height of the top of the arc above the LANDING level, m. */
32
+ readonly maxHeight: number;
33
+ /** Speed at the moment it lands, m/s. */
34
+ readonly impactSpeed: number;
35
+ /** Direction of travel at landing, degrees BELOW the horizontal. */
36
+ readonly impactAngleDeg: number;
37
+ }
38
+ /** The launch speed split into its horizontal and vertical parts. */
39
+ declare const launchVelocity: (launch: Launch) => Components;
40
+ /**
41
+ * Everything about one flight.
42
+ *
43
+ * The time of flight goes through the kinematics solver rather than through a closed form, because
44
+ * with a launch height it IS a quadratic with a root to reject, and routing it through the same
45
+ * code path as the level-ground case means the level-ground case cannot quietly be a different
46
+ * piece of physics.
47
+ */
48
+ declare function flight(launch: Launch): Flight;
49
+ /** Where the projectile is at time `t`, measured from the launch point. */
50
+ declare function positionAt(launch: Launch, t: number): Components;
51
+ /** How fast and which way it is going at time `t`. Horizontal never changes; that is the point. */
52
+ declare function velocityAt(launch: Launch, t: number): Components;
53
+ /** The arc, sampled for drawing. Always includes the landing point exactly. */
54
+ declare function arc(launch: Launch, samples?: number): readonly Components[];
55
+ /**
56
+ * Every moment the projectile is at a given height above the LAUNCH point.
57
+ *
58
+ * Usually two, and that is the interesting part: on the way up and on the way down. A lab that
59
+ * draws both, and a lesson that says why there are two, turns a confusing quadratic into the
60
+ * obvious fact that the arc is symmetric.
61
+ */
62
+ declare function timeAtHeight(launch: Launch, heightAboveLaunch: number): readonly Root[];
63
+ /**
64
+ * The launch angles that put a projectile a given distance away on level ground.
65
+ *
66
+ * There are normally TWO, one low and flat and one high and lobbed, and they are complementary
67
+ * (they add to 90°). That pair is the most under-taught fact in the topic: a mortar and a rifle
68
+ * hitting the same target is the same equation twice. Returns null when the target is out of
69
+ * range at that speed, which is the honest answer and the one a game needs.
70
+ */
71
+ declare function anglesForRange(range: number, speed: number, g?: number): {
72
+ low: number;
73
+ high: number;
74
+ } | null;
75
+ /**
76
+ * The smallest launch speed that can reach a distance on level ground, and the angle that does it.
77
+ *
78
+ * `R = v² sin 2θ / g` is largest for a given speed when `sin 2θ = 1`, so the cheapest shot is
79
+ * always at 45° and needs `v = √(Rg)`. Worth having as its own function because "what is the
80
+ * minimum speed" is a standard exam question and because the answer explains why 45° is the angle
81
+ * everybody remembers.
82
+ */
83
+ declare function minimumSpeedForRange(range: number, g?: number): {
84
+ speed: number;
85
+ angleDeg: number;
86
+ };
87
+ /**
88
+ * The launch angle at which the range equals the maximum height.
89
+ *
90
+ * `R = H` gives `tan θ = 4`, independent of speed and of gravity, which is a genuinely surprising
91
+ * result and a good lab question: the learner predicts whether firing harder changes the angle,
92
+ * and it does not.
93
+ */
94
+ declare const angleWhereRangeEqualsHeight: () => number;
95
+ /**
96
+ * The worked solution for a flight, as a lesson would set it out.
97
+ *
98
+ * Structured as resolve, then vertical, then horizontal, in that order and labelled as such,
99
+ * because that ordering IS the method. A derivation that jumps to `R = u² sin 2θ / g` gives a
100
+ * student a formula to memorise; this one gives them something they can redo when the question has
101
+ * a cliff in it and the memorised formula does not apply.
102
+ */
103
+ declare function flightSteps(launch: Launch, sf?: number): Worked;
104
+ /** The working for the peak: why the highest point is where the vertical velocity is zero. */
105
+ declare function peakSteps(launch: Launch, sf?: number): Worked;
106
+ //#endregion
107
+ export { Flight, Launch, angleWhereRangeEqualsHeight, anglesForRange, arc, flight, flightSteps, launchVelocity, minimumSpeedForRange, peakSteps, positionAt, timeAtHeight, velocityAt };