@fundamental-engine/core 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 (371) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +128 -0
  3. package/dist/agents/element-agent.d.ts +38 -0
  4. package/dist/agents/element-agent.d.ts.map +1 -0
  5. package/dist/agents/element-agent.js +70 -0
  6. package/dist/agents/element-agent.js.map +1 -0
  7. package/dist/agents/event-agent.d.ts +47 -0
  8. package/dist/agents/event-agent.d.ts.map +1 -0
  9. package/dist/agents/event-agent.js +82 -0
  10. package/dist/agents/event-agent.js.map +1 -0
  11. package/dist/agents/index.d.ts +17 -0
  12. package/dist/agents/index.d.ts.map +1 -0
  13. package/dist/agents/index.js +57 -0
  14. package/dist/agents/index.js.map +1 -0
  15. package/dist/agents/region-agents.d.ts +40 -0
  16. package/dist/agents/region-agents.d.ts.map +1 -0
  17. package/dist/agents/region-agents.js +22 -0
  18. package/dist/agents/region-agents.js.map +1 -0
  19. package/dist/agents/relationship.d.ts +55 -0
  20. package/dist/agents/relationship.d.ts.map +1 -0
  21. package/dist/agents/relationship.js +40 -0
  22. package/dist/agents/relationship.js.map +1 -0
  23. package/dist/agents/user-agent.d.ts +57 -0
  24. package/dist/agents/user-agent.d.ts.map +1 -0
  25. package/dist/agents/user-agent.js +45 -0
  26. package/dist/agents/user-agent.js.map +1 -0
  27. package/dist/config/forces.config.d.ts +101 -0
  28. package/dist/config/forces.config.d.ts.map +1 -0
  29. package/dist/config/forces.config.js +239 -0
  30. package/dist/config/forces.config.js.map +1 -0
  31. package/dist/config/manual.d.ts +134 -0
  32. package/dist/config/manual.d.ts.map +1 -0
  33. package/dist/config/manual.js +604 -0
  34. package/dist/config/manual.js.map +1 -0
  35. package/dist/config/palettes.d.ts +18 -0
  36. package/dist/config/palettes.d.ts.map +1 -0
  37. package/dist/config/palettes.js +34 -0
  38. package/dist/config/palettes.js.map +1 -0
  39. package/dist/config/presets.d.ts +48 -0
  40. package/dist/config/presets.d.ts.map +1 -0
  41. package/dist/config/presets.js +87 -0
  42. package/dist/config/presets.js.map +1 -0
  43. package/dist/config/tokens.d.ts +3 -0
  44. package/dist/config/tokens.d.ts.map +1 -0
  45. package/dist/config/tokens.js +16 -0
  46. package/dist/config/tokens.js.map +1 -0
  47. package/dist/conformance/expectations.d.ts +40 -0
  48. package/dist/conformance/expectations.d.ts.map +1 -0
  49. package/dist/conformance/expectations.js +347 -0
  50. package/dist/conformance/expectations.js.map +1 -0
  51. package/dist/conformance/experiments.d.ts +17 -0
  52. package/dist/conformance/experiments.d.ts.map +1 -0
  53. package/dist/conformance/experiments.js +875 -0
  54. package/dist/conformance/experiments.js.map +1 -0
  55. package/dist/conformance/run.d.ts +18 -0
  56. package/dist/conformance/run.d.ts.map +1 -0
  57. package/dist/conformance/run.js +240 -0
  58. package/dist/conformance/run.js.map +1 -0
  59. package/dist/conformance/types.d.ts +100 -0
  60. package/dist/conformance/types.d.ts.map +1 -0
  61. package/dist/conformance/types.js +2 -0
  62. package/dist/conformance/types.js.map +1 -0
  63. package/dist/contracts/guards.d.ts +51 -0
  64. package/dist/contracts/guards.d.ts.map +1 -0
  65. package/dist/contracts/guards.js +100 -0
  66. package/dist/contracts/guards.js.map +1 -0
  67. package/dist/contracts/index.d.ts +18 -0
  68. package/dist/contracts/index.d.ts.map +1 -0
  69. package/dist/contracts/index.js +107 -0
  70. package/dist/contracts/index.js.map +1 -0
  71. package/dist/contracts/passport.d.ts +88 -0
  72. package/dist/contracts/passport.d.ts.map +1 -0
  73. package/dist/contracts/passport.js +135 -0
  74. package/dist/contracts/passport.js.map +1 -0
  75. package/dist/contracts/types.d.ts +120 -0
  76. package/dist/contracts/types.d.ts.map +1 -0
  77. package/dist/contracts/types.js +24 -0
  78. package/dist/contracts/types.js.map +1 -0
  79. package/dist/core/accretion.d.ts +50 -0
  80. package/dist/core/accretion.d.ts.map +1 -0
  81. package/dist/core/accretion.js +98 -0
  82. package/dist/core/accretion.js.map +1 -0
  83. package/dist/core/agents.d.ts +31 -0
  84. package/dist/core/agents.d.ts.map +1 -0
  85. package/dist/core/agents.js +51 -0
  86. package/dist/core/agents.js.map +1 -0
  87. package/dist/core/attention.d.ts +72 -0
  88. package/dist/core/attention.d.ts.map +1 -0
  89. package/dist/core/attention.js +122 -0
  90. package/dist/core/attention.js.map +1 -0
  91. package/dist/core/causality.d.ts +38 -0
  92. package/dist/core/causality.d.ts.map +1 -0
  93. package/dist/core/causality.js +64 -0
  94. package/dist/core/causality.js.map +1 -0
  95. package/dist/core/conditions.d.ts +10 -0
  96. package/dist/core/conditions.d.ts.map +1 -0
  97. package/dist/core/conditions.js +22 -0
  98. package/dist/core/conditions.js.map +1 -0
  99. package/dist/core/currents.d.ts +53 -0
  100. package/dist/core/currents.d.ts.map +1 -0
  101. package/dist/core/currents.js +65 -0
  102. package/dist/core/currents.js.map +1 -0
  103. package/dist/core/dock.d.ts +35 -0
  104. package/dist/core/dock.d.ts.map +1 -0
  105. package/dist/core/dock.js +39 -0
  106. package/dist/core/dock.js.map +1 -0
  107. package/dist/core/events.d.ts +23 -0
  108. package/dist/core/events.d.ts.map +1 -0
  109. package/dist/core/events.js +34 -0
  110. package/dist/core/events.js.map +1 -0
  111. package/dist/core/feedback-sink.d.ts +32 -0
  112. package/dist/core/feedback-sink.d.ts.map +1 -0
  113. package/dist/core/feedback-sink.js +53 -0
  114. package/dist/core/feedback-sink.js.map +1 -0
  115. package/dist/core/feedback.d.ts +11 -0
  116. package/dist/core/feedback.d.ts.map +1 -0
  117. package/dist/core/feedback.js +16 -0
  118. package/dist/core/feedback.js.map +1 -0
  119. package/dist/core/field-store.d.ts +26 -0
  120. package/dist/core/field-store.d.ts.map +1 -0
  121. package/dist/core/field-store.js +54 -0
  122. package/dist/core/field-store.js.map +1 -0
  123. package/dist/core/field.d.ts +18 -0
  124. package/dist/core/field.d.ts.map +1 -0
  125. package/dist/core/field.js +1943 -0
  126. package/dist/core/field.js.map +1 -0
  127. package/dist/core/fieldline-seeds.d.ts +25 -0
  128. package/dist/core/fieldline-seeds.d.ts.map +1 -0
  129. package/dist/core/fieldline-seeds.js +32 -0
  130. package/dist/core/fieldline-seeds.js.map +1 -0
  131. package/dist/core/fieldlines.d.ts +75 -0
  132. package/dist/core/fieldlines.d.ts.map +1 -0
  133. package/dist/core/fieldlines.js +111 -0
  134. package/dist/core/fieldlines.js.map +1 -0
  135. package/dist/core/flow.d.ts +38 -0
  136. package/dist/core/flow.d.ts.map +1 -0
  137. package/dist/core/flow.js +27 -0
  138. package/dist/core/flow.js.map +1 -0
  139. package/dist/core/formations.d.ts +11 -0
  140. package/dist/core/formations.d.ts.map +1 -0
  141. package/dist/core/formations.js +22 -0
  142. package/dist/core/formations.js.map +1 -0
  143. package/dist/core/geometry.d.ts +67 -0
  144. package/dist/core/geometry.d.ts.map +1 -0
  145. package/dist/core/geometry.js +68 -0
  146. package/dist/core/geometry.js.map +1 -0
  147. package/dist/core/heatmap.d.ts +22 -0
  148. package/dist/core/heatmap.d.ts.map +1 -0
  149. package/dist/core/heatmap.js +55 -0
  150. package/dist/core/heatmap.js.map +1 -0
  151. package/dist/core/host.d.ts +46 -0
  152. package/dist/core/host.d.ts.map +1 -0
  153. package/dist/core/host.js +11 -0
  154. package/dist/core/host.js.map +1 -0
  155. package/dist/core/integrator.d.ts +24 -0
  156. package/dist/core/integrator.d.ts.map +1 -0
  157. package/dist/core/integrator.js +375 -0
  158. package/dist/core/integrator.js.map +1 -0
  159. package/dist/core/math.d.ts +37 -0
  160. package/dist/core/math.d.ts.map +1 -0
  161. package/dist/core/math.js +77 -0
  162. package/dist/core/math.js.map +1 -0
  163. package/dist/core/reactions.d.ts +32 -0
  164. package/dist/core/reactions.d.ts.map +1 -0
  165. package/dist/core/reactions.js +45 -0
  166. package/dist/core/reactions.js.map +1 -0
  167. package/dist/core/registry.d.ts +13 -0
  168. package/dist/core/registry.d.ts.map +1 -0
  169. package/dist/core/registry.js +20 -0
  170. package/dist/core/registry.js.map +1 -0
  171. package/dist/core/render-backend.d.ts +46 -0
  172. package/dist/core/render-backend.d.ts.map +1 -0
  173. package/dist/core/render-backend.js +75 -0
  174. package/dist/core/render-backend.js.map +1 -0
  175. package/dist/core/render-modes.d.ts +42 -0
  176. package/dist/core/render-modes.d.ts.map +1 -0
  177. package/dist/core/render-modes.js +141 -0
  178. package/dist/core/render-modes.js.map +1 -0
  179. package/dist/core/reservoir.d.ts +43 -0
  180. package/dist/core/reservoir.d.ts.map +1 -0
  181. package/dist/core/reservoir.js +207 -0
  182. package/dist/core/reservoir.js.map +1 -0
  183. package/dist/core/scalar-grid.d.ts +51 -0
  184. package/dist/core/scalar-grid.d.ts.map +1 -0
  185. package/dist/core/scalar-grid.js +146 -0
  186. package/dist/core/scalar-grid.js.map +1 -0
  187. package/dist/core/scanner.d.ts +59 -0
  188. package/dist/core/scanner.d.ts.map +1 -0
  189. package/dist/core/scanner.js +260 -0
  190. package/dist/core/scanner.js.map +1 -0
  191. package/dist/core/shadow.d.ts +69 -0
  192. package/dist/core/shadow.d.ts.map +1 -0
  193. package/dist/core/shadow.js +84 -0
  194. package/dist/core/shadow.js.map +1 -0
  195. package/dist/core/spatial-hash.d.ts +30 -0
  196. package/dist/core/spatial-hash.d.ts.map +1 -0
  197. package/dist/core/spatial-hash.js +64 -0
  198. package/dist/core/spatial-hash.js.map +1 -0
  199. package/dist/core/streamlines.d.ts +29 -0
  200. package/dist/core/streamlines.d.ts.map +1 -0
  201. package/dist/core/streamlines.js +70 -0
  202. package/dist/core/streamlines.js.map +1 -0
  203. package/dist/core/surface.d.ts +19 -0
  204. package/dist/core/surface.d.ts.map +1 -0
  205. package/dist/core/surface.js +21 -0
  206. package/dist/core/surface.js.map +1 -0
  207. package/dist/core/temporal.d.ts +110 -0
  208. package/dist/core/temporal.d.ts.map +1 -0
  209. package/dist/core/temporal.js +139 -0
  210. package/dist/core/temporal.js.map +1 -0
  211. package/dist/core/thermo.d.ts +48 -0
  212. package/dist/core/thermo.d.ts.map +1 -0
  213. package/dist/core/thermo.js +48 -0
  214. package/dist/core/thermo.js.map +1 -0
  215. package/dist/core/types.d.ts +610 -0
  216. package/dist/core/types.d.ts.map +1 -0
  217. package/dist/core/types.js +2 -0
  218. package/dist/core/types.js.map +1 -0
  219. package/dist/core/weights.d.ts +111 -0
  220. package/dist/core/weights.d.ts.map +1 -0
  221. package/dist/core/weights.js +128 -0
  222. package/dist/core/weights.js.map +1 -0
  223. package/dist/diagnostics/energy.d.ts +21 -0
  224. package/dist/diagnostics/energy.d.ts.map +1 -0
  225. package/dist/diagnostics/energy.js +27 -0
  226. package/dist/diagnostics/energy.js.map +1 -0
  227. package/dist/diagnostics/fields.d.ts +23 -0
  228. package/dist/diagnostics/fields.d.ts.map +1 -0
  229. package/dist/diagnostics/fields.js +30 -0
  230. package/dist/diagnostics/fields.js.map +1 -0
  231. package/dist/diagnostics/index.d.ts +46 -0
  232. package/dist/diagnostics/index.d.ts.map +1 -0
  233. package/dist/diagnostics/index.js +23 -0
  234. package/dist/diagnostics/index.js.map +1 -0
  235. package/dist/diagnostics/modes.d.ts +108 -0
  236. package/dist/diagnostics/modes.d.ts.map +1 -0
  237. package/dist/diagnostics/modes.js +181 -0
  238. package/dist/diagnostics/modes.js.map +1 -0
  239. package/dist/diagnostics/potential.d.ts +30 -0
  240. package/dist/diagnostics/potential.d.ts.map +1 -0
  241. package/dist/diagnostics/potential.js +43 -0
  242. package/dist/diagnostics/potential.js.map +1 -0
  243. package/dist/diagnostics/probes.d.ts +31 -0
  244. package/dist/diagnostics/probes.d.ts.map +1 -0
  245. package/dist/diagnostics/probes.js +61 -0
  246. package/dist/diagnostics/probes.js.map +1 -0
  247. package/dist/diagnostics/render.d.ts +49 -0
  248. package/dist/diagnostics/render.d.ts.map +1 -0
  249. package/dist/diagnostics/render.js +132 -0
  250. package/dist/diagnostics/render.js.map +1 -0
  251. package/dist/export.d.ts +18 -0
  252. package/dist/export.d.ts.map +1 -0
  253. package/dist/export.js +17 -0
  254. package/dist/export.js.map +1 -0
  255. package/dist/forces/extended.d.ts +121 -0
  256. package/dist/forces/extended.d.ts.map +1 -0
  257. package/dist/forces/extended.js +674 -0
  258. package/dist/forces/extended.js.map +1 -0
  259. package/dist/forces/index.d.ts +33 -0
  260. package/dist/forces/index.d.ts.map +1 -0
  261. package/dist/forces/index.js +237 -0
  262. package/dist/forces/index.js.map +1 -0
  263. package/dist/forces/natural.d.ts +106 -0
  264. package/dist/forces/natural.d.ts.map +1 -0
  265. package/dist/forces/natural.js +385 -0
  266. package/dist/forces/natural.js.map +1 -0
  267. package/dist/index.d.ts +59 -0
  268. package/dist/index.d.ts.map +1 -0
  269. package/dist/index.js +71 -0
  270. package/dist/index.js.map +1 -0
  271. package/dist/inspect/budget.d.ts +17 -0
  272. package/dist/inspect/budget.d.ts.map +1 -0
  273. package/dist/inspect/budget.js +19 -0
  274. package/dist/inspect/budget.js.map +1 -0
  275. package/dist/inspect/index.d.ts +10 -0
  276. package/dist/inspect/index.d.ts.map +1 -0
  277. package/dist/inspect/index.js +10 -0
  278. package/dist/inspect/index.js.map +1 -0
  279. package/dist/inspect/report.d.ts +17 -0
  280. package/dist/inspect/report.d.ts.map +1 -0
  281. package/dist/inspect/report.js +44 -0
  282. package/dist/inspect/report.js.map +1 -0
  283. package/dist/inspect/snapshot.d.ts +21 -0
  284. package/dist/inspect/snapshot.d.ts.map +1 -0
  285. package/dist/inspect/snapshot.js +30 -0
  286. package/dist/inspect/snapshot.js.map +1 -0
  287. package/dist/recipes/catalog.d.ts +51 -0
  288. package/dist/recipes/catalog.d.ts.map +1 -0
  289. package/dist/recipes/catalog.js +1496 -0
  290. package/dist/recipes/catalog.js.map +1 -0
  291. package/dist/recipes/charge.d.ts +18 -0
  292. package/dist/recipes/charge.d.ts.map +1 -0
  293. package/dist/recipes/charge.js +27 -0
  294. package/dist/recipes/charge.js.map +1 -0
  295. package/dist/recipes/compile.d.ts +93 -0
  296. package/dist/recipes/compile.d.ts.map +1 -0
  297. package/dist/recipes/compile.js +113 -0
  298. package/dist/recipes/compile.js.map +1 -0
  299. package/dist/recipes/explain.d.ts +8 -0
  300. package/dist/recipes/explain.d.ts.map +1 -0
  301. package/dist/recipes/explain.js +46 -0
  302. package/dist/recipes/explain.js.map +1 -0
  303. package/dist/recipes/gallery.d.ts +6 -0
  304. package/dist/recipes/gallery.d.ts.map +1 -0
  305. package/dist/recipes/gallery.js +6 -0
  306. package/dist/recipes/gallery.js.map +1 -0
  307. package/dist/recipes/gravity.d.ts +16 -0
  308. package/dist/recipes/gravity.d.ts.map +1 -0
  309. package/dist/recipes/gravity.js +27 -0
  310. package/dist/recipes/gravity.js.map +1 -0
  311. package/dist/recipes/index.d.ts +18 -0
  312. package/dist/recipes/index.d.ts.map +1 -0
  313. package/dist/recipes/index.js +36 -0
  314. package/dist/recipes/index.js.map +1 -0
  315. package/dist/recipes/intent.d.ts +44 -0
  316. package/dist/recipes/intent.d.ts.map +1 -0
  317. package/dist/recipes/intent.js +46 -0
  318. package/dist/recipes/intent.js.map +1 -0
  319. package/dist/recipes/schema.d.ts +103 -0
  320. package/dist/recipes/schema.d.ts.map +1 -0
  321. package/dist/recipes/schema.js +123 -0
  322. package/dist/recipes/schema.js.map +1 -0
  323. package/dist/recipes/wayfinding.d.ts +39 -0
  324. package/dist/recipes/wayfinding.d.ts.map +1 -0
  325. package/dist/recipes/wayfinding.js +77 -0
  326. package/dist/recipes/wayfinding.js.map +1 -0
  327. package/dist/semantic/index.d.ts +13 -0
  328. package/dist/semantic/index.d.ts.map +1 -0
  329. package/dist/semantic/index.js +31 -0
  330. package/dist/semantic/index.js.map +1 -0
  331. package/dist/semantic/layers.d.ts +24 -0
  332. package/dist/semantic/layers.d.ts.map +1 -0
  333. package/dist/semantic/layers.js +27 -0
  334. package/dist/semantic/layers.js.map +1 -0
  335. package/dist/semantic/materials.d.ts +20 -0
  336. package/dist/semantic/materials.d.ts.map +1 -0
  337. package/dist/semantic/materials.js +17 -0
  338. package/dist/semantic/materials.js.map +1 -0
  339. package/dist/semantic/states.d.ts +11 -0
  340. package/dist/semantic/states.d.ts.map +1 -0
  341. package/dist/semantic/states.js +26 -0
  342. package/dist/semantic/states.js.map +1 -0
  343. package/dist/visual/channels.d.ts +71 -0
  344. package/dist/visual/channels.d.ts.map +1 -0
  345. package/dist/visual/channels.js +70 -0
  346. package/dist/visual/channels.js.map +1 -0
  347. package/dist/visual/index.d.ts +39 -0
  348. package/dist/visual/index.d.ts.map +1 -0
  349. package/dist/visual/index.js +30 -0
  350. package/dist/visual/index.js.map +1 -0
  351. package/dist/visual/lint.d.ts +41 -0
  352. package/dist/visual/lint.d.ts.map +1 -0
  353. package/dist/visual/lint.js +58 -0
  354. package/dist/visual/lint.js.map +1 -0
  355. package/dist/visual/mapping.d.ts +13 -0
  356. package/dist/visual/mapping.d.ts.map +1 -0
  357. package/dist/visual/mapping.js +43 -0
  358. package/dist/visual/mapping.js.map +1 -0
  359. package/dist/visual/semantic-text.d.ts +28 -0
  360. package/dist/visual/semantic-text.d.ts.map +1 -0
  361. package/dist/visual/semantic-text.js +36 -0
  362. package/dist/visual/semantic-text.js.map +1 -0
  363. package/dist/visual/tokens.d.ts +23 -0
  364. package/dist/visual/tokens.d.ts.map +1 -0
  365. package/dist/visual/tokens.js +54 -0
  366. package/dist/visual/tokens.js.map +1 -0
  367. package/dist/visual/visualization.d.ts +31 -0
  368. package/dist/visual/visualization.d.ts.map +1 -0
  369. package/dist/visual/visualization.js +47 -0
  370. package/dist/visual/visualization.js.map +1 -0
  371. package/package.json +60 -0
