@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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** The registration event names. `composed: true` lets them cross the shadow boundary. */
|
|
2
|
+
export const REGISTER_BODY = 'field:register-body';
|
|
3
|
+
export const UNREGISTER_BODY = 'field:unregister-body';
|
|
4
|
+
export const UPDATE_BODY = 'field:update-body';
|
|
5
|
+
/**
|
|
6
|
+
* Component-side helper (shadow-dom.md §31.1) so a custom element joins the field without
|
|
7
|
+
* repeating event boilerplate. Construct with the host (and optional extra detail), then
|
|
8
|
+
* call `connect()` / `disconnect()` / `update()` from the element's lifecycle callbacks.
|
|
9
|
+
*/
|
|
10
|
+
export class FieldController {
|
|
11
|
+
host;
|
|
12
|
+
detail;
|
|
13
|
+
constructor(host, detail = {}) {
|
|
14
|
+
this.host = host;
|
|
15
|
+
this.detail = detail;
|
|
16
|
+
}
|
|
17
|
+
/** register the host as a body — call from `connectedCallback`. */
|
|
18
|
+
connect() {
|
|
19
|
+
this.emit(REGISTER_BODY);
|
|
20
|
+
}
|
|
21
|
+
/** remove the body — call from `disconnectedCallback`. */
|
|
22
|
+
disconnect() {
|
|
23
|
+
this.emit(UNREGISTER_BODY);
|
|
24
|
+
}
|
|
25
|
+
/** refresh attrs/geometry — call from `attributeChangedCallback`. */
|
|
26
|
+
update() {
|
|
27
|
+
this.emit(UPDATE_BODY);
|
|
28
|
+
}
|
|
29
|
+
emit(type) {
|
|
30
|
+
const detail = { element: this.host, ...this.detail };
|
|
31
|
+
this.host.dispatchEvent(new CustomEvent(type, { bubbles: true, composed: true, detail }));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Engine-side registry of event-registered hosts. Pure of the DOM event system: the field
|
|
36
|
+
* feeds it details and asks for bodies each scan. It prunes hosts that have left the document
|
|
37
|
+
* (do not rely on `disconnectedCallback` alone, §15) and never touches a shadow root.
|
|
38
|
+
*/
|
|
39
|
+
export class ShadowRegistry {
|
|
40
|
+
hosts = new Map();
|
|
41
|
+
/** Register (or, idempotently, refresh) a host. */
|
|
42
|
+
register(detail) {
|
|
43
|
+
this.hosts.set(detail.element, detail);
|
|
44
|
+
}
|
|
45
|
+
/** Drop a host. */
|
|
46
|
+
unregister(element) {
|
|
47
|
+
this.hosts.delete(element);
|
|
48
|
+
}
|
|
49
|
+
/** how many hosts are currently registered (post-prune count is via `bodies`). */
|
|
50
|
+
get size() {
|
|
51
|
+
return this.hosts.size;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build a `Body` per live registered host, pruning any that have disconnected. `build` is
|
|
55
|
+
* the scanner's `bodyFromElement`; `attrs` (if supplied at registration) override the
|
|
56
|
+
* host's own `data-*`, else the host is read directly. A custom `getRect` and `writeTarget`
|
|
57
|
+
* are attached to the resulting body.
|
|
58
|
+
*/
|
|
59
|
+
bodies(build) {
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const [el, detail] of this.hosts) {
|
|
62
|
+
if (!el.isConnected) {
|
|
63
|
+
this.hosts.delete(el);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const attrs = detail.attrs ? attrsView(detail.attrs, el) : undefined;
|
|
67
|
+
const body = build(el, attrs);
|
|
68
|
+
if (detail.getRect)
|
|
69
|
+
body.rect = detail.getRect;
|
|
70
|
+
if (detail.writeTarget)
|
|
71
|
+
body.writeTarget = detail.writeTarget;
|
|
72
|
+
out.push(body);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** A `BodyAttrs` view that prefers the explicit `attrs` record, falling back to the host. */
|
|
78
|
+
function attrsView(attrs, el) {
|
|
79
|
+
return {
|
|
80
|
+
get: (name) => attrs[name] ?? el.getAttribute('data-' + name),
|
|
81
|
+
has: (name) => name in attrs || el.hasAttribute('data-' + name),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=shadow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow.js","sourceRoot":"","sources":["../../src/core/shadow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A uniform-grid spatial hash for neighbour queries — the index that makes
|
|
3
|
+
* particle↔particle forces (§20.1 class [B]) O(n·k) instead of O(n²).
|
|
4
|
+
*
|
|
5
|
+
* Rebuilt each frame from the live particle pool; query with `near(x, y, r)`.
|
|
6
|
+
* Dependency-free.
|
|
7
|
+
*/
|
|
8
|
+
export interface Point {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
/** optional z lane (z-axis.md) — undefined reads as 0 (the flat plane). */
|
|
12
|
+
z?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class SpatialHash<T extends Point> {
|
|
15
|
+
private readonly cell;
|
|
16
|
+
private readonly bins;
|
|
17
|
+
constructor(cellSize?: number);
|
|
18
|
+
private key;
|
|
19
|
+
clear(): void;
|
|
20
|
+
insert(item: T): void;
|
|
21
|
+
rebuild(items: readonly T[]): void;
|
|
22
|
+
/**
|
|
23
|
+
* Items within radius `r` of (x, y, z), filtered by TRUE (3D) distance. Bins stay
|
|
24
|
+
* planar — items at any z share their (x, y) cell — which over-collects candidates
|
|
25
|
+
* in a deep volume but never returns a wrong result; the z² term below is the
|
|
26
|
+
* contract. `z` defaults to 0, so flat-field callers are byte-identical.
|
|
27
|
+
*/
|
|
28
|
+
near(x: number, y: number, r: number, z?: number): T[];
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=spatial-hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spatial-hash.d.ts","sourceRoot":"","sources":["../../src/core/spatial-hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,2EAA2E;IAC3E,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,qBAAa,WAAW,CAAC,CAAC,SAAS,KAAK;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;gBAEnC,QAAQ,SAAK;IAIzB,OAAO,CAAC,GAAG;IAKX,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAUrB,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI;IAKlC;;;;;OAKG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,CAAC,EAAE;CAqBlD"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A uniform-grid spatial hash for neighbour queries — the index that makes
|
|
3
|
+
* particle↔particle forces (§20.1 class [B]) O(n·k) instead of O(n²).
|
|
4
|
+
*
|
|
5
|
+
* Rebuilt each frame from the live particle pool; query with `near(x, y, r)`.
|
|
6
|
+
* Dependency-free.
|
|
7
|
+
*/
|
|
8
|
+
export class SpatialHash {
|
|
9
|
+
cell;
|
|
10
|
+
bins = new Map();
|
|
11
|
+
constructor(cellSize = 64) {
|
|
12
|
+
this.cell = cellSize > 0 ? cellSize : 64;
|
|
13
|
+
}
|
|
14
|
+
key(cx, cy) {
|
|
15
|
+
// pack two signed cell coords into one number (offset to keep non-negative).
|
|
16
|
+
return (cx + 0x8000) * 0x10000 + (cy + 0x8000);
|
|
17
|
+
}
|
|
18
|
+
clear() {
|
|
19
|
+
this.bins.clear();
|
|
20
|
+
}
|
|
21
|
+
insert(item) {
|
|
22
|
+
const k = this.key(Math.floor(item.x / this.cell), Math.floor(item.y / this.cell));
|
|
23
|
+
const bin = this.bins.get(k);
|
|
24
|
+
if (bin)
|
|
25
|
+
bin.push(item);
|
|
26
|
+
else
|
|
27
|
+
this.bins.set(k, [item]);
|
|
28
|
+
}
|
|
29
|
+
rebuild(items) {
|
|
30
|
+
this.clear();
|
|
31
|
+
for (const it of items)
|
|
32
|
+
this.insert(it);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Items within radius `r` of (x, y, z), filtered by TRUE (3D) distance. Bins stay
|
|
36
|
+
* planar — items at any z share their (x, y) cell — which over-collects candidates
|
|
37
|
+
* in a deep volume but never returns a wrong result; the z² term below is the
|
|
38
|
+
* contract. `z` defaults to 0, so flat-field callers are byte-identical.
|
|
39
|
+
*/
|
|
40
|
+
near(x, y, r, z = 0) {
|
|
41
|
+
const out = [];
|
|
42
|
+
const r2 = r * r;
|
|
43
|
+
const minCx = Math.floor((x - r) / this.cell);
|
|
44
|
+
const maxCx = Math.floor((x + r) / this.cell);
|
|
45
|
+
const minCy = Math.floor((y - r) / this.cell);
|
|
46
|
+
const maxCy = Math.floor((y + r) / this.cell);
|
|
47
|
+
for (let cx = minCx; cx <= maxCx; cx++) {
|
|
48
|
+
for (let cy = minCy; cy <= maxCy; cy++) {
|
|
49
|
+
const bin = this.bins.get(this.key(cx, cy));
|
|
50
|
+
if (!bin)
|
|
51
|
+
continue;
|
|
52
|
+
for (const it of bin) {
|
|
53
|
+
const dx = it.x - x;
|
|
54
|
+
const dy = it.y - y;
|
|
55
|
+
const dz = (it.z ?? 0) - z;
|
|
56
|
+
if (dx * dx + dy * dy + dz * dz <= r2)
|
|
57
|
+
out.push(it);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=spatial-hash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spatial-hash.js","sourceRoot":"","sources":["../../src/core/spatial-hash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streamlines / vector-field render (§20.6, diagnostic) — instead of the matter, draw
|
|
3
|
+
* the *forces themselves*. At a grid of probe points we measure the net push a
|
|
4
|
+
* still test particle would feel and draw a short arrow along it, so the invisible
|
|
5
|
+
* field a layout creates becomes visible. Invaluable in the Lab: place forces, then
|
|
6
|
+
* see the field they make.
|
|
7
|
+
*
|
|
8
|
+
* `forceAt` is pure and mirrors the integrator's body-force loop (same range cull),
|
|
9
|
+
* minus the per-particle modifier pass — a faithful-enough probe for a diagnostic.
|
|
10
|
+
*/
|
|
11
|
+
import type { Body, Env, ForceRegistry } from './types.ts';
|
|
12
|
+
/** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
|
|
13
|
+
* A force that defines a `field()` (its visual/structure field) contributes that instead
|
|
14
|
+
* of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
|
|
15
|
+
* even though they no-op on a still, neutral probe. */
|
|
16
|
+
export declare function forceAt(bodies: readonly Body[], forces: ForceRegistry, env: Env, x: number, y: number): {
|
|
17
|
+
fx: number;
|
|
18
|
+
fy: number;
|
|
19
|
+
};
|
|
20
|
+
/** The net *structure* field at (x, y): the superposition of every visible body's `field()`
|
|
21
|
+
* contribution (the dipoles and monopoles only — no apply-probe), with the same range cull
|
|
22
|
+
* as the integrator. This is the field the streamlines view draws and the vector matter
|
|
23
|
+
* follows under `fieldflow`. Pure: same inputs, same output, no `env` mutation (the `field()`
|
|
24
|
+
* hooks read only `b` and the point, so it is safe to call mid-integration). */
|
|
25
|
+
export declare function netField(bodies: readonly Body[], forces: ForceRegistry, x: number, y: number): {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=streamlines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamlines.d.ts","sourceRoot":"","sources":["../../src/core/streamlines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AAIrE;;;wDAGwD;AACxD,wBAAgB,OAAO,CACrB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,GAAG,EACR,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CA+B5B;AAED;;;;iFAIiF;AACjF,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,IAAI,EAAE,EACvB,MAAM,EAAE,aAAa,EACrB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAoB1B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const probe = { x: 0, y: 0, vx: 0, vy: 0, m: 1, heat: 0, size: 1, cap: null };
|
|
2
|
+
/** Net force a zero-velocity test particle would feel at (x, y) — the field vector.
|
|
3
|
+
* A force that defines a `field()` (its visual/structure field) contributes that instead
|
|
4
|
+
* of its `apply`, so velocity- and charge-dependent forces (magnetism, charge) appear here
|
|
5
|
+
* even though they no-op on a still, neutral probe. */
|
|
6
|
+
export function forceAt(bodies, forces, env, x, y) {
|
|
7
|
+
probe.x = x;
|
|
8
|
+
probe.y = y;
|
|
9
|
+
probe.vx = 0;
|
|
10
|
+
probe.vy = 0;
|
|
11
|
+
probe.heat = 0;
|
|
12
|
+
let fxField = 0; // field() contributions, accumulated apart from the apply probe
|
|
13
|
+
let fyField = 0;
|
|
14
|
+
for (const b of bodies) {
|
|
15
|
+
if (!b.vis || b.tokens.length === 0)
|
|
16
|
+
continue;
|
|
17
|
+
const dx = b.cx - x;
|
|
18
|
+
const dy = b.cy - y;
|
|
19
|
+
const d2 = dx * dx + dy * dy;
|
|
20
|
+
if (b.range > 0 && d2 >= b.range * b.range * 2.56)
|
|
21
|
+
continue; // same cull as the integrator
|
|
22
|
+
const d = Math.sqrt(d2);
|
|
23
|
+
env.dx = dx;
|
|
24
|
+
env.dy = dy;
|
|
25
|
+
env.dist = d < 1 ? 1 : d;
|
|
26
|
+
for (const tok of b.tokens) {
|
|
27
|
+
const f = forces[tok];
|
|
28
|
+
if (!f || f.modify)
|
|
29
|
+
continue;
|
|
30
|
+
if (f.field) {
|
|
31
|
+
const v = f.field(b, x, y);
|
|
32
|
+
fxField += v.x;
|
|
33
|
+
fyField += v.y;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
f.apply(b, probe, env);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { fx: probe.vx + fxField, fy: probe.vy + fyField };
|
|
41
|
+
}
|
|
42
|
+
/** The net *structure* field at (x, y): the superposition of every visible body's `field()`
|
|
43
|
+
* contribution (the dipoles and monopoles only — no apply-probe), with the same range cull
|
|
44
|
+
* as the integrator. This is the field the streamlines view draws and the vector matter
|
|
45
|
+
* follows under `fieldflow`. Pure: same inputs, same output, no `env` mutation (the `field()`
|
|
46
|
+
* hooks read only `b` and the point, so it is safe to call mid-integration). */
|
|
47
|
+
export function netField(bodies, forces, x, y) {
|
|
48
|
+
let fx = 0;
|
|
49
|
+
let fy = 0;
|
|
50
|
+
for (const b of bodies) {
|
|
51
|
+
if (!b.vis || b.tokens.length === 0)
|
|
52
|
+
continue;
|
|
53
|
+
if (b.range > 0) {
|
|
54
|
+
const dx = b.cx - x;
|
|
55
|
+
const dy = b.cy - y;
|
|
56
|
+
if (dx * dx + dy * dy >= b.range * b.range * 2.56)
|
|
57
|
+
continue; // same cull as the integrator
|
|
58
|
+
}
|
|
59
|
+
for (const tok of b.tokens) {
|
|
60
|
+
const f = forces[tok];
|
|
61
|
+
if (f?.field) {
|
|
62
|
+
const v = f.field(b, x, y);
|
|
63
|
+
fx += v.x;
|
|
64
|
+
fy += v.y;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { x: fx, y: fy };
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=streamlines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamlines.js","sourceRoot":"","sources":["../../src/core/streamlines.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decorative full-viewport canvas surface (§13, §18) — one source of truth for the
|
|
3
|
+
* fixed, click-through, behind-everything styling every managed mount uses. The vanilla
|
|
4
|
+
* `mountField` / `FieldField` and the React `<FieldField>` render this exact surface; the
|
|
5
|
+
* web component styles its shadow host to match.
|
|
6
|
+
*/
|
|
7
|
+
/** The surface as a style object (React `CSSProperties`-compatible). */
|
|
8
|
+
export declare const FIELD_CANVAS_STYLE: {
|
|
9
|
+
readonly position: "fixed";
|
|
10
|
+
readonly inset: "0";
|
|
11
|
+
readonly width: "100%";
|
|
12
|
+
readonly height: "100%";
|
|
13
|
+
readonly zIndex: "0";
|
|
14
|
+
readonly pointerEvents: "none";
|
|
15
|
+
readonly display: "block";
|
|
16
|
+
};
|
|
17
|
+
/** The same surface as a `cssText` string (camelCase keys → kebab-case), for `style.cssText`. */
|
|
18
|
+
export declare const FIELD_CANVAS_CSS: string;
|
|
19
|
+
//# sourceMappingURL=surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/core/surface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,eAAO,MAAM,kBAAkB;;;;;;;;CAQrB,CAAC;AAEX,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,QAEjB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decorative full-viewport canvas surface (§13, §18) — one source of truth for the
|
|
3
|
+
* fixed, click-through, behind-everything styling every managed mount uses. The vanilla
|
|
4
|
+
* `mountField` / `FieldField` and the React `<FieldField>` render this exact surface; the
|
|
5
|
+
* web component styles its shadow host to match.
|
|
6
|
+
*/
|
|
7
|
+
/** The surface as a style object (React `CSSProperties`-compatible). */
|
|
8
|
+
export const FIELD_CANVAS_STYLE = {
|
|
9
|
+
position: 'fixed',
|
|
10
|
+
inset: '0',
|
|
11
|
+
width: '100%',
|
|
12
|
+
height: '100%',
|
|
13
|
+
zIndex: '0',
|
|
14
|
+
pointerEvents: 'none',
|
|
15
|
+
display: 'block',
|
|
16
|
+
};
|
|
17
|
+
/** The same surface as a `cssText` string (camelCase keys → kebab-case), for `style.cssText`. */
|
|
18
|
+
export const FIELD_CANVAS_CSS = Object.entries(FIELD_CANVAS_STYLE)
|
|
19
|
+
.map(([k, v]) => `${k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())}:${v}`)
|
|
20
|
+
.join(';');
|
|
21
|
+
//# sourceMappingURL=surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../../src/core/surface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wEAAwE;AACxE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,QAAQ,EAAE,OAAO;IACjB,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,GAAG;IACX,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,OAAO;CACR,CAAC;AAEX,iGAAiG;AACjG,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;KAC/D,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;KAC5E,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal kernels — WORLD TIME made computable.
|
|
3
|
+
*
|
|
4
|
+
* field-ui keeps three clocks:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Simulation time** — `env.t` / `dt`, particle age: the integrator's clock.
|
|
7
|
+
* 2. **Experiential time** — the platform metric pipeline's attention / memory / recency:
|
|
8
|
+
* eased integrals of interaction (`@fundamental-engine/platform` `metrics.ts`).
|
|
9
|
+
* 3. **World time** — timestamps carried by the data itself: a launch's T−0, an issue's
|
|
10
|
+
* `updatedAt`, a question's `askedAt`, a fact's last review.
|
|
11
|
+
*
|
|
12
|
+
* These kernels are clock 3. Each is a pure, deterministic map from world timestamps to a
|
|
13
|
+
* `0..1` weight — zero DOM, zero state, and **no `Date.now()`**: the caller supplies `nowMs`
|
|
14
|
+
* (the platform samples it once per frame; pages sample it once per tick). All arguments are
|
|
15
|
+
* epoch/duration **milliseconds**; the day and hour constants the shapes were calibrated in
|
|
16
|
+
* are exported explicitly. Degenerate inputs (NaN, ±Infinity, non-positive timescales) never
|
|
17
|
+
* produce NaN — each kernel documents its safe value.
|
|
18
|
+
*
|
|
19
|
+
* The shapes are lifted, exactly, from the shipped example family (the extraction ratchet:
|
|
20
|
+
* four hand-rolls → one primitive): `imminence` from the calendar page's 1 Hz clock,
|
|
21
|
+
* `retention` from the memory page's forgetting curve, `freshness` as the canonical form of
|
|
22
|
+
* the backlog/inbox recency lanes. `data-field-at` (see `@fundamental-engine/platform`) feeds
|
|
23
|
+
* `freshness` to ground the metric pipeline's recency lane in declared world time.
|
|
24
|
+
*/
|
|
25
|
+
/** One hour in milliseconds — `imminence`'s log-softening unit (the calendar shape is hour-calibrated). */
|
|
26
|
+
export declare const HOUR_MS = 3600000;
|
|
27
|
+
/** One day in milliseconds — `retention`'s τ defaults are day-calibrated (4 + a·56 days). */
|
|
28
|
+
export declare const DAY_MS = 86400000;
|
|
29
|
+
/**
|
|
30
|
+
* How imminent a moment feels: `1` at (or past) the moment, log-ramping down to `0` at the
|
|
31
|
+
* far edge of the horizon.
|
|
32
|
+
*
|
|
33
|
+
* The exact form, with `until = atMs − nowMs`:
|
|
34
|
+
*
|
|
35
|
+
* imminence = clamp01( 1 − ln(until/HOUR_MS + 1) / ln(horizonMs/HOUR_MS + 1) )
|
|
36
|
+
*
|
|
37
|
+
* i.e. the calendar example's weight, `1 − ln(hoursUntil + 1) / ln(horizonHours + 1)`, with
|
|
38
|
+
* hours generalized to milliseconds. The one-hour softening unit (`+1` in hour units) is part
|
|
39
|
+
* of the shape: it keeps the ramp finite at `until = 0` and makes the last hours before the
|
|
40
|
+
* moment the steepest part of the curve. Returns `1` for any `until ≤ 0` (the moment has
|
|
41
|
+
* arrived — what a page does with a *passed* moment, e.g. the calendar's `0.08` floor for
|
|
42
|
+
* passed/TBD launches, is page semantics layered on top). Monotonically non-increasing in
|
|
43
|
+
* `until`; `0` at and beyond the horizon.
|
|
44
|
+
*
|
|
45
|
+
* Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
|
|
46
|
+
* `horizonMs` returns `1` at/past the moment and `0` otherwise (no horizon, no ramp).
|
|
47
|
+
*/
|
|
48
|
+
export declare function imminence(atMs: number, nowMs: number, horizonMs: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Exponential newness decay — the backlog/inbox recency shape in its canonical form:
|
|
51
|
+
*
|
|
52
|
+
* freshness = 2^(−since / halfLifeMs) with since = nowMs − atMs
|
|
53
|
+
*
|
|
54
|
+
* `1` at the moment itself, **exactly `0.5` one half-life later**, `0.25` after two, → `0`
|
|
55
|
+
* asymptotically. Future timestamps (`since < 0`) clamp to `1` — nothing is fresher than now.
|
|
56
|
+
* Monotonically non-increasing in `since`.
|
|
57
|
+
*
|
|
58
|
+
* Naming: this lane reads positively — the complement is *staleness*, and it is deliberately
|
|
59
|
+
* not exported: `staleness = 1 − freshness`. One word per lane.
|
|
60
|
+
*
|
|
61
|
+
* Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
|
|
62
|
+
* `halfLifeMs` returns `1` at/before the moment and `0` after it (instant decay).
|
|
63
|
+
*/
|
|
64
|
+
export declare function freshness(atMs: number, nowMs: number, halfLifeMs: number): number;
|
|
65
|
+
/** Options for {@link retention} — the τ calibration, in milliseconds. */
|
|
66
|
+
export interface RetentionOptions {
|
|
67
|
+
/** τ's base — the decay timescale of a zero-strength anchor. Default `4 * DAY_MS`. */
|
|
68
|
+
tauBaseMs?: number;
|
|
69
|
+
/** τ's growth with anchor strength — `τ(a) = tauBaseMs + a · tauGrowthMs`. Default `56 * DAY_MS`. */
|
|
70
|
+
tauGrowthMs?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Ebbinghaus-shaped retention: how much of an anchored fact is still held after `sinceMs`.
|
|
74
|
+
*
|
|
75
|
+
* The exact form, lifted from the memory example's forgetting curve:
|
|
76
|
+
*
|
|
77
|
+
* retention = a · e^(−since / τ(a)) with τ(a) = tauBaseMs + a · tauGrowthMs
|
|
78
|
+
*
|
|
79
|
+
* which is the memory page's `w = a · exp(−days / τ)` with `τ = 4 + a·56` **in day units**,
|
|
80
|
+
* generalized to milliseconds with the day constant explicit (defaults `4 * DAY_MS` and
|
|
81
|
+
* `56 * DAY_MS`). The stability term is the point: τ *grows* with anchor strength, so deeply
|
|
82
|
+
* anchored facts decay slower — exponential decay alone forgets everything at one rate.
|
|
83
|
+
* `anchor` is clamped to `0..1`; `retention(a, 0)` is exactly `a`; monotonically
|
|
84
|
+
* non-increasing in `sinceMs` (negative `sinceMs` clamps to `0` — a future review holds full
|
|
85
|
+
* strength, it doesn't overshoot).
|
|
86
|
+
*
|
|
87
|
+
* The shape is Ebbinghaus's; the default constants are the memory page's, tuned for
|
|
88
|
+
* legibility, not fitted to recall data. Degenerate inputs: non-finite `anchor` reads as `0`;
|
|
89
|
+
* non-finite `sinceMs` or a non-positive τ returns `0` (nothing held).
|
|
90
|
+
*/
|
|
91
|
+
export declare function retention(anchor: number, sinceMs: number, opts?: RetentionOptions): number;
|
|
92
|
+
/**
|
|
93
|
+
* Cyclical phase: where `nowMs` sits inside a repeating period, as `0..1` (the result is in
|
|
94
|
+
* `[0, 1)` — the wrap point reads as `0`, never `1`).
|
|
95
|
+
*
|
|
96
|
+
* phase = ((nowMs − offsetMs) mod periodMs) / periodMs
|
|
97
|
+
*
|
|
98
|
+
* with a true (sign-safe) modulo, so times before the offset wrap correctly. `offsetMs`
|
|
99
|
+
* anchors the cycle's zero — e.g. a local midnight for a day rhythm, a Monday 00:00 for a
|
|
100
|
+
* week rhythm.
|
|
101
|
+
*
|
|
102
|
+
* Honesty note: this kernel ships for completeness of the world-time family (day/week
|
|
103
|
+
* rhythms are the obvious fourth shape next to imminence, freshness, and retention), but
|
|
104
|
+
* **no shipped page or pipeline consumes it yet** — it has no worked example.
|
|
105
|
+
*
|
|
106
|
+
* Degenerate inputs: a non-finite `nowMs`/`offsetMs` or a non-positive/non-finite `periodMs`
|
|
107
|
+
* returns `0`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function phase(nowMs: number, periodMs: number, offsetMs?: number): number;
|
|
110
|
+
//# sourceMappingURL=temporal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/core/temporal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,2GAA2G;AAC3G,eAAO,MAAM,OAAO,UAAY,CAAC;AAEjC,6FAA6F;AAC7F,eAAO,MAAM,MAAM,WAAa,CAAC;AAIjC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAMhF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMjF;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,MAAM,CAO9F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAM3E"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal kernels — WORLD TIME made computable.
|
|
3
|
+
*
|
|
4
|
+
* field-ui keeps three clocks:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Simulation time** — `env.t` / `dt`, particle age: the integrator's clock.
|
|
7
|
+
* 2. **Experiential time** — the platform metric pipeline's attention / memory / recency:
|
|
8
|
+
* eased integrals of interaction (`@fundamental-engine/platform` `metrics.ts`).
|
|
9
|
+
* 3. **World time** — timestamps carried by the data itself: a launch's T−0, an issue's
|
|
10
|
+
* `updatedAt`, a question's `askedAt`, a fact's last review.
|
|
11
|
+
*
|
|
12
|
+
* These kernels are clock 3. Each is a pure, deterministic map from world timestamps to a
|
|
13
|
+
* `0..1` weight — zero DOM, zero state, and **no `Date.now()`**: the caller supplies `nowMs`
|
|
14
|
+
* (the platform samples it once per frame; pages sample it once per tick). All arguments are
|
|
15
|
+
* epoch/duration **milliseconds**; the day and hour constants the shapes were calibrated in
|
|
16
|
+
* are exported explicitly. Degenerate inputs (NaN, ±Infinity, non-positive timescales) never
|
|
17
|
+
* produce NaN — each kernel documents its safe value.
|
|
18
|
+
*
|
|
19
|
+
* The shapes are lifted, exactly, from the shipped example family (the extraction ratchet:
|
|
20
|
+
* four hand-rolls → one primitive): `imminence` from the calendar page's 1 Hz clock,
|
|
21
|
+
* `retention` from the memory page's forgetting curve, `freshness` as the canonical form of
|
|
22
|
+
* the backlog/inbox recency lanes. `data-field-at` (see `@fundamental-engine/platform`) feeds
|
|
23
|
+
* `freshness` to ground the metric pipeline's recency lane in declared world time.
|
|
24
|
+
*/
|
|
25
|
+
/** One hour in milliseconds — `imminence`'s log-softening unit (the calendar shape is hour-calibrated). */
|
|
26
|
+
export const HOUR_MS = 3_600_000;
|
|
27
|
+
/** One day in milliseconds — `retention`'s τ defaults are day-calibrated (4 + a·56 days). */
|
|
28
|
+
export const DAY_MS = 86_400_000;
|
|
29
|
+
const clamp01 = (n) => (n < 0 ? 0 : n > 1 ? 1 : n);
|
|
30
|
+
/**
|
|
31
|
+
* How imminent a moment feels: `1` at (or past) the moment, log-ramping down to `0` at the
|
|
32
|
+
* far edge of the horizon.
|
|
33
|
+
*
|
|
34
|
+
* The exact form, with `until = atMs − nowMs`:
|
|
35
|
+
*
|
|
36
|
+
* imminence = clamp01( 1 − ln(until/HOUR_MS + 1) / ln(horizonMs/HOUR_MS + 1) )
|
|
37
|
+
*
|
|
38
|
+
* i.e. the calendar example's weight, `1 − ln(hoursUntil + 1) / ln(horizonHours + 1)`, with
|
|
39
|
+
* hours generalized to milliseconds. The one-hour softening unit (`+1` in hour units) is part
|
|
40
|
+
* of the shape: it keeps the ramp finite at `until = 0` and makes the last hours before the
|
|
41
|
+
* moment the steepest part of the curve. Returns `1` for any `until ≤ 0` (the moment has
|
|
42
|
+
* arrived — what a page does with a *passed* moment, e.g. the calendar's `0.08` floor for
|
|
43
|
+
* passed/TBD launches, is page semantics layered on top). Monotonically non-increasing in
|
|
44
|
+
* `until`; `0` at and beyond the horizon.
|
|
45
|
+
*
|
|
46
|
+
* Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
|
|
47
|
+
* `horizonMs` returns `1` at/past the moment and `0` otherwise (no horizon, no ramp).
|
|
48
|
+
*/
|
|
49
|
+
export function imminence(atMs, nowMs, horizonMs) {
|
|
50
|
+
if (!Number.isFinite(atMs) || !Number.isFinite(nowMs))
|
|
51
|
+
return 0;
|
|
52
|
+
const until = atMs - nowMs;
|
|
53
|
+
if (until <= 0)
|
|
54
|
+
return 1;
|
|
55
|
+
if (!Number.isFinite(horizonMs) || horizonMs <= 0)
|
|
56
|
+
return 0;
|
|
57
|
+
return clamp01(1 - Math.log(until / HOUR_MS + 1) / Math.log(horizonMs / HOUR_MS + 1));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Exponential newness decay — the backlog/inbox recency shape in its canonical form:
|
|
61
|
+
*
|
|
62
|
+
* freshness = 2^(−since / halfLifeMs) with since = nowMs − atMs
|
|
63
|
+
*
|
|
64
|
+
* `1` at the moment itself, **exactly `0.5` one half-life later**, `0.25` after two, → `0`
|
|
65
|
+
* asymptotically. Future timestamps (`since < 0`) clamp to `1` — nothing is fresher than now.
|
|
66
|
+
* Monotonically non-increasing in `since`.
|
|
67
|
+
*
|
|
68
|
+
* Naming: this lane reads positively — the complement is *staleness*, and it is deliberately
|
|
69
|
+
* not exported: `staleness = 1 − freshness`. One word per lane.
|
|
70
|
+
*
|
|
71
|
+
* Degenerate inputs: a non-finite `atMs`/`nowMs` returns `0`; a non-positive or non-finite
|
|
72
|
+
* `halfLifeMs` returns `1` at/before the moment and `0` after it (instant decay).
|
|
73
|
+
*/
|
|
74
|
+
export function freshness(atMs, nowMs, halfLifeMs) {
|
|
75
|
+
if (!Number.isFinite(atMs) || !Number.isFinite(nowMs))
|
|
76
|
+
return 0;
|
|
77
|
+
const since = nowMs - atMs;
|
|
78
|
+
if (since <= 0)
|
|
79
|
+
return 1;
|
|
80
|
+
if (!Number.isFinite(halfLifeMs) || halfLifeMs <= 0)
|
|
81
|
+
return 0;
|
|
82
|
+
return Math.pow(2, -since / halfLifeMs);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Ebbinghaus-shaped retention: how much of an anchored fact is still held after `sinceMs`.
|
|
86
|
+
*
|
|
87
|
+
* The exact form, lifted from the memory example's forgetting curve:
|
|
88
|
+
*
|
|
89
|
+
* retention = a · e^(−since / τ(a)) with τ(a) = tauBaseMs + a · tauGrowthMs
|
|
90
|
+
*
|
|
91
|
+
* which is the memory page's `w = a · exp(−days / τ)` with `τ = 4 + a·56` **in day units**,
|
|
92
|
+
* generalized to milliseconds with the day constant explicit (defaults `4 * DAY_MS` and
|
|
93
|
+
* `56 * DAY_MS`). The stability term is the point: τ *grows* with anchor strength, so deeply
|
|
94
|
+
* anchored facts decay slower — exponential decay alone forgets everything at one rate.
|
|
95
|
+
* `anchor` is clamped to `0..1`; `retention(a, 0)` is exactly `a`; monotonically
|
|
96
|
+
* non-increasing in `sinceMs` (negative `sinceMs` clamps to `0` — a future review holds full
|
|
97
|
+
* strength, it doesn't overshoot).
|
|
98
|
+
*
|
|
99
|
+
* The shape is Ebbinghaus's; the default constants are the memory page's, tuned for
|
|
100
|
+
* legibility, not fitted to recall data. Degenerate inputs: non-finite `anchor` reads as `0`;
|
|
101
|
+
* non-finite `sinceMs` or a non-positive τ returns `0` (nothing held).
|
|
102
|
+
*/
|
|
103
|
+
export function retention(anchor, sinceMs, opts = {}) {
|
|
104
|
+
const a = clamp01(Number.isFinite(anchor) ? anchor : 0);
|
|
105
|
+
if (!Number.isFinite(sinceMs))
|
|
106
|
+
return 0;
|
|
107
|
+
const since = sinceMs < 0 ? 0 : sinceMs;
|
|
108
|
+
const tau = (opts.tauBaseMs ?? 4 * DAY_MS) + a * (opts.tauGrowthMs ?? 56 * DAY_MS);
|
|
109
|
+
if (!Number.isFinite(tau) || tau <= 0)
|
|
110
|
+
return 0;
|
|
111
|
+
return a * Math.exp(-since / tau);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Cyclical phase: where `nowMs` sits inside a repeating period, as `0..1` (the result is in
|
|
115
|
+
* `[0, 1)` — the wrap point reads as `0`, never `1`).
|
|
116
|
+
*
|
|
117
|
+
* phase = ((nowMs − offsetMs) mod periodMs) / periodMs
|
|
118
|
+
*
|
|
119
|
+
* with a true (sign-safe) modulo, so times before the offset wrap correctly. `offsetMs`
|
|
120
|
+
* anchors the cycle's zero — e.g. a local midnight for a day rhythm, a Monday 00:00 for a
|
|
121
|
+
* week rhythm.
|
|
122
|
+
*
|
|
123
|
+
* Honesty note: this kernel ships for completeness of the world-time family (day/week
|
|
124
|
+
* rhythms are the obvious fourth shape next to imminence, freshness, and retention), but
|
|
125
|
+
* **no shipped page or pipeline consumes it yet** — it has no worked example.
|
|
126
|
+
*
|
|
127
|
+
* Degenerate inputs: a non-finite `nowMs`/`offsetMs` or a non-positive/non-finite `periodMs`
|
|
128
|
+
* returns `0`.
|
|
129
|
+
*/
|
|
130
|
+
export function phase(nowMs, periodMs, offsetMs = 0) {
|
|
131
|
+
if (!Number.isFinite(nowMs) || !Number.isFinite(offsetMs))
|
|
132
|
+
return 0;
|
|
133
|
+
if (!Number.isFinite(periodMs) || periodMs <= 0)
|
|
134
|
+
return 0;
|
|
135
|
+
const m = (nowMs - offsetMs) % periodMs;
|
|
136
|
+
const f = (m < 0 ? m + periodMs : m) / periodMs;
|
|
137
|
+
return f >= 1 ? 0 : f; // float wrap guard: x + period can round to period
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=temporal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.js","sourceRoot":"","sources":["../../src/core/temporal.ts"],"names":[],"mappings":"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"}
|