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