@@ -0,0 +1,84 @@
1
+ /** The registration event names. `composed: true` lets them cross the shadow boundary. */
2
+ export const REGISTER_BODY = 'field:register-body';
3
+ export const UNREGISTER_BODY = 'field:unregister-body';
4
+ export const UPDATE_BODY = 'field:update-body';
5
+ /**
6
+ * Component-side helper (shadow-dom.md §31.1) so a custom element joins the field without
7
+ * repeating event boilerplate. Construct with the host (and optional extra detail), then
8
+ * call `connect()` / `disconnect()` / `update()` from the element's lifecycle callbacks.
9
+ */
10
+ export class FieldController {
11
+ host;
12
+ detail;
13
+ constructor(host, detail = {}) {
14
+ this.host = host;
15
+ this.detail = detail;
16
+ }
17
+ /** register the host as a body — call from `connectedCallback`. */
18
+ connect() {
19
+ this.emit(REGISTER_BODY);
20
+ }
21
+ /** remove the body — call from `disconnectedCallback`. */
22
+ disconnect() {
23
+ this.emit(UNREGISTER_BODY);
24
+ }
25
+ /** refresh attrs/geometry — call from `attributeChangedCallback`. */
26
+ update() {
27
+ this.emit(UPDATE_BODY);
28
+ }
29
+ emit(type) {
30
+ const detail = { element: this.host, ...this.detail };
31
+ this.host.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
32
+ }
33
+ }
34
+ /**
35
+ * Engine-side registry of event-registered hosts. Pure of the DOM event system: the field
36
+ * feeds it details and asks for bodies each scan. It prunes hosts that have left the document
37
+ * (do not rely on `disconnectedCallback` alone, §15) and never touches a shadow root.
38
+ */
39
+ export class ShadowRegistry {
40
+ hosts = new Map();
41
+ /** Register (or, idempotently, refresh) a host. */
42
+ register(detail) {
43
+ this.hosts.set(detail.element, detail);
44
+ }
45
+ /** Drop a host. */
46
+ unregister(element) {
47
+ this.hosts.delete(element);
48
+ }
49
+ /** how many hosts are currently registered (post-prune count is via `bodies`). */
50
+ get size() {
51
+ return this.hosts.size;
52
+ }
53
+ /**
54
+ * Build a `Body` per live registered host, pruning any that have disconnected. `build` is
55
+ * the scanner's `bodyFromElement`; `attrs` (if supplied at registration) override the
56
+ * host's own `data-*`, else the host is read directly. A custom `getRect` and `writeTarget`
57
+ * are attached to the resulting body.
58
+ */
59
+ bodies(build) {
60
+ const out = [];
61
+ for (const [el, detail] of this.hosts) {
62
+ if (!el.isConnected) {
63
+ this.hosts.delete(el);
64
+ continue;
65
+ }
66
+ const attrs = detail.attrs ? attrsView(detail.attrs, el) : undefined;
67
+ const body = build(el, attrs);
68
+ if (detail.getRect)
69
+ body.rect = detail.getRect;
70
+ if (detail.writeTarget)
71
+ body.writeTarget = detail.writeTarget;
72
+ out.push(body);
73
+ }
74
+ return out;
75
+ }
76
+ }
77
+ /** A `BodyAttrs` view that prefers the explicit `attrs` record, falling back to the host. */
78
+ function attrsView(attrs, el) {
79
+ return {
80
+ get: (name) => attrs[name] ?? el.getAttribute('data-' + name),
81
+ has: (name) => name in attrs || el.hasAttribute('data-' + name),
82
+ };
83
+ }
84
+ //# sourceMappingURL=shadow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../src/core/shadow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A uniform-grid spatial hash for neighbour queries — the index that makes
3
+ * particle↔particle forces (§20.1 class [B]) O(n·k) instead of O(n²).
4
+ *
5
+ * Rebuilt each frame from the live particle pool; query with `near(x, y, r)`.
6
+ * Dependency-free.
7
+ */
8
+ export interface Point {
9
+ x: number;
10
+ y: number;
11
+ /** optional z lane (z-axis.md) — undefined reads as 0 (the flat plane). */
12
+ z?: number;
13
+ }
14
+ export declare class SpatialHash<T extends Point> {
15
+ private readonly cell;
16
+ private readonly bins;
17
+ constructor(cellSize?: number);
18
+ private key;
19
+ clear(): void;
20
+ insert(item: T): void;
21
+ rebuild(items: readonly T[]): void;
22
+ /**
23
+ * Items within radius `r` of (x, y, z), filtered by TRUE (3D) distance. Bins stay
24
+ * planar — items at any z share their (x, y) cell — which over-collects candidates
25
+ * in a deep volume but never returns a wrong result; the z² term below is the
26
+ * contract. `z` defaults to 0, so flat-field callers are byte-identical.
27
+ */
28
+ near(x: number, y: number, r: number, z?: number): T[];
29
+ }
30
+ //# sourceMappingURL=spatial-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-hash.d.ts","sourceRoot":"","sources":["../../src/core/spatial-hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,2EAA2E;IAC3E,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,qBAAa,WAAW,CAAC,CAAC,SAAS,KAAK;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;gBAEnC,QAAQ,SAAK;IAIzB,OAAO,CAAC,GAAG;IAKX,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAUrB,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI;IAKlC;;;;;OAKG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,CAAC,EAAE;CAqBlD"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * A uniform-grid spatial hash for neighbour queries — the index that makes
3
+ * particle↔particle forces (§20.1 class [B]) O(n·k) instead of O(n²).
4
+ *
5
+ * Rebuilt each frame from the live particle pool; query with `near(x, y, r)`.
6
+ * Dependency-free.
7
+ */
8
+ export class SpatialHash {
9
+ cell;
10
+ bins = new Map();
11
+ constructor(cellSize = 64) {
12
+ this.cell = cellSize > 0 ? cellSize : 64;
13
+ }
14
+ key(cx, cy) {
15
+ // pack two signed cell coords into one number (offset to keep non-negative).
16
+ return (cx + 0x8000) * 0x10000 + (cy + 0x8000);
17
+ }
18
+ clear() {
19
+ this.bins.clear();
20
+ }
21
+ insert(item) {
22
+ const k = this.key(Math.floor(item.x / this.cell), Math.floor(item.y / this.cell));
23
+ const bin = this.bins.get(k);
24
+ if (bin)
25
+ bin.push(item);
26
+ else
27
+ this.bins.set(k, [item]);
28
+ }
29
+ rebuild(items) {
30
+ this.clear();
31
+ for (const it of items)
32
+ this.insert(it);
33
+ }
34
+ /**
35
+ * Items within radius `r` of (x, y, z), filtered by TRUE (3D) distance. Bins stay
36
+ * planar — items at any z share their (x, y) cell — which over-collects candidates
37
+ * in a deep volume but never returns a wrong result; the z² term below is the
38
+ * contract. `z` defaults to 0, so flat-field callers are byte-identical.
39
+ */
40
+ near(x, y, r, z = 0) {
41
+ const out = [];
42
+ const r2 = r * r;
43
+ const minCx = Math.floor((x - r) / this.cell);
44
+ const maxCx = Math.floor((x + r) / this.cell);
45
+ const minCy = Math.floor((y - r) / this.cell);
46
+ const maxCy = Math.floor((y + r) / this.cell);
47
+ for (let cx = minCx; cx <= maxCx; cx++) {
48
+ for (let cy = minCy; cy <= maxCy; cy++) {
49
+ const bin = this.bins.get(this.key(cx, cy));
50
+ if (!bin)
51
+ continue;
52
+ for (const it of bin) {
53
+ const dx = it.x - x;
54
+ const dy = it.y - y;
55
+ const dz = (it.z ?? 0) - z;
56
+ if (dx * dx + dy * dy + dz * dz <= r2)
57
+ out.push(it);
58
+ }
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ }
64
+ //# sourceMappingURL=spatial-hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-hash.js","sourceRoot":"","sources":["../../src/core/spatial-hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,OAAO,WAAW;IACL,IAAI,CAAS;IACb,IAAI,GAAG,IAAI,GAAG,EAAe,CAAC;IAE/C,YAAY,QAAQ,GAAG,EAAE;QACvB,IAAI,CAAC,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAEO,GAAG,CAAC,EAAU,EAAE,EAAU;QAChC,6EAA6E;QAC7E,OAAO,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IACjD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,IAAO;QACZ,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAChB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAC9B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAC/B,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,GAAG;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YACnB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,KAAmB;QACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,KAAK,MAAM,EAAE,IAAI,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAC,GAAG,CAAC;QACzC,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;YACvC,KAAK,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;gBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC5C,IAAI,CAAC,GAAG;oBAAE,SAAS;gBACnB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;oBACrB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;oBACpB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;oBACpB,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;oBAC3B,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE;wBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Streamlines / vector-field render (§20.6, diagnostic) — instead of the matter, draw
3
+ * the *forces themselves*. At a grid of probe points we measure the net push a
4
+ * still test particle would feel and draw a short arrow along it, so the invisible
5
+ * field a layout creates becomes visible. Invaluable in the Lab: place forces, then
6
+ * see the field they make.
7
+ *
8
+ * `forceAt` is pure and mirrors the integrator's body-force loop (same range cull),
9
+ * minus the per-particle modifier pass — a faithful-enough probe for a diagnostic.
10
+ */
11
+ import type { Body, Env, ForceRegistry } from './types.ts';
12
+ /** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
13
+ * A force that defines a `field()` (its visual/structure field) contributes that instead
14
+ * of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
15
+ * even though they no-op on a still, neutral probe. */
16
+ export declare function forceAt(bodies: readonly Body[], forces: ForceRegistry, env: Env, x: number, y: number): {
17
+ fx: number;
18
+ fy: number;
19
+ };
20
+ /** The net *structure* field at (x, y): the superposition of every visible body's `field()`
21
+ * contribution (the dipoles and monopoles only — no apply-probe), with the same range cull
22
+ * as the integrator. This is the field the streamlines view draws and the vector matter
23
+ * follows under `fieldflow`. Pure: same inputs, same output, no `env` mutation (the `field()`
24
+ * hooks read only `b` and the point, so it is safe to call mid-integration). */
25
+ export declare function netField(bodies: readonly Body[], forces: ForceRegistry, x: number, y: number): {
26
+ x: number;
27
+ y: number;
28
+ };
29
+ //# sourceMappingURL=streamlines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamlines.d.ts","sourceRoot":"","sources":["../../src/core/streamlines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AAIrE;;;wDAGwD;AACxD,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,GAAG,EACR,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CA+B5B;AAED;;;;iFAIiF;AACjF,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAoB1B"}
@@ -0,0 +1,70 @@
1
+ const probe = { x: 0, y: 0, vx: 0, vy: 0, m: 1, heat: 0, size: 1, cap: null };
2
+ /** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
3
+ * A force that defines a `field()` (its visual/structure field) contributes that instead
4
+ * of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
5
+ * even though they no-op on a still, neutral probe. */
6
+ export function forceAt(bodies, forces, env, x, y) {
7
+ probe.x = x;
8
+ probe.y = y;
9
+ probe.vx = 0;
10
+ probe.vy = 0;
11
+ probe.heat = 0;
12
+ let fxField = 0; // field() contributions, accumulated apart from the apply probe
13
+ let fyField = 0;
14
+ for (const b of bodies) {
15
+ if (!b.vis || b.tokens.length === 0)
16
+ continue;
17
+ const dx = b.cx - x;
18
+ const dy = b.cy - y;
19
+ const d2 = dx * dx + dy * dy;
20
+ if (b.range > 0 && d2 >= b.range * b.range * 2.56)
21
+ continue; // same cull as the integrator
22
+ const d = Math.sqrt(d2);
23
+ env.dx = dx;
24
+ env.dy = dy;
25
+ env.dist = d < 1 ? 1 : d;
26
+ for (const tok of b.tokens) {
27
+ const f = forces[tok];
28
+ if (!f || f.modify)
29
+ continue;
30
+ if (f.field) {
31
+ const v = f.field(b, x, y);
32
+ fxField += v.x;
33
+ fyField += v.y;
34
+ }
35
+ else {
36
+ f.apply(b, probe, env);
37
+ }
38
+ }
39
+ }
40
+ return { fx: probe.vx + fxField, fy: probe.vy + fyField };
41
+ }
42
+ /** The net *structure* field at (x, y): the superposition of every visible body's `field()`
43
+ * contribution (the dipoles and monopoles only — no apply-probe), with the same range cull
44
+ * as the integrator. This is the field the streamlines view draws and the vector matter
45
+ * follows under `fieldflow`. Pure: same inputs, same output, no `env` mutation (the `field()`
46
+ * hooks read only `b` and the point, so it is safe to call mid-integration). */
47
+ export function netField(bodies, forces, x, y) {
48
+ let fx = 0;
49
+ let fy = 0;
50
+ for (const b of bodies) {
51
+ if (!b.vis || b.tokens.length === 0)
52
+ continue;
53
+ if (b.range > 0) {
54
+ const dx = b.cx - x;
55
+ const dy = b.cy - y;
56
+ if (dx * dx + dy * dy >= b.range * b.range * 2.56)
57
+ continue; // same cull as the integrator
58
+ }
59
+ for (const tok of b.tokens) {
60
+ const f = forces[tok];
61
+ if (f?.field) {
62
+ const v = f.field(b, x, y);
63
+ fx += v.x;
64
+ fy += v.y;
65
+ }
66
+ }
67
+ }
68
+ return { x: fx, y: fy };
69
+ }
70
+ //# sourceMappingURL=streamlines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streamlines.js","sourceRoot":"","sources":["../../src/core/streamlines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The decorative full-viewport canvas surface (§13, §18) — one source of truth for the
3
+ * fixed, click-through, behind-everything styling every managed mount uses. The vanilla
4
+ * `mountField` / `FieldField` and the React `<FieldField>` render this exact surface; the
5
+ * web component styles its shadow host to match.
6
+ */
7
+ /** The surface as a style object (React `CSSProperties`-compatible). */
8
+ export declare const FIELD_CANVAS_STYLE: {
9
+ readonly position: "fixed";
10
+ readonly inset: "0";
11
+ readonly width: "100%";
12
+ readonly height: "100%";
13
+ readonly zIndex: "0";
14
+ readonly pointerEvents: "none";
15
+ readonly display: "block";
16
+ };
17
+ /** The same surface as a `cssText` string (camelCase keys → kebab-case), for `style.cssText`. */
18
+ export declare const FIELD_CANVAS_CSS: string;
19
+ //# sourceMappingURL=surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/core/surface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,eAAO,MAAM,kBAAkB;;;;;;;;CAQrB,CAAC;AAEX,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,QAEjB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The decorative full-viewport canvas surface (§13, §18) — one source of truth for the
3
+ * fixed, click-through, behind-everything styling every managed mount uses. The vanilla
4
+ * `mountField` / `FieldField` and the React `<FieldField>` render this exact surface; the
5
+ * web component styles its shadow host to match.
6
+ */
7
+ /** The surface as a style object (React `CSSProperties`-compatible). */
8
+ export const FIELD_CANVAS_STYLE = {
9
+ position: 'fixed',
10
+ inset: '0',
11
+ width: '100%',
12
+ height: '100%',
13
+ zIndex: '0',
14
+ pointerEvents: 'none',
15
+ display: 'block',
16
+ };
17
+ /** The same surface as a `cssText` string (camelCase keys → kebab-case), for `style.cssText`. */
18
+ export const FIELD_CANVAS_CSS = Object.entries(FIELD_CANVAS_STYLE)
19
+ .map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())}:${v}`)
20
+ .join(';');
21
+ //# sourceMappingURL=surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.js","sourceRoot":"","sources":["../../src/core/surface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ,EAAE,OAAO;IACjB,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,GAAG;IACX,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,OAAO;CACR,CAAC;AAEX,iGAAiG;AACjG,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;KAC/D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;KAC5E,IAAI,CAAC,GAAG,CAAC,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Temporal kernels — WORLD TIME made computable.
3
+ *
4
+ * field-ui keeps three clocks:
5
+ *
6
+ * 1. **Simulation time** — `env.t` / `dt`, particle age: the integrator's clock.
7
+ * 2. **Experiential time** — the platform metric pipeline's attention / memory / recency:
8
+ * eased integrals of interaction (`@fundamental-engine/platform` `metrics.ts`).
9
+ * 3. **World time** — timestamps carried by the data itself: a launch's T−0, an issue's
10
+ * `updatedAt`, a question's `askedAt`, a fact's last review.
11
+ *
12
+ * These kernels are clock 3. Each is a pure, deterministic map from world timestamps to a
13
+ * `0..1` weight — zero DOM, zero state, and **no `Date.now()`**: the caller supplies `nowMs`
14
+ * (the platform samples it once per frame; pages sample it once per tick). All arguments are
15
+ * epoch/duration **milliseconds**; the day and hour constants the shapes were calibrated in
16
+ * are exported explicitly. Degenerate inputs (NaN, ±Infinity, non-positive timescales) never
17
+ * produce NaN — each kernel documents its safe value.
18
+ *
19
+ * The shapes are lifted, exactly, from the shipped example family (the extraction ratchet:
20
+ * four hand-rolls → one primitive): `imminence` from the calendar page's 1 Hz clock,
21
+ * `retention` from the memory page's forgetting curve, `freshness` as the canonical form of
22
+ * the backlog/inbox recency lanes. `data-field-at` (see `@fundamental-engine/platform`) feeds
23
+ * `freshness` to ground the metric pipeline's recency lane in declared world time.
24
+ */
25
+ /** One hour in milliseconds — `imminence`'s log-softening unit (the calendar shape is hour-calibrated). */
26
+ export declare const HOUR_MS = 3600000;
27
+ /** One day in milliseconds — `retention`'s τ defaults are day-calibrated (4 + a·56 days). */
28
+ export declare const DAY_MS = 86400000;
29
+ /**
30
+ * How imminent a moment feels: `1` at (or past) the moment, log-ramping down to `0` at the
31
+ * far edge of the horizon.
32
+ *
33
+ * The exact form, with `until = atMs − nowMs`:
34
+ *
35
+ * imminence = clamp01( 1 − ln(until/HOUR_MS + 1) / ln(horizonMs/HOUR_MS + 1) )
36
+ *
37
+ * i.e. the calendar example's weight, `1 − ln(hoursUntil + 1) / ln(horizonHours + 1)`, with
38
+ * hours generalized to milliseconds. The one-hour softening unit (`+1` in hour units) is part
39
+ * of the shape: it keeps the ramp finite at `until = 0` and makes the last hours before the
40
+ * moment the steepest part of the curve. Returns `1` for any `until ≤ 0` (the moment has
41
+ * arrived — what a page does with a *passed* moment, e.g. the calendar's `0.08` floor for
42
+ * passed/TBD launches, is page semantics layered on top). Monotonically non-increasing in
43
+ * `until`; `0` at and beyond the horizon.
44
+ *
45
+ * Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
46
+ * `horizonMs` returns `1` at/past the moment and `0` otherwise (no horizon, no ramp).
47
+ */
48
+ export declare function imminence(atMs: number, nowMs: number, horizonMs: number): number;
49
+ /**
50
+ * Exponential newness decay — the backlog/inbox recency shape in its canonical form:
51
+ *
52
+ * freshness = 2^(−since / halfLifeMs) with since = nowMs − atMs
53
+ *
54
+ * `1` at the moment itself, **exactly `0.5` one half-life later**, `0.25` after two, → `0`
55
+ * asymptotically. Future timestamps (`since < 0`) clamp to `1` — nothing is fresher than now.
56
+ * Monotonically non-increasing in `since`.
57
+ *
58
+ * Naming: this lane reads positively — the complement is *staleness*, and it is deliberately
59
+ * not exported: `staleness = 1 − freshness`. One word per lane.
60
+ *
61
+ * Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
62
+ * `halfLifeMs` returns `1` at/before the moment and `0` after it (instant decay).
63
+ */
64
+ export declare function freshness(atMs: number, nowMs: number, halfLifeMs: number): number;
65
+ /** Options for {@link retention} — the τ calibration, in milliseconds. */
66
+ export interface RetentionOptions {
67
+ /** τ's base — the decay timescale of a zero-strength anchor. Default `4 * DAY_MS`. */
68
+ tauBaseMs?: number;
69
+ /** τ's growth with anchor strength — `τ(a) = tauBaseMs + a · tauGrowthMs`. Default `56 * DAY_MS`. */
70
+ tauGrowthMs?: number;
71
+ }
72
+ /**
73
+ * Ebbinghaus-shaped retention: how much of an anchored fact is still held after `sinceMs`.
74
+ *
75
+ * The exact form, lifted from the memory example's forgetting curve:
76
+ *
77
+ * retention = a · e^(−since / τ(a)) with τ(a) = tauBaseMs + a · tauGrowthMs
78
+ *
79
+ * which is the memory page's `w = a · exp(−days / τ)` with `τ = 4 + a·56` **in day units**,
80
+ * generalized to milliseconds with the day constant explicit (defaults `4 * DAY_MS` and
81
+ * `56 * DAY_MS`). The stability term is the point: τ *grows* with anchor strength, so deeply
82
+ * anchored facts decay slower — exponential decay alone forgets everything at one rate.
83
+ * `anchor` is clamped to `0..1`; `retention(a, 0)` is exactly `a`; monotonically
84
+ * non-increasing in `sinceMs` (negative `sinceMs` clamps to `0` — a future review holds full
85
+ * strength, it doesn't overshoot).
86
+ *
87
+ * The shape is Ebbinghaus's; the default constants are the memory page's, tuned for
88
+ * legibility, not fitted to recall data. Degenerate inputs: non-finite `anchor` reads as `0`;
89
+ * non-finite `sinceMs` or a non-positive τ returns `0` (nothing held).
90
+ */
91
+ export declare function retention(anchor: number, sinceMs: number, opts?: RetentionOptions): number;
92
+ /**
93
+ * Cyclical phase: where `nowMs` sits inside a repeating period, as `0..1` (the result is in
94
+ * `[0, 1)` — the wrap point reads as `0`, never `1`).
95
+ *
96
+ * phase = ((nowMs − offsetMs) mod periodMs) / periodMs
97
+ *
98
+ * with a true (sign-safe) modulo, so times before the offset wrap correctly. `offsetMs`
99
+ * anchors the cycle's zero — e.g. a local midnight for a day rhythm, a Monday 00:00 for a
100
+ * week rhythm.
101
+ *
102
+ * Honesty note: this kernel ships for completeness of the world-time family (day/week
103
+ * rhythms are the obvious fourth shape next to imminence, freshness, and retention), but
104
+ * **no shipped page or pipeline consumes it yet** — it has no worked example.
105
+ *
106
+ * Degenerate inputs: a non-finite `nowMs`/`offsetMs` or a non-positive/non-finite `periodMs`
107
+ * returns `0`.
108
+ */
109
+ export declare function phase(nowMs: number, periodMs: number, offsetMs?: number): number;
110
+ //# sourceMappingURL=temporal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/core/temporal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,2GAA2G;AAC3G,eAAO,MAAM,OAAO,UAAY,CAAC;AAEjC,6FAA6F;AAC7F,eAAO,MAAM,MAAM,WAAa,CAAC;AAIjC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMjF;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,MAAM,CAO9F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAM3E"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Temporal kernels — WORLD TIME made computable.
3
+ *
4
+ * field-ui keeps three clocks:
5
+ *
6
+ * 1. **Simulation time** — `env.t` / `dt`, particle age: the integrator's clock.
7
+ * 2. **Experiential time** — the platform metric pipeline's attention / memory / recency:
8
+ * eased integrals of interaction (`@fundamental-engine/platform` `metrics.ts`).
9
+ * 3. **World time** — timestamps carried by the data itself: a launch's T−0, an issue's
10
+ * `updatedAt`, a question's `askedAt`, a fact's last review.
11
+ *
12
+ * These kernels are clock 3. Each is a pure, deterministic map from world timestamps to a
13
+ * `0..1` weight — zero DOM, zero state, and **no `Date.now()`**: the caller supplies `nowMs`
14
+ * (the platform samples it once per frame; pages sample it once per tick). All arguments are
15
+ * epoch/duration **milliseconds**; the day and hour constants the shapes were calibrated in
16
+ * are exported explicitly. Degenerate inputs (NaN, ±Infinity, non-positive timescales) never
17
+ * produce NaN — each kernel documents its safe value.
18
+ *
19
+ * The shapes are lifted, exactly, from the shipped example family (the extraction ratchet:
20
+ * four hand-rolls → one primitive): `imminence` from the calendar page's 1 Hz clock,
21
+ * `retention` from the memory page's forgetting curve, `freshness` as the canonical form of
22
+ * the backlog/inbox recency lanes. `data-field-at` (see `@fundamental-engine/platform`) feeds
23
+ * `freshness` to ground the metric pipeline's recency lane in declared world time.
24
+ */
25
+ /** One hour in milliseconds — `imminence`'s log-softening unit (the calendar shape is hour-calibrated). */
26
+ export const HOUR_MS = 3_600_000;
27
+ /** One day in milliseconds — `retention`'s τ defaults are day-calibrated (4 + a·56 days). */
28
+ export const DAY_MS = 86_400_000;
29
+ const clamp01 = (n) => (n < 0 ? 0 : n > 1 ? 1 : n);
30
+ /**
31
+ * How imminent a moment feels: `1` at (or past) the moment, log-ramping down to `0` at the
32
+ * far edge of the horizon.
33
+ *
34
+ * The exact form, with `until = atMs − nowMs`:
35
+ *
36
+ * imminence = clamp01( 1 − ln(until/HOUR_MS + 1) / ln(horizonMs/HOUR_MS + 1) )
37
+ *
38
+ * i.e. the calendar example's weight, `1 − ln(hoursUntil + 1) / ln(horizonHours + 1)`, with
39
+ * hours generalized to milliseconds. The one-hour softening unit (`+1` in hour units) is part
40
+ * of the shape: it keeps the ramp finite at `until = 0` and makes the last hours before the
41
+ * moment the steepest part of the curve. Returns `1` for any `until ≤ 0` (the moment has
42
+ * arrived — what a page does with a *passed* moment, e.g. the calendar's `0.08` floor for
43
+ * passed/TBD launches, is page semantics layered on top). Monotonically non-increasing in
44
+ * `until`; `0` at and beyond the horizon.
45
+ *
46
+ * Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
47
+ * `horizonMs` returns `1` at/past the moment and `0` otherwise (no horizon, no ramp).
48
+ */
49
+ export function imminence(atMs, nowMs, horizonMs) {
50
+ if (!Number.isFinite(atMs) || !Number.isFinite(nowMs))
51
+ return 0;
52
+ const until = atMs - nowMs;
53
+ if (until <= 0)
54
+ return 1;
55
+ if (!Number.isFinite(horizonMs) || horizonMs <= 0)
56
+ return 0;
57
+ return clamp01(1 - Math.log(until / HOUR_MS + 1) / Math.log(horizonMs / HOUR_MS + 1));
58
+ }
59
+ /**
60
+ * Exponential newness decay — the backlog/inbox recency shape in its canonical form:
61
+ *
62
+ * freshness = 2^(−since / halfLifeMs) with since = nowMs − atMs
63
+ *
64
+ * `1` at the moment itself, **exactly `0.5` one half-life later**, `0.25` after two, → `0`
65
+ * asymptotically. Future timestamps (`since < 0`) clamp to `1` — nothing is fresher than now.
66
+ * Monotonically non-increasing in `since`.
67
+ *
68
+ * Naming: this lane reads positively — the complement is *staleness*, and it is deliberately
69
+ * not exported: `staleness = 1 − freshness`. One word per lane.
70
+ *
71
+ * Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
72
+ * `halfLifeMs` returns `1` at/before the moment and `0` after it (instant decay).
73
+ */
74
+ export function freshness(atMs, nowMs, halfLifeMs) {
75
+ if (!Number.isFinite(atMs) || !Number.isFinite(nowMs))
76
+ return 0;
77
+ const since = nowMs - atMs;
78
+ if (since <= 0)
79
+ return 1;
80
+ if (!Number.isFinite(halfLifeMs) || halfLifeMs <= 0)
81
+ return 0;
82
+ return Math.pow(2, -since / halfLifeMs);
83
+ }
84
+ /**
85
+ * Ebbinghaus-shaped retention: how much of an anchored fact is still held after `sinceMs`.
86
+ *
87
+ * The exact form, lifted from the memory example's forgetting curve:
88
+ *
89
+ * retention = a · e^(−since / τ(a)) with τ(a) = tauBaseMs + a · tauGrowthMs
90
+ *
91
+ * which is the memory page's `w = a · exp(−days / τ)` with `τ = 4 + a·56` **in day units**,
92
+ * generalized to milliseconds with the day constant explicit (defaults `4 * DAY_MS` and
93
+ * `56 * DAY_MS`). The stability term is the point: τ *grows* with anchor strength, so deeply
94
+ * anchored facts decay slower — exponential decay alone forgets everything at one rate.
95
+ * `anchor` is clamped to `0..1`; `retention(a, 0)` is exactly `a`; monotonically
96
+ * non-increasing in `sinceMs` (negative `sinceMs` clamps to `0` — a future review holds full
97
+ * strength, it doesn't overshoot).
98
+ *
99
+ * The shape is Ebbinghaus's; the default constants are the memory page's, tuned for
100
+ * legibility, not fitted to recall data. Degenerate inputs: non-finite `anchor` reads as `0`;
101
+ * non-finite `sinceMs` or a non-positive τ returns `0` (nothing held).
102
+ */
103
+ export function retention(anchor, sinceMs, opts = {}) {
104
+ const a = clamp01(Number.isFinite(anchor) ? anchor : 0);
105
+ if (!Number.isFinite(sinceMs))
106
+ return 0;
107
+ const since = sinceMs < 0 ? 0 : sinceMs;
108
+ const tau = (opts.tauBaseMs ?? 4 * DAY_MS) + a * (opts.tauGrowthMs ?? 56 * DAY_MS);
109
+ if (!Number.isFinite(tau) || tau <= 0)
110
+ return 0;
111
+ return a * Math.exp(-since / tau);
112
+ }
113
+ /**
114
+ * Cyclical phase: where `nowMs` sits inside a repeating period, as `0..1` (the result is in
115
+ * `[0, 1)` — the wrap point reads as `0`, never `1`).
116
+ *
117
+ * phase = ((nowMs − offsetMs) mod periodMs) / periodMs
118
+ *
119
+ * with a true (sign-safe) modulo, so times before the offset wrap correctly. `offsetMs`
120
+ * anchors the cycle's zero — e.g. a local midnight for a day rhythm, a Monday 00:00 for a
121
+ * week rhythm.
122
+ *
123
+ * Honesty note: this kernel ships for completeness of the world-time family (day/week
124
+ * rhythms are the obvious fourth shape next to imminence, freshness, and retention), but
125
+ * **no shipped page or pipeline consumes it yet** — it has no worked example.
126
+ *
127
+ * Degenerate inputs: a non-finite `nowMs`/`offsetMs` or a non-positive/non-finite `periodMs`
128
+ * returns `0`.
129
+ */
130
+ export function phase(nowMs, periodMs, offsetMs = 0) {
131
+ if (!Number.isFinite(nowMs) || !Number.isFinite(offsetMs))
132
+ return 0;
133
+ if (!Number.isFinite(periodMs) || periodMs <= 0)
134
+ return 0;
135
+ const m = (nowMs - offsetMs) % periodMs;
136
+ const f = (m < 0 ? m + periodMs : m) / periodMs;
137
+ return f >= 1 ? 0 : f; // float wrap guard: x + period can round to period
138
+ }
139
+ //# sourceMappingURL=temporal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.js","sourceRoot":"","sources":["../../src/core/temporal.ts"],"names":[],"mappings":"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"}