@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,66 @@
1
+ //#region src/networking/models/vpn.d.ts
2
+ /**
3
+ * What a VPN actually hides, from whom, and what it quietly costs.
4
+ *
5
+ * This topic is taught almost entirely by advertising, and the advertising is wrong in both
6
+ * directions. A VPN does not make anyone anonymous, and it also does not hand a provider your
7
+ * banking password. The truthful version is more interesting than either claim, and it falls out of
8
+ * one mechanism: the original packet is wrapped inside a new one addressed to the gateway, and the
9
+ * inside is encrypted. So anybody between you and the gateway can see that you are talking to the
10
+ * gateway and nothing else, and the gateway can see everything the encryption around it does not
11
+ * cover.
12
+ *
13
+ * The conclusion worth carrying out of the lesson is that a VPN MOVES trust rather than removing
14
+ * it: whatever your network operator could previously see, the VPN provider now sees instead. That
15
+ * is sometimes an excellent trade (hostile café Wi-Fi, a censoring network) and sometimes a bad one
16
+ * (a free provider funded by selling exactly that view).
17
+ *
18
+ * The second honest point is that HTTPS and a VPN protect different things, so the interesting
19
+ * cases are the combinations rather than either alone. And no arrangement of either hides anything
20
+ * from the site you are actually talking to, because it is the one you are talking to.
21
+ */
22
+ type ObserverId = "wifi" | "isp" | "gateway" | "website";
23
+ interface Observer {
24
+ id: ObserverId;
25
+ name: string;
26
+ /** For the diagram, where a box is narrower than a sentence. */
27
+ short: string;
28
+ /** Where this watcher sits, in the learner's words. */
29
+ where: string;
30
+ }
31
+ declare const OBSERVERS: Observer[];
32
+ interface Setup {
33
+ vpn: boolean;
34
+ https: boolean;
35
+ }
36
+ interface Field {
37
+ value: string;
38
+ hidden: boolean;
39
+ }
40
+ interface Sighting {
41
+ observer: Observer;
42
+ /** Who this watcher believes is sending. */
43
+ from: Field;
44
+ /** Where this watcher believes it is going. */
45
+ to: Field;
46
+ contents: Field;
47
+ verdict: string;
48
+ }
49
+ /** Watchers that exist in this setup. Without a tunnel there is no gateway to watch. */
50
+ declare const observersFor: (setup: Setup) => Observer[];
51
+ declare function observe(id: ObserverId, setup: Setup): Sighting | null;
52
+ /** Every watcher's view of one setup, which is where the pattern shows up. */
53
+ declare const surveyOf: (setup: Setup) => Sighting[];
54
+ /** Watchers who can name the site being visited. The count is the honest summary of a setup. */
55
+ declare const canSeeDestination: (setup: Setup) => ObserverId[];
56
+ /** Watchers who can read what you actually sent. */
57
+ declare const canReadContents: (setup: Setup) => ObserverId[];
58
+ /**
59
+ * The tunnel's own cost. A VPN wraps a whole packet inside another one, so the outer headers plus
60
+ * the encryption are pure overhead, and the room left for real data shrinks by the same amount.
61
+ * WireGuard's 60 bytes is the honest modern figure; older tunnels cost noticeably more.
62
+ */
63
+ declare const TUNNEL_OVERHEAD_BYTES = 60;
64
+ declare const usableBytes: (mtu: number, setup: Setup) => number;
65
+ //#endregion
66
+ export { Field, OBSERVERS, Observer, ObserverId, Setup, Sighting, TUNNEL_OVERHEAD_BYTES, canReadContents, canSeeDestination, observe, observersFor, surveyOf, usableBytes };
@@ -0,0 +1,125 @@
1
+ //#region src/networking/models/vpn.ts
2
+ const OBSERVERS = [
3
+ {
4
+ id: "wifi",
5
+ name: "The café Wi-Fi",
6
+ short: "Café Wi-Fi",
7
+ where: "anyone else on the same network, including whoever runs it"
8
+ },
9
+ {
10
+ id: "isp",
11
+ name: "Your internet provider",
12
+ short: "Your provider",
13
+ where: "every packet you send crosses their equipment"
14
+ },
15
+ {
16
+ id: "gateway",
17
+ name: "The VPN provider",
18
+ short: "VPN provider",
19
+ where: "the far end of the tunnel, where the wrapping comes off"
20
+ },
21
+ {
22
+ id: "website",
23
+ name: "The website",
24
+ short: "The website",
25
+ where: "the machine you are actually talking to"
26
+ }
27
+ ];
28
+ const YOU = "You";
29
+ const GATEWAY = "VPN gateway";
30
+ const SITE = "example.com";
31
+ const CIPHER = "unreadable";
32
+ /** Watchers that exist in this setup. Without a tunnel there is no gateway to watch. */
33
+ const observersFor = (setup) => OBSERVERS.filter((observer) => observer.id !== "gateway" || setup.vpn);
34
+ function observe(id, setup) {
35
+ const observer = OBSERVERS.find((item) => item.id === id);
36
+ if (!observer || id === "gateway" && !setup.vpn) return null;
37
+ if (id === "website") return {
38
+ observer,
39
+ from: {
40
+ value: setup.vpn ? GATEWAY : YOU,
41
+ hidden: false
42
+ },
43
+ to: {
44
+ value: SITE,
45
+ hidden: false
46
+ },
47
+ contents: {
48
+ value: "your request, in full",
49
+ hidden: false
50
+ },
51
+ verdict: setup.vpn ? "Sees a request arriving from the VPN gateway rather than from you, and reads it in full. It has to: it is the one answering." : "Sees your own address and reads the request in full. HTTPS protects it from everyone in between, never from the far end."
52
+ };
53
+ if (setup.vpn) {
54
+ if (id === "gateway") return {
55
+ observer,
56
+ from: {
57
+ value: YOU,
58
+ hidden: false
59
+ },
60
+ to: {
61
+ value: SITE,
62
+ hidden: false
63
+ },
64
+ contents: setup.https ? {
65
+ value: CIPHER,
66
+ hidden: true
67
+ } : {
68
+ value: "your request, in full",
69
+ hidden: false
70
+ },
71
+ verdict: setup.https ? "Knows who you are and every site you ask for, but HTTPS still keeps the contents from them. This is the trade: your provider stopped seeing this and they started." : "Knows who you are, every site you ask for, and everything you send. Without HTTPS you have simply changed which company watches you."
72
+ };
73
+ return {
74
+ observer,
75
+ from: {
76
+ value: YOU,
77
+ hidden: false
78
+ },
79
+ to: {
80
+ value: GATEWAY,
81
+ hidden: false
82
+ },
83
+ contents: {
84
+ value: CIPHER,
85
+ hidden: true
86
+ },
87
+ verdict: "Can tell you are using a VPN and nothing else. Which sites you visit is inside the wrapping, so it is not available here at any price."
88
+ };
89
+ }
90
+ return {
91
+ observer,
92
+ from: {
93
+ value: YOU,
94
+ hidden: false
95
+ },
96
+ to: {
97
+ value: SITE,
98
+ hidden: false
99
+ },
100
+ contents: setup.https ? {
101
+ value: CIPHER,
102
+ hidden: true
103
+ } : {
104
+ value: "your request, in full",
105
+ hidden: false
106
+ },
107
+ verdict: setup.https ? "Sees which sites you visit and when, but not what you asked for or what came back." : "Sees which sites you visit and can read every word of it."
108
+ };
109
+ }
110
+ /** Every watcher's view of one setup, which is where the pattern shows up. */
111
+ const surveyOf = (setup) => observersFor(setup).map((observer) => observe(observer.id, setup)).filter((sighting) => sighting !== null);
112
+ /** Watchers who can name the site being visited. The count is the honest summary of a setup. */
113
+ const canSeeDestination = (setup) => surveyOf(setup).filter((sighting) => !sighting.to.hidden && sighting.to.value === SITE).map((sighting) => sighting.observer.id);
114
+ /** Watchers who can read what you actually sent. */
115
+ const canReadContents = (setup) => surveyOf(setup).filter((sighting) => !sighting.contents.hidden).map((sighting) => sighting.observer.id);
116
+ /**
117
+ * The tunnel's own cost. A VPN wraps a whole packet inside another one, so the outer headers plus
118
+ * the encryption are pure overhead, and the room left for real data shrinks by the same amount.
119
+ * WireGuard's 60 bytes is the honest modern figure; older tunnels cost noticeably more.
120
+ */
121
+ const TUNNEL_OVERHEAD_BYTES = 60;
122
+ const usableBytes = (mtu, setup) => mtu - (setup.vpn ? 60 : 0);
123
+
124
+ //#endregion
125
+ export { OBSERVERS, TUNNEL_OVERHEAD_BYTES, canReadContents, canSeeDestination, observe, observersFor, surveyOf, usableBytes };
@@ -0,0 +1,82 @@
1
+ //#region src/networking/models/wifi-privacy.d.ts
2
+ /**
3
+ * What the person at the next table can actually read.
4
+ *
5
+ * Chapter 1 established the fact this whole chapter turns on: radio reaches everyone in range,
6
+ * whether or not they were meant to have it. Nothing about Wi-Fi decides who RECEIVES your signal.
7
+ * Every laptop in the cafe already has it. The only question ever at issue is who can make sense of
8
+ * it, and that is decided by encryption in two separate places that protect two different things.
9
+ *
10
+ * Students arrive with one of two wrong models. Either "it has a password, so it is private", or
11
+ * "there is a padlock in the browser, so it is private". Each is half right in a way that leaves a
12
+ * real hole, and the point of this model is to make both holes visible at once.
13
+ *
14
+ * The one that surprises people is the shared password. A cafe password written on a chalkboard is
15
+ * not a secret, and on WPA2 it is also the material from which every customer's key is derived. Any
16
+ * other customer who has that password, and who was listening when your device joined, can decrypt
17
+ * your traffic. The network is encrypted and it is not private FROM the people it is shared with.
18
+ * WPA3 fixes exactly this, which is the whole reason it exists and is almost never how it is sold.
19
+ *
20
+ * The other hole runs the opposite way. HTTPS protects what you sent from everyone, including the
21
+ * cafe and your provider, and it does not hide WHERE you sent it. The destination is still on the
22
+ * wire, so anyone who can read the link learns every site you visited even though they see none of
23
+ * the contents.
24
+ */
25
+ /** How the radio link itself is protected. */
26
+ type Protection = "open" | "wep" | "wpa2" | "wpa3";
27
+ /** How the conversation with the website is protected, independently of the link. */
28
+ type Transport = "http" | "https";
29
+ /** Who is listening, which decides whether the link's key is available to them. */
30
+ type Listener = "stranger" | "customer";
31
+ interface ProtectionSpec {
32
+ id: Protection;
33
+ label: string;
34
+ note: string;
35
+ }
36
+ declare const PROTECTIONS: Record<Protection, ProtectionSpec>;
37
+ declare const LISTENERS: Record<Listener, {
38
+ id: Listener;
39
+ label: string;
40
+ note: string;
41
+ }>;
42
+ /**
43
+ * Can this listener decrypt the radio link?
44
+ *
45
+ * The WEP row is the one worth reading twice. It is nominally encryption and belongs in the same
46
+ * column as an open network, because a key that anyone can recover is not a key. Stating that in the
47
+ * model rather than in a footnote is the difference between a student who avoids WEP and one who
48
+ * ticks the box marked "encrypted".
49
+ */
50
+ declare function linkReadable(protection: Protection, listener: Listener): boolean;
51
+ interface Exposure {
52
+ id: string;
53
+ /** What is at stake, in the words someone would use about their own life. */
54
+ label: string;
55
+ visible: boolean;
56
+ /** Shown when visible. Entirely fictional, and obviously so. */
57
+ value: string;
58
+ /** Why it is or is not readable, which is the part that has to be learned. */
59
+ why: string;
60
+ }
61
+ /**
62
+ * Everything a listener learns, most harmless first.
63
+ *
64
+ * Ordered that way on purpose. A list that opens with the password makes this look like a lesson
65
+ * about passwords, and it is not: the top two rows leak on EVERY setting including the best one, and
66
+ * a student who notices that has understood something about radio that no amount of encryption
67
+ * changes.
68
+ */
69
+ declare function whatTheySee(protection: Protection, transport: Transport, listener: Listener): Exposure[];
70
+ interface PrivacyVerdict {
71
+ /** How many of the five things this listener can read. */
72
+ exposed: number;
73
+ total: number;
74
+ /** The single sentence a learner should take away from this combination. */
75
+ headline: string;
76
+ tone: "bad" | "mixed" | "good";
77
+ }
78
+ declare function judgePrivacy(protection: Protection, transport: Transport, listener: Listener): PrivacyVerdict;
79
+ /** The honest summary: which of the two protections fixes which hole. */
80
+ declare const ADVICE: string[];
81
+ //#endregion
82
+ export { ADVICE, Exposure, LISTENERS, Listener, PROTECTIONS, PrivacyVerdict, Protection, ProtectionSpec, Transport, judgePrivacy, linkReadable, whatTheySee };
@@ -0,0 +1,130 @@
1
+ //#region src/networking/models/wifi-privacy.ts
2
+ const PROTECTIONS = {
3
+ open: {
4
+ id: "open",
5
+ label: "Open, no password",
6
+ note: "The link carries plain radio that anyone in range can decode with ordinary hardware. Common in cafes, airports and hotels precisely because it is convenient."
7
+ },
8
+ wep: {
9
+ id: "wep",
10
+ label: "WEP",
11
+ note: "Encrypted in name only. The key can be recovered from captured traffic in minutes with tools that have existed since 2001, so treat a WEP network as an open one."
12
+ },
13
+ wpa2: {
14
+ id: "wpa2",
15
+ label: "WPA2, shared password",
16
+ note: "Genuinely encrypted against outsiders. Every user derives their key from the SAME shared password, so anyone who knows it and captured your device joining can derive your key too."
17
+ },
18
+ wpa3: {
19
+ id: "wpa3",
20
+ label: "WPA3",
21
+ note: "Each session negotiates its own key, so knowing the password does not let anyone decrypt anybody else. This is the actual point of WPA3 and it is rarely how it is advertised."
22
+ }
23
+ };
24
+ const LISTENERS = {
25
+ stranger: {
26
+ id: "stranger",
27
+ label: "Someone in range",
28
+ note: "A person sitting nearby who never joined the network. They receive every packet regardless, because that is what radio does."
29
+ },
30
+ customer: {
31
+ id: "customer",
32
+ label: "Another customer",
33
+ note: "Someone who read the same password off the same chalkboard. They are inside the network, which turns out to matter more than most people expect."
34
+ }
35
+ };
36
+ /**
37
+ * Can this listener decrypt the radio link?
38
+ *
39
+ * The WEP row is the one worth reading twice. It is nominally encryption and belongs in the same
40
+ * column as an open network, because a key that anyone can recover is not a key. Stating that in the
41
+ * model rather than in a footnote is the difference between a student who avoids WEP and one who
42
+ * ticks the box marked "encrypted".
43
+ */
44
+ function linkReadable(protection, listener) {
45
+ if (protection === "open" || protection === "wep") return true;
46
+ if (protection === "wpa2") return listener === "customer";
47
+ return false;
48
+ }
49
+ /**
50
+ * Everything a listener learns, most harmless first.
51
+ *
52
+ * Ordered that way on purpose. A list that opens with the password makes this look like a lesson
53
+ * about passwords, and it is not: the top two rows leak on EVERY setting including the best one, and
54
+ * a student who notices that has understood something about radio that no amount of encryption
55
+ * changes.
56
+ */
57
+ function whatTheySee(protection, transport, listener) {
58
+ const readable = linkReadable(protection, listener);
59
+ const contentReadable = readable && transport === "http";
60
+ return [
61
+ {
62
+ id: "presence",
63
+ label: "That you are here at all",
64
+ visible: true,
65
+ value: "a device transmitting, a few metres away",
66
+ why: "Radio cannot be made private in this respect. Anything that transmits announces that something is transmitting, on every setting there is."
67
+ },
68
+ {
69
+ id: "device",
70
+ label: "Your device's address",
71
+ visible: true,
72
+ value: "a4:83:e7:2c:91:0f",
73
+ why: "Addresses ride outside the encryption, because the network needs them to deliver anything at all. This is why phones now invent a new one per network."
74
+ },
75
+ {
76
+ id: "site",
77
+ label: "Which sites you visited",
78
+ visible: readable,
79
+ value: "bank.example.com, then clinic.example.org",
80
+ why: readable ? "The destination has to be readable by whatever carries the packet. HTTPS hides what you sent and not where you sent it." : "The link is encrypted and this listener has no key for it, so even the destinations are hidden."
81
+ },
82
+ {
83
+ id: "page",
84
+ label: "What was on the page",
85
+ visible: contentReadable,
86
+ value: "Account balance, transactions, the lot",
87
+ why: contentReadable ? "Plain HTTP puts the page on the air as text. Anyone who can read the link can read the page." : readable ? "HTTPS encrypts the page end to end, so reading the link is not enough." : "The link cannot be read, and the page is separately encrypted on top of that."
88
+ },
89
+ {
90
+ id: "credentials",
91
+ label: "What you typed in",
92
+ visible: contentReadable,
93
+ value: "user=you@example.com password=OpenSesame1",
94
+ why: contentReadable ? "A form submitted over plain HTTP travels as text, including the password field." : readable ? "HTTPS protects what you submit even when the link around it is wide open." : "Protected twice over: the link is encrypted and so is the conversation inside it."
95
+ }
96
+ ];
97
+ }
98
+ function judgePrivacy(protection, transport, listener) {
99
+ const rows = whatTheySee(protection, transport, listener);
100
+ const exposed = rows.filter((row) => row.visible).length;
101
+ const readable = linkReadable(protection, listener);
102
+ let headline;
103
+ let tone;
104
+ if (readable && transport === "http") {
105
+ headline = "Everything, including what you typed. This is a stranger reading over your shoulder.";
106
+ tone = "bad";
107
+ } else if (readable) {
108
+ headline = "Not the contents, but every site you visited. That alone says a great deal about you.";
109
+ tone = "mixed";
110
+ } else {
111
+ headline = "Only that a device is here, and its address. The link and the contents are both closed.";
112
+ tone = "good";
113
+ }
114
+ return {
115
+ exposed,
116
+ total: rows.length,
117
+ headline,
118
+ tone
119
+ };
120
+ }
121
+ /** The honest summary: which of the two protections fixes which hole. */
122
+ const ADVICE = [
123
+ "HTTPS protects what you send from everyone, including the cafe, the network owner and your provider. It does not hide where you sent it.",
124
+ "A network password protects the link from outsiders. On WPA2 it does not protect you from the other people who have that same password.",
125
+ "WPA3 gives every session its own key, so a shared password stops being a shared key. This is the hole it was designed to close.",
126
+ "Nothing hides the fact that a device is transmitting, or the address it transmits with, because the network needs both to work."
127
+ ];
128
+
129
+ //#endregion
130
+ export { ADVICE, LISTENERS, PROTECTIONS, judgePrivacy, linkReadable, whatTheySee };
@@ -0,0 +1,240 @@
1
+ //#region src/networking/models/wifi.d.ts
2
+ /**
3
+ * Indoor radio coverage: why the far bedroom is dead, and why moving the router two metres fixes it.
4
+ *
5
+ * Wireless is taught as a list of standards and a table of speeds, which produces students who can
6
+ * state that 5 GHz is faster and cannot explain why their own phone drops to 2.4 GHz in the kitchen.
7
+ * The thing that decides real coverage is not the standard. It is DISTANCE and WHAT IS IN THE WAY,
8
+ * and both are geometry, so both can be drawn.
9
+ *
10
+ * Two mechanisms, and students need to feel them separately:
11
+ *
12
+ * Spreading. A transmitter radiates into a sphere. Double the distance and the same power is
13
+ * spread over four times the area, so the received power falls with the SQUARE of distance even
14
+ * with nothing in the way. Indoors it falls faster still, because energy is absorbed rather than
15
+ * simply spread, which is what the path-loss exponent below carries.
16
+ *
17
+ * Absorption. Every wall takes a fixed bite out of the signal as it passes through, and the size
18
+ * of that bite depends on the material and on the frequency. This is the half that a speed table
19
+ * hides completely, and it is the half that decides where a router should sit.
20
+ *
21
+ * The frequency trade is the payoff, and it is genuinely counter-intuitive: 5 GHz is the faster band
22
+ * and the WORSE one. A shorter wave starts about 6 dB down at the same distance and loses roughly
23
+ * twice as much through every wall it meets. So the honest statement is not "5 GHz is better", it is
24
+ * "5 GHz is faster where it reaches, and it reaches less far". A learner who has dragged a router
25
+ * around a floor plan owns that sentence. A learner who read a table does not.
26
+ *
27
+ * Everything here is in decibels, because absorption is multiplicative: two brick walls do not
28
+ * subtract twice, they halve twice. Decibels turn that into addition, which is the entire reason
29
+ * radio engineering uses them, and it is worth a learner meeting that reason in a place where the
30
+ * arithmetic is visibly easier rather than in a definition.
31
+ */
32
+ /** The two bands a home or campus access point actually offers. */
33
+ type Band = "2.4" | "5";
34
+ interface BandSpec {
35
+ id: Band;
36
+ label: string;
37
+ /** Centre frequency in MHz, used for the one-metre reference loss. */
38
+ megahertz: number;
39
+ /** Non-overlapping 20 MHz channels. The reason a crowded 2.4 GHz band stays slow. */
40
+ channels: number;
41
+ /** Ceiling for a good link on this band, in Mbps, for a typical two-stream client. */
42
+ peakMbps: number;
43
+ note: string;
44
+ }
45
+ declare const BANDS: Record<Band, BandSpec>;
46
+ /**
47
+ * Wall materials, ordered as a learner meets them: the partition you could put a fist through,
48
+ * up to the lift shaft nothing gets through at all.
49
+ */
50
+ type WallMaterial = "drywall" | "wood" | "glass" | "brick" | "concrete" | "metal";
51
+ interface MaterialSpec {
52
+ id: WallMaterial;
53
+ label: string;
54
+ /** One-way loss in dB, per band. Typical measured values for a single wall of this kind. */
55
+ loss: Record<Band, number>;
56
+ note: string;
57
+ }
58
+ /**
59
+ * Loss per wall, in dB. These are the numbers a site survey actually uses, rounded to whole
60
+ * decibels because the spread between real buildings is wider than the rounding.
61
+ *
62
+ * The column to read across is the band. Concrete costs 12 dB at 2.4 GHz and 20 dB at 5 GHz: the
63
+ * SAME wall takes eight extra decibels out of the faster band, which is a further sixfold drop in
64
+ * power. One interior wall is survivable on either band. Two concrete walls is where 5 GHz stops
65
+ * being a choice.
66
+ */
67
+ declare const MATERIALS: Record<WallMaterial, MaterialSpec>;
68
+ /** A wall segment on the plan, in metres. */
69
+ interface Wall {
70
+ x1: number;
71
+ y1: number;
72
+ x2: number;
73
+ y2: number;
74
+ material: WallMaterial;
75
+ }
76
+ /** A named rectangular room, in metres, used for per-room verdicts. */
77
+ interface Room {
78
+ id: string;
79
+ name: string;
80
+ x: number;
81
+ y: number;
82
+ w: number;
83
+ h: number;
84
+ }
85
+ /**
86
+ * A place a router could realistically stand, named the way someone would say it out loud.
87
+ *
88
+ * Offering named spots rather than a free drag is a teaching decision, not a technical one. A
89
+ * learner dragging a marker optimises by watching the colour and stops as soon as it turns green,
90
+ * having formed no reason. Choosing between "the corner where the cable enters" and "the hallway
91
+ * wall" is a choice between two things you could actually do on a Saturday, and it has to be
92
+ * justified before the answer appears.
93
+ */
94
+ interface Spot {
95
+ id: string;
96
+ name: string;
97
+ x: number;
98
+ y: number;
99
+ }
100
+ interface FloorPlan {
101
+ id: string;
102
+ name: string;
103
+ /** Overall extent in metres, so the drawing and the physics share one coordinate system. */
104
+ widthM: number;
105
+ heightM: number;
106
+ rooms: Room[];
107
+ walls: Wall[];
108
+ spots: Spot[];
109
+ note: string;
110
+ }
111
+ interface Point {
112
+ x: number;
113
+ y: number;
114
+ }
115
+ /**
116
+ * Transmit power of a domestic access point, in dBm. 20 dBm is 100 mW, the legal ceiling in most
117
+ * places and what essentially every home router emits, which is worth knowing because it means
118
+ * "buy a more powerful router" is not available as an answer. The only levers are position,
119
+ * frequency, and a second access point.
120
+ */
121
+ declare const TX_POWER_DBM = 20;
122
+ /**
123
+ * How fast power falls with distance indoors.
124
+ *
125
+ * In free space the exponent is 2: pure spreading over a sphere. Indoors, 3.0 is the standard
126
+ * figure for a home or small office, because furniture, floors and people absorb as well as the
127
+ * geometry spreading. The walls are counted separately and explicitly, so this number represents
128
+ * everything that is NOT a wall the learner placed.
129
+ */
130
+ declare const PATH_LOSS_EXPONENT = 3;
131
+ /**
132
+ * The floor below which a number stops meaning anything, in dBm.
133
+ *
134
+ * Thermal noise in a 20 MHz channel sits near -101 dBm, so a receiver cannot distinguish a signal
135
+ * from the noise it arrives in much below this. An uncapped model happily reports -114 dBm, which
136
+ * looks precise and is fiction: the honest statement is "below the noise floor", and the lab should
137
+ * say that rather than print a number a real radio could never measure.
138
+ */
139
+ declare const NOISE_FLOOR_DBM = -100;
140
+ /**
141
+ * Loss over the first metre, in dB. This is where frequency enters before any wall is involved:
142
+ * about 40 dB at 2.4 GHz and 46 dB at 5 GHz. The faster band starts six decibels behind at the
143
+ * very first metre, having passed through nothing at all.
144
+ */
145
+ declare function referenceLossDb(band: Band): number;
146
+ /** The walls a straight line from the router to a point passes through. */
147
+ declare function wallsBetween(plan: FloorPlan, from: Point, to: Point): Wall[];
148
+ interface Reading {
149
+ /** Received power in dBm. Negative, and less negative is better. */
150
+ rssi: number;
151
+ distanceM: number;
152
+ /** Every wall on the straight path, in no particular order. */
153
+ obstacles: Wall[];
154
+ /** Total absorption from those walls, in dB. */
155
+ wallLossDb: number;
156
+ }
157
+ /**
158
+ * Received signal strength at a point, by the log-distance model with explicit wall terms.
159
+ *
160
+ * This treats the signal as travelling in a straight line and ignores reflection, which in a real
161
+ * flat delivers some signal around a corner that this model calls dead. That simplification is
162
+ * deliberate and is the right one for teaching: it keeps the cause of every number visible, and a
163
+ * model that says "a wall costs you this much" is exactly the intuition a learner should leave with.
164
+ */
165
+ declare function signalAt(plan: FloorPlan, router: Point, point: Point, band: Band): Reading;
166
+ type Grade = "excellent" | "good" | "usable" | "weak" | "dead";
167
+ interface GradeSpec {
168
+ id: Grade;
169
+ label: string;
170
+ /** Lowest RSSI in dBm that still counts as this grade. */
171
+ floor: number;
172
+ /** What the learner could actually do standing here. */
173
+ can: string;
174
+ }
175
+ /**
176
+ * The grade ladder, in dBm.
177
+ *
178
+ * These are the thresholds a real site survey designs against rather than round numbers chosen to
179
+ * look tidy: -67 dBm is the industry target for voice and video, and -70 is where ordinary data
180
+ * starts to struggle. Naming what a learner could DO at each level, rather than calling it "3 bars",
181
+ * is the point. Bars are a made-up scale that differs between handsets; dBm is a measurement.
182
+ */
183
+ declare const GRADES: GradeSpec[];
184
+ declare function grade(rssi: number): GradeSpec;
185
+ /**
186
+ * A rough throughput for a reading, in Mbps.
187
+ *
188
+ * Real rate selection is a ladder of modulation schemes, and the shape that matters to a learner is
189
+ * that throughput does not fade gently with distance: it holds up, then falls off a cliff as each
190
+ * rung becomes unreadable. Interpolating between the grade thresholds reproduces that staircase
191
+ * feel without pretending to model MCS tables.
192
+ */
193
+ declare function throughputMbps(rssi: number, band: Band): number;
194
+ interface RoomVerdict {
195
+ room: Room;
196
+ /** The weakest sample inside the room: a room is only as good as its worst corner. */
197
+ rssi: number;
198
+ grade: GradeSpec;
199
+ mbps: number;
200
+ /** Materials responsible for the worst corner, most costly first. */
201
+ blamed: WallMaterial[];
202
+ }
203
+ /**
204
+ * Grade every room from its WORST corner rather than its centre.
205
+ *
206
+ * Judging a room by its middle is how a coverage plan passes on paper and fails in the building:
207
+ * the desk is against the far wall, not in the centre of the floor. Reporting the worst sample also
208
+ * makes the lab honest when a learner parks the router in the hallway and every room reads "usable"
209
+ * from its midpoint while the bed and the desk do not.
210
+ */
211
+ declare function roomVerdicts(plan: FloorPlan, router: Point, band: Band): RoomVerdict[];
212
+ /**
213
+ * RSSI on a regular grid over the whole plan, for the heat map.
214
+ *
215
+ * Returned row-major as `[row][col]` with row 0 at the top, matching how the SVG draws it, so the
216
+ * scene never has to flip an index and quietly mirror the picture.
217
+ */
218
+ declare function coverageGrid(plan: FloorPlan, router: Point, band: Band, cols: number, rows: number): number[][];
219
+ /** Share of the rooms that reach at least `usable`, which is the number a learner is trying to raise. */
220
+ declare function coverageScore(plan: FloorPlan, router: Point, band: Band): number;
221
+ /**
222
+ * Floor plans a learner recognises, which is most of the work.
223
+ *
224
+ * A generic rectangle labelled "room A / room B" teaches the model and none of the intuition. The
225
+ * three-bedroom flat below is the ordinary shape of an apartment in Dhaka or Chattogram: brick
226
+ * partitions, a concrete wet wall around the bathroom, and the router wherever the broadband cable
227
+ * happened to enter, which is almost never where it should be. A learner who fixes THIS plan can
228
+ * walk home and fix theirs, and that transfer is the whole reason to draw a room instead of a graph.
229
+ */
230
+ declare const FLOOR_PLANS: FloorPlan[];
231
+ /**
232
+ * The best spot on the plan, found by trying a coarse grid of positions.
233
+ *
234
+ * Present this only AFTER a learner has committed to a position of their own. Shown first it is an
235
+ * answer key and they will drag toward it without forming a reason; shown second it is feedback on
236
+ * a guess they already had to justify, and the gap between the two is the lesson.
237
+ */
238
+ declare function bestPlacement(plan: FloorPlan, band: Band, step?: number): Point;
239
+ //#endregion
240
+ export { BANDS, Band, BandSpec, FLOOR_PLANS, FloorPlan, GRADES, Grade, GradeSpec, MATERIALS, MaterialSpec, NOISE_FLOOR_DBM, PATH_LOSS_EXPONENT, Point, Reading, Room, RoomVerdict, Spot, TX_POWER_DBM, Wall, WallMaterial, bestPlacement, coverageGrid, coverageScore, grade, referenceLossDb, roomVerdicts, signalAt, throughputMbps, wallsBetween };