@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,1496 @@
1
+ import { EXPERIMENTAL_RECIPES } from "./wayfinding.js";
2
+ // ── Gravity: priority, convergence, hierarchy ───────────────────────────────────────
3
+ export const PRIORITY_WELL = {
4
+ id: 'priority-well',
5
+ name: 'Priority Well',
6
+ intent: 'make important elements feel naturally weighted without shouting',
7
+ naturalField: 'gravity',
8
+ primitives: ['attract', 'gravity'],
9
+ bodies: [
10
+ { body: 'attract', strength: 1.2, range: 320, feedback: true },
11
+ { body: 'gravity', strength: 0.6, range: 360 },
12
+ ],
13
+ render: ['particles', 'trails'],
14
+ metrics: ['density', 'attention', 'priority'],
15
+ diagnostics: ['potential', 'prediction', 'force-vectors'],
16
+ accessibility: {
17
+ reducedMotion: 'weight, glow, and the current-state marker hold their last value — no travel',
18
+ meaningWithoutMotion: 'the important element is also stronger in weight, outline, and reading order',
19
+ },
20
+ notes: 'Gravity + attract pull matter and attention into one well; --field-attention / --field-priority write back to drive weight and bloom. (The density lane is host-supplied — set data-field-density to ground --field-density; the engine\'s own live density channel is --d on data-feedback bodies.)',
21
+ };
22
+ export const FOCUS_ORBIT = {
23
+ id: 'focus-orbit',
24
+ name: 'Focus Orbit',
25
+ intent: 'keep related options moving around the active item',
26
+ naturalField: 'gravity',
27
+ primitives: ['attract', 'magnetism', 'tether'],
28
+ bodies: [
29
+ { body: 'attract', strength: 1, range: 260, feedback: true },
30
+ { body: 'magnetism', strength: 0.8, range: 300, spin: 1 },
31
+ { body: 'tether', strength: 0.5, range: 220 },
32
+ ],
33
+ render: ['particles', 'field-lines'],
34
+ metrics: ['attention', 'relation-strength'],
35
+ diagnostics: ['prediction', 'topology', 'field-lines'],
36
+ accessibility: {
37
+ reducedMotion: 'a static relationship ring marks the active item; related items keep their weighted emphasis',
38
+ meaningWithoutMotion: 'the active item is marked current; related items are listed beside it',
39
+ },
40
+ notes: 'The active item is a gravity well; magnetism curves the surrounding motion around it (gravity + electromagnetic), and tether keeps related options nearby.',
41
+ };
42
+ export const SEARCH_RELEVANCE_FIELD = {
43
+ id: 'search-relevance-field',
44
+ name: 'Search Relevance Field',
45
+ intent: 'let search results settle by relevance, confidence, and recency',
46
+ naturalField: 'gravity',
47
+ primitives: ['attract', 'memory', 'repel'],
48
+ bodies: [
49
+ { body: 'attract', strength: 1, range: 280, feedback: true },
50
+ { body: 'memory', strength: 0.6, range: 320 },
51
+ { body: 'repel', strength: 0.5, range: 200 },
52
+ ],
53
+ render: ['particles', 'heatmap'],
54
+ metrics: ['density', 'memory', 'recency'],
55
+ diagnostics: ['potential', 'prediction', 'heatmap'],
56
+ accessibility: {
57
+ reducedMotion: 'results re-rank into a static ordered list; memory shows as a "seen" tick',
58
+ meaningWithoutMotion: 'ranking is a numbered list; relevance and recency are labelled',
59
+ },
60
+ notes: 'Relevance becomes attract strength so confident results sink into deeper wells; weak results drift out (repel); previously opened results retain memory.',
61
+ };
62
+ // ── Electromagnetic: polarity, signal, flow, contrast ───────────────────────────────
63
+ export const SIGNAL_PATH = {
64
+ id: 'signal-path',
65
+ name: 'Signal Path',
66
+ intent: 'show information flowing through citations, dependencies, or routes',
67
+ naturalField: 'electromagnetic',
68
+ primitives: ['charge', 'propagate', 'fieldflow'],
69
+ bodies: [
70
+ { body: 'charge', strength: 1, range: 300, spin: 1 },
71
+ { body: 'propagate', strength: 0.8, range: 360 },
72
+ { body: 'fieldflow', strength: 0.8, range: 0 },
73
+ ],
74
+ render: ['streamlines', 'field-lines', 'trails'],
75
+ metrics: ['signal', 'strength'],
76
+ diagnostics: ['field-lines', 'causality', 'force-vectors'],
77
+ accessibility: {
78
+ reducedMotion: 'a persistent path line with step markers replaces the travelling signal',
79
+ meaningWithoutMotion: 'the route is also an ordered list of steps with a current-step state',
80
+ },
81
+ notes: 'A signal travels source → target along declared relationships: charge sets polarity, propagate carries the wave, fieldflow carries matter along the structure. Electric pushes, magnetic bends, fieldflow carries.',
82
+ };
83
+ export const EVIDENCE_FIELD = {
84
+ id: 'evidence-field',
85
+ name: 'Evidence Field',
86
+ intent: 'show how sources support, weaken, or contradict a claim',
87
+ naturalField: 'electromagnetic',
88
+ primitives: ['charge', 'link', 'cohesion', 'repel'],
89
+ bodies: [
90
+ { body: 'charge', strength: 0.9, range: 280, spin: 1 },
91
+ { body: 'link', strength: 0.7, range: 320 },
92
+ { body: 'cohesion', strength: 0.6, range: 260, feedback: true },
93
+ { body: 'repel', strength: 0.5, range: 200 },
94
+ ],
95
+ relationships: [{ from: 'claim', to: 'source', type: 'supports', strength: 0.7 }],
96
+ render: ['links', 'particles', 'heatmap'],
97
+ metrics: ['coherence', 'entropy'],
98
+ diagnostics: ['topology', 'causality', 'links'],
99
+ accessibility: {
100
+ reducedMotion: 'a static claim/source table with support and conflict badges',
101
+ meaningWithoutMotion: 'each source is listed as supporting or contradicting, with a confidence label',
102
+ },
103
+ notes: 'Claims are bodies; supporting sources bind them (link + cohesion), contradictory sources repel and raise entropy (electromagnetic + strong). Strong evidence increases coherence.',
104
+ };
105
+ export const CONFLICT_FIELD = {
106
+ id: 'conflict-field',
107
+ name: 'Conflict Field',
108
+ intent: 'make contradiction, uncertainty, and unstable state visible',
109
+ naturalField: 'weak',
110
+ primitives: ['charge', 'repel', 'morph', 'diffuse'],
111
+ bodies: [
112
+ { body: 'charge', strength: 0.8, range: 260, spin: -1 },
113
+ { body: 'repel', strength: 0.7, range: 220 },
114
+ { body: 'morph', strength: 0.5, range: 240 },
115
+ { body: 'diffuse', strength: 0.4, range: 240 },
116
+ ],
117
+ render: ['particles', 'heatmap'],
118
+ metrics: ['conflict', 'entropy', 'coherence'],
119
+ diagnostics: ['causality', 'contours', 'inspector'],
120
+ accessibility: {
121
+ reducedMotion: 'a static conflict rail lists contradictions and the fields they affect',
122
+ meaningWithoutMotion: 'each contradiction is named with the states in conflict',
123
+ },
124
+ notes: 'Opposing states repel and raise entropy (electromagnetic); morph carries the transformation pressure toward resolution or a decayed warning (weak).',
125
+ };
126
+ // ── Strong: binding, cohesion, structure, clusters ──────────────────────────────────
127
+ export const RELATIONSHIP_BOND = {
128
+ id: 'relationship-bond',
129
+ name: 'Relationship Bond',
130
+ intent: 'keep related elements visually and behaviorally connected',
131
+ naturalField: 'strong',
132
+ primitives: ['link', 'tether', 'cohesion'],
133
+ bodies: [
134
+ { body: 'link', strength: 0.8, range: 320, feedback: true },
135
+ { body: 'tether', strength: 0.6, range: 240 },
136
+ { body: 'cohesion', strength: 0.5, range: 260 },
137
+ ],
138
+ relationships: [{ from: 'a', to: 'b', type: 'related', strength: 0.6 }],
139
+ render: ['links', 'particles'],
140
+ metrics: ['relation-strength', 'tension'],
141
+ diagnostics: ['topology', 'links', 'force-vectors'],
142
+ accessibility: {
143
+ reducedMotion: 'a static connector and a paired highlight stand in for the live bond',
144
+ meaningWithoutMotion: 'related elements share a label/color and are listed as connected',
145
+ },
146
+ notes: 'Related elements hold together through a bond with strength, tension, and memory — the strong force: binding and local structure.',
147
+ };
148
+ export const CONCEPT_CLUSTER = {
149
+ id: 'concept-cluster',
150
+ name: 'Concept Cluster',
151
+ intent: 'group related terms, cards, or sections without hard layout changes',
152
+ naturalField: 'strong',
153
+ primitives: ['cohesion', 'crystallize', 'link', 'memory'],
154
+ bodies: [
155
+ { body: 'cohesion', strength: 0.7, range: 300, feedback: true },
156
+ { body: 'crystallize', strength: 0.5, range: 260 },
157
+ { body: 'link', strength: 0.5, range: 280 },
158
+ { body: 'memory', strength: 0.4, range: 320 },
159
+ ],
160
+ render: ['metaballs', 'links', 'particles'],
161
+ metrics: ['cluster', 'memory', 'density'],
162
+ diagnostics: ['topology', 'heatmap', 'inspector'],
163
+ accessibility: {
164
+ reducedMotion: 'concepts collapse into grouped lists; active groups keep emphasis',
165
+ meaningWithoutMotion: 'related concepts are grouped under headings with relation badges',
166
+ },
167
+ notes: 'Related concepts cluster without a rigid layout (cohesion + crystallize); active concepts strengthen nearby terms; unrelated ones cool and drift.',
168
+ };
169
+ export const COHERENCE_FIELD = {
170
+ id: 'coherence-field',
171
+ name: 'Coherence Field',
172
+ intent: 'show whether a form, workflow, or dataset is becoming stable',
173
+ naturalField: 'strong',
174
+ primitives: ['cohesion', 'pressure', 'link', 'repel'],
175
+ bodies: [
176
+ { body: 'cohesion', strength: 0.7, range: 280, feedback: true },
177
+ { body: 'pressure', strength: 0.5, range: 240 },
178
+ { body: 'link', strength: 0.5, range: 260 },
179
+ { body: 'repel', strength: 0.4, range: 180 },
180
+ ],
181
+ render: ['particles', 'heatmap'],
182
+ metrics: ['coherence', 'entropy', 'pressure'],
183
+ diagnostics: ['inspector', 'causality', 'heatmap'],
184
+ accessibility: {
185
+ reducedMotion: 'a static coherence/progress rail marks stable and unstable sections',
186
+ meaningWithoutMotion: 'validity is announced and shown with icon + text per field',
187
+ },
188
+ notes: 'As valid pieces align, the field becomes more coherent (strong binding); missing or contradictory pieces raise pressure and entropy.',
189
+ };
190
+ // ── Gravity + memory + relationships: reading ───────────────────────────────────────
191
+ export const READING_FIELD = {
192
+ id: 'reading-field',
193
+ name: 'Reading Field',
194
+ intent: 'make long content pages reveal attention, memory, and concept links',
195
+ naturalField: 'gravity',
196
+ primitives: ['attract', 'memory', 'link'],
197
+ bodies: [
198
+ { body: 'attract', strength: 0.8, range: 300, feedback: true },
199
+ { body: 'memory', strength: 0.7, range: 360 },
200
+ { body: 'link', strength: 0.5, range: 320 },
201
+ ],
202
+ relationships: [{ from: 'section', to: 'citation', type: 'cites', strength: 0.5 }],
203
+ render: ['trails', 'links', 'particles'],
204
+ metrics: ['attention', 'memory'],
205
+ diagnostics: ['heatmap', 'topology', 'inspector'],
206
+ accessibility: {
207
+ reducedMotion: 'a memory-weighted table of contents and static section rails replace the live trail',
208
+ meaningWithoutMotion: 'progress is a read-state marker; citations are listed inline',
209
+ },
210
+ notes: 'Sections near the viewport centre gain attention (gravity); dwelled sections accumulate memory; related concepts and citations light up through relationships. The flagship /docs/reading-field demo runs this on the production platform runtime.',
211
+ };
212
+ // ── Weak / metric: memory, decay, transformation ────────────────────────────────────
213
+ export const MEMORY_TRACE = {
214
+ id: 'memory-trace',
215
+ name: 'Memory Trace',
216
+ intent: 'show where a user has been, paused, returned, or accumulated attention',
217
+ naturalField: 'weak',
218
+ primitives: ['memory', 'diffuse'],
219
+ bodies: [
220
+ { body: 'memory', strength: 0.8, range: 360, feedback: true },
221
+ { body: 'diffuse', strength: 0.4, range: 280 },
222
+ ],
223
+ render: ['trails', 'heatmap', 'particles'],
224
+ metrics: ['memory', 'recency', 'decay'],
225
+ diagnostics: ['heatmap', 'contours', 'inspector'],
226
+ accessibility: {
227
+ reducedMotion: 'static history marks and recency labels replace the decaying trail',
228
+ meaningWithoutMotion: 'visited items are marked with a timestamp / recency label',
229
+ },
230
+ notes: 'Interaction leaves a decaying trace (weak-force decay via memory); repeated interaction strengthens it; inactive traces cool over time.',
231
+ };
232
+ export const DECAY_NOTICE = {
233
+ id: 'decay-notice',
234
+ name: 'Decay Notice',
235
+ intent: 'let stale, temporary, or completed state fade gracefully',
236
+ naturalField: 'weak',
237
+ primitives: ['morph', 'memory', 'diffuse'],
238
+ bodies: [
239
+ { body: 'morph', strength: 0.6, range: 240, feedback: true },
240
+ { body: 'memory', strength: 0.5, range: 280 },
241
+ { body: 'diffuse', strength: 0.4, range: 240 },
242
+ ],
243
+ render: ['particles', 'heatmap'],
244
+ metrics: ['decay', 'age', 'heat'],
245
+ diagnostics: ['inspector', 'heatmap', 'causality'],
246
+ accessibility: {
247
+ reducedMotion: 'a timestamp and a faded state marker replace the decay animation',
248
+ meaningWithoutMotion: 'the state stays announced as text while emphasis fades',
249
+ },
250
+ notes: 'A state begins strong then naturally releases (weak force: expiration); the element stays semantically clear while visual emphasis decays.',
251
+ };
252
+ export const PHASE_SHIFT = {
253
+ id: 'phase-shift',
254
+ name: 'Phase Shift',
255
+ intent: 'show a state transition: draft → published, pending → complete, hidden → active',
256
+ naturalField: 'weak',
257
+ primitives: ['morph', 'cohesion'],
258
+ bodies: [
259
+ { body: 'morph', strength: 0.7, range: 260, feedback: true },
260
+ { body: 'cohesion', strength: 0.5, range: 240 },
261
+ ],
262
+ render: ['particles', 'metaballs'],
263
+ metrics: ['phase', 'coherence', 'progress'],
264
+ diagnostics: ['inspector', 'causality', 'prediction'],
265
+ accessibility: {
266
+ reducedMotion: 'a state label and progress marker replace the transition; non-motion styling shows the change',
267
+ meaningWithoutMotion: 'the from/to state is named and announced on change',
268
+ },
269
+ notes: 'A body transitions between named states (weak-force transformation via morph); the interface shows continuity rather than replacement.',
270
+ };
271
+ // ── Electromagnetic + transport: flow ───────────────────────────────────────────────
272
+ export const GUIDED_FLOW = {
273
+ id: 'guided-flow',
274
+ name: 'Guided Flow',
275
+ intent: 'move particles or attention along field lines, relationships, or paths',
276
+ naturalField: 'electromagnetic',
277
+ primitives: ['magnetism', 'fieldflow', 'stream', 'propagate'],
278
+ bodies: [
279
+ { body: 'magnetism', strength: 1, range: 420, spin: 1 },
280
+ { body: 'fieldflow', strength: 0.8, range: 0 },
281
+ { body: 'stream', strength: 0.6, range: 320, angle: 0 },
282
+ { body: 'propagate', strength: 0.5, range: 300 },
283
+ ],
284
+ render: ['streamlines', 'field-lines', 'trails', 'particles'],
285
+ metrics: ['flow', 'velocity', 'density'],
286
+ diagnostics: ['field-lines', 'force-vectors', 'prediction'],
287
+ accessibility: {
288
+ reducedMotion: 'a static path contour with a numbered route and direction markers',
289
+ meaningWithoutMotion: 'the route is an ordered list of steps with direction labels',
290
+ },
291
+ notes: 'Matter and attention move along field lines / relationship paths (electromagnetic + transport). Magnetism bends, fieldflow carries — the recipe-level expression of field.flowTo() and fieldflow.',
292
+ };
293
+ // ── Diagnostic + platform layers ────────────────────────────────────────────────────
294
+ export const DIAGNOSTIC_LENS = {
295
+ id: 'diagnostic-lens',
296
+ name: 'Diagnostic Lens',
297
+ intent: 'reveal field lines, causality, prediction, topology, energy, and overlays',
298
+ primitives: ['attract'],
299
+ bodies: [{ body: 'attract', strength: 0.6, range: 260 }],
300
+ render: ['particles', 'field-lines'],
301
+ metrics: ['density', 'energy', 'entropy'],
302
+ diagnostics: ['topology', 'inspector', 'causality', 'prediction', 'energy', 'potential', 'contours', 'force-vectors'],
303
+ accessibility: {
304
+ reducedMotion: 'a static inspector table and overlay toggles replace the live overlays',
305
+ meaningWithoutMotion: 'every overlay has a textual table equivalent (counts, contributions, energy)',
306
+ },
307
+ notes: 'The lens reveals why something moved, where energy accumulated, which relationships are active, and which primitive caused the result. It reads diagnostics over any field rather than adding force.',
308
+ };
309
+ export const ACCESSIBILITY_EQUIVALENCE = {
310
+ id: 'accessibility-equivalence',
311
+ name: 'Accessibility Equivalence',
312
+ intent: 'convert motion-heavy behavior into static, semantic, reduced-motion equivalents',
313
+ primitives: ['attract'],
314
+ bodies: [{ body: 'attract', strength: 0.8, range: 280, feedback: true }],
315
+ render: ['particles'],
316
+ metrics: ['attention', 'memory', 'coherence'],
317
+ diagnostics: ['inspector'],
318
+ accessibility: {
319
+ reducedMotion: 'this recipe defines the equivalent: motion-heavy behavior maps to a static, semantic, reduced-motion form',
320
+ meaningWithoutMotion: 'field visuals clarify state but are never the only source of meaning — semantics carry it',
321
+ },
322
+ notes: 'The contract recipe: any motion-heavy behavior must map to a semantic, static, reduced-motion equivalent. No field behavior may be the only source of meaning.',
323
+ };
324
+ /** Tier 1 — core interface + accessibility fields (recipes 1-16). */
325
+ const TIER_CORE = [
326
+ PRIORITY_WELL,
327
+ FOCUS_ORBIT,
328
+ SEARCH_RELEVANCE_FIELD,
329
+ SIGNAL_PATH,
330
+ EVIDENCE_FIELD,
331
+ CONFLICT_FIELD,
332
+ RELATIONSHIP_BOND,
333
+ CONCEPT_CLUSTER,
334
+ COHERENCE_FIELD,
335
+ READING_FIELD,
336
+ MEMORY_TRACE,
337
+ DECAY_NOTICE,
338
+ PHASE_SHIFT,
339
+ GUIDED_FLOW,
340
+ DIAGNOSTIC_LENS,
341
+ ACCESSIBILITY_EQUIVALENCE,
342
+ ];
343
+ /**
344
+ * Tier 2 (applied) — product, workflow, trust, collaboration (recipes 17-32). Applied product patterns built
345
+ * from the same primitives as the core tier.
346
+ */
347
+ const TIER_PRODUCT = [
348
+ {
349
+ id: 'attention-weather',
350
+ name: 'Attention Weather',
351
+ intent: 'show system urgency, density, and activity across a dashboard',
352
+ naturalField: 'gravity',
353
+ primitives: ['gravity', 'thermal', 'pressure', 'diffuse', 'memory'],
354
+ bodies: [
355
+ { body: 'gravity', strength: 1, range: 380, feedback: true },
356
+ { body: 'thermal', strength: 0.8, range: 320 },
357
+ { body: 'pressure', strength: 0.7, range: 300 },
358
+ { body: 'diffuse memory', strength: 0.5, range: 260 },
359
+ ],
360
+ render: ['heatmap', 'metaballs', 'particles'],
361
+ metrics: ['heat', 'pressure', 'attention', 'density'],
362
+ diagnostics: ['heatmap', 'energy', 'contours', 'inspector'],
363
+ accessibility: {
364
+ reducedMotion: 'a status rail with a pressure badge per section and a priority-ordered list',
365
+ meaningWithoutMotion: 'section tone, a numeric pressure badge, and priority ordering carry urgency without animation',
366
+ },
367
+ notes: 'Mass falls toward what matters and heat rises where the system runs hot — gravitational priority and thermal weather translated to a dashboard.',
368
+ },
369
+ {
370
+ id: 'navigation-current',
371
+ name: 'Navigation Current',
372
+ intent: 'make routes, breadcrumbs, and likely next paths feel connected',
373
+ naturalField: 'electromagnetic',
374
+ primitives: ['fieldflow', 'stream', 'memory', 'propagate', 'link'],
375
+ bodies: [
376
+ { body: 'fieldflow', strength: 0.9, range: 0, feedback: true },
377
+ { body: 'stream', strength: 0.7, range: 340, angle: 0 },
378
+ { body: 'memory', strength: 0.5, range: 280 },
379
+ { body: 'propagate link', strength: 0.5, range: 300 },
380
+ ],
381
+ render: ['streamlines', 'field-lines', 'links', 'trails', 'particles'],
382
+ metrics: ['current', 'memory', 'signal', 'route-strength'],
383
+ diagnostics: ['field-lines', 'force-vectors', 'topology'],
384
+ accessibility: {
385
+ reducedMotion: 'an active-path rail with visited markers and next-step hints',
386
+ meaningWithoutMotion: 'the route reads as an ordered breadcrumb list with visited and next-step labels',
387
+ },
388
+ notes: 'Magnetism bends the route, fieldflow carries the traveller along it — the active path emits a current while prior routes linger as memory.',
389
+ },
390
+ {
391
+ id: 'citation-thread',
392
+ name: 'Citation Thread',
393
+ intent: 'bind citations, footnotes, evidence, references into visible relationships',
394
+ naturalField: 'electromagnetic',
395
+ primitives: ['link', 'fieldflow', 'charge', 'memory'],
396
+ bodies: [
397
+ { body: 'link', strength: 1, range: 360, feedback: true },
398
+ { body: 'fieldflow', strength: 0.7, range: 0 },
399
+ { body: 'charge', strength: 0.6, range: 300, spin: 1 },
400
+ { body: 'memory', strength: 0.5, range: 260 },
401
+ ],
402
+ relationships: [{ from: 'citation', to: 'source', type: 'cites', strength: 0.9 }],
403
+ render: ['links', 'field-lines', 'trails', 'particles'],
404
+ metrics: ['relation-strength', 'confidence', 'memory'],
405
+ diagnostics: ['topology', 'causality', 'inspector'],
406
+ accessibility: {
407
+ reducedMotion: 'persistent source highlights with numbered source links and support badges',
408
+ meaningWithoutMotion: 'each claim names its source via a numbered link and a support badge, no thread animation needed',
409
+ },
410
+ notes: 'Charge binds a citation to its source and fieldflow carries the eye down the thread — electromagnetic relation made readable from either end.',
411
+ },
412
+ {
413
+ id: 'form-stability-field',
414
+ name: 'Form Stability Field',
415
+ intent: 'show validation as coherence instead of error noise',
416
+ naturalField: 'strong',
417
+ primitives: ['cohesion', 'pressure', 'morph', 'memory', 'link'],
418
+ bodies: [
419
+ { body: 'cohesion', strength: 1, range: 320, feedback: true },
420
+ { body: 'pressure', strength: 0.7, range: 280 },
421
+ { body: 'morph memory', strength: 0.5, range: 260 },
422
+ { body: 'link', strength: 0.6, range: 300 },
423
+ ],
424
+ render: ['metaballs', 'links', 'particles'],
425
+ metrics: ['coherence', 'entropy', 'pressure', 'completion'],
426
+ diagnostics: ['inspector', 'causality', 'topology'],
427
+ accessibility: {
428
+ reducedMotion: 'a coherence meter with grouped validation messages and stable/unstable markers',
429
+ meaningWithoutMotion: 'a coherence meter and per-group stable/unstable markers report validity without motion',
430
+ },
431
+ notes: 'The strong force binds valid fields into one coherent body while contradiction raises pressure — weak-style decay (morph) releases the tension as completion settles in.',
432
+ },
433
+ {
434
+ id: 'command-intent-field',
435
+ name: 'Command Intent Field',
436
+ intent: 'let command palettes settle around likely intent',
437
+ naturalField: 'gravity',
438
+ primitives: ['gravity', 'charge', 'memory', 'cohesion', 'repel'],
439
+ bodies: [
440
+ { body: 'gravity', strength: 1, range: 360, feedback: true },
441
+ { body: 'charge', strength: 0.6, range: 300, spin: 1 },
442
+ { body: 'memory cohesion', strength: 0.6, range: 280 },
443
+ { body: 'repel', strength: 0.7, range: 260 },
444
+ ],
445
+ render: ['dots', 'metaballs', 'particles'],
446
+ metrics: ['intent', 'confidence', 'memory', 'risk'],
447
+ diagnostics: ['potential', 'causality', 'topology'],
448
+ accessibility: {
449
+ reducedMotion: 'ranked command groups with risk labels and recency indicators',
450
+ meaningWithoutMotion: 'commands appear as a ranked list with risk labels and recency badges, no settling animation required',
451
+ },
452
+ notes: 'Likely commands sink into a gravity well while dangerous ones repel — electromagnetic charge clusters the related, gravity decides what rises to the top.',
453
+ },
454
+ {
455
+ id: 'selection-wake',
456
+ name: 'Selection Wake',
457
+ intent: 'leave a subtle trail of user interaction and selection',
458
+ naturalField: 'weak',
459
+ primitives: ['memory', 'diffuse', 'fieldflow', 'stream'],
460
+ bodies: [
461
+ { body: 'memory', strength: 0.9, range: 300, feedback: true },
462
+ { body: 'diffuse', strength: 0.6, range: 280 },
463
+ { body: 'fieldflow', strength: 0.6, range: 0 },
464
+ { body: 'stream', strength: 0.5, range: 320, angle: 0 },
465
+ ],
466
+ render: ['trails', 'heatmap', 'particles'],
467
+ metrics: ['memory', 'recency', 'trail'],
468
+ diagnostics: ['heatmap', 'contours', 'force-vectors'],
469
+ accessibility: {
470
+ reducedMotion: 'selection-history marks with recent-item badges and a static trail rail',
471
+ meaningWithoutMotion: 'a static history rail lists recently touched items with recency badges in place of a fading wake',
472
+ },
473
+ notes: 'Memory holds the wake while diffuse lets it fade, and fieldflow carries repeated paths into usage trails — transport that remembers where attention has been.',
474
+ },
475
+ {
476
+ id: 'availability-pressure',
477
+ name: 'Availability Pressure',
478
+ intent: 'show schedule density, conflicts, and open space',
479
+ naturalField: 'gravity',
480
+ primitives: ['gravity', 'pressure', 'tether', 'repel', 'memory'],
481
+ bodies: [
482
+ { body: 'gravity', strength: 1, range: 380, feedback: true },
483
+ { body: 'pressure', strength: 0.8, range: 300 },
484
+ { body: 'tether', strength: 0.6, range: 280 },
485
+ { body: 'repel memory', strength: 0.6, range: 260 },
486
+ ],
487
+ render: ['heatmap', 'metaballs', 'particles'],
488
+ metrics: ['pressure', 'availability', 'conflict', 'flexibility'],
489
+ diagnostics: ['contours', 'potential', 'causality'],
490
+ accessibility: {
491
+ reducedMotion: 'density shading with conflict badges and open-space markers',
492
+ meaningWithoutMotion: 'busy and open blocks read through density shading, conflict badges, and explicit open-space markers',
493
+ },
494
+ notes: 'Deadlines sink into gravitational wells and busy blocks raise pressure, while elastic events ride a tether (spring) — schedule density read as a gravity-and-pressure landscape.',
495
+ },
496
+ {
497
+ id: 'dependency-tension',
498
+ name: 'Dependency Tension',
499
+ intent: 'reveal constraints, blockers, and coupled states',
500
+ naturalField: 'strong',
501
+ primitives: ['link', 'tether', 'charge', 'pressure'],
502
+ bodies: [
503
+ { body: 'link', strength: 1, range: 360, feedback: true },
504
+ { body: 'tether', strength: 0.8, range: 320 },
505
+ { body: 'charge', strength: 0.6, range: 300, spin: 1 },
506
+ { body: 'pressure', strength: 0.6, range: 280 },
507
+ ],
508
+ relationships: [{ from: 'task', to: 'blocker', type: 'depends-on', strength: 0.9 }],
509
+ render: ['links', 'field-lines', 'particles'],
510
+ metrics: ['tension', 'blocked', 'coherence', 'heat'],
511
+ diagnostics: ['topology', 'causality', 'inspector'],
512
+ accessibility: {
513
+ reducedMotion: 'a dependency table with a blocker count and tension badges',
514
+ meaningWithoutMotion: 'dependencies and blockers read as a table with a blocker count and per-edge tension badges',
515
+ },
516
+ notes: 'The strong force binds coupled items through tether (spring) tension while electromagnetic charge pulls conflicting paths apart — blocked links heat, resolved ones cool.',
517
+ },
518
+ {
519
+ id: 'staleness-drift',
520
+ name: 'Staleness Drift',
521
+ intent: 'make outdated content, data, or files cool and recede',
522
+ naturalField: 'weak',
523
+ primitives: ['memory', 'morph', 'diffuse'],
524
+ bodies: [
525
+ { body: 'memory', strength: 0.9, range: 300, feedback: true },
526
+ { body: 'morph', strength: 0.6, range: 280 },
527
+ { body: 'diffuse', strength: 0.6, range: 260 },
528
+ ],
529
+ render: ['heatmap', 'trails', 'particles'],
530
+ metrics: ['age', 'staleness', 'memory', 'confidence'],
531
+ diagnostics: ['heatmap', 'contours', 'inspector'],
532
+ accessibility: {
533
+ reducedMotion: 'stale badges with an aging tone and a last-verified marker',
534
+ meaningWithoutMotion: 'staleness reads through stale badges, aging tone, and an explicit last-verified date',
535
+ },
536
+ notes: 'Like a weak-force decay, unattended items morph and diffuse toward the background while memory lets a revisit pull them back into coherence.',
537
+ },
538
+ {
539
+ id: 'trust-gradient',
540
+ name: 'Trust Gradient',
541
+ intent: 'show confidence, verification, and unsupported claims',
542
+ naturalField: 'electromagnetic',
543
+ primitives: ['charge', 'link', 'cohesion', 'memory'],
544
+ bodies: [
545
+ { body: 'charge', strength: 1, range: 360, spin: 1, feedback: true },
546
+ { body: 'link', strength: 0.7, range: 320 },
547
+ { body: 'cohesion', strength: 0.6, range: 300 },
548
+ { body: 'memory', strength: 0.5, range: 260 },
549
+ ],
550
+ render: ['heatmap', 'links', 'particles'],
551
+ metrics: ['trust', 'confidence', 'coherence', 'entropy'],
552
+ diagnostics: ['causality', 'topology', 'inspector'],
553
+ accessibility: {
554
+ reducedMotion: 'trust badges with an evidence table and an unsupported-claim list',
555
+ meaningWithoutMotion: 'trust reads through per-claim badges, a supporting-evidence table, and a flagged unsupported-claim list',
556
+ },
557
+ notes: 'Electromagnetic charge pulls verified claims into coherence and separates contradictions, while links to sources set the trust gradient — evidence is the field, confidence the potential.',
558
+ },
559
+ {
560
+ id: 'completion-release',
561
+ name: 'Completion Release',
562
+ intent: 'let finished work release pressure and settle into memory',
563
+ naturalField: 'weak',
564
+ primitives: ['morph', 'memory', 'gravity', 'pressure', 'cohesion'],
565
+ bodies: [
566
+ { body: 'morph', strength: 0.9, range: 300, feedback: true },
567
+ { body: 'memory', strength: 0.7, range: 280 },
568
+ { body: 'gravity pressure', strength: 0.6, range: 320 },
569
+ { body: 'cohesion', strength: 0.6, range: 280 },
570
+ ],
571
+ render: ['metaballs', 'trails', 'particles'],
572
+ metrics: ['completion', 'pressure', 'memory', 'coherence'],
573
+ diagnostics: ['energy', 'inspector', 'prediction'],
574
+ accessibility: {
575
+ reducedMotion: 'a completion marker with a resolved-state badge and a stable history line',
576
+ meaningWithoutMotion: 'finished work reads as a resolved-state badge plus a stable history-line entry rather than vanishing',
577
+ },
578
+ notes: 'Active work holds pressure under gravity; completion is a weak-force phase change (morph) that releases the tension and leaves a memory mark instead of disappearing.',
579
+ },
580
+ {
581
+ id: 'group-magnet',
582
+ name: 'Group Magnet',
583
+ intent: 'let related cards, assets, or controls cluster intelligently',
584
+ naturalField: 'strong',
585
+ primitives: ['cohesion', 'gravity', 'crystallize', 'link', 'memory'],
586
+ bodies: [
587
+ { body: 'cohesion', strength: 1, range: 340, feedback: true },
588
+ { body: 'gravity', strength: 0.8, range: 360 },
589
+ { body: 'crystallize link', strength: 0.6, range: 300 },
590
+ { body: 'memory', strength: 0.5, range: 260 },
591
+ ],
592
+ render: ['metaballs', 'links', 'particles'],
593
+ metrics: ['cluster', 'density', 'relation-strength'],
594
+ diagnostics: ['topology', 'potential', 'heatmap'],
595
+ accessibility: {
596
+ reducedMotion: 'grouped sections with relation badges and cluster headings',
597
+ meaningWithoutMotion: 'clusters read as labeled grouped sections with relation badges, no magnetic motion required',
598
+ },
599
+ notes: 'The strong force binds related items into one cluster around a representative center while gravity sets the local hub — crystallize snaps stragglers onto the lattice.',
600
+ },
601
+ {
602
+ id: 'error-pressure',
603
+ name: 'Error Pressure',
604
+ intent: 'show accumulated instability without harsh alert patterns',
605
+ naturalField: 'weak',
606
+ primitives: ['thermal', 'pressure', 'morph', 'memory', 'diffuse'],
607
+ bodies: [
608
+ { body: 'thermal', strength: 1, range: 320, feedback: true },
609
+ { body: 'pressure', strength: 0.8, range: 300 },
610
+ { body: 'morph memory', strength: 0.5, range: 280 },
611
+ { body: 'diffuse', strength: 0.6, range: 260 },
612
+ ],
613
+ render: ['heatmap', 'metaballs', 'particles'],
614
+ metrics: ['error', 'heat', 'entropy', 'pressure'],
615
+ diagnostics: ['heatmap', 'energy', 'causality'],
616
+ accessibility: {
617
+ reducedMotion: 'an error summary with heat badges and an affected-section rail',
618
+ meaningWithoutMotion: 'errors read through a summary count, per-section heat badges, and an affected-section rail',
619
+ },
620
+ notes: 'Errors add thermal heat and entropy that accumulate as pressure; resolved ones cool and, like a weak decay, morph into history instead of flashing an alarm.',
621
+ },
622
+ {
623
+ id: 'handoff-stream',
624
+ name: 'Handoff Stream',
625
+ intent: 'show ownership or state moving from one person or system to another',
626
+ naturalField: 'electromagnetic',
627
+ primitives: ['fieldflow', 'propagate', 'link', 'memory', 'morph'],
628
+ bodies: [
629
+ { body: 'fieldflow', strength: 1, range: 0, feedback: true },
630
+ { body: 'propagate', strength: 0.7, range: 320 },
631
+ { body: 'link memory', strength: 0.6, range: 300 },
632
+ { body: 'morph', strength: 0.5, range: 280 },
633
+ ],
634
+ relationships: [{ from: 'owner', to: 'recipient', type: 'hands-off', strength: 0.9 }],
635
+ render: ['streamlines', 'field-lines', 'trails', 'particles'],
636
+ metrics: ['handoff', 'current', 'memory', 'state'],
637
+ diagnostics: ['field-lines', 'force-vectors', 'topology'],
638
+ accessibility: {
639
+ reducedMotion: 'a transfer timeline with owner badges and a handoff log',
640
+ meaningWithoutMotion: 'the transfer reads as a timeline of owner badges plus a handoff log entry, not a flowing animation',
641
+ },
642
+ notes: 'Magnetism bends the path between owners and fieldflow carries the object along it — the source cools, the target warms, and a memory trace records the transfer.',
643
+ },
644
+ {
645
+ id: 'context-halo',
646
+ name: 'Context Halo',
647
+ intent: 'reveal nearby relevant context around a focused element',
648
+ naturalField: 'gravity',
649
+ primitives: ['gravity', 'memory', 'link', 'cohesion'],
650
+ bodies: [
651
+ { body: 'gravity', strength: 1, range: 360, feedback: true },
652
+ { body: 'memory', strength: 0.6, range: 300 },
653
+ { body: 'link', strength: 0.6, range: 320 },
654
+ { body: 'cohesion', strength: 0.6, range: 280 },
655
+ ],
656
+ render: ['metaballs', 'links', 'particles'],
657
+ metrics: ['context', 'attention', 'memory', 'relation-strength'],
658
+ diagnostics: ['topology', 'potential', 'inspector'],
659
+ accessibility: {
660
+ reducedMotion: 'a context panel with a related-links list and local callouts',
661
+ meaningWithoutMotion: 'related context reads as a panel of ordered related links and callouts ranked by relation strength',
662
+ },
663
+ notes: 'A focused element becomes a gravity well that draws nearby definitions, examples, and prior interactions inward — relevance ranked by relation strength, not fixed placement.',
664
+ },
665
+ {
666
+ id: 'field-tutorial',
667
+ name: 'Field Tutorial',
668
+ intent: 'teach field-ui by revealing DOM, bodies, fields, metrics, feedback, and overlays',
669
+ primitives: ['attract'],
670
+ bodies: [{ body: 'attract', strength: 0.6, range: 300, feedback: true }],
671
+ render: ['particles', 'field-lines', 'dots'],
672
+ metrics: ['teaching', 'attention'],
673
+ diagnostics: ['inspector', 'topology', 'field-lines', 'causality', 'prediction'],
674
+ accessibility: {
675
+ reducedMotion: 'a stepper with static diagrams and live code snippets at each stage',
676
+ meaningWithoutMotion: 'each stage is a labeled step with a static diagram and the exact code, so the lesson reads fully without animation',
677
+ },
678
+ notes: 'A narrative diagnostic recipe: a single attract body gives the inspector something real to read while the interface reveals itself stage by stage — DOM, bodies, fields, metrics, feedback, overlays, reduced-motion.',
679
+ },
680
+ ];
681
+ /**
682
+ * Tier 3 (systems) — safety, provenance, governance (recipes 33-48). Advanced semantic,
683
+ * safety, and inspection patterns.
684
+ */
685
+ const TIER_SYSTEMS = [
686
+ {
687
+ id: 'semantic-gravity-map',
688
+ name: 'Semantic Gravity Map',
689
+ intent: 'let a document or app reveal which concepts carry the most weight',
690
+ naturalField: 'gravity',
691
+ primitives: ['gravity', 'link', 'cohesion', 'memory'],
692
+ bodies: [
693
+ { body: 'gravity', strength: 1.1, range: 400, feedback: true },
694
+ { body: 'link', strength: 0.7, range: 320 },
695
+ { body: 'cohesion', strength: 0.6, range: 280 },
696
+ { body: 'memory', strength: 0.5, range: 260 },
697
+ ],
698
+ render: ['heatmap', 'metaballs', 'links', 'particles'],
699
+ metrics: ['mass', 'attention', 'relation-strength', 'density'],
700
+ diagnostics: ['potential', 'topology', 'heatmap'],
701
+ accessibility: {
702
+ reducedMotion: 'a weighted concept index with an importance rail and a section density map',
703
+ meaningWithoutMotion: 'mass becomes a sorted importance ranking with explicit weight values per concept',
704
+ },
705
+ notes: 'Gravity pulls heavy concepts to the center while link and cohesion bind related ones; importance is mass, memory keeps recurrence felt over time.',
706
+ },
707
+ {
708
+ id: 'polarity-filter',
709
+ name: 'Polarity Filter',
710
+ intent: 'let opposing states, tags, or preferences sort themselves visibly',
711
+ naturalField: 'electromagnetic',
712
+ primitives: ['charge', 'repel', 'attract', 'diffuse'],
713
+ bodies: [
714
+ { body: 'charge', strength: 1, range: 380, spin: 1, feedback: true },
715
+ { body: 'repel', strength: 0.8, range: 320 },
716
+ { body: 'attract', strength: 0.7, range: 340 },
717
+ { body: 'diffuse', strength: 0.5, range: 260 },
718
+ ],
719
+ render: ['field-lines', 'particles', 'dots', 'trails'],
720
+ metrics: ['polarity', 'match', 'distance'],
721
+ diagnostics: ['field-lines', 'causality', 'potential'],
722
+ accessibility: {
723
+ reducedMotion: 'grouped filter lanes with signed badges and separate match and conflict sections',
724
+ meaningWithoutMotion: 'polarity reads as a signed badge and items live in labeled match or conflict groups',
725
+ },
726
+ notes: 'Electric pushes and pulls by sign: matching charge attracts toward the active filter, opposing charge repels, and diffuse keeps neutral items quietly stable.',
727
+ },
728
+ {
729
+ id: 'source-constellation',
730
+ name: 'Source Constellation',
731
+ intent: 'show how multiple sources gather around claims, topics, or decisions',
732
+ naturalField: 'strong',
733
+ primitives: ['link', 'charge', 'gravity', 'memory', 'cohesion'],
734
+ bodies: [
735
+ { body: 'link', strength: 1, range: 360, feedback: true },
736
+ { body: 'charge', strength: 0.7, range: 340, spin: 1 },
737
+ { body: 'gravity', strength: 0.8, range: 380 },
738
+ { body: 'memory', strength: 0.5, range: 280 },
739
+ { body: 'cohesion', strength: 0.6, range: 300 },
740
+ ],
741
+ relationships: [{ from: 'source', to: 'claim', type: 'support', strength: 0.8 }],
742
+ render: ['links', 'metaballs', 'particles', 'trails'],
743
+ metrics: ['confidence', 'support', 'citation-density', 'memory'],
744
+ diagnostics: ['topology', 'causality', 'potential'],
745
+ accessibility: {
746
+ reducedMotion: 'a claim and source matrix with a source ranking and labeled support clusters',
747
+ meaningWithoutMotion: 'support becomes a ranked matrix where distance is a number and contradiction is a marked row',
748
+ },
749
+ notes: 'Strong binding holds sources to the claims they support while electric charge lets contradictory sources carry the opposite sign; repeatedly cited sources gain mass and memory.',
750
+ },
751
+ {
752
+ id: 'drift-correction',
753
+ name: 'Drift Correction',
754
+ intent: 'bring wandering attention or unstable layout back into coherence',
755
+ naturalField: 'weak',
756
+ primitives: ['gravity', 'tether', 'memory', 'morph'],
757
+ bodies: [
758
+ { body: 'gravity', strength: 0.6, range: 360, feedback: true },
759
+ { body: 'tether', strength: 0.7, range: 320 },
760
+ { body: 'memory', strength: 0.5, range: 280 },
761
+ { body: 'morph', strength: 0.4, range: 240 },
762
+ ],
763
+ render: ['streamlines', 'trails', 'particles', 'dots'],
764
+ metrics: ['drift', 'return', 'stability'],
765
+ diagnostics: ['prediction', 'force-vectors', 'inspector'],
766
+ accessibility: {
767
+ reducedMotion: 'a snap guide with a restore marker and a stable-state outline',
768
+ meaningWithoutMotion: 'drift reads as a labeled distance from the stable state with a one-step restore control',
769
+ },
770
+ notes: 'A weak corrective pull is the gentle counterpart to gravity: tether (spring) remembers the stable relation and morph eases the return so wandering settles without snapping.',
771
+ },
772
+ {
773
+ id: 'resonance-match',
774
+ name: 'Resonance Match',
775
+ intent: 'highlight elements that ring with the user current intent',
776
+ naturalField: 'electromagnetic',
777
+ primitives: ['charge', 'memory', 'cohesion', 'propagate'],
778
+ bodies: [
779
+ { body: 'charge', strength: 1, range: 380, spin: 1, feedback: true },
780
+ { body: 'memory', strength: 0.7, range: 300 },
781
+ { body: 'cohesion', strength: 0.6, range: 280 },
782
+ { body: 'propagate', strength: 0.5, range: 320 },
783
+ ],
784
+ render: ['field-lines', 'links', 'particles', 'trails'],
785
+ metrics: ['resonance', 'intent', 'confidence', 'memory'],
786
+ diagnostics: ['causality', 'topology', 'field-lines'],
787
+ accessibility: {
788
+ reducedMotion: 'a related-item list with resonance badges and ranked suggestions',
789
+ meaningWithoutMotion: 'resonance becomes a ranked list of matches with explicit strength badges rather than a glow',
790
+ },
791
+ notes: 'Electric charge lets elements ring with shared terms while memory carries history and propagate spreads the match; resonance shows as coherence, not noise.',
792
+ },
793
+ {
794
+ id: 'friction-gate',
795
+ name: 'Friction Gate',
796
+ intent: 'slow risky, destructive, or irreversible actions without modal noise',
797
+ primitives: ['viscosity', 'pressure', 'gate', 'morph'],
798
+ bodies: [
799
+ { body: 'viscosity', strength: 1, range: 300, feedback: true },
800
+ { body: 'pressure', strength: 0.7, range: 280 },
801
+ { body: 'gate', strength: 0.6, range: 240 },
802
+ { body: 'morph', strength: 0.5, range: 220 },
803
+ ],
804
+ render: ['streamlines', 'heatmap', 'particles', 'trails'],
805
+ metrics: ['risk', 'friction', 'intent', 'readiness'],
806
+ diagnostics: ['inspector', 'prediction', 'energy'],
807
+ accessibility: {
808
+ reducedMotion: 'a confirmation rail moving from a disabled to a ready state with an explicit risk summary',
809
+ meaningWithoutMotion: 'friction becomes a readiness meter and the action stays disabled until an explicit risk summary is acknowledged',
810
+ },
811
+ notes: 'Derived from drag: viscosity makes risky motion deliberate, gate holds release until coherence builds, and morph marks the disabled-to-ready transition without a disruptive modal.',
812
+ },
813
+ {
814
+ id: 'boundary-field',
815
+ name: 'Boundary Field',
816
+ intent: 'make safe zones, drop zones, scopes, and containers perceptible',
817
+ naturalField: 'strong',
818
+ primitives: ['wall', 'sink', 'repel', 'cohesion'],
819
+ bodies: [
820
+ { body: 'wall', strength: 1.1, range: 320, feedback: true },
821
+ { body: 'sink', strength: 0.7, range: 280 },
822
+ { body: 'repel', strength: 0.8, range: 300 },
823
+ { body: 'cohesion', strength: 0.6, range: 260 },
824
+ ],
825
+ render: ['field-lines', 'metaballs', 'particles', 'dots'],
826
+ metrics: ['boundary', 'proximity', 'validity'],
827
+ diagnostics: ['contours', 'force-vectors', 'inspector'],
828
+ accessibility: {
829
+ reducedMotion: 'a boundary outline with valid and invalid zone labels and a static drop affordance',
830
+ meaningWithoutMotion: 'the container shows a drawn outline and each item is labeled valid or invalid for that zone',
831
+ },
832
+ notes: 'Strong containment gives containers an edge: wall reflects invalid objects, sink absorbs valid ones into the scope, and cohesion makes the boundary visible as you approach; electric repel screens what does not belong.',
833
+ },
834
+ {
835
+ id: 'threshold-bloom',
836
+ name: 'Threshold Bloom',
837
+ intent: 'reveal meaningful state changes only when a threshold is crossed',
838
+ naturalField: 'weak',
839
+ primitives: ['gate', 'morph', 'spawn', 'charge', 'memory'],
840
+ bodies: [
841
+ { body: 'gate', strength: 1, range: 280, feedback: true },
842
+ { body: 'morph', strength: 0.7, range: 260 },
843
+ { body: 'spawn', strength: 0.6, range: 300 },
844
+ { body: 'charge', strength: 0.5, range: 320, spin: 1 },
845
+ { body: 'memory', strength: 0.5, range: 240 },
846
+ ],
847
+ render: ['metaballs', 'heatmap', 'particles', 'trails'],
848
+ metrics: ['threshold', 'activation', 'heat', 'memory'],
849
+ diagnostics: ['causality', 'energy', 'inspector'],
850
+ accessibility: {
851
+ reducedMotion: 'a threshold marker with a status badge and an event log entry',
852
+ meaningWithoutMotion: 'crossing the threshold flips a status badge and writes a dated event log entry instead of a bloom',
853
+ },
854
+ notes: 'A weak event waits quietly until the gate opens, then morph and spawn bloom the transition while charge marks the moment; memory keeps the event inspectable after it settles.',
855
+ },
856
+ {
857
+ id: 'latency-ripple',
858
+ name: 'Latency Ripple',
859
+ intent: 'show delay, loading, sync, and distributed system response as waves',
860
+ naturalField: 'electromagnetic',
861
+ primitives: ['propagate', 'diffuse', 'fieldflow', 'memory'],
862
+ bodies: [
863
+ { body: 'propagate', strength: 1, range: 400, feedback: true },
864
+ { body: 'diffuse', strength: 0.7, range: 320 },
865
+ { body: 'fieldflow', strength: 0.6, range: 0 },
866
+ { body: 'memory', strength: 0.5, range: 280 },
867
+ ],
868
+ render: ['streamlines', 'field-lines', 'particles', 'trails'],
869
+ metrics: ['latency', 'signal', 'damping', 'sync'],
870
+ diagnostics: ['contours', 'force-vectors', 'prediction'],
871
+ accessibility: {
872
+ reducedMotion: 'a sync timeline with an affected-region list and latency badges',
873
+ meaningWithoutMotion: 'delay becomes a per-region latency badge and a timeline rather than a traveling wave',
874
+ },
875
+ notes: 'A signal propagates outward and fieldflow carries it to affected regions; diffuse damps slow or blocked areas so delay reads as distance, not a spinner.',
876
+ },
877
+ {
878
+ id: 'provenance-trail',
879
+ name: 'Provenance Trail',
880
+ intent: 'preserve the origin and transformation history of content or data',
881
+ naturalField: 'strong',
882
+ primitives: ['memory', 'link', 'morph', 'cohesion'],
883
+ bodies: [
884
+ { body: 'memory', strength: 1.1, range: 320, feedback: true },
885
+ { body: 'link', strength: 0.8, range: 360 },
886
+ { body: 'morph', strength: 0.5, range: 260 },
887
+ { body: 'cohesion', strength: 0.6, range: 280 },
888
+ ],
889
+ render: ['links', 'trails', 'particles', 'field-lines'],
890
+ metrics: ['provenance', 'memory', 'transform-count', 'source-strength'],
891
+ diagnostics: ['causality', 'topology', 'inspector'],
892
+ accessibility: {
893
+ reducedMotion: 'a provenance drawer with a lineage list and source badges',
894
+ meaningWithoutMotion: 'history becomes an ordered lineage list with source badges and a transform count per step',
895
+ },
896
+ notes: 'Strong binding keeps sources fused to content while memory holds the trace and morph records each transformation; lineage stays inspectable without flooding the view.',
897
+ },
898
+ {
899
+ id: 'review-pressure',
900
+ name: 'Review Pressure',
901
+ intent: 'surface items needing review before they decay, expire, or block work',
902
+ naturalField: 'gravity',
903
+ primitives: ['gravity', 'pressure', 'memory', 'morph', 'thermal'],
904
+ bodies: [
905
+ { body: 'gravity', strength: 1.1, range: 400, feedback: true },
906
+ { body: 'pressure', strength: 0.8, range: 320 },
907
+ { body: 'memory', strength: 0.6, range: 280 },
908
+ { body: 'morph', strength: 0.5, range: 240 },
909
+ { body: 'thermal', strength: 0.5, range: 260 },
910
+ ],
911
+ render: ['heatmap', 'metaballs', 'particles', 'dots'],
912
+ metrics: ['review-pressure', 'age', 'risk', 'priority'],
913
+ diagnostics: ['potential', 'heatmap', 'inspector'],
914
+ accessibility: {
915
+ reducedMotion: 'a review queue ranking with urgency badges and age markers',
916
+ meaningWithoutMotion: 'pressure becomes a sorted review queue where age and risk are explicit badges per item',
917
+ },
918
+ notes: 'Items build gravitational priority as the weak pull of age and pressure accumulates; thermal stands in for rising entropy so high-risk or blocked work surfaces on its own while low-risk stays calm.',
919
+ },
920
+ {
921
+ id: 'semantic-snap',
922
+ name: 'Semantic Snap',
923
+ intent: 'align objects, cards, or text fragments by meaning instead of only geometry',
924
+ naturalField: 'strong',
925
+ primitives: ['link', 'tether', 'cohesion', 'crystallize'],
926
+ bodies: [
927
+ { body: 'link', strength: 1, range: 360, feedback: true },
928
+ { body: 'tether', strength: 0.8, range: 300 },
929
+ { body: 'cohesion', strength: 0.6, range: 280 },
930
+ { body: 'crystallize', strength: 0.6, range: 260 },
931
+ ],
932
+ render: ['links', 'field-lines', 'particles', 'dots'],
933
+ metrics: ['snap', 'relation-strength', 'alignment'],
934
+ diagnostics: ['topology', 'force-vectors', 'inspector'],
935
+ accessibility: {
936
+ reducedMotion: 'snap guides with semantic alignment labels and relation hints',
937
+ meaningWithoutMotion: 'snapping becomes labeled alignment guides naming the relationship that pulled two items together',
938
+ },
939
+ notes: 'Strong relational binding lets objects snap by meaning: link and tether (spring) draw matching tags or dependent blocks together while crystallize locks them into a clean semantic alignment.',
940
+ },
941
+ {
942
+ id: 'ambient-tutor',
943
+ name: 'Ambient Tutor',
944
+ intent: 'teach the interface quietly based on hesitation, return, and attention',
945
+ naturalField: 'gravity',
946
+ primitives: ['memory', 'gravity', 'propagate', 'link'],
947
+ bodies: [
948
+ { body: 'memory', strength: 1, range: 300, feedback: true },
949
+ { body: 'gravity', strength: 0.7, range: 360 },
950
+ { body: 'propagate', strength: 0.5, range: 320 },
951
+ { body: 'link', strength: 0.6, range: 280 },
952
+ ],
953
+ render: ['heatmap', 'trails', 'particles', 'links'],
954
+ metrics: ['hesitation', 'return', 'helpfulness', 'attention'],
955
+ diagnostics: ['heatmap', 'causality', 'inspector'],
956
+ accessibility: {
957
+ reducedMotion: 'contextual tips with a help rail and related-explanation markers',
958
+ meaningWithoutMotion: 'help surfaces as a contextual tip near the point of need with a list of related explanations',
959
+ },
960
+ notes: 'Memory watches hesitation and repeated returns while gravity gives the right explanation subtle priority near the point of need; propagate and link carry help to related controls.',
961
+ },
962
+ {
963
+ id: 'relation-lens',
964
+ name: 'Relation Lens',
965
+ intent: 'temporarily reveal hidden connections without changing layout',
966
+ naturalField: 'strong',
967
+ primitives: ['link', 'memory', 'cohesion'],
968
+ bodies: [
969
+ { body: 'link', strength: 1.1, range: 380, feedback: true },
970
+ { body: 'memory', strength: 0.6, range: 280 },
971
+ { body: 'cohesion', strength: 0.6, range: 300 },
972
+ ],
973
+ render: ['links', 'field-lines', 'particles', 'dots'],
974
+ metrics: ['relation-strength', 'active-relation', 'density'],
975
+ diagnostics: ['topology', 'inspector', 'causality'],
976
+ accessibility: {
977
+ reducedMotion: 'a relation list with numbered connectors and a static map',
978
+ meaningWithoutMotion: 'connections become a numbered list pairing each element with what it relates to, layout unchanged',
979
+ },
980
+ notes: 'Strong relational binding lets the lens light up link bonds among visible elements; memory and cohesion hold the revealed map steady so definitions, citations, and dependencies show without moving anything.',
981
+ },
982
+ {
983
+ id: 'priority-tide',
984
+ name: 'Priority Tide',
985
+ intent: 'let importance rise and fall over time, workload, or context',
986
+ naturalField: 'gravity',
987
+ primitives: ['gravity', 'morph', 'memory', 'diffuse', 'pressure'],
988
+ bodies: [
989
+ { body: 'gravity', strength: 1, range: 400, feedback: true },
990
+ { body: 'morph', strength: 0.6, range: 280 },
991
+ { body: 'memory', strength: 0.6, range: 260 },
992
+ { body: 'diffuse', strength: 0.5, range: 300 },
993
+ { body: 'pressure', strength: 0.6, range: 320 },
994
+ ],
995
+ render: ['heatmap', 'metaballs', 'particles', 'trails'],
996
+ metrics: ['priority', 'age', 'deadline', 'decay'],
997
+ diagnostics: ['potential', 'prediction', 'heatmap'],
998
+ accessibility: {
999
+ reducedMotion: 'a priority ordering with aging badges and a deadline rail',
1000
+ meaningWithoutMotion: 'tidal importance becomes a re-sortable ranked list with explicit age and deadline values',
1001
+ },
1002
+ notes: 'Gravity sets importance while the weak pulls of age and deadline make it tidal: morph and diffuse let priority rise and ebb so nothing stays permanently loud, and memory keeps the decay honest.',
1003
+ },
1004
+ {
1005
+ id: 'field-contract-preview',
1006
+ name: 'Field Contract Preview',
1007
+ intent: 'show exactly what a recipe will register, measure, write, and render before enabling it',
1008
+ primitives: ['attract'],
1009
+ bodies: [{ body: 'attract', strength: 0.6, range: 280, feedback: true }],
1010
+ render: ['particles', 'dots'],
1011
+ metrics: ['scope', 'impact', 'risk'],
1012
+ diagnostics: ['inspector', 'topology', 'causality'],
1013
+ accessibility: {
1014
+ reducedMotion: 'a static contract table listing what the recipe registers, measures, writes, and renders',
1015
+ meaningWithoutMotion: 'the preview is a plain table of registrations, measurements, writes, and announcements with no motion at all',
1016
+ },
1017
+ notes: 'A platform diagnostic, not a force: it reads the registries and lintPlatform to make field behavior auditable before enabling, with one minimal sample body so the contract itself stays inspectable.',
1018
+ },
1019
+ ];
1020
+ /**
1021
+ * Tier 4 (operational) — multi-actor, collaborative, adaptive (recipes 49-64). Multi-actor and
1022
+ * live-system patterns.
1023
+ */
1024
+ const TIER_ENTERPRISE = [
1025
+ {
1026
+ id: 'presence-field',
1027
+ name: 'Presence Field',
1028
+ intent: 'show collaborators as live influence, not static avatars',
1029
+ naturalField: 'electromagnetic',
1030
+ primitives: ['charge', 'propagate', 'fieldflow', 'memory', 'link'],
1031
+ bodies: [
1032
+ { body: 'charge', strength: 0.9, range: 360, spin: 1, feedback: true },
1033
+ { body: 'propagate', strength: 0.6, range: 320 },
1034
+ { body: 'fieldflow', strength: 0.7, range: 0 },
1035
+ { body: 'memory', strength: 0.5, range: 260 },
1036
+ { body: 'link', strength: 0.6, range: 300 },
1037
+ ],
1038
+ relationships: [{ from: 'collaborator', to: 'object', type: 'present-at', strength: 0.7 }],
1039
+ render: ['field-lines', 'links', 'heatmap', 'particles'],
1040
+ metrics: ['presence', 'recency', 'signal', 'attention'],
1041
+ diagnostics: ['topology', 'causality', 'heatmap'],
1042
+ accessibility: {
1043
+ reducedMotion: 'a collaborator rail with recent-edit marks and static presence badges',
1044
+ meaningWithoutMotion: 'each collaborator is a labelled badge with a recency timestamp and the object they are near',
1045
+ },
1046
+ notes: 'Each focused collaborator is a charge emitting signal; propagate carries it, fieldflow draws presence toward shared objects, and recent edits cool into memory. Electric pushes, magnetic bends, fieldflow carries.',
1047
+ },
1048
+ {
1049
+ id: 'consensus-well',
1050
+ name: 'Consensus Well',
1051
+ intent: 'let agreement gather around stable options or decisions',
1052
+ naturalField: 'gravity',
1053
+ primitives: ['gravity', 'cohesion', 'link', 'pressure', 'memory'],
1054
+ bodies: [
1055
+ { body: 'gravity', strength: 1.1, range: 400, feedback: true },
1056
+ { body: 'cohesion', strength: 0.8, range: 320 },
1057
+ { body: 'link', strength: 0.6, range: 300 },
1058
+ { body: 'pressure', strength: 0.5, range: 240 },
1059
+ { body: 'memory', strength: 0.4, range: 260 },
1060
+ ],
1061
+ relationships: [{ from: 'argument', to: 'option', type: 'supports', strength: 0.7 }],
1062
+ render: ['metaballs', 'links', 'heatmap', 'particles'],
1063
+ metrics: ['consensus', 'coherence', 'support', 'tension'],
1064
+ diagnostics: ['potential', 'topology', 'causality'],
1065
+ accessibility: {
1066
+ reducedMotion: 'a support matrix with an agreement meter and dissent markers',
1067
+ meaningWithoutMotion: 'each option shows a numeric support count, a coherence label, and listed dissenting arguments',
1068
+ },
1069
+ notes: 'Options that gather agreement gain mass and pull arguments into a single well; cohesion binds the supporters while pressure exposes fragile, contested consensus instead of false certainty (gravity gathering mass, the strong bind holding it).',
1070
+ },
1071
+ {
1072
+ id: 'disagreement-charge',
1073
+ name: 'Disagreement Charge',
1074
+ intent: 'make unresolved conflict visible without turning it into noise',
1075
+ naturalField: 'electromagnetic',
1076
+ primitives: ['charge', 'repel', 'thermal', 'morph', 'memory'],
1077
+ bodies: [
1078
+ { body: 'charge', strength: 1, range: 340, spin: 1, feedback: true },
1079
+ { body: 'repel', strength: 0.7, range: 300 },
1080
+ { body: 'thermal', strength: 0.5, range: 280 },
1081
+ { body: 'morph', strength: 0.4, range: 220 },
1082
+ { body: 'memory', strength: 0.4, range: 260 },
1083
+ ],
1084
+ relationships: [{ from: 'claim', to: 'counter-claim', type: 'opposes', strength: 0.6 }],
1085
+ render: ['field-lines', 'heatmap', 'links', 'particles'],
1086
+ metrics: ['disagreement', 'entropy', 'resolution', 'memory'],
1087
+ diagnostics: ['causality', 'topology', 'field-lines'],
1088
+ accessibility: {
1089
+ reducedMotion: 'conflict pairs with a resolution-state column and a disagreement summary',
1090
+ meaningWithoutMotion: 'each conflict is a labelled pair of claims with a resolved/open state and an entropy score',
1091
+ },
1092
+ notes: 'Opposing claims carry like charge and repel into visible separation, thermal entropy marking heated conflict; once resolved, the claim morphs and decays into memory rather than alarming. Electric pushes, magnetic bends.',
1093
+ },
1094
+ {
1095
+ id: 'change-shockwave',
1096
+ name: 'Change Shockwave',
1097
+ intent: 'show the downstream impact of a change across a system',
1098
+ naturalField: 'electromagnetic',
1099
+ primitives: ['propagate', 'link', 'pressure', 'morph', 'memory'],
1100
+ bodies: [
1101
+ { body: 'propagate', strength: 1, range: 400, feedback: true },
1102
+ { body: 'link', strength: 0.7, range: 320 },
1103
+ { body: 'pressure', strength: 0.6, range: 280 },
1104
+ { body: 'morph', strength: 0.4, range: 220 },
1105
+ { body: 'memory', strength: 0.4, range: 260 },
1106
+ ],
1107
+ relationships: [{ from: 'change', to: 'dependency', type: 'affects', strength: 0.7 }],
1108
+ render: ['streamlines', 'field-lines', 'links', 'particles'],
1109
+ metrics: ['impact', 'latency', 'risk', 'distance'],
1110
+ diagnostics: ['contours', 'topology', 'causality', 'prediction'],
1111
+ accessibility: {
1112
+ reducedMotion: 'an impact tree with an affected-item list and downstream badges',
1113
+ meaningWithoutMotion: 'each affected item is listed by dependency distance with a risk badge, ordered by impact',
1114
+ },
1115
+ notes: 'A change emits a wave that propagates along links: immediate dependencies light first, distant ones respond damped and late, and critical downstream effects raise pressure (propagation carries the wavefront; the weak interaction lets items morph).',
1116
+ },
1117
+ {
1118
+ id: 'permission-boundary',
1119
+ name: 'Permission Boundary',
1120
+ intent: 'make access, scope, and protected regions legible',
1121
+ naturalField: 'strong',
1122
+ primitives: ['wall', 'sink', 'charge', 'link'],
1123
+ bodies: [
1124
+ { body: 'wall', strength: 1.1, range: 320, feedback: true },
1125
+ { body: 'sink', strength: 0.6, range: 240 },
1126
+ { body: 'charge', strength: 0.6, range: 300, spin: 1 },
1127
+ { body: 'link', strength: 0.5, range: 280 },
1128
+ ],
1129
+ relationships: [{ from: 'actor', to: 'region', type: 'authorized-for', strength: 0.7 }],
1130
+ render: ['voronoi', 'links', 'field-lines', 'particles'],
1131
+ metrics: ['permission', 'scope', 'risk', 'boundary'],
1132
+ diagnostics: ['contours', 'force-vectors', 'inspector'],
1133
+ accessibility: {
1134
+ reducedMotion: 'access labels with protected-region outlines and a permission summary',
1135
+ meaningWithoutMotion: 'each region is an outlined zone with an access label and a per-actor allow/deny list',
1136
+ },
1137
+ notes: 'Protected regions hold like walls: authorized actors pass cleanly while unauthorized or risky ones meet resistance and are absorbed (sink) at the boundary. The strong bind confines scope; charge gives each actor its polarity.',
1138
+ },
1139
+ {
1140
+ id: 'risk-horizon',
1141
+ name: 'Risk Horizon',
1142
+ intent: 'reveal approaching risk before it becomes an error',
1143
+ naturalField: 'gravity',
1144
+ primitives: ['gravity', 'pressure', 'morph', 'diffuse', 'memory'],
1145
+ bodies: [
1146
+ { body: 'gravity', strength: 1, range: 400, feedback: true },
1147
+ { body: 'pressure', strength: 0.7, range: 300 },
1148
+ { body: 'morph', strength: 0.5, range: 240 },
1149
+ { body: 'diffuse', strength: 0.4, range: 280 },
1150
+ { body: 'memory', strength: 0.4, range: 260 },
1151
+ ],
1152
+ render: ['heatmap', 'field-lines', 'metaballs', 'particles'],
1153
+ metrics: ['risk', 'pressure', 'threshold', 'entropy'],
1154
+ diagnostics: ['potential', 'contours', 'prediction'],
1155
+ accessibility: {
1156
+ reducedMotion: 'a risk-horizon line with threshold markers and an affected-region list',
1157
+ meaningWithoutMotion: 'risk is a labelled threshold line; affected regions are listed with their distance to it',
1158
+ },
1159
+ notes: 'Risk forms a horizon that pulls like gravity: as it rises, affected elements gain pressure, draw attention, and drift toward the threshold, diffusing the warning outward before any error lands (the weak interaction lets the state morph as it crosses).',
1160
+ },
1161
+ {
1162
+ id: 'intent-magnet',
1163
+ name: 'Intent Magnet',
1164
+ intent: "pull likely actions toward the user's current context",
1165
+ naturalField: 'gravity',
1166
+ primitives: ['gravity', 'memory', 'link', 'cohesion'],
1167
+ bodies: [
1168
+ { body: 'gravity', strength: 0.9, range: 380, feedback: true },
1169
+ { body: 'memory', strength: 0.6, range: 280 },
1170
+ { body: 'link', strength: 0.6, range: 300 },
1171
+ { body: 'cohesion', strength: 0.5, range: 260 },
1172
+ ],
1173
+ relationships: [{ from: 'focus', to: 'action', type: 'suggests', strength: 0.6 }],
1174
+ render: ['links', 'field-lines', 'dots', 'particles'],
1175
+ metrics: ['intent', 'confidence', 'memory', 'next-action'],
1176
+ diagnostics: ['potential', 'causality', 'inspector'],
1177
+ accessibility: {
1178
+ reducedMotion: 'a suggested-actions list with a next-step badge and contextual shortcuts',
1179
+ meaningWithoutMotion: 'likely actions are ranked in a list by confidence, each labelled with why it was suggested',
1180
+ },
1181
+ notes: 'Current focus, history, and task state become a gentle gravity center that draws likely next actions closer; memory weights what worked before while cohesion keeps related actions together, assisting without taking control.',
1182
+ },
1183
+ {
1184
+ id: 'flow-checkpoint',
1185
+ name: 'Flow Checkpoint',
1186
+ intent: 'stabilize multi-step flows around milestones',
1187
+ naturalField: 'strong',
1188
+ primitives: ['fieldflow', 'link', 'cohesion', 'memory', 'morph'],
1189
+ bodies: [
1190
+ { body: 'fieldflow', strength: 0.9, range: 0, feedback: true },
1191
+ { body: 'link', strength: 0.7, range: 320 },
1192
+ { body: 'cohesion', strength: 0.7, range: 300 },
1193
+ { body: 'memory', strength: 0.5, range: 260 },
1194
+ { body: 'morph', strength: 0.4, range: 220 },
1195
+ ],
1196
+ relationships: [{ from: 'step', to: 'checkpoint', type: 'anchors-to', strength: 0.7 }],
1197
+ render: ['streamlines', 'links', 'field-lines', 'particles'],
1198
+ metrics: ['progress', 'checkpoint', 'memory', 'coherence'],
1199
+ diagnostics: ['topology', 'force-vectors', 'prediction'],
1200
+ accessibility: {
1201
+ reducedMotion: 'a stepper with a checkpoint rail and completed-step markers',
1202
+ meaningWithoutMotion: 'the flow is an ordered stepper; completed milestones are marked and anchor the remaining steps',
1203
+ },
1204
+ notes: 'Multi-step flows form a current that fieldflow carries forward, but checkpoints bind like strong anchors: completed milestones hold structure with cohesion while progress keeps streaming ahead (the strong bind stabilizes, transport carries).',
1205
+ },
1206
+ {
1207
+ id: 'version-gravity',
1208
+ name: 'Version Gravity',
1209
+ intent: 'show which version, branch, or draft is becoming canonical',
1210
+ naturalField: 'gravity',
1211
+ primitives: ['gravity', 'memory', 'link', 'morph'],
1212
+ bodies: [
1213
+ { body: 'gravity', strength: 1.1, range: 400, feedback: true },
1214
+ { body: 'memory', strength: 0.6, range: 280 },
1215
+ { body: 'link', strength: 0.6, range: 300 },
1216
+ { body: 'morph', strength: 0.4, range: 220 },
1217
+ ],
1218
+ relationships: [{ from: 'fork', to: 'canonical', type: 'derives-from', strength: 0.6 }],
1219
+ render: ['metaballs', 'links', 'field-lines', 'particles'],
1220
+ metrics: ['version-weight', 'recency', 'approval', 'fork-distance'],
1221
+ diagnostics: ['topology', 'potential', 'causality'],
1222
+ accessibility: {
1223
+ reducedMotion: 'a version tree with a canonical badge and a fork list',
1224
+ meaningWithoutMotion: 'versions form a tree; the canonical one carries a badge and a weight, forks list their distance from it',
1225
+ },
1226
+ notes: 'Versions gain and lose mass by recency, approval, references, and edits, so the canonical draft becomes a gravity center pulling the rest while forks stay visible as related bodies that may morph toward it.',
1227
+ },
1228
+ {
1229
+ id: 'review-constellation',
1230
+ name: 'Review Constellation',
1231
+ intent: 'bind reviewers, comments, issues, and artifacts into one field',
1232
+ naturalField: 'strong',
1233
+ primitives: ['link', 'charge', 'cohesion', 'pressure', 'memory'],
1234
+ bodies: [
1235
+ { body: 'link', strength: 1, range: 340, feedback: true },
1236
+ { body: 'charge', strength: 0.7, range: 300, spin: 1 },
1237
+ { body: 'cohesion', strength: 0.7, range: 300 },
1238
+ { body: 'pressure', strength: 0.6, range: 260 },
1239
+ { body: 'memory', strength: 0.4, range: 260 },
1240
+ ],
1241
+ relationships: [{ from: 'reviewer', to: 'artifact', type: 'reviews', strength: 0.7 }],
1242
+ render: ['links', 'field-lines', 'heatmap', 'particles'],
1243
+ metrics: ['review', 'tension', 'resolution', 'attention'],
1244
+ diagnostics: ['topology', 'causality', 'heatmap'],
1245
+ accessibility: {
1246
+ reducedMotion: 'a reviewer matrix with issue clusters and an unresolved-count rail',
1247
+ meaningWithoutMotion: 'reviewers, comments, issues, and artifacts form a labelled matrix with an unresolved count per cluster',
1248
+ },
1249
+ notes: 'Reviewers, comments, issues, and artifacts bind into one constellation: open issues hold tension, resolved comments cool into memory, and a reviewer in focus emits current to the artifact (the strong bind holds it, charge marks active focus).',
1250
+ },
1251
+ {
1252
+ id: 'anomaly-bloom',
1253
+ name: 'Anomaly Bloom',
1254
+ intent: 'surface unusual behavior as local heat and instability',
1255
+ naturalField: 'weak',
1256
+ primitives: ['thermal', 'diffuse', 'pressure', 'morph', 'memory'],
1257
+ bodies: [
1258
+ { body: 'thermal', strength: 1, range: 320, feedback: true },
1259
+ { body: 'diffuse', strength: 0.7, range: 300 },
1260
+ { body: 'pressure', strength: 0.6, range: 260 },
1261
+ { body: 'morph', strength: 0.4, range: 220 },
1262
+ { body: 'memory', strength: 0.4, range: 260 },
1263
+ ],
1264
+ render: ['heatmap', 'metaballs', 'particles'],
1265
+ metrics: ['anomaly', 'heat', 'spread', 'confidence'],
1266
+ diagnostics: ['heatmap', 'contours', 'energy', 'causality'],
1267
+ accessibility: {
1268
+ reducedMotion: 'anomaly badges with an affected-region list and a severity gradient',
1269
+ meaningWithoutMotion: 'each anomaly is a labelled badge with a severity value and the region it affects, ranked by heat',
1270
+ },
1271
+ notes: 'Anomalies bloom locally as thermal heat that diffuses outward; they never auto-alarm, instead letting heat, pressure, and spread reveal whether the event is isolated, growing, or cooling into memory (the weak interaction is the local instability that lets behavior morph).',
1272
+ },
1273
+ {
1274
+ id: 'scope-lens',
1275
+ name: 'Scope Lens',
1276
+ intent: 'reveal what a component, recipe, or action can affect',
1277
+ primitives: ['link', 'wall', 'lens'],
1278
+ bodies: [
1279
+ { body: 'link', strength: 0.8, range: 340, feedback: true },
1280
+ { body: 'wall', strength: 0.6, range: 280 },
1281
+ { body: 'lens', strength: 0.5, range: 300 },
1282
+ ],
1283
+ relationships: [{ from: 'action', to: 'target', type: 'can-affect', strength: 0.6 }],
1284
+ render: ['links', 'field-lines', 'voronoi', 'particles'],
1285
+ metrics: ['scope', 'impact', 'risk', 'relation-strength'],
1286
+ diagnostics: ['topology', 'inspector', 'causality'],
1287
+ accessibility: {
1288
+ reducedMotion: 'an affected-item table with an impact list and a scope outline',
1289
+ meaningWithoutMotion: 'activating the lens lists every item an action can affect in a table, each with a relation strength',
1290
+ },
1291
+ notes: 'A diagnostic overlay, not a field of its own: links trace what an action can reach, walls mark where its scope stops, and the lens focuses the view on reach before mutation. It reads the relationship graph rather than translating a natural field.',
1292
+ },
1293
+ {
1294
+ id: 'calibration-field',
1295
+ name: 'Calibration Field',
1296
+ intent: 'help users tune settings toward a stable target',
1297
+ naturalField: 'gravity',
1298
+ primitives: ['gravity', 'cohesion', 'pressure', 'memory'],
1299
+ bodies: [
1300
+ { body: 'gravity', strength: 1, range: 400, feedback: true },
1301
+ { body: 'cohesion', strength: 0.7, range: 300 },
1302
+ { body: 'pressure', strength: 0.6, range: 260 },
1303
+ { body: 'memory', strength: 0.4, range: 260 },
1304
+ ],
1305
+ render: ['metaballs', 'field-lines', 'heatmap', 'particles'],
1306
+ metrics: ['calibration', 'distance', 'coherence', 'pressure'],
1307
+ diagnostics: ['potential', 'prediction', 'inspector'],
1308
+ accessibility: {
1309
+ reducedMotion: 'a target meter with a stability marker and a recommended range',
1310
+ meaningWithoutMotion: 'the target is a labelled meter; current config shows its distance and whether it sits in the recommended range',
1311
+ },
1312
+ notes: 'A target state sits as a stable gravity well: as the user tunes, the current config moves toward or away from coherence, and over-tuned or contradictory settings add pressure that pushes it back out.',
1313
+ },
1314
+ {
1315
+ id: 'semantic-drag',
1316
+ name: 'Semantic Drag',
1317
+ intent: 'add resistance when movement would break meaning',
1318
+ primitives: ['viscosity', 'link', 'tether', 'cohesion'],
1319
+ bodies: [
1320
+ { body: 'viscosity', strength: 0.9, range: 300, feedback: true },
1321
+ { body: 'link', strength: 0.7, range: 320 },
1322
+ { body: 'tether', strength: 0.6, range: 280 },
1323
+ { body: 'cohesion', strength: 0.5, range: 260 },
1324
+ ],
1325
+ relationships: [{ from: 'object', to: 'neighbor', type: 'meaningful-with', strength: 0.6 }],
1326
+ render: ['links', 'field-lines', 'trails', 'particles'],
1327
+ metrics: ['drag', 'validity', 'relation-strength', 'friction'],
1328
+ diagnostics: ['force-vectors', 'topology', 'prediction'],
1329
+ accessibility: {
1330
+ reducedMotion: 'valid/invalid guides with relation warnings and a drop-cost marker',
1331
+ meaningWithoutMotion: 'valid drop targets are listed; invalid moves show a warning and a labelled cost before commit',
1332
+ },
1333
+ notes: 'A derived friction recipe, not a natural field: dragging an object away from meaningful neighbors thickens viscosity while tether (spring) and links resist, and moving toward a valid relationship lets resistance fall away. The user can always override.',
1334
+ },
1335
+ {
1336
+ id: 'recovery-path',
1337
+ name: 'Recovery Path',
1338
+ intent: 'guide users back from error, drift, or interrupted state',
1339
+ naturalField: 'weak',
1340
+ primitives: ['memory', 'morph', 'link', 'fieldflow', 'gravity'],
1341
+ bodies: [
1342
+ { body: 'memory', strength: 1, range: 320, feedback: true },
1343
+ { body: 'morph', strength: 0.6, range: 240 },
1344
+ { body: 'link', strength: 0.6, range: 300 },
1345
+ { body: 'fieldflow', strength: 0.7, range: 0 },
1346
+ { body: 'gravity', strength: 0.6, range: 360 },
1347
+ ],
1348
+ relationships: [{ from: 'state', to: 'last-stable', type: 'restores-to', strength: 0.7 }],
1349
+ render: ['field-lines', 'streamlines', 'links', 'particles'],
1350
+ metrics: ['recovery', 'memory', 'last-stable', 'confidence'],
1351
+ diagnostics: ['heatmap', 'prediction', 'causality'],
1352
+ accessibility: {
1353
+ reducedMotion: 'a recovery checklist with a last-good-state marker and a restore path',
1354
+ meaningWithoutMotion: 'the last coherent state is marked and recovery is an ordered checklist back to it, not a generic error screen',
1355
+ },
1356
+ notes: 'When a process fails or interrupts, memory holds the last coherent path while gravity pulls the user back toward it and fieldflow carries them along the guided return, morphing the broken state back into a stable one.',
1357
+ },
1358
+ {
1359
+ id: 'system-pulse',
1360
+ name: 'System Pulse',
1361
+ intent: 'show the living rhythm of a product, workflow, or data system',
1362
+ naturalField: 'electromagnetic',
1363
+ primitives: ['propagate', 'thermal', 'memory', 'cohesion', 'spawn'],
1364
+ bodies: [
1365
+ { body: 'propagate', strength: 0.9, range: 400, feedback: true },
1366
+ { body: 'thermal', strength: 0.6, range: 300 },
1367
+ { body: 'memory', strength: 0.5, range: 260 },
1368
+ { body: 'cohesion', strength: 0.5, range: 280 },
1369
+ { body: 'spawn', strength: 0.5, range: 240 },
1370
+ ],
1371
+ render: ['field-lines', 'heatmap', 'streamlines', 'particles'],
1372
+ metrics: ['pulse', 'health', 'sync', 'heat'],
1373
+ diagnostics: ['energy', 'contours', 'inspector'],
1374
+ accessibility: {
1375
+ reducedMotion: 'a health rail with a pulse timestamp and a static system-status indicator',
1376
+ meaningWithoutMotion: 'system health is a labelled status indicator with a last-pulse timestamp and a sync state',
1377
+ },
1378
+ notes: 'The system emits a low-frequency pulse that propagates as an ambient heartbeat, thermal heat reflecting live activity while cohesion reads sync and memory holds the trend, the emitter (spawn) issuing each beat without distracting from content.',
1379
+ },
1380
+ ];
1381
+ // ── lane data layered onto the records by id ────────────────────────────────────────
1382
+ // The records above carry the strict runtime lanes (primitives / metrics / diagnostics). CONCEPTS and
1383
+ // CONDITIONS add the two remaining lanes — product language and activation logic — without polluting
1384
+ // the token data. A word here is deliberately NOT a runtime token (orbit, spring, trust, dwell, stale).
1385
+ /** CONCEPTS lane — human-facing product language per recipe (never runtime tokens). */
1386
+ const CONCEPTS = {
1387
+ 'focus-orbit': ['orbit'],
1388
+ 'search-relevance-field': ['relevance'],
1389
+ 'availability-pressure': ['spring'],
1390
+ 'dependency-tension': ['spring'],
1391
+ 'drift-correction': ['spring'],
1392
+ 'semantic-snap': ['spring'],
1393
+ 'semantic-drag': ['drag', 'spring'],
1394
+ 'friction-gate': ['drag', 'friction'],
1395
+ 'boundary-field': ['reflect', 'absorb'],
1396
+ 'permission-boundary': ['reflect', 'absorb'],
1397
+ 'threshold-bloom': ['threshold', 'bloom'],
1398
+ 'decay-notice': ['decay'],
1399
+ 'staleness-drift': ['staleness', 'decay'],
1400
+ 'memory-trace': ['decay'],
1401
+ 'handoff-stream': ['handoff'],
1402
+ 'trust-gradient': ['trust'],
1403
+ 'consensus-well': ['consensus'],
1404
+ 'disagreement-charge': ['disagreement'],
1405
+ 'system-pulse': ['pulse', 'heartbeat'],
1406
+ 'review-pressure': ['review pressure'],
1407
+ 'review-constellation': ['constellation'],
1408
+ 'conflict-field': ['conflict'],
1409
+ 'phase-shift': ['phase shift'],
1410
+ 'completion-release': ['completion', 'release'],
1411
+ 'risk-horizon': ['risk horizon'],
1412
+ 'change-shockwave': ['shockwave', 'blast radius'],
1413
+ 'anomaly-bloom': ['anomaly', 'bloom'],
1414
+ 'version-gravity': ['canonical version'],
1415
+ 'provenance-trail': ['provenance', 'lineage'],
1416
+ 'latency-ripple': ['ripple'],
1417
+ 'attention-weather': ['weather'],
1418
+ 'selection-wake': ['wake'],
1419
+ 'semantic-gravity-map': ['semantic mass'],
1420
+ 'presence-field': ['presence'],
1421
+ 'scope-lens': ['scope'],
1422
+ 'field-contract-preview': ['contract'],
1423
+ 'diagnostic-lens': ['inspectability'],
1424
+ 'priority-tide': ['tide'],
1425
+ };
1426
+ /** CONDITIONS lane — activation logic per recipe (never runtime tokens). */
1427
+ const CONDITIONS = {
1428
+ 'priority-well': ['in-view'],
1429
+ 'focus-orbit': ['focused', 'related'],
1430
+ 'search-relevance-field': ['related'],
1431
+ 'reading-field': ['in-view', 'dwell'],
1432
+ 'ambient-tutor': ['dwell', 'return'],
1433
+ 'context-halo': ['focused'],
1434
+ 'command-intent-field': ['focused'],
1435
+ 'intent-magnet': ['focused'],
1436
+ 'selection-wake': ['selected'],
1437
+ 'staleness-drift': ['stale'],
1438
+ 'drift-correction': ['stale'],
1439
+ 'decay-notice': ['stale'],
1440
+ 'recovery-path': ['stale'],
1441
+ 'review-pressure': ['stale'],
1442
+ 'friction-gate': ['threshold', 'dwell'],
1443
+ 'threshold-bloom': ['threshold'],
1444
+ 'anomaly-bloom': ['threshold'],
1445
+ 'risk-horizon': ['threshold'],
1446
+ 'calibration-field': ['threshold'],
1447
+ 'trust-gradient': ['trusted'],
1448
+ 'conflict-field': ['conflicted'],
1449
+ 'disagreement-charge': ['conflicted'],
1450
+ 'relationship-bond': ['related'],
1451
+ 'evidence-field': ['related'],
1452
+ 'citation-thread': ['related'],
1453
+ 'review-constellation': ['related'],
1454
+ 'semantic-snap': ['related'],
1455
+ 'semantic-drag': ['related'],
1456
+ };
1457
+ /** Layer tier + status + the concept/condition lanes onto a tier's raw records. */
1458
+ const decorate = (recipes, tier) => recipes.map((r) => ({
1459
+ ...r,
1460
+ tier,
1461
+ status: r.status ?? 'shipped',
1462
+ ...(CONCEPTS[r.id] ? { concepts: [...CONCEPTS[r.id]] } : {}),
1463
+ ...(CONDITIONS[r.id] ? { conditions: [...CONDITIONS[r.id]] } : {}),
1464
+ }));
1465
+ /** The four catalog tiers, in order — the navigable structure over {@link FIELD_RECIPES}. */
1466
+ export const RECIPE_TIERS = [
1467
+ { key: 'core', label: 'Core — interface & accessibility', recipes: decorate(TIER_CORE, 'core') },
1468
+ { key: 'applied', label: 'Applied — product, workflow & collaboration', recipes: decorate(TIER_PRODUCT, 'applied') },
1469
+ { key: 'systems', label: 'Systems — safety, provenance & governance', recipes: decorate(TIER_SYSTEMS, 'systems') },
1470
+ { key: 'operational', label: 'Operational — multi-actor, adaptive & live', recipes: decorate(TIER_ENTERPRISE, 'operational') },
1471
+ ];
1472
+ /** The full field-recipe catalog (authoring §7) — 64 recipes across four tiers, in catalog order. */
1473
+ export const FIELD_RECIPES = RECIPE_TIERS.flatMap((t) => t.recipes);
1474
+ /** @deprecated renamed to {@link FIELD_RECIPES}. */
1475
+ export const ESSENTIAL_RECIPES = FIELD_RECIPES;
1476
+ /**
1477
+ * The recommended first-release set: eight recipes that explain the system quickly and span the four
1478
+ * fields. The full sixteen give the project its range; these eight are the front door.
1479
+ */
1480
+ export const FIRST_RELEASE_RECIPE_IDS = [
1481
+ 'priority-well',
1482
+ 'signal-path',
1483
+ 'relationship-bond',
1484
+ 'reading-field',
1485
+ 'evidence-field',
1486
+ 'coherence-field',
1487
+ 'memory-trace',
1488
+ 'guided-flow',
1489
+ ];
1490
+ /** The first-release recipes, resolved from {@link FIRST_RELEASE_RECIPE_IDS} in declared order. */
1491
+ export const FIRST_RELEASE_RECIPES = FIRST_RELEASE_RECIPE_IDS.map((id) => FIELD_RECIPES.find((r) => r.id === id));
1492
+ /** Look up a recipe by id — the canonical 64 first, then the experimental set (undefined if unknown). */
1493
+ export function recipeById(id) {
1494
+ return FIELD_RECIPES.find((r) => r.id === id) ?? EXPERIMENTAL_RECIPES.find((r) => r.id === id);
1495
+ }
1496
+ //# sourceMappingURL=catalog.js.map