@classytic/stage 0.3.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 (431) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  2. package/dist/atomic/aufbau.d.mts +144 -0
  3. package/dist/atomic/aufbau.mjs +384 -0
  4. package/dist/atomic/elements.d.mts +67 -0
  5. package/dist/atomic/elements.mjs +785 -0
  6. package/dist/atomic/emission.d.mts +112 -0
  7. package/dist/atomic/emission.mjs +179 -0
  8. package/dist/atomic/index.d.mts +8 -0
  9. package/dist/atomic/index.mjs +9 -0
  10. package/dist/atomic/periodic.d.mts +82 -0
  11. package/dist/atomic/periodic.mjs +231 -0
  12. package/dist/atomic/properties.d.mts +100 -0
  13. package/dist/atomic/properties.mjs +574 -0
  14. package/dist/atomic/shells.d.mts +137 -0
  15. package/dist/atomic/shells.mjs +170 -0
  16. package/dist/atomic/trends.d.mts +148 -0
  17. package/dist/atomic/trends.mjs +225 -0
  18. package/dist/chem/chromatography.d.mts +66 -0
  19. package/dist/chem/chromatography.mjs +63 -0
  20. package/dist/chem/complex.d.mts +114 -0
  21. package/dist/chem/complex.mjs +234 -0
  22. package/dist/chem/cycle.d.mts +75 -0
  23. package/dist/chem/cycle.mjs +145 -0
  24. package/dist/chem/equation.d.mts +86 -0
  25. package/dist/chem/equation.mjs +168 -0
  26. package/dist/chem/formula.d.mts +90 -0
  27. package/dist/chem/formula.mjs +201 -0
  28. package/dist/chem/functional-groups.d.mts +31 -0
  29. package/dist/chem/functional-groups.mjs +187 -0
  30. package/dist/chem/hazard.d.mts +94 -0
  31. package/dist/chem/hazard.mjs +329 -0
  32. package/dist/chem/index.d.mts +34 -33
  33. package/dist/chem/index.mjs +34 -28
  34. package/dist/chem/ionic.d.mts +98 -0
  35. package/dist/chem/ionic.mjs +156 -0
  36. package/dist/chem/layout.d.mts +46 -0
  37. package/dist/chem/layout.mjs +342 -0
  38. package/dist/chem/lewis.d.mts +79 -0
  39. package/dist/chem/lewis.mjs +163 -0
  40. package/dist/chem/molecular-orbital.d.mts +114 -0
  41. package/dist/chem/molecular-orbital.mjs +201 -0
  42. package/dist/chem/molecule.d.mts +154 -0
  43. package/dist/chem/molecule.mjs +282 -0
  44. package/dist/chem/nmr.d.mts +153 -0
  45. package/dist/chem/nmr.mjs +165 -0
  46. package/dist/chem/polymer.d.mts +65 -0
  47. package/dist/chem/polymer.mjs +179 -0
  48. package/dist/chem/redox.d.mts +138 -0
  49. package/dist/chem/redox.mjs +328 -0
  50. package/dist/chem/relations.d.mts +183 -0
  51. package/dist/chem/relations.mjs +299 -0
  52. package/dist/chem/skeleton.d.mts +51 -0
  53. package/dist/chem/skeleton.mjs +186 -0
  54. package/dist/chem/solution.d.mts +116 -0
  55. package/dist/chem/solution.mjs +186 -0
  56. package/dist/chem/species.d.mts +47 -0
  57. package/dist/chem/species.mjs +128 -0
  58. package/dist/chem/stereo.d.mts +108 -0
  59. package/dist/chem/stereo.mjs +286 -0
  60. package/dist/chem/stoichiometry.d.mts +95 -0
  61. package/dist/chem/stoichiometry.mjs +145 -0
  62. package/dist/chem/synthesis.d.mts +113 -0
  63. package/dist/chem/synthesis.mjs +281 -0
  64. package/dist/chem/vsepr.d.mts +80 -0
  65. package/dist/chem/vsepr.mjs +247 -0
  66. package/dist/circuit/ac.d.mts +163 -0
  67. package/dist/circuit/ac.mjs +452 -0
  68. package/dist/circuit/dc.d.mts +92 -0
  69. package/dist/circuit/dc.mjs +333 -0
  70. package/dist/circuit/index.d.mts +5 -92
  71. package/dist/circuit/index.mjs +5 -332
  72. package/dist/circuit/network.d.mts +99 -0
  73. package/dist/circuit/network.mjs +440 -0
  74. package/dist/circuit/topology.d.mts +102 -0
  75. package/dist/circuit/topology.mjs +143 -0
  76. package/dist/colour/absorption.d.mts +79 -0
  77. package/dist/colour/absorption.mjs +137 -0
  78. package/dist/colour/index.d.mts +6 -0
  79. package/dist/colour/index.mjs +7 -0
  80. package/dist/colour/name.d.mts +14 -0
  81. package/dist/colour/name.mjs +76 -0
  82. package/dist/colour/observer.d.mts +31 -0
  83. package/dist/colour/observer.mjs +46 -0
  84. package/dist/colour/spectrum.d.mts +61 -0
  85. package/dist/colour/spectrum.mjs +108 -0
  86. package/dist/colour/srgb.d.mts +49 -0
  87. package/dist/colour/srgb.mjs +108 -0
  88. package/dist/core/constants.d.mts +138 -0
  89. package/dist/core/constants.mjs +139 -0
  90. package/dist/core/index.d.mts +3 -1
  91. package/dist/core/index.mjs +3 -1
  92. package/dist/core/vec3.d.mts +94 -0
  93. package/dist/core/vec3.mjs +123 -0
  94. package/dist/core/worked.d.mts +35 -0
  95. package/dist/core/worked.mjs +44 -0
  96. package/dist/electro/cell.d.mts +102 -0
  97. package/dist/electro/cell.mjs +170 -0
  98. package/dist/electro/conductivity.d.mts +157 -0
  99. package/dist/electro/conductivity.mjs +156 -0
  100. package/dist/electro/couples.d.mts +114 -0
  101. package/dist/electro/couples.mjs +334 -0
  102. package/dist/electro/electrolysis.d.mts +96 -0
  103. package/dist/electro/electrolysis.mjs +274 -0
  104. package/dist/electro/faraday.d.mts +150 -0
  105. package/dist/electro/faraday.mjs +118 -0
  106. package/dist/electro/index.d.mts +6 -0
  107. package/dist/electro/index.mjs +7 -0
  108. package/dist/finance/accounting/adjustments.d.mts +17 -0
  109. package/dist/finance/accounting/adjustments.mjs +202 -0
  110. package/dist/finance/accounting/analysis.d.mts +8 -0
  111. package/dist/finance/accounting/analysis.mjs +205 -0
  112. package/dist/finance/accounting/clubs.d.mts +21 -0
  113. package/dist/finance/accounting/clubs.mjs +217 -0
  114. package/dist/finance/accounting/company-statements.d.mts +7 -0
  115. package/dist/finance/accounting/company-statements.mjs +150 -0
  116. package/dist/finance/accounting/harness.d.mts +7 -0
  117. package/dist/finance/accounting/harness.mjs +45 -0
  118. package/dist/finance/accounting/index.d.mts +18 -0
  119. package/dist/finance/accounting/index.mjs +18 -0
  120. package/dist/finance/accounting/journalize.d.mts +16 -0
  121. package/dist/finance/accounting/journalize.mjs +128 -0
  122. package/dist/finance/accounting/manufacturing.d.mts +8 -0
  123. package/dist/finance/accounting/manufacturing.mjs +236 -0
  124. package/dist/finance/accounting/partnership.d.mts +7 -0
  125. package/dist/finance/accounting/partnership.mjs +152 -0
  126. package/dist/finance/accounting/period-case.d.mts +6 -0
  127. package/dist/finance/accounting/period-case.mjs +71 -0
  128. package/dist/finance/accounting/post.d.mts +9 -0
  129. package/dist/finance/accounting/post.mjs +84 -0
  130. package/dist/finance/accounting/precision.d.mts +9 -0
  131. package/dist/finance/accounting/precision.mjs +15 -0
  132. package/dist/finance/accounting/rules.d.mts +21 -0
  133. package/dist/finance/accounting/rules.mjs +37 -0
  134. package/dist/finance/accounting/solve.d.mts +28 -0
  135. package/dist/finance/accounting/solve.mjs +92 -0
  136. package/dist/finance/accounting/statements.d.mts +7 -0
  137. package/dist/finance/accounting/statements.mjs +142 -0
  138. package/dist/finance/accounting/types.d.mts +649 -0
  139. package/dist/finance/accounting/validate.d.mts +7 -0
  140. package/dist/finance/accounting/validate.mjs +67 -0
  141. package/dist/finance/accounting/verification.d.mts +24 -0
  142. package/dist/finance/accounting/verification.mjs +386 -0
  143. package/dist/finance/bizsim.d.mts +21 -39
  144. package/dist/finance/bizsim.mjs +276 -97
  145. package/dist/finance/index.d.mts +20 -43
  146. package/dist/finance/index.mjs +19 -77
  147. package/dist/finance/investment-math.d.mts +7 -0
  148. package/dist/finance/investment-math.mjs +18 -0
  149. package/dist/finance/management-accounting/budgeting.d.mts +7 -0
  150. package/dist/finance/management-accounting/budgeting.mjs +189 -0
  151. package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
  152. package/dist/finance/management-accounting/cash-budget.mjs +154 -0
  153. package/dist/finance/management-accounting/costing.d.mts +8 -0
  154. package/dist/finance/management-accounting/costing.mjs +175 -0
  155. package/dist/finance/management-accounting/decisions.d.mts +8 -0
  156. package/dist/finance/management-accounting/decisions.mjs +164 -0
  157. package/dist/finance/management-accounting/index.d.mts +13 -0
  158. package/dist/finance/management-accounting/index.mjs +13 -0
  159. package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
  160. package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
  161. package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
  162. package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
  163. package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
  164. package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
  165. package/dist/finance/management-accounting/management-case.d.mts +8 -0
  166. package/dist/finance/management-accounting/management-case.mjs +91 -0
  167. package/dist/finance/management-accounting/master-budget.d.mts +7 -0
  168. package/dist/finance/management-accounting/master-budget.mjs +137 -0
  169. package/dist/finance/management-accounting/production-costing.d.mts +8 -0
  170. package/dist/finance/management-accounting/production-costing.mjs +214 -0
  171. package/dist/finance/management-accounting/types.d.mts +644 -0
  172. package/dist/finance/management-accounting/variances.d.mts +7 -0
  173. package/dist/finance/management-accounting/variances.mjs +150 -0
  174. package/dist/index.d.mts +6 -6
  175. package/dist/index.mjs +1 -1
  176. package/dist/math/analysis.d.mts +61 -0
  177. package/dist/math/analysis.mjs +187 -0
  178. package/dist/math/answer-check.d.mts +50 -0
  179. package/dist/math/answer-check.mjs +106 -0
  180. package/dist/math/calculus.d.mts +4 -9
  181. package/dist/math/calculus.mjs +216 -7
  182. package/dist/math/complex.d.mts +93 -0
  183. package/dist/math/complex.mjs +239 -0
  184. package/dist/math/expr.d.mts +23 -0
  185. package/dist/math/expr.mjs +36 -0
  186. package/dist/math/index.d.mts +8 -22
  187. package/dist/math/index.mjs +8 -37
  188. package/dist/math/latex.mjs +2 -1
  189. package/dist/math/parse.mjs +1 -1
  190. package/dist/math/poly.d.mts +55 -0
  191. package/dist/math/poly.mjs +273 -0
  192. package/dist/math/rearrange.d.mts +14 -0
  193. package/dist/math/rearrange.mjs +125 -0
  194. package/dist/math/solve.d.mts +21 -0
  195. package/dist/math/solve.mjs +75 -0
  196. package/dist/networking/addressing.d.mts +26 -0
  197. package/dist/networking/addressing.mjs +33 -0
  198. package/dist/networking/cloud/access.d.mts +36 -0
  199. package/dist/networking/cloud/access.mjs +95 -0
  200. package/dist/networking/cloud/containers.d.mts +43 -0
  201. package/dist/networking/cloud/containers.mjs +54 -0
  202. package/dist/networking/cloud/edge.d.mts +17 -0
  203. package/dist/networking/cloud/edge.mjs +31 -0
  204. package/dist/networking/cloud/failure-domains.d.mts +19 -0
  205. package/dist/networking/cloud/failure-domains.mjs +22 -0
  206. package/dist/networking/cloud/geo-routing.d.mts +22 -0
  207. package/dist/networking/cloud/geo-routing.mjs +64 -0
  208. package/dist/networking/cloud/index.d.mts +18 -0
  209. package/dist/networking/cloud/index.mjs +19 -0
  210. package/dist/networking/cloud/inference-reliability.d.mts +30 -0
  211. package/dist/networking/cloud/inference-reliability.mjs +76 -0
  212. package/dist/networking/cloud/inference.d.mts +118 -0
  213. package/dist/networking/cloud/inference.mjs +179 -0
  214. package/dist/networking/cloud/infrastructure.d.mts +45 -0
  215. package/dist/networking/cloud/infrastructure.mjs +96 -0
  216. package/dist/networking/cloud/observability.d.mts +24 -0
  217. package/dist/networking/cloud/observability.mjs +34 -0
  218. package/dist/networking/cloud/orchestration.d.mts +32 -0
  219. package/dist/networking/cloud/orchestration.mjs +38 -0
  220. package/dist/networking/cloud/recovery.d.mts +21 -0
  221. package/dist/networking/cloud/recovery.mjs +27 -0
  222. package/dist/networking/cloud/releases.d.mts +42 -0
  223. package/dist/networking/cloud/releases.mjs +135 -0
  224. package/dist/networking/cloud/scaling.d.mts +25 -0
  225. package/dist/networking/cloud/scaling.mjs +65 -0
  226. package/dist/networking/cloud/secrets.d.mts +39 -0
  227. package/dist/networking/cloud/secrets.mjs +68 -0
  228. package/dist/networking/cloud/server-deployment.d.mts +29 -0
  229. package/dist/networking/cloud/server-deployment.mjs +72 -0
  230. package/dist/networking/cloud/storage.d.mts +16 -0
  231. package/dist/networking/cloud/storage.mjs +58 -0
  232. package/dist/networking/cloud/vpc.d.mts +18 -0
  233. package/dist/networking/cloud/vpc.mjs +100 -0
  234. package/dist/networking/delivery.d.mts +34 -0
  235. package/dist/networking/delivery.mjs +52 -0
  236. package/dist/networking/index.d.mts +47 -0
  237. package/dist/networking/index.mjs +47 -0
  238. package/dist/networking/ipv6.d.mts +28 -0
  239. package/dist/networking/ipv6.mjs +17 -0
  240. package/dist/networking/journeys.d.mts +83 -0
  241. package/dist/networking/journeys.mjs +161 -0
  242. package/dist/networking/models/airtime.d.mts +87 -0
  243. package/dist/networking/models/airtime.mjs +130 -0
  244. package/dist/networking/models/cellular.d.mts +157 -0
  245. package/dist/networking/models/cellular.mjs +252 -0
  246. package/dist/networking/models/encapsulation.d.mts +98 -0
  247. package/dist/networking/models/encapsulation.mjs +132 -0
  248. package/dist/networking/models/handover.d.mts +116 -0
  249. package/dist/networking/models/handover.mjs +209 -0
  250. package/dist/networking/models/handshake.d.mts +90 -0
  251. package/dist/networking/models/handshake.mjs +122 -0
  252. package/dist/networking/models/index.d.mts +14 -0
  253. package/dist/networking/models/index.mjs +15 -0
  254. package/dist/networking/models/media.d.mts +82 -0
  255. package/dist/networking/models/media.mjs +188 -0
  256. package/dist/networking/models/satellite.d.mts +86 -0
  257. package/dist/networking/models/satellite.mjs +121 -0
  258. package/dist/networking/models/spectrum.d.mts +83 -0
  259. package/dist/networking/models/spectrum.mjs +235 -0
  260. package/dist/networking/models/switch.d.mts +80 -0
  261. package/dist/networking/models/switch.mjs +155 -0
  262. package/dist/networking/models/vlan.d.mts +62 -0
  263. package/dist/networking/models/vlan.mjs +100 -0
  264. package/dist/networking/models/vpn.d.mts +66 -0
  265. package/dist/networking/models/vpn.mjs +125 -0
  266. package/dist/networking/models/wifi-privacy.d.mts +82 -0
  267. package/dist/networking/models/wifi-privacy.mjs +130 -0
  268. package/dist/networking/models/wifi.d.mts +240 -0
  269. package/dist/networking/models/wifi.mjs +562 -0
  270. package/dist/networking/nat-traversal.d.mts +24 -0
  271. package/dist/networking/nat-traversal.mjs +38 -0
  272. package/dist/networking/protocols.d.mts +17 -0
  273. package/dist/networking/protocols.mjs +57 -0
  274. package/dist/networking/queue.d.mts +12 -0
  275. package/dist/networking/queue.mjs +18 -0
  276. package/dist/networking/route-learning.d.mts +23 -0
  277. package/dist/networking/route-learning.mjs +43 -0
  278. package/dist/networking/routing.d.mts +11 -0
  279. package/dist/networking/routing.mjs +25 -0
  280. package/dist/networking/signals.d.mts +26 -0
  281. package/dist/networking/signals.mjs +35 -0
  282. package/dist/networking/subnet.d.mts +49 -0
  283. package/dist/networking/subnet.mjs +89 -0
  284. package/dist/networking/tcp-reliability.d.mts +24 -0
  285. package/dist/networking/tcp-reliability.mjs +38 -0
  286. package/dist/networking/topology/contract.d.mts +123 -0
  287. package/dist/networking/topology/index.d.mts +4 -0
  288. package/dist/networking/topology/index.mjs +4 -0
  289. package/dist/networking/topology/presets.d.mts +7 -0
  290. package/dist/networking/topology/presets.mjs +302 -0
  291. package/dist/networking/topology/simulation.d.mts +8 -0
  292. package/dist/networking/topology/simulation.mjs +179 -0
  293. package/dist/networking/wireless.d.mts +11 -0
  294. package/dist/networking/wireless.mjs +17 -0
  295. package/dist/optics/imaging.d.mts +218 -0
  296. package/dist/optics/imaging.mjs +276 -0
  297. package/dist/optics/index.d.mts +7 -0
  298. package/dist/optics/index.mjs +8 -0
  299. package/dist/optics/laws.d.mts +70 -0
  300. package/dist/optics/laws.mjs +195 -0
  301. package/dist/optics/prism.d.mts +148 -0
  302. package/dist/optics/prism.mjs +197 -0
  303. package/dist/optics/refraction.d.mts +201 -0
  304. package/dist/optics/refraction.mjs +270 -0
  305. package/dist/optics/wave-optics.d.mts +171 -0
  306. package/dist/optics/wave-optics.mjs +259 -0
  307. package/dist/physics/ac/index.d.mts +183 -0
  308. package/dist/physics/ac/index.mjs +203 -0
  309. package/dist/physics/dynamics/forces.d.mts +98 -0
  310. package/dist/physics/dynamics/forces.mjs +153 -0
  311. package/dist/physics/dynamics/friction.d.mts +76 -0
  312. package/dist/physics/dynamics/friction.mjs +119 -0
  313. package/dist/physics/dynamics/system.d.mts +68 -0
  314. package/dist/physics/dynamics/system.mjs +125 -0
  315. package/dist/physics/electrostatics/index.d.mts +169 -0
  316. package/dist/physics/electrostatics/index.mjs +249 -0
  317. package/dist/physics/energy/centre-of-mass.d.mts +115 -0
  318. package/dist/physics/energy/centre-of-mass.mjs +180 -0
  319. package/dist/physics/energy/conservation.d.mts +81 -0
  320. package/dist/physics/energy/conservation.mjs +129 -0
  321. package/dist/physics/energy/power.d.mts +90 -0
  322. package/dist/physics/energy/power.mjs +167 -0
  323. package/dist/physics/energy/spring.d.mts +73 -0
  324. package/dist/physics/energy/spring.mjs +129 -0
  325. package/dist/physics/energy/store.d.mts +63 -0
  326. package/dist/physics/energy/store.mjs +108 -0
  327. package/dist/physics/energy/theorem.d.mts +65 -0
  328. package/dist/physics/energy/theorem.mjs +113 -0
  329. package/dist/physics/energy/work.d.mts +114 -0
  330. package/dist/physics/energy/work.mjs +219 -0
  331. package/dist/physics/gravitation/body.d.mts +85 -0
  332. package/dist/physics/gravitation/body.mjs +168 -0
  333. package/dist/physics/gravitation/kepler.d.mts +127 -0
  334. package/dist/physics/gravitation/kepler.mjs +216 -0
  335. package/dist/physics/gravitation/law.d.mts +117 -0
  336. package/dist/physics/gravitation/law.mjs +175 -0
  337. package/dist/physics/gravitation/orbit.d.mts +119 -0
  338. package/dist/physics/gravitation/orbit.mjs +202 -0
  339. package/dist/physics/gravitation/potential.d.mts +114 -0
  340. package/dist/physics/gravitation/potential.mjs +202 -0
  341. package/dist/physics/gravitation/variation.d.mts +97 -0
  342. package/dist/physics/gravitation/variation.mjs +175 -0
  343. package/dist/physics/index.d.mts +35 -0
  344. package/dist/physics/index.mjs +36 -0
  345. package/dist/physics/integral-sweep.d.mts +63 -0
  346. package/dist/physics/integral-sweep.mjs +126 -0
  347. package/dist/physics/kinematics/equations.d.mts +47 -0
  348. package/dist/physics/kinematics/equations.mjs +126 -0
  349. package/dist/physics/kinematics/free-fall.d.mts +53 -0
  350. package/dist/physics/kinematics/free-fall.mjs +71 -0
  351. package/dist/physics/kinematics/given.d.mts +16 -0
  352. package/dist/physics/kinematics/given.mjs +55 -0
  353. package/dist/physics/kinematics/roots.d.mts +41 -0
  354. package/dist/physics/kinematics/roots.mjs +72 -0
  355. package/dist/physics/kinematics/solve.d.mts +52 -0
  356. package/dist/physics/kinematics/solve.mjs +172 -0
  357. package/dist/physics/magnetism/biot-savart.d.mts +161 -0
  358. package/dist/physics/magnetism/biot-savart.mjs +353 -0
  359. package/dist/physics/magnetism/flux.d.mts +94 -0
  360. package/dist/physics/magnetism/flux.mjs +313 -0
  361. package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
  362. package/dist/physics/magnetism/geomagnetism.mjs +184 -0
  363. package/dist/physics/magnetism/index.d.mts +12 -0
  364. package/dist/physics/magnetism/index.mjs +74 -0
  365. package/dist/physics/magnetism/lorentz.d.mts +28 -0
  366. package/dist/physics/magnetism/lorentz.mjs +88 -0
  367. package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
  368. package/dist/physics/magnetism/magnetic-force.mjs +169 -0
  369. package/dist/physics/momentum/collide.d.mts +77 -0
  370. package/dist/physics/momentum/collide.mjs +115 -0
  371. package/dist/physics/momentum/impulse.d.mts +89 -0
  372. package/dist/physics/momentum/impulse.mjs +159 -0
  373. package/dist/physics/momentum/planar.d.mts +60 -0
  374. package/dist/physics/momentum/planar.mjs +110 -0
  375. package/dist/physics/projectile.d.mts +107 -0
  376. package/dist/physics/projectile.mjs +185 -0
  377. package/dist/physics/rotation/angular.d.mts +85 -0
  378. package/dist/physics/rotation/angular.mjs +130 -0
  379. package/dist/physics/rotation/circular.d.mts +79 -0
  380. package/dist/physics/rotation/circular.mjs +131 -0
  381. package/dist/physics/rotation/inertia.d.mts +164 -0
  382. package/dist/physics/rotation/inertia.mjs +332 -0
  383. package/dist/physics/rotation/torque.d.mts +65 -0
  384. package/dist/physics/rotation/torque.mjs +134 -0
  385. package/dist/physics/vectors.d.mts +64 -0
  386. package/dist/physics/vectors.mjs +114 -0
  387. package/dist/quantity/index.d.mts +119 -0
  388. package/dist/quantity/index.mjs +417 -0
  389. package/dist/relation/derive.d.mts +74 -0
  390. package/dist/relation/derive.mjs +73 -0
  391. package/dist/relation/index.d.mts +56 -0
  392. package/dist/relation/index.mjs +234 -0
  393. package/dist/scene/evaluators.mjs +1 -1
  394. package/dist/sim/thermal.mjs +45 -20
  395. package/dist/thermo/calorimetry.d.mts +207 -0
  396. package/dist/thermo/calorimetry.mjs +345 -0
  397. package/dist/thermo/cycles.d.mts +142 -0
  398. package/dist/thermo/cycles.mjs +256 -0
  399. package/dist/thermo/entropy.d.mts +87 -0
  400. package/dist/thermo/entropy.mjs +140 -0
  401. package/dist/thermo/expansion.d.mts +130 -0
  402. package/dist/thermo/expansion.mjs +178 -0
  403. package/dist/thermo/gas.d.mts +197 -0
  404. package/dist/thermo/gas.mjs +279 -0
  405. package/dist/thermo/heat-transfer.d.mts +164 -0
  406. package/dist/thermo/heat-transfer.mjs +217 -0
  407. package/dist/thermo/index.d.mts +9 -82
  408. package/dist/thermo/index.mjs +9 -132
  409. package/dist/thermo/processes.d.mts +95 -0
  410. package/dist/thermo/processes.mjs +154 -0
  411. package/dist/thermo/temperature.d.mts +174 -0
  412. package/dist/thermo/temperature.mjs +236 -0
  413. package/dist/waves/damping.d.mts +224 -0
  414. package/dist/waves/damping.mjs +317 -0
  415. package/dist/waves/doppler.d.mts +72 -0
  416. package/dist/waves/doppler.mjs +125 -0
  417. package/dist/waves/index.d.mts +10 -0
  418. package/dist/waves/index.mjs +10 -0
  419. package/dist/waves/pendulum.d.mts +130 -0
  420. package/dist/waves/pendulum.mjs +211 -0
  421. package/dist/waves/pitch.d.mts +125 -0
  422. package/dist/waves/pitch.mjs +158 -0
  423. package/dist/waves/shm.d.mts +170 -0
  424. package/dist/waves/shm.mjs +279 -0
  425. package/dist/waves/springs.d.mts +103 -0
  426. package/dist/waves/springs.mjs +176 -0
  427. package/dist/waves/superposition.d.mts +124 -0
  428. package/dist/waves/superposition.mjs +196 -0
  429. package/dist/waves/wave.d.mts +154 -0
  430. package/dist/waves/wave.mjs +178 -0
  431. package/package.json +74 -2
