@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zach Shallbetter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # field-ui
2
+
3
+ **The renderer-agnostic field engine.** `@fundamental-engine/core` computes the field: forces, particles, metrics,
4
+ recipes, diagnostics, and conformance, against plain data, with **zero runtime dependencies** and
5
+ **zero DOM**. Your page's elements become physical bodies in one shared field; they exert force, and
6
+ the field's local density bends them back. The visible canvas is one render surface, not the system.
7
+
8
+ This is the core. Most apps consume it through a thin adapter that wires the browser for you:
9
+ [`@fundamental-engine/elements`](../elements) (web component), [`@fundamental-engine/react`](../react), or
10
+ [`@fundamental-engine/vanilla`](../vanilla). Reach for the core directly when you own the render loop or target a
11
+ renderer other than the DOM canvas.
12
+
13
+ → Live manual, Lab, and design system at **[fundamental-engine.com](https://fundamental-engine.com)**.
14
+
15
+ ## Install
16
+
17
+ ```sh
18
+ npm i @fundamental-engine/core
19
+ ```
20
+
21
+ The browser host lives in [`@fundamental-engine/platform`](../platform); most apps reach for a thin adapter
22
+ ([`@fundamental-engine/elements`](../elements), [`@fundamental-engine/react`](../react), [`@fundamental-engine/vanilla`](../vanilla))
23
+ instead of wiring the host themselves. The public surface is frozen for `0.x` (see
24
+ [API stability](../../docs/canonical/field-ui-api-stability.md)).
25
+
26
+ ## What's inside
27
+
28
+ - **36 forces** in three families: **9 canonical** verbs (`attract`, `repel`, `swirl`, `stream`,
29
+ `viscosity`, `jet`, `tether`, `wall`, `sink`), **8 natural** primitives (`gravity`, `charge`,
30
+ `magnetism`, `thermal`, `collide`, `diffuse`, `propagate`, `memory`), and **19 designed-extended**
31
+ forces (`lens`, `gate`, `buoyancy`, `shear`, `crystallize`, `align`, `wind`, `cohesion`, `pressure`,
32
+ `link`, `morph`, `hunt`, `spawn`, `resonate`, `spotlight`, the `screen` quiet zone, `pigment`,
33
+ field-line transport `fieldflow`, and wormhole relocate `warp`).
34
+ - **8 presets** compose those primitives into cosmology with no new engine code (`blackhole`, `star`,
35
+ `galaxy`, `tornado`, …), plus **5 formations** that bias the whole field and **6 condition** gates.
36
+ - **16 render modes**: matter/structure (`dots`, `trails`, `links`, `streamlines`, `metaballs`,
37
+ `voronoi`, `field-lines`, `heatmap`) and diagnostics (`force-vectors`, `contours`, `potential`,
38
+ `energy`, `topology`, `inspector`, `causality`, `prediction`).
39
+ - **64 recipes** across 4 tiers: a recipe is a portable field program. `compileRecipe()` lives here
40
+ (pure, no DOM); `applyRecipe()` and `bindData()` are in [`@fundamental-engine/platform`](../platform).
41
+ - **A conformance framework** that fires known particles into each force and checks the measured
42
+ trajectory against the math. The same catalog drives the tests and the visual Lab.
43
+
44
+ ## Quick start
45
+
46
+ `createField` is renderer-agnostic, so it **requires a host** (a `FieldHost`: viewport, scroll, raf,
47
+ and a canvas). In the browser, the host comes from [`@fundamental-engine/platform`](../platform):
48
+
49
+ ```ts
50
+ import { createField } from '@fundamental-engine/core';
51
+ import { browserHost } from '@fundamental-engine/platform';
52
+
53
+ const canvas = document.querySelector('canvas')!;
54
+ const field = createField(canvas, { host: browserHost(), accent: '#4da3ff' });
55
+
56
+ // Any [data-body] element on the page becomes a force the field reacts to:
57
+ // <a data-body="attract" data-strength="0.9" data-range="320" data-feedback>pull me</a>
58
+ field.scan(); // re-scan [data-body] after a DOM change
59
+ ```
60
+
61
+ If you do not want to wire the host yourself, [`@fundamental-engine/vanilla`](../vanilla) re-exports a
62
+ host-bundled `createField` (and a `FieldField` class), and [`@fundamental-engine/elements`](../elements) /
63
+ [`@fundamental-engine/react`](../react) wrap it as a custom element / component. `createField` called without a
64
+ host throws a clear error pointing you to those doors.
65
+
66
+ ## The model
67
+
68
+ - **Bodies** are declared in markup with `data-body="<force> <force>…"` (forces compose). Common
69
+ attributes: `data-strength`, `data-range`, `data-color`, `data-when` (a condition gate), and
70
+ `data-feedback` (two-way density write-back).
71
+ - **The field** is one conserved pool of particles. It re-reads every body's rectangle each frame, so
72
+ any layout change *is* a change to the force geometry.
73
+ - **Feedback** samples the density gathered on a body and eases it into the element's `--field-density`
74
+ custom property (with `--d` and `--forces-density` as legacy aliases). Drive weight, glow, and scale
75
+ from it.
76
+
77
+ ## The handle
78
+
79
+ `createField` returns a `FieldHandle`:
80
+
81
+ ```ts
82
+ field.scan(); // re-scan [data-body] after a DOM change
83
+ field.setAccent('#a78bfa'); // recolor the travelling accent
84
+ field.setPalette('heatmap'); // swap the accent color template
85
+ field.setFormation('wells'); // switch the global formation
86
+ field.setAttention(true); // conserved attention — one finite strength budget
87
+ field.setCausality(true); // cross-boundary causality — density spills to neighbours
88
+ field.setRender('streamlines'); // draw the force field itself (a diagnostic mode)
89
+ field.flowTo(x, y); // place a movable flow focus the field bends toward
90
+ field.burst(x, y, '#fff'); // a one-shot shove + heat near a point
91
+ field.destroy(); // stop the loop, release listeners
92
+ ```
93
+
94
+ Reduced motion is honoured (`prefers-reduced-motion` freezes the sim), and the loop pauses when the tab
95
+ is backgrounded.
96
+
97
+ ## Recipes
98
+
99
+ A recipe names an intent and composes existing tokens into behavior. It never adds engine behavior, and
100
+ its lanes stay separate: concepts describe, tokens execute, metrics measure, diagnostics explain,
101
+ conditions activate. `compileRecipe()` turns a `FieldRecipe` into a compiled plan with no DOM:
102
+
103
+ ```ts
104
+ import { compileRecipe, recipeById } from '@fundamental-engine/core';
105
+
106
+ const plan = compileRecipe(recipeById('priority-well')!);
107
+ // → bodies, relationships, feedback, diagnostics, metrics, and a reduced-motion output.
108
+ ```
109
+
110
+ `applyRecipe()` (run a recipe on a live DOM platform) and `bindData()` (records → bodies) are in
111
+ [`@fundamental-engine/platform`](../platform). Browse all 64 at [`/docs/gallery`](https://fundamental-engine.com/docs/gallery).
112
+
113
+ ## Renderer-agnostic
114
+
115
+ The engine touches no DOM globals (a boundary test keeps the allowlist empty). Everything the browser
116
+ provides arrives through an injected `FieldHost`, so the same engine runs on a DOM canvas, an offscreen
117
+ canvas, a headless harness, or any renderer you implement. `browserHost()` (in
118
+ [`@fundamental-engine/platform`](../platform)) is the canonical DOM implementation of that contract.
119
+
120
+ ## Related
121
+
122
+ [`@fundamental-engine/platform`](../platform) · [`@fundamental-engine/elements`](../elements) ·
123
+ [`@fundamental-engine/react`](../react) · [`@fundamental-engine/vanilla`](../vanilla) · the
124
+ [documentation map](../../docs/README.md).
125
+
126
+ ## License
127
+
128
+ MIT © Zach Shallbetter
@@ -0,0 +1,38 @@
1
+ /**
2
+ * ElementAgent (system-contracts §6) — a DOM element that receives field metrics and writes DOM
3
+ * state. The engine already writes `--d` / `--field-density` for the density metric; this widens
4
+ * that to the full ElementAgent metric set (attention, heat, entropy, coherence, memory, pressure,
5
+ * pull-x/y) and emits the `--field-*` var for each, plus a
6
+ * `data-field-*` state attribute band for CSS that prefers attribute selectors.
7
+ *
8
+ * `elementAgentVars` / `elementAgentState` are pure (no DOM) so they are node-testable; the thin
9
+ * `writeElementAgent` applies them to a real element. An ElementAgent never mutates particles
10
+ * unless it is also a registered body (the §6 rule).
11
+ */
12
+ /** The metrics an ElementAgent can receive (system-contracts §6). All optional. */
13
+ export interface ElementMetrics {
14
+ density?: number;
15
+ attention?: number;
16
+ heat?: number;
17
+ entropy?: number;
18
+ coherence?: number;
19
+ memory?: number;
20
+ pressure?: number;
21
+ pullX?: number;
22
+ pullY?: number;
23
+ }
24
+ /**
25
+ * The CSS custom properties an ElementAgent writes for a metric set — each metric as
26
+ * `--field-<m>`. Pure.
27
+ */
28
+ export declare function elementAgentVars(m: ElementMetrics): Record<string, string>;
29
+ /**
30
+ * A coarse `data-field-*` state band for a metric (`low` < 0.33 ≤ `mid` < 0.66 ≤ `high`), so CSS
31
+ * can switch on `[data-field-density="high"]` without reading the numeric var. Pure.
32
+ */
33
+ export declare function elementAgentState(m: ElementMetrics): Record<string, string>;
34
+ /** Apply an ElementAgent's metrics to a real element (CSS vars + data-field-* state). Thin DOM. */
35
+ export declare function writeElementAgent(el: HTMLElement, m: ElementMetrics): void;
36
+ /** Clear everything an ElementAgent wrote (teardown / unregister). Thin DOM. */
37
+ export declare function clearElementAgent(el: HTMLElement): void;
38
+ //# sourceMappingURL=element-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-agent.d.ts","sourceRoot":"","sources":["../../src/agents/element-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mFAAmF;AACnF,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ1E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS3E;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,cAAc,GAAG,IAAI,CAK1E;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,CAKvD"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * ElementAgent (system-contracts §6) — a DOM element that receives field metrics and writes DOM
3
+ * state. The engine already writes `--d` / `--field-density` for the density metric; this widens
4
+ * that to the full ElementAgent metric set (attention, heat, entropy, coherence, memory, pressure,
5
+ * pull-x/y) and emits the `--field-*` var for each, plus a
6
+ * `data-field-*` state attribute band for CSS that prefers attribute selectors.
7
+ *
8
+ * `elementAgentVars` / `elementAgentState` are pure (no DOM) so they are node-testable; the thin
9
+ * `writeElementAgent` applies them to a real element. An ElementAgent never mutates particles
10
+ * unless it is also a registered body (the §6 rule).
11
+ */
12
+ /** metric key → CSS-var suffix (kebab). */
13
+ const SUFFIX = {
14
+ density: 'density',
15
+ attention: 'attention',
16
+ heat: 'heat',
17
+ entropy: 'entropy',
18
+ coherence: 'coherence',
19
+ memory: 'memory',
20
+ pressure: 'pressure',
21
+ pullX: 'pull-x',
22
+ pullY: 'pull-y',
23
+ };
24
+ const fmt = (n) => (Number.isFinite(n) ? n.toFixed(3) : '0');
25
+ /**
26
+ * The CSS custom properties an ElementAgent writes for a metric set — each metric as
27
+ * `--field-<m>`. Pure.
28
+ */
29
+ export function elementAgentVars(m) {
30
+ const out = {};
31
+ for (const key of Object.keys(m)) {
32
+ const v = m[key];
33
+ if (v == null)
34
+ continue;
35
+ out[`--field-${SUFFIX[key]}`] = fmt(v);
36
+ }
37
+ return out;
38
+ }
39
+ /**
40
+ * A coarse `data-field-*` state band for a metric (`low` < 0.33 ≤ `mid` < 0.66 ≤ `high`), so CSS
41
+ * can switch on `[data-field-density="high"]` without reading the numeric var. Pure.
42
+ */
43
+ export function elementAgentState(m) {
44
+ const band = (v) => (v < 0.33 ? 'low' : v < 0.66 ? 'mid' : 'high');
45
+ const out = {};
46
+ for (const key of Object.keys(m)) {
47
+ const v = m[key];
48
+ if (v == null || key === 'pullX' || key === 'pullY')
49
+ continue; // bands are for scalar 0..1 metrics
50
+ out[`data-field-${SUFFIX[key]}`] = band(v);
51
+ }
52
+ return out;
53
+ }
54
+ /** Apply an ElementAgent's metrics to a real element (CSS vars + data-field-* state). Thin DOM. */
55
+ export function writeElementAgent(el, m) {
56
+ const vars = elementAgentVars(m);
57
+ for (const name of Object.keys(vars))
58
+ el.style.setProperty(name, vars[name]);
59
+ const state = elementAgentState(m);
60
+ for (const name of Object.keys(state))
61
+ el.setAttribute(name, state[name]);
62
+ }
63
+ /** Clear everything an ElementAgent wrote (teardown / unregister). Thin DOM. */
64
+ export function clearElementAgent(el) {
65
+ for (const key of Object.keys(SUFFIX)) {
66
+ el.style.removeProperty(`--field-${SUFFIX[key]}`);
67
+ el.removeAttribute(`data-field-${SUFFIX[key]}`);
68
+ }
69
+ }
70
+ //# sourceMappingURL=element-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-agent.js","sourceRoot":"","sources":["../../src/agents/element-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * EventAgent — the Event Contract runtime (system-contracts §9). A field event must be
3
+ * thresholded, debounced, and not fire every frame. The `Thresholder` turns a continuous metric
4
+ * (density, attention, relationship strength…) into discrete `entered` / `exited` edges with
5
+ * hysteresis (separate enter/exit levels) and a debounce window, so a body crossing a level emits
6
+ * one clean event instead of a per-frame storm.
7
+ */
8
+ export type ThresholdEdge = 'entered' | 'exited' | null;
9
+ export interface ThresholdConfig {
10
+ /** value at or above which the agent becomes "lit" (fires `entered`). */
11
+ enter: number;
12
+ /** value at or below which it goes "dim" (fires `exited`). Should be ≤ enter for hysteresis. */
13
+ exit: number;
14
+ /** minimum ms between edge changes — debounce. */
15
+ debounceMs: number;
16
+ }
17
+ /** A hysteretic, debounced edge detector over a single metric. */
18
+ export declare class Thresholder {
19
+ private lit;
20
+ private lastEdgeMs;
21
+ private readonly cfg;
22
+ constructor(cfg: ThresholdConfig);
23
+ /** Feed the current metric value and time; returns the edge crossed this tick, or null. */
24
+ update(value: number, nowMs: number): ThresholdEdge;
25
+ /** Whether the agent is currently above threshold. */
26
+ get isLit(): boolean;
27
+ /** Reset to the dim state (e.g. on teardown). */
28
+ reset(): void;
29
+ }
30
+ /** A named field event with its `field:*` name. */
31
+ export interface FieldEventName {
32
+ field: string;
33
+ /** the metric whose threshold crossing fires it (where applicable). */
34
+ metric?: string;
35
+ }
36
+ /**
37
+ * The named field-event catalog (system-contracts §9, shadow-dom §22, interaction §12). These are
38
+ * the thresholded, debounced events the engine may dispatch — never per-frame by default.
39
+ * `field:lit`/`dim` and the `*-body` lifecycle events are dispatched today; the rest are the agreed
40
+ * names for agent/threshold events as they wire up.
41
+ */
42
+ export declare const FIELD_EVENTS: Readonly<Record<string, FieldEventName>>;
43
+ /** Map a metric to its conventional `field:*` event name for an edge. */
44
+ export declare function eventNamesFor(metric: string, edge: Exclude<ThresholdEdge, null>): {
45
+ field: string;
46
+ };
47
+ //# sourceMappingURL=event-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-agent.d.ts","sourceRoot":"","sources":["../../src/agents/event-agent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC;AAExD,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,kEAAkE;AAClE,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;gBAC1B,GAAG,EAAE,eAAe;IAIhC,2FAA2F;IAC3F,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa;IAenD,sDAAsD;IACtD,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,iDAAiD;IACjD,KAAK,IAAI,IAAI;CAId;AAED,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAsBjE,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAWnG"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * EventAgent — the Event Contract runtime (system-contracts §9). A field event must be
3
+ * thresholded, debounced, and not fire every frame. The `Thresholder` turns a continuous metric
4
+ * (density, attention, relationship strength…) into discrete `entered` / `exited` edges with
5
+ * hysteresis (separate enter/exit levels) and a debounce window, so a body crossing a level emits
6
+ * one clean event instead of a per-frame storm.
7
+ */
8
+ /** A hysteretic, debounced edge detector over a single metric. */
9
+ export class Thresholder {
10
+ lit = false;
11
+ lastEdgeMs = -Infinity;
12
+ cfg;
13
+ constructor(cfg) {
14
+ this.cfg = cfg;
15
+ }
16
+ /** Feed the current metric value and time; returns the edge crossed this tick, or null. */
17
+ update(value, nowMs) {
18
+ const settled = nowMs - this.lastEdgeMs >= this.cfg.debounceMs;
19
+ if (!this.lit && value >= this.cfg.enter && settled) {
20
+ this.lit = true;
21
+ this.lastEdgeMs = nowMs;
22
+ return 'entered';
23
+ }
24
+ if (this.lit && value <= this.cfg.exit && settled) {
25
+ this.lit = false;
26
+ this.lastEdgeMs = nowMs;
27
+ return 'exited';
28
+ }
29
+ return null;
30
+ }
31
+ /** Whether the agent is currently above threshold. */
32
+ get isLit() {
33
+ return this.lit;
34
+ }
35
+ /** Reset to the dim state (e.g. on teardown). */
36
+ reset() {
37
+ this.lit = false;
38
+ this.lastEdgeMs = -Infinity;
39
+ }
40
+ }
41
+ /**
42
+ * The named field-event catalog (system-contracts §9, shadow-dom §22, interaction §12). These are
43
+ * the thresholded, debounced events the engine may dispatch — never per-frame by default.
44
+ * `field:lit`/`dim` and the `*-body` lifecycle events are dispatched today; the rest are the agreed
45
+ * names for agent/threshold events as they wire up.
46
+ */
47
+ export const FIELD_EVENTS = {
48
+ // --- dispatched today (shipped) ---
49
+ registerBody: { field: 'field:register-body' },
50
+ unregisterBody: { field: 'field:unregister-body' },
51
+ updateBody: { field: 'field:update-body' },
52
+ lit: { field: 'field:lit', metric: 'density' },
53
+ dim: { field: 'field:dim', metric: 'density' },
54
+ // capture/release (§22.3): a sink fires field:captured on the rising edge of accreting and
55
+ // field:released on supernova; docked elements fire them too. Edge-debounced (see field.ts).
56
+ captured: { field: 'field:captured' },
57
+ released: { field: 'field:released' },
58
+ // relocate (§22.3): a [data-warp] element teleports its transform to its paired throat.
59
+ relocated: { field: 'field:relocated' },
60
+ // --- names reserved; NOT yet dispatched by the engine (planned agent-threshold events).
61
+ // See docs/canonical/field-ui-agent-consumption-model.md (Events). ---
62
+ entered: { field: 'field:entered', metric: 'density' },
63
+ exited: { field: 'field:exited', metric: 'density' },
64
+ saturated: { field: 'field:saturated', metric: 'accreted' },
65
+ attentionShifted: { field: 'field:attention-shifted', metric: 'attention' },
66
+ relationshipStrengthened: { field: 'field:relationship-strengthened', metric: 'strength' },
67
+ memoryThreshold: { field: 'field:memory-threshold', metric: 'memory' },
68
+ entropyWarning: { field: 'field:entropy-warning', metric: 'entropy' },
69
+ };
70
+ /** Map a metric to its conventional `field:*` event name for an edge. */
71
+ export function eventNamesFor(metric, edge) {
72
+ // density → lit/dim; attention → attention-shifted; generic → entered/exited
73
+ const verb = metric === 'density'
74
+ ? edge === 'entered'
75
+ ? 'lit'
76
+ : 'dim'
77
+ : edge === 'entered'
78
+ ? 'entered'
79
+ : 'exited';
80
+ return { field: `field:${verb}` };
81
+ }
82
+ //# sourceMappingURL=event-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-agent.js","sourceRoot":"","sources":["../../src/agents/event-agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The FieldAgent model (Phase 5 — interaction-and-relationship-model). Particles are only one kind
3
+ * of agent: an agent is anything that can receive influence, hold state, change behavior, or affect
4
+ * another thing. This module adds the non-particle agents (element, relationship, user, layout,
5
+ * data) and the thresholded EventAgent runtime, plus the agent-type contracts deferred from Phase 4.
6
+ */
7
+ import type { ContractMeta } from '../contracts/types.ts';
8
+ export * from './event-agent.ts';
9
+ export * from './relationship.ts';
10
+ export * from './element-agent.ts';
11
+ export * from './user-agent.ts';
12
+ export * from './region-agents.ts';
13
+ /** The kinds of agent that can participate in the field (definition-document). */
14
+ export type FieldAgentKind = 'particle' | 'element' | 'relationship' | 'user' | 'layout' | 'data' | 'event';
15
+ /** The agent-type contracts (system-contracts §5–§9), formalized in Phase 5. */
16
+ export declare const AGENT_CONTRACTS: readonly ContractMeta[];
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AAEnC,kFAAkF;AAClF,MAAM,MAAM,cAAc,GACtB,UAAU,GACV,SAAS,GACT,cAAc,GACd,MAAM,GACN,QAAQ,GACR,MAAM,GACN,OAAO,CAAC;AAEZ,gFAAgF;AAChF,eAAO,MAAM,eAAe,EAAE,SAAS,YAAY,EAiDlD,CAAC"}
@@ -0,0 +1,57 @@
1
+ export * from "./event-agent.js";
2
+ export * from "./relationship.js";
3
+ export * from "./element-agent.js";
4
+ export * from "./user-agent.js";
5
+ export * from "./region-agents.js";
6
+ /** The agent-type contracts (system-contracts §5–§9), formalized in Phase 5. */
7
+ export const AGENT_CONTRACTS = [
8
+ {
9
+ name: 'ElementAgent Contract',
10
+ mustExist: 'a DOM element + the metrics it receives (density, attention, heat, entropy, coherence, memory, pressure, pull-x/y)',
11
+ mayMutate: 'CSS variables and data-field-* state on its element',
12
+ sideEffectFree: 'metric reads; it must not mutate particles unless also a registered body',
13
+ testable: 'receives metrics → writes the matching --field-* vars and data bands; respects reduced motion',
14
+ inspectable: 'the CSS variables and data-field-* attributes on the element',
15
+ },
16
+ {
17
+ name: 'RelationshipAgent Contract',
18
+ mustExist: 'id, from, to, type, strength, tension, memory, active',
19
+ mayMutate: 'its own strength/tension/memory; the attention it transfers between its endpoints',
20
+ sideEffectFree: 'its dynamics are a pure function of (active, tension, dt)',
21
+ testable: 'strengthens with use, decays over time, transfers attention, emits thresholded events',
22
+ inspectable: 'strength/tension/memory and the strengthen/weaken threshold edges',
23
+ },
24
+ {
25
+ name: 'UserAgent Contract',
26
+ mustExist: 'pointer position/velocity, focus, selection, scroll, reduced-motion flag',
27
+ mayMutate: 'nothing in the DOM — it projects a field source the engine consumes',
28
+ sideEffectFree: 'the source it derives from its input state',
29
+ testable: 'pointer creates a wake; focus creates an accessible attention source; reduced motion drops travel',
30
+ inspectable: 'the derived UserFieldSource (wake / focus / capture)',
31
+ },
32
+ {
33
+ name: 'LayoutAgent Contract',
34
+ mustExist: 'a region rect + the metrics aggregated over the bodies inside it',
35
+ mayMutate: 'its own aggregated metrics (then writes back like an ElementAgent)',
36
+ sideEffectFree: 'the aggregation',
37
+ testable: 'aggregates contained body metrics; empty region reads zero',
38
+ inspectable: 'the region rect and aggregated metrics',
39
+ },
40
+ {
41
+ name: 'DataAgent Contract',
42
+ mustExist: 'a record’s semantic fields + a salience that decays unless reinforced',
43
+ mayMutate: 'its own salience',
44
+ sideEffectFree: 'the salience update is a pure function of (reinforced, dt)',
45
+ testable: 'reinforce raises salience; idle decays it; bounded to [0,1]',
46
+ inspectable: 'the record fields and current salience',
47
+ },
48
+ {
49
+ name: 'EventAgent Contract',
50
+ mustExist: 'a metric, an enter/exit threshold with hysteresis, and a debounce window',
51
+ mayMutate: 'nothing — it emits notifications',
52
+ sideEffectFree: 'the edge detection is a pure function of (value, now)',
53
+ testable: 'one clean edge per crossing; no per-frame firing; hysteresis prevents flicker',
54
+ inspectable: 'the lit state and the configured thresholds',
55
+ },
56
+ ];
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAQA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AAYnC,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAA4B;IACtD;QACE,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,oHAAoH;QAC/H,SAAS,EAAE,qDAAqD;QAChE,cAAc,EAAE,0EAA0E;QAC1F,QAAQ,EAAE,+FAA+F;QACzG,WAAW,EAAE,8DAA8D;KAC5E;IACD;QACE,IAAI,EAAE,4BAA4B;QAClC,SAAS,EAAE,uDAAuD;QAClE,SAAS,EAAE,mFAAmF;QAC9F,cAAc,EAAE,2DAA2D;QAC3E,QAAQ,EAAE,uFAAuF;QACjG,WAAW,EAAE,mEAAmE;KACjF;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,SAAS,EAAE,0EAA0E;QACrF,SAAS,EAAE,qEAAqE;QAChF,cAAc,EAAE,4CAA4C;QAC5D,QAAQ,EAAE,mGAAmG;QAC7G,WAAW,EAAE,sDAAsD;KACpE;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,SAAS,EAAE,kEAAkE;QAC7E,SAAS,EAAE,oEAAoE;QAC/E,cAAc,EAAE,iBAAiB;QACjC,QAAQ,EAAE,4DAA4D;QACtE,WAAW,EAAE,wCAAwC;KACtD;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,SAAS,EAAE,uEAAuE;QAClF,SAAS,EAAE,kBAAkB;QAC7B,cAAc,EAAE,4DAA4D;QAC5E,QAAQ,EAAE,6DAA6D;QACvE,WAAW,EAAE,wCAAwC;KACtD;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,SAAS,EAAE,0EAA0E;QACrF,SAAS,EAAE,kCAAkC;QAC7C,cAAc,EAAE,uDAAuD;QACvE,QAAQ,EAAE,+EAA+E;QACzF,WAAW,EAAE,6CAA6C;KAC3D;CACF,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * LayoutAgent and DataAgent (interaction-and-relationship-model) — the region-level and
3
+ * record-level field participants. A LayoutAgent is a viewport region that aggregates the field
4
+ * metrics under it (so a whole column or card can respond, not just leaf elements). A DataAgent is
5
+ * a semantic record placed in the field, carrying a salience that decays unless reinforced.
6
+ *
7
+ * Pure aggregation/decay, node-testable. Rendering and DOM binding live in the field loop.
8
+ */
9
+ import type { ElementMetrics } from './element-agent.ts';
10
+ export interface LayoutAgent {
11
+ id: string;
12
+ /** the region in field space. */
13
+ rect: {
14
+ x: number;
15
+ y: number;
16
+ w: number;
17
+ h: number;
18
+ };
19
+ /** aggregated metrics over the bodies inside the region. */
20
+ metrics: ElementMetrics;
21
+ }
22
+ /**
23
+ * Aggregate a metric across the bodies whose centre falls in the region (mean of the contained
24
+ * values). Returns 0 for an empty region. Pure.
25
+ */
26
+ export declare function aggregateMetric(region: LayoutAgent, bodies: readonly {
27
+ cx: number;
28
+ cy: number;
29
+ value: number;
30
+ }[]): number;
31
+ export interface DataAgent {
32
+ id: string;
33
+ /** arbitrary semantic fields of the record. */
34
+ fields: Readonly<Record<string, unknown>>;
35
+ /** attention/relevance ∈ [0,1] — decays unless reinforced. */
36
+ salience: number;
37
+ }
38
+ /** Reinforce (matched a query / was viewed) or let salience decay. Pure. */
39
+ export declare function updateDataAgent(d: DataAgent, reinforced: boolean, dt: number, decay?: number, gain?: number): void;
40
+ //# sourceMappingURL=region-agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-agents.d.ts","sourceRoot":"","sources":["../../src/agents/region-agents.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,4DAA4D;IAC5D,OAAO,EAAE,cAAc,CAAC;CACzB;AAKD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GAC3D,MAAM,CAUR;AAGD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,+CAA+C;IAC/C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,SAAM,EAAE,IAAI,SAAM,GAAG,IAAI,CAE5G"}
@@ -0,0 +1,22 @@
1
+ const inRect = (r, x, y) => x >= r.x && x <= r.x + r.w && y >= r.y && y <= r.y + r.h;
2
+ /**
3
+ * Aggregate a metric across the bodies whose centre falls in the region (mean of the contained
4
+ * values). Returns 0 for an empty region. Pure.
5
+ */
6
+ export function aggregateMetric(region, bodies) {
7
+ let sum = 0;
8
+ let n = 0;
9
+ for (const b of bodies) {
10
+ if (inRect(region.rect, b.cx, b.cy)) {
11
+ sum += b.value;
12
+ n++;
13
+ }
14
+ }
15
+ return n === 0 ? 0 : sum / n;
16
+ }
17
+ const clamp01 = (n) => (n < 0 ? 0 : n > 1 ? 1 : n);
18
+ /** Reinforce (matched a query / was viewed) or let salience decay. Pure. */
19
+ export function updateDataAgent(d, reinforced, dt, decay = 0.4, gain = 1.2) {
20
+ d.salience = clamp01(d.salience + (reinforced ? gain : -decay) * dt);
21
+ }
22
+ //# sourceMappingURL=region-agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-agents.js","sourceRoot":"","sources":["../../src/agents/region-agents.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,GAAG,CAAC,CAAsB,EAAE,CAAS,EAAE,CAAS,EAAW,EAAE,CACvE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAE3D;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAmB,EACnB,MAA4D;IAE5D,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACpC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC;YACf,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;AAC/B,CAAC;AAWD,MAAM,OAAO,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnE,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,CAAY,EAAE,UAAmB,EAAE,EAAU,EAAE,KAAK,GAAG,GAAG,EAAE,IAAI,GAAG,GAAG;IACpG,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * RelationshipAgent (system-contracts §7) — an active connection between two bodies. It is not
3
+ * merely a rendered line: it carries strength, tension, and memory; it strengthens with use and
4
+ * decays over time; it can transfer attention and emit thresholded events.
5
+ *
6
+ * The dynamics here are pure (plain state + dt), so they are deterministic and node-testable. The
7
+ * rendering (a line, a current) and the DOM event dispatch live in the field loop / feedback layer.
8
+ */
9
+ import { Thresholder } from './event-agent.ts';
10
+ export interface RelationshipAgent {
11
+ id: string;
12
+ /** body ids. */
13
+ from: string;
14
+ to: string;
15
+ /** relationship kind, e.g. 'cites', 'reply', 'depends'. */
16
+ type: string;
17
+ /** active coupling strength ∈ [0,1]. */
18
+ strength: number;
19
+ /** instantaneous strain ∈ [0,1] (e.g. distance vs. desired). */
20
+ tension: number;
21
+ /** slow-moving accumulated familiarity ∈ [0,1]. */
22
+ memory: number;
23
+ /** whether it was used this tick. */
24
+ active: boolean;
25
+ }
26
+ export interface RelationshipDynamics {
27
+ /** strength gained per second while active. */
28
+ strengthen: number;
29
+ /** strength lost per second while idle. */
30
+ decay: number;
31
+ /** memory gained per second while active (lost at half-rate while idle). */
32
+ remember: number;
33
+ }
34
+ export declare const DEFAULT_RELATIONSHIP_DYNAMICS: RelationshipDynamics;
35
+ /**
36
+ * Advance a relationship one step. `active` is whether it was exercised this tick (a click, a
37
+ * traversal, attention flowing across it); `tension` is the current strain. Strengthens toward 1
38
+ * while active, decays toward 0 while idle, and memory follows more slowly — so a long-used
39
+ * relationship stays warm after a pause, while a one-off fades.
40
+ */
41
+ export declare function updateRelationship(r: RelationshipAgent, active: boolean, tension: number, dt: number, dyn?: RelationshipDynamics): void;
42
+ /**
43
+ * Attention transferred across a relationship: a fraction of the source body's attention flows to
44
+ * the target, scaled by the live strength. Pure — returns the amount to add at `to` and remove at
45
+ * `from` (the caller applies it, conserving the budget).
46
+ */
47
+ export declare function attentionTransfer(r: RelationshipAgent, fromAttention: number, rate?: number): number;
48
+ /** A relationship paired with a strength thresholder, for `field:relationship-strengthened` events. */
49
+ export interface WatchedRelationship {
50
+ agent: RelationshipAgent;
51
+ threshold: Thresholder;
52
+ }
53
+ /** Build a watched relationship with a sensible strengthen/weaken threshold. */
54
+ export declare function watchRelationship(agent: RelationshipAgent, debounceMs?: number): WatchedRelationship;
55
+ //# sourceMappingURL=relationship.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../../src/agents/relationship.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,6BAA6B,EAAE,oBAI3C,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,iBAAiB,EACpB,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,EACV,GAAG,GAAE,oBAAoD,GACxD,IAAI,CAKN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,SAAO,GAAG,MAAM,CAElG;AAED,uGAAuG;AACvG,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,iBAAiB,CAAC;IACzB,SAAS,EAAE,WAAW,CAAC;CACxB;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,EAAE,UAAU,SAAM,GAAG,mBAAmB,CAEjG"}