@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,180 @@
1
+ import { calc, texSigFigs } from "../../core/worked.mjs";
2
+ import { G_EARTH } from "../kinematics/free-fall.mjs";
3
+ import { sweep } from "../integral-sweep.mjs";
4
+
5
+ //#region src/physics/energy/centre-of-mass.ts
6
+ /**
7
+ * Work on things that are not point masses: stacks of bricks, hanging chains, a well full of water.
8
+ *
9
+ * ONE IDEA COVERS ALL OF THEM, and it is the idea that makes this family stop being a set of tricks:
10
+ *
11
+ * **The work done against gravity on an extended body is `mg` times the rise of its CENTRE OF
12
+ * MASS.** Not the rise of its top, not the rise of its bottom, and not the distance anything
13
+ * travelled along the floor.
14
+ *
15
+ * Once that is in place, every question below is the same question. Standing a brick on its end
16
+ * raises its centre from half its thickness to half its length. Stacking eight bricks raises each
17
+ * one by a different amount and you add them. Hauling a chain up a well raises its centre by half
18
+ * the depth while the bucket on the end rises the whole depth, so they are counted separately.
19
+ * Emptying a tank raises each layer by a different amount, so the sum becomes an integral, and the
20
+ * integral is just the centre of mass again with the arithmetic done properly.
21
+ *
22
+ * THE FACTOR OF TWO. Nearly every wrong answer in this family is out by a factor close to two, and
23
+ * it is always the same mistake: using the full depth where the centre of mass only moved half of
24
+ * it. It is worth being caught by that once, deliberately, which is why {@link columnDrain} reports
25
+ * the naive answer alongside the right one.
26
+ *
27
+ * Pure: no React, no pixels.
28
+ */
29
+ /**
30
+ * The general statement: work against gravity is `mg` times the rise of the centre of mass.
31
+ *
32
+ * Everything else in this file is this function with the two heights worked out for a particular
33
+ * shape. Having it exist separately is the point, because it is what a learner should reach for when
34
+ * they meet a shape nobody has tabulated.
35
+ */
36
+ function centreOfMassLift(mass, fromHeight, toHeight, g = G_EARTH, sf = 4) {
37
+ const rise = toHeight - fromHeight;
38
+ const value = mass * g * rise;
39
+ return {
40
+ rise,
41
+ value,
42
+ worked: calc().step("W = mg\\,\\Delta \\bar{h}", "the rise of the CENTRE OF MASS. Not of the top of the object, and not of the bottom").step(`\\Delta \\bar{h} = ${texSigFigs(toHeight, sf)} - ${texSigFigs(fromHeight, sf)} = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`W = ${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(rise, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
43
+ };
44
+ }
45
+ /**
46
+ * Standing a uniform block on a different face: the brick question.
47
+ *
48
+ * A uniform body's centre of mass sits at the middle, so lying on a face it is half the THICKNESS
49
+ * above the table, and stood on end it is half the LENGTH. The rise is half the difference, and the
50
+ * other two dimensions never enter, which surprises people who were carefully multiplying all three.
51
+ */
52
+ function standBlockOnEnd(mass, lyingDimension, standingDimension, g = G_EARTH, sf = 4) {
53
+ const from = lyingDimension / 2;
54
+ const to = standingDimension / 2;
55
+ const lift = centreOfMassLift(mass, from, to, g, sf);
56
+ const worked = calc().step("\\bar{h} = \\tfrac{1}{2} \\times (\\text{height of the face it is resting on})", "a uniform block has its centre of mass exactly in the middle, so it sits half its current height above the table").step(`\\bar{h}_{\\text{before}} = \\frac{${texSigFigs(lyingDimension, sf)}}{2} = ${texSigFigs(from, sf)}\\ \\mathrm{m}, \\quad \\bar{h}_{\\text{after}} = \\frac{${texSigFigs(standingDimension, sf)}}{2} = ${texSigFigs(to, sf)}\\ \\mathrm{m}`).step(`\\Delta\\bar{h} = ${texSigFigs(lift.rise, sf)}\\ \\mathrm{m}`, "the third dimension never appears. Tipping a brick does not care how wide it is").step(`W = mg\\,\\Delta\\bar{h} = ${texSigFigs(lift.value, sf)}\\ \\mathrm{J}`).done(lift.value);
57
+ return {
58
+ rise: lift.rise,
59
+ value: lift.value,
60
+ worked
61
+ };
62
+ }
63
+ /**
64
+ * Tipping a hinged rod (or a hinged plank) through an angle from the vertical.
65
+ *
66
+ * The centre of mass of a uniform rod is at its midpoint, so it traces a circle of radius `l/2`, and
67
+ * the rise is `(l/2)(1 − cos θ)`: the pendulum geometry again, with the length halved because the
68
+ * mass is spread rather than hanging at the end. That reuse is worth naming out loud, because a
69
+ * learner who sees the same `(1 − cos θ)` in a swing and in a toppling rod has genuinely learned the
70
+ * geometry rather than two formulas.
71
+ */
72
+ function tiltRod(mass, length, angleFromVerticalDeg, g = G_EARTH, sf = 4) {
73
+ const rad = angleFromVerticalDeg * Math.PI / 180;
74
+ const rise = length / 2 * (1 - Math.cos(rad));
75
+ const value = mass * g * rise;
76
+ return {
77
+ rise,
78
+ value,
79
+ worked: calc().step("\\bar{h} = \\frac{l}{2}", "a uniform rod carries its centre of mass at the midpoint, so that is the only point whose height matters").step("\\Delta\\bar{h} = \\frac{l}{2}(1 - \\cos\\theta)", "the same (1 - cos theta) as a pendulum, with l/2 in place of l because the mass sits at the middle, not at the end").step(`\\Delta\\bar{h} = \\frac{${texSigFigs(length, sf)}}{2}(1 - \\cos ${texSigFigs(angleFromVerticalDeg, sf)}^\\circ) = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`W = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
80
+ };
81
+ }
82
+ /**
83
+ * Building a column out of `count` identical bricks that all start lying on the ground.
84
+ *
85
+ * DERIVED, NOT QUOTED. The textbook prints `W = ⁿC₂ mgh` and a binomial coefficient appearing in a
86
+ * mechanics problem looks like a conjuring trick. It is not: the bottom brick does not move, the
87
+ * next rises `h`, the next `2h`, and adding `0 + 1 + 2 + ... + (n−1)` gives `n(n−1)/2`, which is the
88
+ * triangle number and which happens to equal `ⁿC₂`. The coefficient is a coincidence of arithmetic,
89
+ * not a combinatorial insight, and saying so is more honest than letting it look profound.
90
+ *
91
+ * `height` is the thickness of one brick, which is how far each brick sits above the one below it.
92
+ */
93
+ function stackColumn(count, massEach, height, g = G_EARTH, sf = 4) {
94
+ if (!Number.isInteger(count) || count < 1) throw new Error("A stack is built from a whole number of bricks, and at least one.");
95
+ const rises = Array.from({ length: count }, (_, i) => i * height);
96
+ const triangleNumber = count * (count - 1) / 2;
97
+ const value = massEach * g * height * triangleNumber;
98
+ return {
99
+ value,
100
+ rises,
101
+ triangleNumber,
102
+ worked: calc().step("\\text{brick } k \\text{ rises } (k-1)h", "they all start on the ground. The bottom one never moves; the second climbs one brick; the third climbs two").step(`W = mgh\\left(0 + 1 + 2 + \\ldots + ${count - 1}\\right)`, "add up what each brick cost. Nothing clever has happened yet").step(`0 + 1 + \\ldots + (n-1) = \\frac{n(n-1)}{2} = \\frac{${count} \\times ${count - 1}}{2} = ${texSigFigs(triangleNumber, sf)}`, "the triangle number. It also equals nC2, which is why the book prints a binomial coefficient, but there is no counting argument here").step(`W = ${texSigFigs(massEach, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)} \\times ${texSigFigs(triangleNumber, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).step(`\\text{check: } \\bar{h} \\text{ rose from } \\frac{h}{2} \\text{ to } \\frac{nh}{2}`, "the same answer falls out of the centre of mass alone, which is the faster route once you trust it").done(value)
103
+ };
104
+ }
105
+ /**
106
+ * Hauling a chain up a well, with a load on the end.
107
+ *
108
+ * Two contributions and they rise by different amounts, which is the entire question. The load on
109
+ * the end travels the full depth. The chain's centre of mass starts halfway down and finishes at the
110
+ * top, so it rises only HALF the depth. Treating the chain as though all of it climbed the full
111
+ * depth doubles its share, and the resulting answer is wrong by an amount that depends on how heavy
112
+ * the chain is relative to the load, which is why it can pass unnoticed.
113
+ */
114
+ function chainLift(depth, chainMassPerMetre, loadMass, g = G_EARTH, sf = 4) {
115
+ const chainMass = chainMassPerMetre * depth;
116
+ const chainWork = chainMass * g * (depth / 2);
117
+ const loadWork = loadMass * g * depth;
118
+ const value = chainWork + loadWork;
119
+ return {
120
+ chainWork,
121
+ loadWork,
122
+ value,
123
+ chainMass,
124
+ worked: calc().step("W = W_{\\text{chain}} + W_{\\text{load}}", "two things are being raised and they do not rise by the same amount, so they are counted separately").step(`m_{\\text{chain}} = ${texSigFigs(chainMassPerMetre, sf)} \\times ${texSigFigs(depth, sf)} = ${texSigFigs(chainMass, sf)}\\ \\mathrm{kg}`).step(`W_{\\text{chain}} = m_{\\text{chain}}\\,g\\,\\frac{l}{2} = ${texSigFigs(chainMass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(depth / 2, sf)} = ${texSigFigs(chainWork, sf)}\\ \\mathrm{J}`, "HALF the depth: the chain hangs from the top, so its centre of mass starts at the midpoint and ends at the rim").step(`W_{\\text{load}} = ${texSigFigs(loadMass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(depth, sf)} = ${texSigFigs(loadWork, sf)}\\ \\mathrm{J}`, "the full depth: the load is a single lump on the end and every part of it makes the whole journey").step(`W = ${texSigFigs(value, sf)}\\ \\mathrm{J}`).done(value)
125
+ };
126
+ }
127
+ /**
128
+ * Pumping every drop of liquid out over the rim of an upright container.
129
+ *
130
+ * The layer at height `y` has to rise `(H − y)`, so the work is `∫ ρgA(H − y) dy` over whatever is
131
+ * actually in there. The integral is performed symbolically by the shared integrator, so the sweep
132
+ * this returns can be animated as layers leaving one at a time while the running total fills, and
133
+ * the number on the meter is the real antiderivative rather than a sum of rectangles.
134
+ *
135
+ * `fillFraction` is how full it is, measured from the BOTTOM. The mean lift comes out as
136
+ * `H(1 − f/2)`, which is worth reading twice: a FULL tank has the lowest mean lift of all, `H/2`,
137
+ * because most of its water is near the bottom where there is a lot of water and the top layers cost
138
+ * almost nothing. A quarter-full tank lifts its water `7H/8` on average, because all of it is at the
139
+ * bottom and all of it has nearly the whole height to travel. The emptier the tank, the harder each
140
+ * kilogram is to get out.
141
+ */
142
+ function columnDrain(height, crossSection, fillFraction = 1, density = 1e3, g = G_EARTH, sf = 4) {
143
+ if (fillFraction <= 0 || fillFraction > 1) throw new Error("The fill fraction is how full the container is, measured from the bottom, and lies between 0 and 1.");
144
+ const filled = height * fillFraction;
145
+ const mass = density * crossSection * filled;
146
+ const s = sweep({
147
+ element: "rho*g*A*(H - y)",
148
+ variable: "y",
149
+ from: "0",
150
+ to: "filled"
151
+ }, {
152
+ rho: density,
153
+ g,
154
+ A: crossSection,
155
+ H: height,
156
+ filled
157
+ });
158
+ const value = s.total;
159
+ const meanLift = mass === 0 ? 0 : value / (mass * g);
160
+ const naiveValue = mass * g * height;
161
+ return {
162
+ mass,
163
+ meanLift,
164
+ value,
165
+ naiveValue,
166
+ sweep: s,
167
+ worked: calc().step("dm = \\rho A\\,dy", "slice the liquid into thin horizontal layers. Each layer is its own little lifting problem").step("dW = dm\\,g(H - y) = \\rho g A (H - y)\\,dy", "the layer at height y still has (H - y) to climb before it clears the rim").step(`W = \\int_{0}^{${texSigFigs(filled, sf)}} \\rho g A (H - y)\\,dy = ${texSigFigs(value, sf)}\\ \\mathrm{J}`, "add up every layer. The lower layers dominate, because there is just as much of them and they travel further").step(`\\bar{h} = \\frac{W}{mg} = ${texSigFigs(meanLift, sf)}\\ \\mathrm{m} = H\\left(1 - \\frac{f}{2}\\right)`, "the mean lift, which is the height the centre of mass of the liquid rose").step(`\\text{using } H \\text{ for every drop would give } ${texSigFigs(naiveValue, sf)}\\ \\mathrm{J}`, `a factor of ${texSigFigs(naiveValue / (value || 1), 3)} too big. This is the standard wrong answer in this family`).done(value)
168
+ };
169
+ }
170
+ /**
171
+ * The mean lift alone, for feeding into {@link pumpPower}.
172
+ *
173
+ * A well being pumped dry is the `fillFraction = 1` case, where the mean lift is half the depth. It
174
+ * is its own named function because that is the number a power question needs and because writing
175
+ * `depth / 2` inline in a pump calculation is how the reasoning gets lost.
176
+ */
177
+ const meanLiftToRim = (height, fillFraction = 1) => height * (1 - fillFraction / 2);
178
+
179
+ //#endregion
180
+ export { centreOfMassLift, chainLift, columnDrain, meanLiftToRim, stackColumn, standBlockOnEnd, tiltRod };
@@ -0,0 +1,81 @@
1
+ import { Worked } from "../../core/worked.mjs";
2
+
3
+ //#region src/physics/energy/conservation.d.ts
4
+ interface Station {
5
+ readonly label: string;
6
+ /** Height above the chosen reference level, metres. */
7
+ readonly height: number;
8
+ /** Speed at this station, metres per second. */
9
+ readonly speed: number;
10
+ }
11
+ interface Rung {
12
+ readonly label: string;
13
+ readonly kinetic: number;
14
+ readonly potential: number;
15
+ readonly total: number;
16
+ /** Mechanical energy lost since the PREVIOUS station. Zero at the first, and never negative. */
17
+ readonly lostSincePrevious: number;
18
+ }
19
+ interface Ladder {
20
+ readonly rungs: readonly Rung[];
21
+ readonly totalLost: number;
22
+ /** True when the total held to within tolerance across every station. */
23
+ readonly conserved: boolean;
24
+ readonly worked: Worked;
25
+ }
26
+ /**
27
+ * Track the two piles of energy across a journey.
28
+ *
29
+ * The tolerance is relative to the largest total, for the same reason it is in `isBalanced`: a
30
+ * shortfall of a millijoule is nothing in a roller coaster and is everything in a pendulum swinging
31
+ * in a lecture demonstration.
32
+ */
33
+ declare function energyLadder(mass: number, stations: readonly Station[], g?: number, sf?: number): Ladder;
34
+ /**
35
+ * The speed reached after falling through a height, from energy: `v = √(2gh)`.
36
+ *
37
+ * The mass cancels, which is the point and is the same fact that makes a feather and a hammer land
38
+ * together on the Moon. The path does not appear at all, which is the harder and more useful point:
39
+ * this is the speed at the bottom of a slide, a curved ramp, or a swing, not only of a vertical drop.
40
+ */
41
+ declare function speedAfterDrop(height: number, g?: number, sf?: number): Worked;
42
+ /** The height a body of known kinetic energy fell from: the drop run backwards. */
43
+ declare function dropForKinetic(mass: number, kinetic: number, g?: number, sf?: number): Worked;
44
+ /**
45
+ * Where on a fall the potential and kinetic energies stand in a given ratio.
46
+ *
47
+ * Their Example-19 asks where the potential energy is twice the kinetic during a 300 m fall, and it
48
+ * is a good question because the mass and `g` both cancel and the answer is a pure fraction of the
49
+ * height. `ratio` is potential-to-kinetic, so 2 means "potential is twice kinetic".
50
+ *
51
+ * Returns the height ABOVE THE GROUND, which is what such a question asks for, rather than the
52
+ * distance fallen, which is what the algebra naturally produces. Confusing the two is the trap.
53
+ */
54
+ declare function heightWherePotentialIs(dropFrom: number, ratio: number, sf?: number): {
55
+ readonly heightAboveGround: number;
56
+ readonly distanceFallen: number;
57
+ readonly worked: Worked;
58
+ };
59
+ interface SwingResult {
60
+ /** How far the bob rose: `l(1 − cos θ)`. */
61
+ readonly rise: number;
62
+ /** Speed at the lowest point. */
63
+ readonly speed: number;
64
+ /** Horizontal distance of the bob from the vertical through the pivot, at the extreme. */
65
+ readonly offset: number;
66
+ readonly worked: Worked;
67
+ }
68
+ /**
69
+ * A pendulum released from an angle: how high the bob started, and how fast it passes the bottom.
70
+ *
71
+ * `h = l(1 − cos θ)` is the only real content, and it is geometry rather than physics. The bob hangs
72
+ * `l cos θ` below the pivot at the extreme and `l` below it at the bottom, so it fell the difference.
73
+ * Learners who memorise `l(1 − cos θ)` without that picture reliably write `l sin θ`, which is the
74
+ * sideways offset and is also returned here so the two can be seen side by side and never confused
75
+ * again.
76
+ */
77
+ declare function pendulumSwing(length: number, releaseAngleDeg: number, g?: number, sf?: number): SwingResult;
78
+ /** The angle a pendulum must be released from to pass the bottom at a stated speed. */
79
+ declare function releaseAngleForSpeed(length: number, speed: number, g?: number, sf?: number): Worked;
80
+ //#endregion
81
+ export { Ladder, Rung, Station, SwingResult, dropForKinetic, energyLadder, heightWherePotentialIs, pendulumSwing, releaseAngleForSpeed, speedAfterDrop };
@@ -0,0 +1,129 @@
1
+ import { calc, texSigFigs } from "../../core/worked.mjs";
2
+ import { toDegrees, toRadians } from "../vectors.mjs";
3
+ import { G_EARTH } from "../kinematics/free-fall.mjs";
4
+
5
+ //#region src/physics/energy/conservation.ts
6
+ /**
7
+ * Conservation of mechanical energy: the accountant's view of motion.
8
+ *
9
+ * Everything here could be done with SUVAT instead, and for a straight drop it would be no harder.
10
+ * The reason to reach for energy is that energy DOES NOT CARE ABOUT THE PATH. A bead on a wire, a
11
+ * pendulum bob, a ball down a curved slide: the speed at the bottom depends on the drop and on
12
+ * nothing else, and no kinematic equation will tell you that because the acceleration is changing
13
+ * direction the whole way down. That is the aha, and it is why a pendulum is the standard first
14
+ * example rather than a dropped stone.
15
+ *
16
+ * THE ENERGY LADDER is the model this module returns. A journey is a list of stations; at each one
17
+ * the energy is split between a kinetic pile and a potential pile, and if the total shrinks from one
18
+ * station to the next, that shortfall went somewhere and can be named. Setting a problem out this
19
+ * way turns "where did the energy go" from a rhetorical question into a column you can read.
20
+ *
21
+ * Pure: no React, no pixels.
22
+ */
23
+ /**
24
+ * Track the two piles of energy across a journey.
25
+ *
26
+ * The tolerance is relative to the largest total, for the same reason it is in `isBalanced`: a
27
+ * shortfall of a millijoule is nothing in a roller coaster and is everything in a pendulum swinging
28
+ * in a lecture demonstration.
29
+ */
30
+ function energyLadder(mass, stations, g = G_EARTH, sf = 3) {
31
+ if (stations.length === 0) throw new Error("A ladder with no stations describes no journey.");
32
+ const rungs = [];
33
+ let previousTotal = null;
34
+ for (const s of stations) {
35
+ const kinetic = .5 * mass * s.speed * s.speed;
36
+ const potential = mass * g * s.height;
37
+ const total = kinetic + potential;
38
+ const lostSincePrevious = previousTotal === null ? 0 : Math.max(0, previousTotal - total);
39
+ rungs.push({
40
+ label: s.label,
41
+ kinetic,
42
+ potential,
43
+ total,
44
+ lostSincePrevious
45
+ });
46
+ previousTotal = total;
47
+ }
48
+ const largest = rungs.reduce((m, r) => Math.max(m, Math.abs(r.total)), 0);
49
+ const totalLost = rungs.reduce((sum, r) => sum + r.lostSincePrevious, 0);
50
+ const conserved = totalLost <= Math.max(largest, 1) * 1e-9;
51
+ const w = calc().step("E_k + E_p = \\text{constant}", "true only when nothing takes energy out. Any shortfall between two stations is the measure of what did");
52
+ for (const r of rungs) w.step(`\\text{${r.label}}: E_k = ${texSigFigs(r.kinetic, sf)},\\ E_p = ${texSigFigs(r.potential, sf)},\\ \\text{total} = ${texSigFigs(r.total, sf)}\\ \\mathrm{J}`, r.lostSincePrevious > 0 ? `${texSigFigs(r.lostSincePrevious, sf)} J went missing since the last station` : void 0);
53
+ w.step(conserved ? "\\text{total unchanged throughout}" : `\\text{lost} = ${texSigFigs(totalLost, sf)}\\ \\mathrm{J}`, conserved ? "mechanical energy was conserved, so the journey was smooth and nothing was pushed" : "this did not vanish. It became heat, sound, or deformation, and naming which is part of the answer");
54
+ return {
55
+ rungs,
56
+ totalLost,
57
+ conserved,
58
+ worked: w.done(totalLost)
59
+ };
60
+ }
61
+ /**
62
+ * The speed reached after falling through a height, from energy: `v = √(2gh)`.
63
+ *
64
+ * The mass cancels, which is the point and is the same fact that makes a feather and a hammer land
65
+ * together on the Moon. The path does not appear at all, which is the harder and more useful point:
66
+ * this is the speed at the bottom of a slide, a curved ramp, or a swing, not only of a vertical drop.
67
+ */
68
+ function speedAfterDrop(height, g = G_EARTH, sf = 3) {
69
+ if (height < 0) throw new Error("A negative drop is a rise, and a body does not gain speed rising.");
70
+ const value = Math.sqrt(2 * g * height);
71
+ return calc().step("mgh = \\tfrac{1}{2}mv^2", "all the potential energy given up becomes kinetic energy").step("v = \\sqrt{2gh}", "the mass cancels from both sides, so a heavy body and a light one arrive at the same speed").step(`v = \\sqrt{2 \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m\\,s^{-1}}`, "and the shape of the path never entered the working, so this is the speed at the bottom of any smooth route down").done(value);
72
+ }
73
+ /** The height a body of known kinetic energy fell from: the drop run backwards. */
74
+ function dropForKinetic(mass, kinetic, g = G_EARTH, sf = 3) {
75
+ const value = kinetic / (mass * g);
76
+ return calc().step("mgh = E_k \\Rightarrow h = \\frac{E_k}{mg}").step(`h = \\frac{${texSigFigs(kinetic, sf)}}{${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m}`).done(value);
77
+ }
78
+ /**
79
+ * Where on a fall the potential and kinetic energies stand in a given ratio.
80
+ *
81
+ * Their Example-19 asks where the potential energy is twice the kinetic during a 300 m fall, and it
82
+ * is a good question because the mass and `g` both cancel and the answer is a pure fraction of the
83
+ * height. `ratio` is potential-to-kinetic, so 2 means "potential is twice kinetic".
84
+ *
85
+ * Returns the height ABOVE THE GROUND, which is what such a question asks for, rather than the
86
+ * distance fallen, which is what the algebra naturally produces. Confusing the two is the trap.
87
+ */
88
+ function heightWherePotentialIs(dropFrom, ratio, sf = 3) {
89
+ if (ratio <= 0) throw new Error("A ratio of potential to kinetic energy must be positive during a fall.");
90
+ const distanceFallen = dropFrom / (ratio + 1);
91
+ const heightAboveGround = dropFrom - distanceFallen;
92
+ return {
93
+ heightAboveGround,
94
+ distanceFallen,
95
+ worked: calc().step("E_k = mgx, \\quad E_p = mg(h - x)", "after falling x, the energy given up is mgx and what is left of the store is mg(h - x)").step(`\\frac{E_p}{E_k} = \\frac{h - x}{x} = ${texSigFigs(ratio, sf)}`, "the mass and g cancel, so the answer is a pure fraction of the height and holds for any body").step(`x = \\frac{h}{${texSigFigs(ratio, sf)} + 1} = \\frac{${texSigFigs(dropFrom, sf)}}{${texSigFigs(ratio + 1, sf)}} = ${texSigFigs(distanceFallen, sf)}\\ \\mathrm{m}`, "this is the distance FALLEN").step(`h - x = ${texSigFigs(heightAboveGround, sf)}\\ \\mathrm{m}`, "and this is the height above the ground, which is what the question asked for. Stopping one line early is the trap").done(heightAboveGround)
96
+ };
97
+ }
98
+ /**
99
+ * A pendulum released from an angle: how high the bob started, and how fast it passes the bottom.
100
+ *
101
+ * `h = l(1 − cos θ)` is the only real content, and it is geometry rather than physics. The bob hangs
102
+ * `l cos θ` below the pivot at the extreme and `l` below it at the bottom, so it fell the difference.
103
+ * Learners who memorise `l(1 − cos θ)` without that picture reliably write `l sin θ`, which is the
104
+ * sideways offset and is also returned here so the two can be seen side by side and never confused
105
+ * again.
106
+ */
107
+ function pendulumSwing(length, releaseAngleDeg, g = G_EARTH, sf = 4) {
108
+ const rad = toRadians(releaseAngleDeg);
109
+ const rise = length * (1 - Math.cos(rad));
110
+ const offset = length * Math.sin(rad);
111
+ const speed = Math.sqrt(2 * g * rise);
112
+ return {
113
+ rise,
114
+ speed,
115
+ offset,
116
+ worked: calc().step("h = l - l\\cos\\theta = l(1 - \\cos\\theta)", "at the extreme the bob hangs l cos theta below the pivot; at the bottom it hangs l below. It fell the difference").step(`h = ${texSigFigs(length, sf)}(1 - \\cos ${texSigFigs(releaseAngleDeg, sf)}^\\circ) = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`l\\sin\\theta = ${texSigFigs(offset, sf)}\\ \\mathrm{m}`, "the SIDEWAYS offset, not the rise. Writing this into mgh is the standard slip").step("mgh = \\tfrac{1}{2}mv^2 \\Rightarrow v = \\sqrt{2gl(1 - \\cos\\theta)}", "the string tension does no work: it is always perpendicular to the motion, so it never appears").step(`v = ${texSigFigs(speed, sf)}\\ \\mathrm{m\\,s^{-1}}`, "at the lowest point of the swing").done(speed)
117
+ };
118
+ }
119
+ /** The angle a pendulum must be released from to pass the bottom at a stated speed. */
120
+ function releaseAngleForSpeed(length, speed, g = G_EARTH, sf = 3) {
121
+ const rise = speed * speed / (2 * g);
122
+ const cos = 1 - rise / length;
123
+ if (cos < -1) throw new Error(`Reaching ${speed} m/s needs a drop of ${rise.toPrecision(3)} m, but a pendulum of length ${length} m can only ever drop ${(2 * length).toPrecision(3)} m, from straight up.`);
124
+ const value = toDegrees(Math.acos(cos));
125
+ return calc().step("h = \\frac{v^2}{2g}", "the drop the speed implies").step(`h = ${texSigFigs(rise, sf)}\\ \\mathrm{m}`).step(`\\cos\\theta = 1 - \\frac{h}{l} = 1 - \\frac{${texSigFigs(rise, sf)}}{${texSigFigs(length, sf)}} = ${texSigFigs(cos, sf)}`).step(`\\theta = ${texSigFigs(value, sf)}^\\circ`, "measured from the downward vertical").done(value);
126
+ }
127
+
128
+ //#endregion
129
+ export { dropForKinetic, energyLadder, heightWherePotentialIs, pendulumSwing, releaseAngleForSpeed, speedAfterDrop };
@@ -0,0 +1,90 @@
1
+ import { Worked } from "../../core/worked.mjs";
2
+
3
+ //#region src/physics/energy/power.d.ts
4
+ /** Mechanical (imperial) horsepower, 550 ft lb per second. What "h.p." means in a physics paper. */
5
+ declare const HORSEPOWER = 745.699872;
6
+ /** Metric horsepower (PS, cv), the one used in European car brochures. Not what exams mean. */
7
+ declare const HORSEPOWER_METRIC = 735.49875;
8
+ /** Watts to horsepower. */
9
+ declare const toHorsepower: (watts: number, unit?: number) => number;
10
+ /** `P = W/t`. */
11
+ declare function power(work: number, time: number, sf?: number): Worked;
12
+ /**
13
+ * `P = Fv`, the steady-speed form.
14
+ *
15
+ * Derived in the first step rather than quoted, because the derivation is the whole reason a learner
16
+ * can choose between the two forms instead of guessing.
17
+ */
18
+ declare function powerFromForceSpeed(force: number, speed: number, sf?: number): Worked;
19
+ /** The steady speed a stated power can sustain against a stated resisting force: `v = P/F`. */
20
+ declare function speedFromPower(availablePower: number, resistance: number, sf?: number): Worked;
21
+ interface EfficiencyResult {
22
+ /** As a fraction from 0 to 1. */
23
+ readonly fraction: number;
24
+ readonly percent: number;
25
+ /** Power (or energy) that did not do the wanted job. */
26
+ readonly wasted: number;
27
+ readonly worked: Worked;
28
+ }
29
+ /**
30
+ * Useful out over total in.
31
+ *
32
+ * The trap is not the arithmetic, it is which way up. "A motor is 90 per cent efficient and lifts
33
+ * water at 7.2 m" means the LIFTING is the 90 per cent and the electrical supply is the 100 per
34
+ * cent, so the useful output is `0.9 × input`, and dividing instead of multiplying gives an answer
35
+ * that is wrong by a factor of 1.23 and looks entirely reasonable.
36
+ */
37
+ declare function efficiency(usefulOutput: number, totalInput: number, sf?: number): EfficiencyResult;
38
+ /**
39
+ * Stages in series: the efficiencies MULTIPLY.
40
+ *
41
+ * An 80 per cent motor driving a 50 per cent crane is 40 per cent overall, not 65 and not 130. Each
42
+ * stage takes its cut of whatever reached it, which is why a long chain of quite good machines can
43
+ * still be dreadful end to end.
44
+ */
45
+ declare function chainEfficiency(stages: readonly number[], sf?: number): EfficiencyResult;
46
+ /** Useful output power from an input and an efficiency: the direction most questions need. */
47
+ declare function usefulOutput(inputPower: number, efficiencyFraction: number, sf?: number): Worked;
48
+ interface LiftingPower {
49
+ /** The force the machine must exert, newtons. */
50
+ readonly force: number;
51
+ /** Power at the load, before any efficiency is applied. */
52
+ readonly usefulPower: number;
53
+ /** Power the supply must deliver once the efficiency is taken into account. */
54
+ readonly inputPower: number;
55
+ readonly horsepower: number;
56
+ readonly worked: Worked;
57
+ }
58
+ /**
59
+ * A hoist or a lift cage raising a load at a steady speed, against a stated friction.
60
+ *
61
+ * Their Example-29, and the reason it is a good question is that it is `P = Fv` with a force that
62
+ * has to be ASSEMBLED first: the weight of the cage, the weight of the load, and the friction, all
63
+ * of which the motor must overcome at once. Getting the power right is easy; getting the force right
64
+ * is where the question lives.
65
+ */
66
+ declare function hoistPower(cageMass: number, loadMass: number, speed: number, friction?: number, g?: number, efficiencyFraction?: number, sf?: number): LiftingPower;
67
+ /**
68
+ * Pumping a mass of liquid through a mean lift, in a stated time.
69
+ *
70
+ * `meanLift` is deliberately a parameter and not computed from a depth, because THE MEAN LIFT IS THE
71
+ * WHOLE DIFFICULTY and it depends on the shape of what is being emptied. Pumping from a tank at a
72
+ * fixed level lifts every kilogram the same distance. Emptying a well lifts the top layer barely at
73
+ * all and the bottom layer the full depth, so the mean is the depth to the centre of mass of the
74
+ * water, which for a uniform column is half the depth. Getting that wrong is a factor of two, and it
75
+ * is the single most common error in this family of questions.
76
+ *
77
+ * `centreOfMassLift` and `columnDrain` in `centre-of-mass.ts` compute that mean for the standard
78
+ * shapes, and feed it here.
79
+ */
80
+ declare function pumpPower(mass: number, meanLift: number, time: number, g?: number, efficiencyFraction?: number, sf?: number): LiftingPower;
81
+ /**
82
+ * How much a machine of stated input power and efficiency can raise in a given time.
83
+ *
84
+ * Their Example-27 inverted into the form the question actually asks: kilograms per minute, given
85
+ * the motor rating. Worth having as its own function because the rearrangement puts `g` and `h` in
86
+ * the denominator, and a learner who rearranges under pressure tends to leave one of them upstairs.
87
+ */
88
+ declare function massRaisedInTime(inputPower: number, efficiencyFraction: number, height: number, time: number, g?: number, sf?: number): Worked;
89
+ //#endregion
90
+ export { EfficiencyResult, HORSEPOWER, HORSEPOWER_METRIC, LiftingPower, chainEfficiency, efficiency, hoistPower, massRaisedInTime, power, powerFromForceSpeed, pumpPower, speedFromPower, toHorsepower, usefulOutput };
@@ -0,0 +1,167 @@
1
+ import { calc, texSigFigs } from "../../core/worked.mjs";
2
+ import { G_EARTH } from "../kinematics/free-fall.mjs";
3
+
4
+ //#region src/physics/energy/power.ts
5
+ /**
6
+ * Power: the rate, not the amount, and the confusion that costs the most marks in this chapter.
7
+ *
8
+ * WORK AND POWER ARE NOT THE SAME KIND OF THING and a surprising number of wrong answers come from
9
+ * treating them as interchangeable. Carrying a load up four flights of stairs is the same WORK
10
+ * whether you stroll or sprint; sprinting is more POWER. A question that gives a time is almost
11
+ * always a power question, and a question that does not give a time cannot be one.
12
+ *
13
+ * THE TWO FORMS ARE THE SAME FORM.
14
+ *
15
+ * `P = W/t` and `P = Fv` look like separate facts and are one line apart: `W = Fd`, so
16
+ * `P = Fd/t = Fv`. Knowing that, the choice between them stops being a memory problem and becomes
17
+ * a question of which quantity you were handed. Given a time, use the first; given a steady speed,
18
+ * use the second.
19
+ *
20
+ * `P = Fv` also carries the answer to "why does a car have a top speed". At constant speed the
21
+ * engine's force exactly balances the resistance, and since `P = Fv` with `P` capped, the speed can
22
+ * only rise until the resistance has eaten the whole power budget.
23
+ *
24
+ * ABOUT HORSEPOWER. It is not an SI unit and there are two of them, which is exactly the sort of
25
+ * detail that turns a correct method into a wrong number. Both are defined here with their sizes,
26
+ * and {@link HORSEPOWER} is the mechanical one at 745.7 W, because that is the one every exam board
27
+ * in this market means when it prints "h.p.".
28
+ *
29
+ * Pure: no React, no pixels.
30
+ */
31
+ /** Mechanical (imperial) horsepower, 550 ft lb per second. What "h.p." means in a physics paper. */
32
+ const HORSEPOWER = 745.699872;
33
+ /** Metric horsepower (PS, cv), the one used in European car brochures. Not what exams mean. */
34
+ const HORSEPOWER_METRIC = 735.49875;
35
+ /** Watts to horsepower. */
36
+ const toHorsepower = (watts, unit = HORSEPOWER) => watts / unit;
37
+ /** `P = W/t`. */
38
+ function power(work, time, sf = 3) {
39
+ if (time <= 0) throw new Error("Power is work per unit time, and no time means no rate to report.");
40
+ const value = work / time;
41
+ return calc().step("P = \\frac{W}{t}", "power is a RATE. The same work done in half the time is twice the power").step(`P = \\frac{${texSigFigs(work, sf)}}{${texSigFigs(time, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).step(`= ${texSigFigs(toHorsepower(value), sf)}\\ \\mathrm{h.p.}`, "one horsepower is 745.7 W. Metric horsepower is 735.5 W, and picking the wrong one is worth about one per cent").done(value);
42
+ }
43
+ /**
44
+ * `P = Fv`, the steady-speed form.
45
+ *
46
+ * Derived in the first step rather than quoted, because the derivation is the whole reason a learner
47
+ * can choose between the two forms instead of guessing.
48
+ */
49
+ function powerFromForceSpeed(force, speed, sf = 3) {
50
+ const value = force * speed;
51
+ return calc().step("P = \\frac{W}{t} = \\frac{Fd}{t} = F\\frac{d}{t} = Fv", "not a second formula. It is P = W/t with W = Fd substituted and d/t recognised as the speed").step(`P = ${texSigFigs(force, sf)} \\times ${texSigFigs(speed, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).done(value);
52
+ }
53
+ /** The steady speed a stated power can sustain against a stated resisting force: `v = P/F`. */
54
+ function speedFromPower(availablePower, resistance, sf = 3) {
55
+ if (resistance <= 0) throw new Error("With no resistance the speed is not limited by the power, so it has no steady value.");
56
+ const value = availablePower / resistance;
57
+ return calc().step("P = Fv \\Rightarrow v = \\frac{P}{F}", "at a steady speed the driving force exactly balances the resistance, so F is the resistance").step(`v = \\frac{${texSigFigs(availablePower, sf)}}{${texSigFigs(resistance, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{m\\,s^{-1}}`, "this is the top speed: the resistance has absorbed the entire power budget, so nothing is left to accelerate with").done(value);
58
+ }
59
+ /**
60
+ * Useful out over total in.
61
+ *
62
+ * The trap is not the arithmetic, it is which way up. "A motor is 90 per cent efficient and lifts
63
+ * water at 7.2 m" means the LIFTING is the 90 per cent and the electrical supply is the 100 per
64
+ * cent, so the useful output is `0.9 × input`, and dividing instead of multiplying gives an answer
65
+ * that is wrong by a factor of 1.23 and looks entirely reasonable.
66
+ */
67
+ function efficiency(usefulOutput, totalInput, sf = 3) {
68
+ if (totalInput <= 0) throw new Error("Efficiency compares output with input, and there was no input.");
69
+ if (usefulOutput > totalInput) throw new Error(`A useful output of ${usefulOutput} cannot exceed an input of ${totalInput}. An efficiency above 100 per cent means the two have been divided the wrong way round, or a loss has been counted as an output.`);
70
+ const fraction = usefulOutput / totalInput;
71
+ const wasted = totalInput - usefulOutput;
72
+ const worked = calc().step("\\eta = \\frac{\\text{useful output}}{\\text{total input}}", "always a fraction below 1. If you get more than 1, the division is upside down").step(`\\eta = \\frac{${texSigFigs(usefulOutput, sf)}}{${texSigFigs(totalInput, sf)}} = ${texSigFigs(fraction, sf)} = ${texSigFigs(fraction * 100, sf)}\\%`).step(`\\text{wasted} = ${texSigFigs(wasted, sf)}`, "mostly heat. It is not destroyed, it is just no longer doing the job you wanted").done(fraction);
73
+ return {
74
+ fraction,
75
+ percent: fraction * 100,
76
+ wasted,
77
+ worked
78
+ };
79
+ }
80
+ /**
81
+ * Stages in series: the efficiencies MULTIPLY.
82
+ *
83
+ * An 80 per cent motor driving a 50 per cent crane is 40 per cent overall, not 65 and not 130. Each
84
+ * stage takes its cut of whatever reached it, which is why a long chain of quite good machines can
85
+ * still be dreadful end to end.
86
+ */
87
+ function chainEfficiency(stages, sf = 3) {
88
+ if (stages.length === 0) throw new Error("A chain with no stages has nothing to be efficient at.");
89
+ const fraction = stages.reduce((product, s) => product * s, 1);
90
+ const worked = calc().step("\\eta_{\\text{total}} = \\eta_1 \\times \\eta_2 \\times \\ldots", "each stage takes its cut of what reached it, so the fractions multiply. They never add and never average").step(`\\eta = ${stages.map((s) => texSigFigs(s, sf)).join(" \\times ")} = ${texSigFigs(fraction, sf)} = ${texSigFigs(fraction * 100, sf)}\\%`).done(fraction);
91
+ return {
92
+ fraction,
93
+ percent: fraction * 100,
94
+ wasted: 1 - fraction,
95
+ worked
96
+ };
97
+ }
98
+ /** Useful output power from an input and an efficiency: the direction most questions need. */
99
+ function usefulOutput(inputPower, efficiencyFraction, sf = 3) {
100
+ const value = inputPower * efficiencyFraction;
101
+ return calc().step("P_{\\text{out}} = \\eta P_{\\text{in}}", "the efficiency MULTIPLIES the input. Dividing gives more out than in, which is the giveaway").step(`P_{\\text{out}} = ${texSigFigs(efficiencyFraction, sf)} \\times ${texSigFigs(inputPower, sf)} = ${texSigFigs(value, sf)}\\ \\mathrm{W}`).done(value);
102
+ }
103
+ /**
104
+ * A hoist or a lift cage raising a load at a steady speed, against a stated friction.
105
+ *
106
+ * Their Example-29, and the reason it is a good question is that it is `P = Fv` with a force that
107
+ * has to be ASSEMBLED first: the weight of the cage, the weight of the load, and the friction, all
108
+ * of which the motor must overcome at once. Getting the power right is easy; getting the force right
109
+ * is where the question lives.
110
+ */
111
+ function hoistPower(cageMass, loadMass, speed, friction = 0, g = G_EARTH, efficiencyFraction = 1, sf = 4) {
112
+ const force = (cageMass + loadMass) * g + friction;
113
+ const usefulPowerValue = force * speed;
114
+ const inputPower = usefulPowerValue / efficiencyFraction;
115
+ const worked = calc().step("F = (m_{\\text{cage}} + m_{\\text{load}})g + f", "the motor holds up everything it is carrying AND beats the friction. Assembling this force is the actual question").step(`F = (${texSigFigs(cageMass, sf)} + ${texSigFigs(loadMass, sf)}) \\times ${texSigFigs(g, sf)} + ${texSigFigs(friction, sf)} = ${texSigFigs(force, sf)}\\ \\mathrm{N}`).step(`P = Fv = ${texSigFigs(force, sf)} \\times ${texSigFigs(speed, sf)} = ${texSigFigs(usefulPowerValue, sf)}\\ \\mathrm{W}`, "steady speed, so there is no acceleration term and the force is exactly what is resisting");
116
+ if (efficiencyFraction !== 1) worked.step(`P_{\\text{in}} = \\frac{P}{\\eta} = ${texSigFigs(inputPower, sf)}\\ \\mathrm{W}`, "the supply must deliver more than the load receives, because some is lost on the way");
117
+ return {
118
+ force,
119
+ usefulPower: usefulPowerValue,
120
+ inputPower,
121
+ horsepower: toHorsepower(inputPower),
122
+ worked: worked.done(inputPower)
123
+ };
124
+ }
125
+ /**
126
+ * Pumping a mass of liquid through a mean lift, in a stated time.
127
+ *
128
+ * `meanLift` is deliberately a parameter and not computed from a depth, because THE MEAN LIFT IS THE
129
+ * WHOLE DIFFICULTY and it depends on the shape of what is being emptied. Pumping from a tank at a
130
+ * fixed level lifts every kilogram the same distance. Emptying a well lifts the top layer barely at
131
+ * all and the bottom layer the full depth, so the mean is the depth to the centre of mass of the
132
+ * water, which for a uniform column is half the depth. Getting that wrong is a factor of two, and it
133
+ * is the single most common error in this family of questions.
134
+ *
135
+ * `centreOfMassLift` and `columnDrain` in `centre-of-mass.ts` compute that mean for the standard
136
+ * shapes, and feed it here.
137
+ */
138
+ function pumpPower(mass, meanLift, time, g = G_EARTH, efficiencyFraction = 1, sf = 4) {
139
+ if (time <= 0) throw new Error("Power is a rate, so the pumping has to take some time.");
140
+ const force = mass * g;
141
+ const work = force * meanLift;
142
+ const usefulPowerValue = work / time;
143
+ const inputPower = usefulPowerValue / efficiencyFraction;
144
+ const worked = calc().step("W = mg\\bar{h}", "h-bar is the MEAN lift, the distance the centre of mass of the liquid rose. Not the depth, unless every drop rose the same amount").step(`W = ${texSigFigs(mass, sf)} \\times ${texSigFigs(g, sf)} \\times ${texSigFigs(meanLift, sf)} = ${texSigFigs(work, sf)}\\ \\mathrm{J}`).step(`P = \\frac{W}{t} = \\frac{${texSigFigs(work, sf)}}{${texSigFigs(time, sf)}} = ${texSigFigs(usefulPowerValue, sf)}\\ \\mathrm{W}`).step(`= ${texSigFigs(toHorsepower(inputPower), sf)}\\ \\mathrm{h.p.}`, "dividing by 745.7 W. Using the depth instead of the mean lift here would double the answer").done(inputPower);
145
+ return {
146
+ force,
147
+ usefulPower: usefulPowerValue,
148
+ inputPower,
149
+ horsepower: toHorsepower(inputPower),
150
+ worked
151
+ };
152
+ }
153
+ /**
154
+ * How much a machine of stated input power and efficiency can raise in a given time.
155
+ *
156
+ * Their Example-27 inverted into the form the question actually asks: kilograms per minute, given
157
+ * the motor rating. Worth having as its own function because the rearrangement puts `g` and `h` in
158
+ * the denominator, and a learner who rearranges under pressure tends to leave one of them upstairs.
159
+ */
160
+ function massRaisedInTime(inputPower, efficiencyFraction, height, time, g = G_EARTH, sf = 4) {
161
+ const useful = inputPower * efficiencyFraction;
162
+ const value = useful * time / (g * height);
163
+ return calc().step("P_{\\text{useful}} = \\eta P_{\\text{in}} = \\frac{mgh}{t}", "only the useful share of the supply ends up in the load. The rest is lost in the machine").step(`P_{\\text{useful}} = ${texSigFigs(efficiencyFraction, sf)} \\times ${texSigFigs(inputPower, sf)} = ${texSigFigs(useful, sf)}\\ \\mathrm{W}`).step("m = \\frac{\\eta P_{\\text{in}} t}{gh}", "both g and h belong in the denominator. Dropping either is the usual rearrangement slip").step(`m = \\frac{${texSigFigs(useful, sf)} \\times ${texSigFigs(time, sf)}}{${texSigFigs(g, sf)} \\times ${texSigFigs(height, sf)}} = ${texSigFigs(value, sf)}\\ \\mathrm{kg}`).done(value);
164
+ }
165
+
166
+ //#endregion
167
+ export { HORSEPOWER, HORSEPOWER_METRIC, chainEfficiency, efficiency, hoistPower, massRaisedInTime, power, powerFromForceSpeed, pumpPower, speedFromPower, toHorsepower, usefulOutput };