@@ -0,0 +1,130 @@
1
+ //#region src/networking/models/airtime.ts
2
+ /**
3
+ * One channel, several devices, and the thing everyone is actually sharing.
4
+ *
5
+ * A switch gives every port its own wire. Wi-Fi gives everybody the same air, so devices take turns,
6
+ * and what they are taking turns at is TIME rather than bandwidth. That one substitution explains the
7
+ * most confusing thing about a home network: a laptop sitting beside the router, showing a perfect
8
+ * signal, can be slow because of a phone in a distant bedroom.
9
+ *
10
+ * The mechanism has a name, the 802.11 performance anomaly, and it is worth stating precisely because
11
+ * it is so counter-intuitive. The access point gives each device roughly the same number of turns.
12
+ * A device with a weak signal negotiates a low data rate, so ITS turn takes far longer to deliver the
13
+ * same bytes. While that turn runs, nobody else may transmit at all. With one device at 260 Mbps and
14
+ * one at 15 Mbps, the fast device does not get 260: both end up near 14, because the slow device is
15
+ * occupying the channel for most of every round.
16
+ *
17
+ * So chapter 1 is not finished when a room reaches a usable signal. A room that is merely usable
18
+ * drags down every other room, and the fix for a slow house is often to improve the WORST corner
19
+ * rather than to buy a faster router. That is the opposite of what the advertising suggests and it
20
+ * follows from one line of arithmetic.
21
+ */
22
+ /**
23
+ * Bits carried in one transmission opportunity.
24
+ *
25
+ * Not one frame. Modern Wi-Fi aggregates dozens of frames into a single transmission, precisely
26
+ * because the fixed cost below would otherwise dominate at high rates. Modelling a lone 1500-byte
27
+ * frame would show a 300 Mbps link delivering 60 Mbps, which is what 802.11 looked like twenty years
28
+ * ago and would teach an efficiency problem that has since been solved.
29
+ */
30
+ const PAYLOAD_BITS = 8 * 1500 * 32;
31
+ /**
32
+ * Fixed cost of taking a turn, in microseconds.
33
+ *
34
+ * Contention, the gap before transmitting, the preamble and the acknowledgement. It is paid per turn
35
+ * regardless of how fast the device is, which is why it hurts fast devices most and why aggregation
36
+ * exists.
37
+ */
38
+ const TURN_OVERHEAD_US = 200;
39
+ /**
40
+ * Data rate a device negotiates from its signal, in Mbps.
41
+ *
42
+ * A staircase rather than a curve, because rate selection is a ladder of modulation schemes and a
43
+ * device drops a whole rung at a time. The figures are for a two-stream client on a modern 5 GHz
44
+ * channel. The shape is what matters: rate holds up and then falls off a cliff, so a room that is
45
+ * merely "usable" is already several rungs down.
46
+ */
47
+ function rateFromRssi(rssiDbm) {
48
+ if (rssiDbm >= -50) return 400;
49
+ if (rssiDbm >= -58) return 260;
50
+ if (rssiDbm >= -65) return 150;
51
+ if (rssiDbm >= -70) return 80;
52
+ if (rssiDbm >= -75) return 40;
53
+ if (rssiDbm >= -80) return 15;
54
+ if (rssiDbm >= -85) return 6;
55
+ return 0;
56
+ }
57
+ /**
58
+ * Share the channel between devices that all want to send at once.
59
+ *
60
+ * Each device gets an equal number of turns, so a round is the sum of everyone's turn length, and
61
+ * every device delivers one payload per round. That is why the effective rates come out EQUAL: the
62
+ * arithmetic makes the fast device wait through the slow one's turn, every round, forever.
63
+ */
64
+ function shareAirtime(clients) {
65
+ const active = clients.filter((client) => rateFromRssi(client.rssiDbm) > 0);
66
+ if (!active.length) return {
67
+ shares: [],
68
+ totalMbps: 0,
69
+ aloneMbps: 0,
70
+ worstShare: 0
71
+ };
72
+ const turns = active.map((client) => {
73
+ const rateMbps = rateFromRssi(client.rssiDbm);
74
+ return {
75
+ client,
76
+ rateMbps,
77
+ turnUs: 200 + PAYLOAD_BITS / rateMbps
78
+ };
79
+ });
80
+ const roundUs = turns.reduce((sum, turn) => sum + turn.turnUs, 0);
81
+ const perClientMbps = PAYLOAD_BITS / roundUs;
82
+ const shares = turns.map((turn) => ({
83
+ client: turn.client,
84
+ rateMbps: turn.rateMbps,
85
+ turnUs: turn.turnUs,
86
+ airtimeShare: turn.turnUs / roundUs,
87
+ effectiveMbps: perClientMbps
88
+ }));
89
+ const fastest = turns.reduce((best, turn) => turn.rateMbps > best.rateMbps ? turn : best, turns[0]);
90
+ return {
91
+ shares,
92
+ totalMbps: perClientMbps * active.length,
93
+ aloneMbps: PAYLOAD_BITS / fastest.turnUs,
94
+ worstShare: Math.max(...shares.map((share) => share.airtimeShare))
95
+ };
96
+ }
97
+ /** A device's signal placed into words, so a share can be read without decoding dBm. */
98
+ function signalWord(rssiDbm) {
99
+ if (rssiDbm >= -58) return "beside the router";
100
+ if (rssiDbm >= -67) return "same floor";
101
+ if (rssiDbm >= -75) return "through a wall";
102
+ if (rssiDbm >= -85) return "far bedroom";
103
+ return "out of range";
104
+ }
105
+ /** A household worth arguing about: three healthy devices and one in the corner that is not. */
106
+ const HOUSEHOLD = [
107
+ {
108
+ id: "desk",
109
+ label: "Laptop by the router",
110
+ rssiDbm: -45
111
+ },
112
+ {
113
+ id: "sofa",
114
+ label: "TV in the living room",
115
+ rssiDbm: -60
116
+ },
117
+ {
118
+ id: "kitchen",
119
+ label: "Phone in the kitchen",
120
+ rssiDbm: -68
121
+ },
122
+ {
123
+ id: "far",
124
+ label: "Tablet in the far bedroom",
125
+ rssiDbm: -82
126
+ }
127
+ ];
128
+
129
+ //#endregion
130
+ export { HOUSEHOLD, PAYLOAD_BITS, TURN_OVERHEAD_US, rateFromRssi, shareAirtime, signalWord };
@@ -0,0 +1,157 @@
1
+ //#region src/networking/models/cellular.d.ts
2
+ /**
3
+ * Mobile generations, as a trade rather than a league table.
4
+ *
5
+ * "5G is faster than 4G" is the whole of what most students are told, and it explains nothing they
6
+ * can see. It does not explain why their 5G phone shows 4G indoors, why coverage maps are patchy in
7
+ * exactly the places the advertising features, or why an operator would keep a twenty-year-old
8
+ * 900 MHz band running at all.
9
+ *
10
+ * The thing that explains all three is that a generation is not one number, it is a position on a
11
+ * trade. A higher frequency has more spectrum free, so it carries more data. The same higher
12
+ * frequency travels less far, so its cell is smaller. Cell area falls with the SQUARE of the radius,
13
+ * so a modest drop in reach multiplies the number of towers needed to cover the same city. Capacity
14
+ * is bought with civil engineering, and that is why the rollout looks the way it does.
15
+ *
16
+ * The second half is the part even the trade press gets wrong. What 5G actually changed is LATENCY,
17
+ * not throughput. 4G already carries 4K video comfortably; what it cannot do is answer in ten
18
+ * milliseconds. Anything interactive at a distance, which now includes every request to a model that
19
+ * streams its answer back, is bounded by the round trip and not by the bit rate. A learner who has
20
+ * seen the reachable region expand downward rather than rightward owns that distinction.
21
+ */
22
+ /** Speed of light is not needed here; the propagation model is empirical. */
23
+ type GenerationId = "1g" | "2g" | "3g" | "4g" | "5g" | "5g-mmwave";
24
+ interface Generation {
25
+ id: GenerationId;
26
+ label: string;
27
+ /** First widely deployed. */
28
+ year: number;
29
+ /** A representative band, in MHz, for the radius model. */
30
+ megahertz: number;
31
+ /** What a user realistically gets, in Mbps. 1G carried no data at all. */
32
+ typicalMbps: number;
33
+ /**
34
+ * Round trip to the first server, in ms. The number that decides how a thing FEELS.
35
+ *
36
+ * Meaningless for 1G, which had no data service to measure, and quoted there only so the field is
37
+ * total. Read it alongside `typicalMbps`: a generation carrying no data has no round trip either.
38
+ */
39
+ latencyMs: number;
40
+ /**
41
+ * How a voice call is carried.
42
+ *
43
+ * Worth its own field rather than being folded into the data rate, because for most of this
44
+ * history a call was NOT data. It rode a dedicated circuit held open for its whole duration,
45
+ * which is why a call connected on a 2G network that could not load a web page, and why a phone
46
+ * showing one bar can still ring. Voice became data only with VoLTE.
47
+ */
48
+ voice: "analogue-circuit" | "digital-circuit" | "over-data";
49
+ note: string;
50
+ }
51
+ /**
52
+ * Representative bands and realistic user-experienced figures, not peak laboratory numbers.
53
+ *
54
+ * Quoting peaks is how the marketing gets away with it. A 5G peak of several gigabits is real and
55
+ * nobody has ever seen it on a phone, so the typical column below is what a learner should compare.
56
+ */
57
+ declare const GENERATIONS: Generation[];
58
+ /**
59
+ * Link budget for a macro cell, in dB.
60
+ *
61
+ * A base station transmits around 43 dBm into an antenna with roughly 18 dBi of gain, and a handset
62
+ * stops working near -100 dBm. The difference is how much loss the path is allowed to introduce.
63
+ */
64
+ declare const MAX_PATH_LOSS_DB = 161;
65
+ type Terrain = "city" | "suburb" | "open";
66
+ interface TerrainSpec {
67
+ id: Terrain;
68
+ label: string;
69
+ /** Extra loss in dB beyond the base model: buildings cost reach. */
70
+ extraDb: number;
71
+ note: string;
72
+ }
73
+ declare const TERRAIN: Record<Terrain, TerrainSpec>;
74
+ /**
75
+ * Cell radius in km, from the COST-231 Hata model for a 30 m base station antenna.
76
+ *
77
+ * PL = 46.3 + 33.9·log10(f) - 13.82·log10(h) + (44.9 - 6.55·log10(h))·log10(d) + C
78
+ *
79
+ * Solved for d at the maximum tolerable path loss. This is the model a network planner actually
80
+ * reaches for, which is why it is worth using rather than inventing a curve: at 900 MHz it returns
81
+ * cells of several kilometres and at 28 GHz a few hundred metres, and both match what is deployed.
82
+ *
83
+ * It is specified only up to about 2 GHz, so the millimetre-wave figure is an extrapolation. It
84
+ * lands in the right place for the wrong reasons, and a learner should be told that rather than
85
+ * shown a number that looks authoritative.
86
+ */
87
+ declare function cellRadiusKm(megahertz: number, terrain?: Terrain): number;
88
+ /**
89
+ * Path loss at a distance, in dB, from the same model the cell radius comes from.
90
+ *
91
+ * Exposed because the next chapter needs the loss at every point along a road rather than only at
92
+ * the edge of a cell. Deriving both from one pair of coefficients is the whole reason to factor it
93
+ * out: a handover lab built on a second, slightly different propagation model would put its cell
94
+ * boundaries in a different place from the coverage lab, and a learner comparing the two figures
95
+ * would be looking at a discrepancy we invented.
96
+ */
97
+ declare function pathLossDb(distanceKm: number, megahertz: number, terrain?: Terrain): number;
98
+ /**
99
+ * Effective radiated power of a macro cell, in dBm, and the level below which a handset gives up.
100
+ *
101
+ * Their difference is `MAX_PATH_LOSS_DB`, which is what makes the cell radius and the signal level
102
+ * along a road two views of one calculation rather than two separate claims.
103
+ */
104
+ declare const EIRP_DBM = 61;
105
+ declare const HANDSET_SENSITIVITY_DBM: number;
106
+ /** Signal a handset sees from one mast at a given distance, in dBm. */
107
+ declare const rssiFromMast: (distanceKm: number, megahertz: number, terrain?: Terrain) => number;
108
+ /**
109
+ * Area one cell serves, in km².
110
+ *
111
+ * Cells are drawn as hexagons because hexagons tile a plane with no gaps and no overlap, and are the
112
+ * closest tiling shape to the circle a transmitter actually produces. A regular hexagon whose
113
+ * circumradius is r has area 3√3/2 · r², which is about 2.598 r².
114
+ */
115
+ declare const cellAreaKm2: (radiusKm: number) => number;
116
+ /**
117
+ * Towers needed to cover an area.
118
+ *
119
+ * This is the number that carries the lesson, because it goes as 1/r². Halving the reach does not
120
+ * double the tower count, it quadruples it, and that single square is most of the economics of every
121
+ * rollout since 3G.
122
+ */
123
+ declare const towersFor: (areaKm2: number, radiusKm: number) => number;
124
+ interface Task {
125
+ id: string;
126
+ label: string;
127
+ /** Sustained rate the task needs, in Mbps. */
128
+ needMbps: number;
129
+ /** Round trip the task tolerates before it stops feeling usable, in ms. */
130
+ needLatencyMs: number;
131
+ /**
132
+ * True when a dedicated voice circuit can carry this instead of the data service.
133
+ *
134
+ * Only a phone call qualifies, and it is the reason every generation serves one. Without this the
135
+ * model says 1G could not make a call, which is exactly backwards: making calls was the only
136
+ * thing it did.
137
+ */
138
+ onVoiceCircuit?: boolean;
139
+ note: string;
140
+ }
141
+ /**
142
+ * Things a person actually tries to do, with the two numbers each of them needs.
143
+ *
144
+ * Two numbers rather than one, because that is the whole point. A task fails if either the rate or
145
+ * the round trip is missing, and the tasks that separate the recent generations fail on LATENCY
146
+ * while having rate to spare.
147
+ */
148
+ declare const TASKS: Task[];
149
+ type Blocker = "rate" | "latency" | "both" | null;
150
+ /** Why a generation cannot serve a task, or null when it can. Naming the blocker IS the lesson. */
151
+ declare function blockedBy(generation: Generation, task: Task): Blocker;
152
+ declare const canServe: (generation: Generation, task: Task) => boolean;
153
+ /** The first generation able to serve a task, which is the honest way to date a capability. */
154
+ declare function firstGenerationFor(task: Task): Generation | undefined;
155
+ declare const generationById: (id: string) => Generation;
156
+ //#endregion
157
+ export { Blocker, EIRP_DBM, GENERATIONS, Generation, GenerationId, HANDSET_SENSITIVITY_DBM, MAX_PATH_LOSS_DB, TASKS, TERRAIN, Task, Terrain, TerrainSpec, blockedBy, canServe, cellAreaKm2, cellRadiusKm, firstGenerationFor, generationById, pathLossDb, rssiFromMast, towersFor };
@@ -0,0 +1,252 @@
1
+ //#region src/networking/models/cellular.ts
2
+ /**
3
+ * Representative bands and realistic user-experienced figures, not peak laboratory numbers.
4
+ *
5
+ * Quoting peaks is how the marketing gets away with it. A 5G peak of several gigabits is real and
6
+ * nobody has ever seen it on a phone, so the typical column below is what a learner should compare.
7
+ */
8
+ const GENERATIONS = [
9
+ {
10
+ id: "1g",
11
+ label: "1G",
12
+ year: 1981,
13
+ megahertz: 450,
14
+ typicalMbps: 0,
15
+ latencyMs: 500,
16
+ voice: "analogue-circuit",
17
+ note: "Analogue voice, and nothing else. There was no data service to be slow, and anyone with a scanner could listen to a call."
18
+ },
19
+ {
20
+ id: "2g",
21
+ label: "2G",
22
+ year: 1991,
23
+ megahertz: 900,
24
+ typicalMbps: .05,
25
+ latencyMs: 600,
26
+ voice: "digital-circuit",
27
+ note: "Digital, which brought encryption and SMS. Data arrived later as GPRS, and at these rates a single photograph was a genuine wait."
28
+ },
29
+ {
30
+ id: "3g",
31
+ label: "3G",
32
+ year: 2001,
33
+ megahertz: 2100,
34
+ typicalMbps: 2,
35
+ latencyMs: 150,
36
+ voice: "digital-circuit",
37
+ note: "The web on a phone, and the first video calls. The move to 2100 MHz is where cells started shrinking and tower counts started climbing."
38
+ },
39
+ {
40
+ id: "4g",
41
+ label: "4G LTE",
42
+ year: 2009,
43
+ megahertz: 1800,
44
+ typicalMbps: 50,
45
+ latencyMs: 50,
46
+ voice: "over-data",
47
+ note: "Enough for HD video, which is most of what anyone does. Operators deliberately used lower bands here, buying back the reach that 3G had spent."
48
+ },
49
+ {
50
+ id: "5g",
51
+ label: "5G mid band",
52
+ year: 2019,
53
+ megahertz: 3500,
54
+ typicalMbps: 300,
55
+ latencyMs: 10,
56
+ voice: "over-data",
57
+ note: "The real 5G most people meet. The headline is the data rate and the change that matters is the latency, which is five times better."
58
+ },
59
+ {
60
+ id: "5g-mmwave",
61
+ label: "5G millimetre wave",
62
+ year: 2019,
63
+ megahertz: 28e3,
64
+ typicalMbps: 1e3,
65
+ latencyMs: 8,
66
+ voice: "over-data",
67
+ note: "Enormous capacity over a few hundred metres. Deployed at stadiums and transport hubs, because covering a city this way is not affordable."
68
+ }
69
+ ];
70
+ /**
71
+ * Link budget for a macro cell, in dB.
72
+ *
73
+ * A base station transmits around 43 dBm into an antenna with roughly 18 dBi of gain, and a handset
74
+ * stops working near -100 dBm. The difference is how much loss the path is allowed to introduce.
75
+ */
76
+ const MAX_PATH_LOSS_DB = 161;
77
+ const TERRAIN = {
78
+ city: {
79
+ id: "city",
80
+ label: "Dense city",
81
+ extraDb: 3,
82
+ note: "Tall buildings block and reflect. Cells are smallest here, and it is also where the most people need serving."
83
+ },
84
+ suburb: {
85
+ id: "suburb",
86
+ label: "Suburb",
87
+ extraDb: -5,
88
+ note: "Lower buildings and more open ground, so the same equipment reaches noticeably further."
89
+ },
90
+ open: {
91
+ id: "open",
92
+ label: "Open country",
93
+ extraDb: -14,
94
+ note: "Very little in the way. One tower can cover a whole district, which is the only reason rural coverage is affordable at all."
95
+ }
96
+ };
97
+ /**
98
+ * Cell radius in km, from the COST-231 Hata model for a 30 m base station antenna.
99
+ *
100
+ * PL = 46.3 + 33.9·log10(f) - 13.82·log10(h) + (44.9 - 6.55·log10(h))·log10(d) + C
101
+ *
102
+ * Solved for d at the maximum tolerable path loss. This is the model a network planner actually
103
+ * reaches for, which is why it is worth using rather than inventing a curve: at 900 MHz it returns
104
+ * cells of several kilometres and at 28 GHz a few hundred metres, and both match what is deployed.
105
+ *
106
+ * It is specified only up to about 2 GHz, so the millimetre-wave figure is an extrapolation. It
107
+ * lands in the right place for the wrong reasons, and a learner should be told that rather than
108
+ * shown a number that looks authoritative.
109
+ */
110
+ function cellRadiusKm(megahertz, terrain = "city") {
111
+ const { intercept, slope } = hataTerms(megahertz, terrain);
112
+ return 10 ** ((161 - intercept) / slope);
113
+ }
114
+ /** The two coefficients of the model, so radius and loss are solved from ONE set of numbers. */
115
+ function hataTerms(megahertz, terrain) {
116
+ const logH = Math.log10(30);
117
+ return {
118
+ intercept: 46.3 + 33.9 * Math.log10(megahertz) - 13.82 * logH + TERRAIN[terrain].extraDb,
119
+ slope: 44.9 - 6.55 * logH
120
+ };
121
+ }
122
+ /**
123
+ * Path loss at a distance, in dB, from the same model the cell radius comes from.
124
+ *
125
+ * Exposed because the next chapter needs the loss at every point along a road rather than only at
126
+ * the edge of a cell. Deriving both from one pair of coefficients is the whole reason to factor it
127
+ * out: a handover lab built on a second, slightly different propagation model would put its cell
128
+ * boundaries in a different place from the coverage lab, and a learner comparing the two figures
129
+ * would be looking at a discrepancy we invented.
130
+ */
131
+ function pathLossDb(distanceKm, megahertz, terrain = "city") {
132
+ const { intercept, slope } = hataTerms(megahertz, terrain);
133
+ return intercept + slope * Math.log10(Math.max(.02, distanceKm));
134
+ }
135
+ /**
136
+ * Effective radiated power of a macro cell, in dBm, and the level below which a handset gives up.
137
+ *
138
+ * Their difference is `MAX_PATH_LOSS_DB`, which is what makes the cell radius and the signal level
139
+ * along a road two views of one calculation rather than two separate claims.
140
+ */
141
+ const EIRP_DBM = 61;
142
+ const HANDSET_SENSITIVITY_DBM = 61 - 161;
143
+ /** Signal a handset sees from one mast at a given distance, in dBm. */
144
+ const rssiFromMast = (distanceKm, megahertz, terrain = "city") => 61 - pathLossDb(distanceKm, megahertz, terrain);
145
+ /**
146
+ * Area one cell serves, in km².
147
+ *
148
+ * Cells are drawn as hexagons because hexagons tile a plane with no gaps and no overlap, and are the
149
+ * closest tiling shape to the circle a transmitter actually produces. A regular hexagon whose
150
+ * circumradius is r has area 3√3/2 · r², which is about 2.598 r².
151
+ */
152
+ const cellAreaKm2 = (radiusKm) => 3 * Math.sqrt(3) / 2 * radiusKm * radiusKm;
153
+ /**
154
+ * Towers needed to cover an area.
155
+ *
156
+ * This is the number that carries the lesson, because it goes as 1/r². Halving the reach does not
157
+ * double the tower count, it quadruples it, and that single square is most of the economics of every
158
+ * rollout since 3G.
159
+ */
160
+ const towersFor = (areaKm2, radiusKm) => Math.max(1, Math.ceil(areaKm2 / cellAreaKm2(radiusKm)));
161
+ /**
162
+ * Things a person actually tries to do, with the two numbers each of them needs.
163
+ *
164
+ * Two numbers rather than one, because that is the whole point. A task fails if either the rate or
165
+ * the round trip is missing, and the tasks that separate the recent generations fail on LATENCY
166
+ * while having rate to spare.
167
+ */
168
+ const TASKS = [
169
+ {
170
+ id: "voice",
171
+ label: "Phone call",
172
+ needMbps: .013,
173
+ needLatencyMs: 300,
174
+ onVoiceCircuit: true,
175
+ note: "A compressed voice codec is about 13 kbps. Every generation since the first carries this easily."
176
+ },
177
+ {
178
+ id: "text",
179
+ label: "Send a message",
180
+ needMbps: .001,
181
+ needLatencyMs: 2e3,
182
+ note: "Almost free, and tolerant of delay. This is why a text gets through where a call will not connect."
183
+ },
184
+ {
185
+ id: "web",
186
+ label: "Load a web page",
187
+ needMbps: 1,
188
+ needLatencyMs: 1e3,
189
+ note: "Modest by modern standards. It was the thing 3G was built to make possible."
190
+ },
191
+ {
192
+ id: "video-call",
193
+ label: "Video call",
194
+ needMbps: 1.5,
195
+ needLatencyMs: 200,
196
+ note: "Needs the round trip as much as the rate. Beyond about 200 ms people start talking over each other."
197
+ },
198
+ {
199
+ id: "hd",
200
+ label: "Stream HD video",
201
+ needMbps: 5,
202
+ needLatencyMs: 2e3,
203
+ note: "Buffered, so delay barely matters. It needs rate and nothing else, which is why 4G was enough."
204
+ },
205
+ {
206
+ id: "uhd",
207
+ label: "Stream 4K video",
208
+ needMbps: 25,
209
+ needLatencyMs: 2e3,
210
+ note: "Four times the pixels and still buffered. 4G already carries this, which is worth noticing before believing a 5G advertisement."
211
+ },
212
+ {
213
+ id: "cloud-game",
214
+ label: "Cloud gaming",
215
+ needMbps: 15,
216
+ needLatencyMs: 30,
217
+ note: "The first ordinary thing that 4G cannot do. Not for want of speed: the round trip is what breaks it."
218
+ },
219
+ {
220
+ id: "agent",
221
+ label: "A model that answers as you type",
222
+ needMbps: 2,
223
+ needLatencyMs: 40,
224
+ note: "The rate is trivial. How quickly the first words appear is bounded by the round trip, so this lives or dies on latency."
225
+ },
226
+ {
227
+ id: "remote-control",
228
+ label: "Controlling a machine at a distance",
229
+ needMbps: 10,
230
+ needLatencyMs: 10,
231
+ note: "Remote surgery and industrial control. This is the case 5G was genuinely designed for, and it is a latency requirement."
232
+ }
233
+ ];
234
+ /** Why a generation cannot serve a task, or null when it can. Naming the blocker IS the lesson. */
235
+ function blockedBy(generation, task) {
236
+ if (task.onVoiceCircuit) return null;
237
+ const slowRate = generation.typicalMbps < task.needMbps;
238
+ const slowTrip = generation.latencyMs > task.needLatencyMs;
239
+ if (slowRate && slowTrip) return "both";
240
+ if (slowRate) return "rate";
241
+ if (slowTrip) return "latency";
242
+ return null;
243
+ }
244
+ const canServe = (generation, task) => blockedBy(generation, task) === null;
245
+ /** The first generation able to serve a task, which is the honest way to date a capability. */
246
+ function firstGenerationFor(task) {
247
+ return [...GENERATIONS].sort((a, b) => a.year - b.year || a.typicalMbps - b.typicalMbps).find((generation) => canServe(generation, task));
248
+ }
249
+ const generationById = (id) => GENERATIONS.find((item) => item.id === id) ?? GENERATIONS[0];
250
+
251
+ //#endregion
252
+ export { EIRP_DBM, GENERATIONS, HANDSET_SENSITIVITY_DBM, MAX_PATH_LOSS_DB, TASKS, TERRAIN, blockedBy, canServe, cellAreaKm2, cellRadiusKm, firstGenerationFor, generationById, pathLossDb, rssiFromMast, towersFor };
@@ -0,0 +1,98 @@
1
+ //#region src/networking/models/encapsulation.d.ts
2
+ /**
3
+ * Encapsulation: what a message actually becomes, and what survives the trip.
4
+ *
5
+ * The stack is normally taught as a mnemonic, which is why students can recite seven layer names
6
+ * and still cannot say what a router changes. Two facts do the real work, and both are checkable:
7
+ *
8
+ * 1. Going down, each layer WRAPS what it was given and never edits it. The message you sent is
9
+ * still the same bytes at the bottom, sitting inside a few dozen bytes of addressing. For a big
10
+ * download that overhead is a rounding error; for a single keystroke it is most of the traffic.
11
+ *
12
+ * 2. Going across, the MAC pair is replaced at every routed hop and the IP pair is not. That is the
13
+ * whole difference between the two kinds of address: one names the next box on this wire, the
14
+ * other names the far end of the journey. Exams ask it constantly and it is nearly always missed.
15
+ *
16
+ * The one honest caveat is NAT, which does rewrite the source IP at the boundary of a home or
17
+ * office network. The scenario here is deliberately inside one organisation so the rule holds
18
+ * exactly, and the lab says so rather than quietly hoping nobody asks.
19
+ */
20
+ type LayerKind = "application" | "transport" | "network" | "data-link";
21
+ interface Header {
22
+ kind: LayerKind;
23
+ protocol: string;
24
+ /** Bytes this layer adds. Real sizes: a reader can check them against a capture. */
25
+ bytes: number;
26
+ /**
27
+ * Of those bytes, how many go AFTER the payload. Only Ethernet has any: its 4-byte checksum sits
28
+ * at the end of the frame, which is the whole reason the word "trailer" exists. Drawing it at the
29
+ * front would be neater and would teach a frame layout that does not exist.
30
+ */
31
+ trailerBytes?: number;
32
+ /** What kind of address this header carries, if any. */
33
+ addressing: string | null;
34
+ /** The question this header exists to answer. */
35
+ answers: string;
36
+ }
37
+ /** Outermost last: this is the order the headers are ADDED going down the stack. */
38
+ declare const HEADERS: Header[];
39
+ declare const OVERHEAD_BYTES: number;
40
+ interface Encapsulation {
41
+ payloadBytes: number;
42
+ headers: Header[];
43
+ /** Headers added so far, going down. `depth` 0 is the bare message. */
44
+ depth: number;
45
+ onWireBytes: number;
46
+ overheadBytes: number;
47
+ /** Overhead as a share of what is actually transmitted, 0 to 1. */
48
+ overheadShare: number;
49
+ }
50
+ /** Wrap a payload in the first `depth` headers. Full depth is the frame that goes on the wire. */
51
+ declare function encapsulate(payloadBytes: number, depth?: number): Encapsulation;
52
+ /** Unwrap one layer. The payload is never touched, which is the point. */
53
+ declare const decapsulate: (state: Encapsulation) => Encapsulation;
54
+ type NodeKind = "host" | "switch" | "router";
55
+ interface PathNode {
56
+ id: string;
57
+ name: string;
58
+ kind: NodeKind;
59
+ mac: string;
60
+ /** Hosts have one; routers have one per side, so the scene names them by segment instead. */
61
+ ip?: string;
62
+ }
63
+ /** How deep a device opens the frame before it can do its job. */
64
+ declare const opensTo: (kind: NodeKind) => LayerKind;
65
+ interface EncapsulationSegment {
66
+ /** Layer-2 endpoints of this stretch of wire. */
67
+ fromMac: string;
68
+ toMac: string;
69
+ from: PathNode;
70
+ to: PathNode;
71
+ /** Switches sit inside a segment without ending it: they are invisible at layer 3. */
72
+ through: PathNode[];
73
+ }
74
+ /**
75
+ * Split a path at its layer-3 boundaries. A switch forwards a frame without terminating it, so it
76
+ * does not start a new segment. A router does, because it builds a brand new frame for the next
77
+ * wire. The number of segments is therefore routers + 1, however many switches are in the way.
78
+ */
79
+ declare function segmentsOf(path: PathNode[]): EncapsulationSegment[];
80
+ interface WireFrame {
81
+ segment: EncapsulationSegment;
82
+ mac: {
83
+ from: string;
84
+ to: string;
85
+ };
86
+ /** The same on every segment. That is the whole lesson. */
87
+ ip: {
88
+ from: string;
89
+ to: string;
90
+ };
91
+ note: string;
92
+ }
93
+ declare function frameOn(segment: EncapsulationSegment, source: PathNode, destination: PathNode): WireFrame;
94
+ /** Every frame the message travels in, end to end. */
95
+ declare const journey: (path: PathNode[]) => WireFrame[];
96
+ declare const DEFAULT_PATH: PathNode[];
97
+ //#endregion
98
+ export { DEFAULT_PATH, Encapsulation, EncapsulationSegment, HEADERS, Header, LayerKind, NodeKind, OVERHEAD_BYTES, PathNode, WireFrame, decapsulate, encapsulate, frameOn, journey, opensTo, segmentsOf };