@uptimizr/sdk-core 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/aggregation/aggregator.d.ts +62 -0
  2. package/dist/aggregation/aggregator.d.ts.map +1 -0
  3. package/dist/aggregation/aggregator.js +194 -0
  4. package/dist/aggregation/aggregator.js.map +1 -0
  5. package/dist/aggregation/index.d.ts +14 -0
  6. package/dist/aggregation/index.d.ts.map +1 -0
  7. package/dist/aggregation/index.js +11 -0
  8. package/dist/aggregation/index.js.map +1 -0
  9. package/dist/aggregation/math.d.ts +63 -0
  10. package/dist/aggregation/math.d.ts.map +1 -0
  11. package/dist/aggregation/math.js +118 -0
  12. package/dist/aggregation/math.js.map +1 -0
  13. package/dist/aggregation/snapshot.d.ts +123 -0
  14. package/dist/aggregation/snapshot.d.ts.map +1 -0
  15. package/dist/aggregation/snapshot.js +16 -0
  16. package/dist/aggregation/snapshot.js.map +1 -0
  17. package/dist/aggregationSink.d.ts +67 -0
  18. package/dist/aggregationSink.d.ts.map +1 -0
  19. package/dist/aggregationSink.js +110 -0
  20. package/dist/aggregationSink.js.map +1 -0
  21. package/dist/client.d.ts +22 -0
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/client.js +69 -3
  24. package/dist/client.js.map +1 -1
  25. package/dist/index.d.ts +4 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/offloadProtocol.d.ts +52 -8
  30. package/dist/offloadProtocol.d.ts.map +1 -1
  31. package/dist/offloadWorker.js +38 -7
  32. package/dist/offloadWorker.js.map +1 -1
  33. package/dist/processor.d.ts +2 -0
  34. package/dist/processor.d.ts.map +1 -1
  35. package/dist/processor.js +1 -1
  36. package/dist/processor.js.map +1 -1
  37. package/dist/types.d.ts +15 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +2 -2
@@ -0,0 +1,62 @@
1
+ import type { EventInput } from "../types.js";
2
+ import type { Snapshot } from "./snapshot.js";
3
+ /**
4
+ * Serializable per-channel configuration for the {@link Aggregator}, mirroring the
5
+ * connector's resolved capture config. It holds only plain data (no callbacks or
6
+ * handles) so it can be `postMessage`d to the offload worker unchanged. Passed
7
+ * once at construction so per-frame snapshots stay lean.
8
+ */
9
+ export interface AggregatorConfig {
10
+ /** Frame-perf channel knobs (#41). */
11
+ perf?: {
12
+ /** Suppress a perf sample whose FPS is within `fpsThreshold` of the last. */
13
+ suppressIdle: boolean;
14
+ /** FPS dead-zone for idle suppression. */
15
+ fpsThreshold: number;
16
+ };
17
+ /** Node/bone transform channel knobs (ADR 0027). */
18
+ node?: {
19
+ /** Suppress a transform sample unchanged from the last within its epsilon. */
20
+ suppressIdle: boolean;
21
+ };
22
+ /** Mesh-visibility channel knobs (#37, ADR 0012). */
23
+ visibility?: {
24
+ /** Cosine of the centred half-angle (`centeredMs` gate). */
25
+ centeredCos: number;
26
+ /** Whether to ride along world AABBs (#53). */
27
+ boundingBox: boolean;
28
+ /** AABB change dead-zone before a bounds re-send. */
29
+ boundsEps: number;
30
+ };
31
+ }
32
+ /**
33
+ * {@link Aggregator} construction options: the serializable {@link AggregatorConfig}
34
+ * plus the (non-serializable) sink for finalized events. In main mode the sink is
35
+ * the client `emit`; in the worker it buffers events to post back to the page.
36
+ */
37
+ export interface AggregatorOptions extends AggregatorConfig {
38
+ /** Sink for finalized events. In main mode this is the client `emit`. */
39
+ emit: (event: EventInput) => void;
40
+ }
41
+ /**
42
+ * The engine-agnostic **Aggregator** (ADR 0031 follow-up, #10): the single home
43
+ * for the offload-eligible *processing* phase of per-frame capture. It consumes
44
+ * the connectors' plain-number {@link Snapshot} DTOs and produces finalized
45
+ * `@uptimizr/schema` events — running the frame-time percentiles, matrix
46
+ * decomposition, mesh-visibility bucketing, idle-diffing and gesture
47
+ * classification that used to live, duplicated, inside each connector.
48
+ *
49
+ * It holds no engine or DOM handle, so the *same instance logic* runs unchanged
50
+ * on the main thread (default) or inside the offload worker (opt-in). All math is
51
+ * the shared, isomorphic functions from {@link ./math.js}, {@link ../matrix.js}
52
+ * and {@link ../gesture.js} — there is no worker-only fork (ADR 0031 §2).
53
+ */
54
+ export interface Aggregator {
55
+ /** Ingest one snapshot, emitting any resulting finalized events synchronously. */
56
+ ingest(snapshot: Snapshot): void;
57
+ /** Reset all per-channel windowed state (e.g. between sessions). Idempotent. */
58
+ reset(): void;
59
+ }
60
+ /** Create an {@link Aggregator}. */
61
+ export declare function createAggregator(options: AggregatorOptions): Aggregator;
62
+ //# sourceMappingURL=aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../src/aggregation/aggregator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAU9C,OAAO,KAAK,EAA8B,QAAQ,EAA0B,MAAM,eAAe,CAAC;AAElG;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,IAAI,CAAC,EAAE;QACL,6EAA6E;QAC7E,YAAY,EAAE,OAAO,CAAC;QACtB,0CAA0C;QAC1C,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,oDAAoD;IACpD,IAAI,CAAC,EAAE;QACL,8EAA8E;QAC9E,YAAY,EAAE,OAAO,CAAC;KACvB,CAAC;IACF,qDAAqD;IACrD,UAAU,CAAC,EAAE;QACX,4DAA4D;QAC5D,WAAW,EAAE,MAAM,CAAC;QACpB,+CAA+C;QAC/C,WAAW,EAAE,OAAO,CAAC;QACrB,qDAAqD;QACrD,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,yEAAyE;IACzE,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACnC;AAUD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU;IACzB,kFAAkF;IAClF,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IACjC,gFAAgF;IAChF,KAAK,IAAI,IAAI,CAAC;CACf;AAED,oCAAoC;AACpC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CA6LvE"}
@@ -0,0 +1,194 @@
1
+ import { classifyCameraGesture } from "../gesture.js";
2
+ import { decomposeWorldMatrix } from "../matrix.js";
3
+ import { aabbClose, nodeSampleUnchanged, percentileAsc, roundAabb, visibilityContribution, length3, } from "./math.js";
4
+ /** Create an {@link Aggregator}. */
5
+ export function createAggregator(options) {
6
+ const emit = options.emit;
7
+ // --- frame_perf state ---
8
+ let lastFps;
9
+ // --- node_transform state (keyed by nodeId\0(childPath|boneId)) ---
10
+ const lastNodeSample = new Map();
11
+ // --- mesh_visibility window state ---
12
+ let accums = new Map();
13
+ const sentBounds = new Map();
14
+ function handlePerf(s) {
15
+ const window = s.frameTimes;
16
+ let percentiles;
17
+ if (window.length > 0) {
18
+ let longFrames = 0;
19
+ for (let i = 0; i < window.length; i++) {
20
+ if (window[i] > s.jankFrameMs)
21
+ longFrames++;
22
+ }
23
+ const sorted = Array.from(window).sort((a, b) => a - b);
24
+ percentiles = {
25
+ frameTimeP95Ms: percentileAsc(sorted, 95),
26
+ frameTimeP99Ms: percentileAsc(sorted, 99),
27
+ longFrames,
28
+ };
29
+ }
30
+ const suppress = options.perf?.suppressIdle ?? false;
31
+ const threshold = options.perf?.fpsThreshold ?? 0;
32
+ if (suppress && lastFps !== undefined && Math.abs(s.fps - lastFps) <= threshold) {
33
+ return;
34
+ }
35
+ lastFps = s.fps;
36
+ emit({
37
+ type: "frame_perf",
38
+ fps: s.fps,
39
+ ...(percentiles ?? {}),
40
+ ...(typeof s.dpr === "number" && s.dpr > 0 ? { dpr: s.dpr } : {}),
41
+ ...(s.renderScale !== undefined ? { renderScale: s.renderScale } : {}),
42
+ });
43
+ }
44
+ function handleNode(s) {
45
+ const sample = s.decomposed ?? decomposeNode(s.matrix, s.scaleEps);
46
+ const key = s.boneId
47
+ ? `${s.nodeId}\u0000bone\u0000${s.boneId}`
48
+ : s.childPath !== undefined
49
+ ? `${s.nodeId}\u0000${s.childPath}`
50
+ : s.nodeId;
51
+ const suppress = options.node?.suppressIdle ?? false;
52
+ const prev = lastNodeSample.get(key);
53
+ if (suppress && prev && nodeSampleUnchanged(prev, sample, s.scaleEps)) {
54
+ return;
55
+ }
56
+ lastNodeSample.set(key, sample);
57
+ emit({
58
+ type: "node_transform",
59
+ nodeId: s.nodeId,
60
+ ...(s.childPath !== undefined ? { childPath: s.childPath } : {}),
61
+ ...(s.boneId !== undefined ? { boneId: s.boneId } : {}),
62
+ position: sample.position,
63
+ rotation: sample.rotation,
64
+ ...(sample.scale ? { scale: sample.scale } : {}),
65
+ });
66
+ }
67
+ function handleVisibilityTick(s) {
68
+ if (s.stepMs <= 0)
69
+ return;
70
+ const centeredCos = options.visibility?.centeredCos ?? 1;
71
+ const boundingBox = options.visibility?.boundingBox ?? false;
72
+ const fwdLen = length3(s.forward) || 1;
73
+ const halfFov = (s.fov || 0.8) / 2;
74
+ for (const obs of s.meshes) {
75
+ const { centered, frac } = visibilityContribution(s.camPos, s.forward, fwdLen, halfFov, obs.center, obs.radius, centeredCos);
76
+ let acc = accums.get(obs.mesh);
77
+ if (!acc) {
78
+ acc = { visibleMs: 0, centeredMs: 0, maxScreenFraction: 0 };
79
+ accums.set(obs.mesh, acc);
80
+ }
81
+ acc.visibleMs += s.stepMs;
82
+ if (centered)
83
+ acc.centeredMs += s.stepMs;
84
+ if (frac > acc.maxScreenFraction)
85
+ acc.maxScreenFraction = frac;
86
+ if (boundingBox && obs.aabb)
87
+ acc.bounds = obs.aabb;
88
+ }
89
+ }
90
+ function handleVisibilityFlush() {
91
+ if (accums.size === 0)
92
+ return;
93
+ const boundsEps = options.visibility?.boundsEps ?? 1e-3;
94
+ const pending = accums;
95
+ accums = new Map();
96
+ for (const [mesh, acc] of pending) {
97
+ if (acc.visibleMs <= 0)
98
+ continue;
99
+ let bounds;
100
+ if (acc.bounds) {
101
+ const prev = sentBounds.get(mesh);
102
+ if (!prev || !aabbClose(prev, acc.bounds, boundsEps)) {
103
+ bounds = roundAabb(acc.bounds);
104
+ sentBounds.set(mesh, acc.bounds);
105
+ }
106
+ }
107
+ emit({
108
+ type: "mesh_visibility",
109
+ mesh,
110
+ visibleMs: Math.round(acc.visibleMs),
111
+ ...(acc.centeredMs > 0 ? { centeredMs: Math.round(acc.centeredMs) } : {}),
112
+ ...(acc.maxScreenFraction > 0
113
+ ? { maxScreenFraction: Math.round(acc.maxScreenFraction * 1e4) / 1e4 }
114
+ : {}),
115
+ ...(bounds ? { bounds } : {}),
116
+ });
117
+ }
118
+ }
119
+ return {
120
+ ingest(snapshot) {
121
+ switch (snapshot.channel) {
122
+ case "camera":
123
+ emit({
124
+ type: "camera_sample",
125
+ position: snapshot.position,
126
+ direction: snapshot.direction,
127
+ ...(snapshot.target ? { target: snapshot.target } : {}),
128
+ ...(snapshot.fov !== undefined ? { fov: snapshot.fov } : {}),
129
+ ...(snapshot.aspect !== undefined ? { aspect: snapshot.aspect } : {}),
130
+ ...(snapshot.near !== undefined ? { near: snapshot.near } : {}),
131
+ ...(snapshot.hitPoint ? { hitPoint: snapshot.hitPoint } : {}),
132
+ ...(snapshot.hitMesh ? { hitMesh: snapshot.hitMesh } : {}),
133
+ });
134
+ return;
135
+ case "perf":
136
+ handlePerf(snapshot);
137
+ return;
138
+ case "node":
139
+ handleNode(snapshot);
140
+ return;
141
+ case "visibilityTick":
142
+ handleVisibilityTick(snapshot);
143
+ return;
144
+ case "visibilityFlush":
145
+ handleVisibilityFlush();
146
+ return;
147
+ case "gesture": {
148
+ const classified = classifyCameraGesture(snapshot.start, snapshot.end, snapshot.options ?? {});
149
+ if (!classified)
150
+ return;
151
+ emit({
152
+ type: "camera_gesture",
153
+ kind: classified.kind,
154
+ durationMs: snapshot.durationMs,
155
+ ...(classified.orbitDeg !== undefined ? { orbitDeg: classified.orbitDeg } : {}),
156
+ ...(classified.rollDeg !== undefined ? { rollDeg: classified.rollDeg } : {}),
157
+ ...(classified.zoomRatio !== undefined ? { zoomRatio: classified.zoomRatio } : {}),
158
+ ...(classified.panDist !== undefined ? { panDist: classified.panDist } : {}),
159
+ ...(snapshot.source ? { source: snapshot.source } : {}),
160
+ });
161
+ return;
162
+ }
163
+ case "hover":
164
+ emit({
165
+ type: "hover_dwell",
166
+ mesh: snapshot.mesh,
167
+ dwellMs: snapshot.dwellMs,
168
+ ...(snapshot.source ? { source: snapshot.source } : {}),
169
+ });
170
+ return;
171
+ }
172
+ },
173
+ reset() {
174
+ lastFps = undefined;
175
+ lastNodeSample.clear();
176
+ accums = new Map();
177
+ sentBounds.clear();
178
+ },
179
+ };
180
+ }
181
+ /** Decompose a 16-float column-major matrix into a node sample (scale omitted if identity). */
182
+ function decomposeNode(matrix, scaleEps) {
183
+ if (!matrix || matrix.length < 16) {
184
+ return { position: [0, 0, 0], rotation: [0, 0, 0, 1] };
185
+ }
186
+ const d = decomposeWorldMatrix(matrix);
187
+ const sample = { position: d.position, rotation: d.rotation };
188
+ const [sx, sy, sz] = d.scale;
189
+ if (Math.abs(sx - 1) > scaleEps || Math.abs(sy - 1) > scaleEps || Math.abs(sz - 1) > scaleEps) {
190
+ sample.scale = d.scale;
191
+ }
192
+ return sample;
193
+ }
194
+ //# sourceMappingURL=aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.js","sourceRoot":"","sources":["../../src/aggregation/aggregator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Connector-side offload aggregation (ADR 0031 follow-up, #10).
3
+ *
4
+ * The {@link Aggregator} owns the offload-eligible *processing* phase of
5
+ * per-frame capture; connectors feed it plain-number {@link Snapshot} DTOs. The
6
+ * pure math is exported too so it has a single, shared home (no per-engine fork).
7
+ */
8
+ export { createAggregator } from "./aggregator.js";
9
+ export type { Aggregator, AggregatorConfig, AggregatorOptions } from "./aggregator.js";
10
+ export { collectSnapshotTransferables } from "./snapshot.js";
11
+ export type { Snapshot, SnapshotChannel, CameraSnapshot, PerfSnapshot, NodeSnapshot, VisibilityMeshObservation, VisibilityTickSnapshot, VisibilityFlushSnapshot, GestureSnapshot, HoverSnapshot, } from "./snapshot.js";
12
+ export { percentileAsc, visibilityContribution, aabbClose, roundAabb, vec3Close, poseUnchanged, nodeSampleUnchanged, clamp01, sub3, dot3, length3, } from "./math.js";
13
+ export type { VisibilityContribution, CameraPose, NodeSample } from "./math.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/aggregation/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EACV,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,sBAAsB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Connector-side offload aggregation (ADR 0031 follow-up, #10).
3
+ *
4
+ * The {@link Aggregator} owns the offload-eligible *processing* phase of
5
+ * per-frame capture; connectors feed it plain-number {@link Snapshot} DTOs. The
6
+ * pure math is exported too so it has a single, shared home (no per-engine fork).
7
+ */
8
+ export { createAggregator } from "./aggregator.js";
9
+ export { collectSnapshotTransferables } from "./snapshot.js";
10
+ export { percentileAsc, visibilityContribution, aabbClose, roundAabb, vec3Close, poseUnchanged, nodeSampleUnchanged, clamp01, sub3, dot3, length3, } from "./math.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/aggregation/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,4BAA4B,EAAE,MAAM,eAAe,CAAC;AAa7D,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,SAAS,EACT,SAAS,EACT,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,OAAO,GACR,MAAM,WAAW,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { Aabb, Quat, Vec3 } from "@uptimizr/schema";
2
+ /**
3
+ * Shared, engine-agnostic aggregation math (ADR 0031 follow-up, #10).
4
+ *
5
+ * These are the pure number-crunching helpers that used to live, duplicated,
6
+ * inside each connector's `collector.ts` (percentile, mesh-visibility, and
7
+ * idle-diff math). They are extracted here so the offload {@link Aggregator}
8
+ * and any remaining main-thread caller share **one** implementation — the same
9
+ * function runs unchanged on the main thread or inside a worker (ADR 0031 §2,
10
+ * "no worker-only forks of logic").
11
+ */
12
+ /**
13
+ * Nearest-rank percentile over an **ascending-sorted** array. `p` is in `[0,100]`.
14
+ * Returns `0` for an empty window. Matches the connectors' historical
15
+ * `percentileAsc` exactly so percentile output is byte-for-byte unchanged.
16
+ */
17
+ export declare function percentileAsc(sortedAsc: number[], p: number): number;
18
+ export declare function sub3(a: Vec3, b: Vec3): Vec3;
19
+ export declare function dot3(a: Vec3, b: Vec3): number;
20
+ export declare function length3(a: Vec3): number;
21
+ /** Clamp a value into the `[0, 1]` range (for normalized fractions). */
22
+ export declare function clamp01(n: number): number;
23
+ /** One mesh's per-tick contribution to its visibility accumulator. */
24
+ export interface VisibilityContribution {
25
+ /** Whether the object's centre is within the centred half-angle (gaze proxy). */
26
+ centered: boolean;
27
+ /** Bounding-sphere angular size as a fraction of the vertical FOV (`0`–`1`). */
28
+ frac: number;
29
+ }
30
+ /**
31
+ * Per-tick screen-fraction + centred test for one mesh, given the camera pose and
32
+ * the mesh's world bounding sphere. Mirrors the connectors' historical math: a
33
+ * coarse prominence proxy from the bounding-sphere angular size as a fraction of
34
+ * the vertical FOV (ADR 0014 — proxy AABBs, not assets), and a "near the view
35
+ * centre" test from the angle between the view forward and the camera→centre ray.
36
+ */
37
+ export declare function visibilityContribution(camPos: Vec3, forward: Vec3, forwardLen: number, halfFov: number, center: Vec3, radius: number, centeredCos: number): VisibilityContribution;
38
+ /** True when two AABBs match on every component within `eps` (#53 dedupe). */
39
+ export declare function aabbClose(a: Aabb, b: Aabb, eps: number): boolean;
40
+ /** Round an AABB to millimetre precision for the wire (and to coarsen layout). */
41
+ export declare function roundAabb(a: Aabb): Aabb;
42
+ /** True when two vectors are equal within `eps` on every component. */
43
+ export declare function vec3Close(a: Vec3, b: Vec3, eps: number): boolean;
44
+ /** A camera pose compared between samples for idle suppression. */
45
+ export interface CameraPose {
46
+ position: Vec3;
47
+ direction: Vec3;
48
+ target?: Vec3;
49
+ fov?: number;
50
+ aspect?: number;
51
+ near?: number;
52
+ }
53
+ /** True when two poses are equal within `eps` (target/fov presence must also match). */
54
+ export declare function poseUnchanged(a: CameraPose, b: CameraPose, eps: number): boolean;
55
+ /** A captured world/local transform for a scene actor (`node_transform`, ADR 0027). */
56
+ export interface NodeSample {
57
+ position: Vec3;
58
+ rotation: Quat;
59
+ scale?: Vec3;
60
+ }
61
+ /** True when two node samples are equal within `eps` (scale presence must also match). */
62
+ export declare function nodeSampleUnchanged(a: NodeSample, b: NodeSample, eps: number): boolean;
63
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../src/aggregation/math.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;;;;;;GASG;AAIH;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAKpE;AAID,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,CAE3C;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAEvC;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzC;AAID,sEAAsE;AACtE,MAAM,WAAW,sBAAsB;IACrC,iFAAiF;IACjF,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,IAAI,EACZ,OAAO,EAAE,IAAI,EACb,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,sBAAsB,CAQxB;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAKhE;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,CASvC;AAID,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAIhE;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAahF;AAED,uFAAuF;AACvF,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,IAAI,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAatF"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Shared, engine-agnostic aggregation math (ADR 0031 follow-up, #10).
3
+ *
4
+ * These are the pure number-crunching helpers that used to live, duplicated,
5
+ * inside each connector's `collector.ts` (percentile, mesh-visibility, and
6
+ * idle-diff math). They are extracted here so the offload {@link Aggregator}
7
+ * and any remaining main-thread caller share **one** implementation — the same
8
+ * function runs unchanged on the main thread or inside a worker (ADR 0031 §2,
9
+ * "no worker-only forks of logic").
10
+ */
11
+ // --- Frame-time percentiles (#41) ------------------------------------------
12
+ /**
13
+ * Nearest-rank percentile over an **ascending-sorted** array. `p` is in `[0,100]`.
14
+ * Returns `0` for an empty window. Matches the connectors' historical
15
+ * `percentileAsc` exactly so percentile output is byte-for-byte unchanged.
16
+ */
17
+ export function percentileAsc(sortedAsc, p) {
18
+ if (sortedAsc.length === 0)
19
+ return 0;
20
+ const rank = Math.ceil((p / 100) * sortedAsc.length);
21
+ const idx = Math.min(sortedAsc.length, Math.max(1, rank)) - 1;
22
+ return sortedAsc[idx] ?? 0;
23
+ }
24
+ // --- Vector helpers --------------------------------------------------------
25
+ export function sub3(a, b) {
26
+ return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
27
+ }
28
+ export function dot3(a, b) {
29
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
30
+ }
31
+ export function length3(a) {
32
+ return Math.hypot(a[0], a[1], a[2]);
33
+ }
34
+ /** Clamp a value into the `[0, 1]` range (for normalized fractions). */
35
+ export function clamp01(n) {
36
+ return n < 0 ? 0 : n > 1 ? 1 : n;
37
+ }
38
+ /**
39
+ * Per-tick screen-fraction + centred test for one mesh, given the camera pose and
40
+ * the mesh's world bounding sphere. Mirrors the connectors' historical math: a
41
+ * coarse prominence proxy from the bounding-sphere angular size as a fraction of
42
+ * the vertical FOV (ADR 0014 — proxy AABBs, not assets), and a "near the view
43
+ * centre" test from the angle between the view forward and the camera→centre ray.
44
+ */
45
+ export function visibilityContribution(camPos, forward, forwardLen, halfFov, center, radius, centeredCos) {
46
+ const toCenter = sub3(center, camPos);
47
+ const dist = length3(toCenter) || 1e-6;
48
+ const cosAngle = dot3(toCenter, forward) / (dist * forwardLen);
49
+ const centered = cosAngle >= centeredCos;
50
+ const angularRadius = Math.atan2(radius, dist);
51
+ const frac = clamp01(angularRadius / (halfFov || 1e-6));
52
+ return { centered, frac };
53
+ }
54
+ /** True when two AABBs match on every component within `eps` (#53 dedupe). */
55
+ export function aabbClose(a, b, eps) {
56
+ for (let i = 0; i < 6; i++) {
57
+ if (Math.abs((a[i] ?? 0) - (b[i] ?? 0)) > eps)
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+ /** Round an AABB to millimetre precision for the wire (and to coarsen layout). */
63
+ export function roundAabb(a) {
64
+ return [
65
+ Math.round(a[0] * 1e3) / 1e3,
66
+ Math.round(a[1] * 1e3) / 1e3,
67
+ Math.round(a[2] * 1e3) / 1e3,
68
+ Math.round(a[3] * 1e3) / 1e3,
69
+ Math.round(a[4] * 1e3) / 1e3,
70
+ Math.round(a[5] * 1e3) / 1e3,
71
+ ];
72
+ }
73
+ // --- Idle-diffing (ADR 0012 conservative defaults) -------------------------
74
+ /** True when two vectors are equal within `eps` on every component. */
75
+ export function vec3Close(a, b, eps) {
76
+ return (Math.abs(a[0] - b[0]) <= eps && Math.abs(a[1] - b[1]) <= eps && Math.abs(a[2] - b[2]) <= eps);
77
+ }
78
+ /** True when two poses are equal within `eps` (target/fov presence must also match). */
79
+ export function poseUnchanged(a, b, eps) {
80
+ if (!vec3Close(a.position, b.position, eps))
81
+ return false;
82
+ if (!vec3Close(a.direction, b.direction, eps))
83
+ return false;
84
+ if ((a.target === undefined) !== (b.target === undefined))
85
+ return false;
86
+ if (a.target && b.target && !vec3Close(a.target, b.target, eps))
87
+ return false;
88
+ if ((a.fov === undefined) !== (b.fov === undefined))
89
+ return false;
90
+ if (a.fov !== undefined && b.fov !== undefined && Math.abs(a.fov - b.fov) > eps)
91
+ return false;
92
+ if ((a.aspect === undefined) !== (b.aspect === undefined))
93
+ return false;
94
+ if (a.aspect !== undefined && b.aspect !== undefined && Math.abs(a.aspect - b.aspect) > eps)
95
+ return false;
96
+ if ((a.near === undefined) !== (b.near === undefined))
97
+ return false;
98
+ if (a.near !== undefined && b.near !== undefined && Math.abs(a.near - b.near) > eps)
99
+ return false;
100
+ return true;
101
+ }
102
+ /** True when two node samples are equal within `eps` (scale presence must also match). */
103
+ export function nodeSampleUnchanged(a, b, eps) {
104
+ if (!vec3Close(a.position, b.position, eps))
105
+ return false;
106
+ if (Math.abs(a.rotation[0] - b.rotation[0]) > eps ||
107
+ Math.abs(a.rotation[1] - b.rotation[1]) > eps ||
108
+ Math.abs(a.rotation[2] - b.rotation[2]) > eps ||
109
+ Math.abs(a.rotation[3] - b.rotation[3]) > eps) {
110
+ return false;
111
+ }
112
+ if ((a.scale === undefined) !== (b.scale === undefined))
113
+ return false;
114
+ if (a.scale && b.scale && !vec3Close(a.scale, b.scale, eps))
115
+ return false;
116
+ return true;
117
+ }
118
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sourceRoot":"","sources":["../../src/aggregation/math.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import type { Vec3 } from "@uptimizr/schema";
2
+ import type { CameraGestureSample, GestureClassifyOptions } from "../gesture.js";
3
+ import type { CameraPose, NodeSample } from "./math.js";
4
+ /**
5
+ * Internal **snapshot DTOs** for the connector-side offload seam (ADR 0031
6
+ * follow-up, #10).
7
+ *
8
+ * These are the plain-data records a connector produces on the main thread after
9
+ * reading live engine state (the cheap "snapshot" phase) and hands to the
10
+ * {@link Aggregator} (the offload-eligible "processing" phase). They are an
11
+ * **internal SDK transport contract** — they never reach the wire, so they are
12
+ * deliberately *not* part of `@uptimizr/schema` (the wire contract stays
13
+ * unchanged; ADR 0031 §7, ADR 0003). The aggregator consumes them and produces
14
+ * the Zod-shaped `@uptimizr/schema` events.
15
+ *
16
+ * The boundary is kept clean: no engine or DOM handle crosses it, only numbers,
17
+ * ids and timestamps. High-volume channels (the frame-time window, node/bone
18
+ * matrices) are typed-array-backed so they can move to a worker zero-copy via
19
+ * the transferable mechanism (#98).
20
+ */
21
+ /** A camera pose + optional gaze hit. The connector has already idle-gated this. */
22
+ export interface CameraSnapshot {
23
+ channel: "camera";
24
+ position: Vec3;
25
+ direction: Vec3;
26
+ target?: Vec3;
27
+ fov?: number;
28
+ /** Viewport aspect ratio (width / height), when the connector captures it (#22). */
29
+ aspect?: number;
30
+ /** Camera near-plane distance in world units, when the connector captures it (#22). */
31
+ near?: number;
32
+ /** Surface hit of the forward gaze ray, when gaze capture is on (ADR 0030). */
33
+ hitPoint?: Vec3;
34
+ hitMesh?: string;
35
+ }
36
+ /**
37
+ * A frame-time window plus the engine perf reads taken at finalize time. The
38
+ * percentile sort, `longFrames` count and FPS idle-diff move to the aggregator.
39
+ * `frameTimes` is a fresh, owned `Float32Array` so it can be transferred.
40
+ */
41
+ export interface PerfSnapshot {
42
+ channel: "perf";
43
+ /** Per-frame deltas (ms) collected since the previous perf sample. */
44
+ frameTimes: Float32Array;
45
+ fps: number;
46
+ /** Frames slower than this (ms) count as `longFrames`. */
47
+ jankFrameMs: number;
48
+ dpr?: number;
49
+ renderScale?: number;
50
+ }
51
+ /**
52
+ * A node/bone transform snapshot. Either already-decomposed (engines that expose
53
+ * an absolute position/quaternion/scale, e.g. Babylon world nodes) or a raw
54
+ * column-major matrix (bones, three.js world matrices) the aggregator decomposes.
55
+ * Idle-diffing is keyed by `(nodeId, childPath ?? boneId)` and runs aggregator-side.
56
+ */
57
+ export interface NodeSnapshot {
58
+ channel: "node";
59
+ nodeId: string;
60
+ childPath?: string;
61
+ boneId?: string;
62
+ /** Pre-decomposed transform (mutually exclusive with {@link matrix}). */
63
+ decomposed?: NodeSample;
64
+ /** Column-major 16-float world/local matrix to decompose (transferable-backed). */
65
+ matrix?: Float32Array;
66
+ /** Scale dead-zone: scale within `scaleEps` of identity is omitted. */
67
+ scaleEps: number;
68
+ }
69
+ /** One mesh's per-tick visibility observation (engine reads already taken). */
70
+ export interface VisibilityMeshObservation {
71
+ mesh: string;
72
+ center: Vec3;
73
+ radius: number;
74
+ /** World AABB `[minX,minY,minZ,maxX,maxY,maxZ]`, when bounds capture is on (#53). */
75
+ aabb?: [number, number, number, number, number, number];
76
+ }
77
+ /** A single render-tick of mesh-visibility observations (#37). */
78
+ export interface VisibilityTickSnapshot {
79
+ channel: "visibilityTick";
80
+ /** Elapsed time of this tick in ms (the dwell increment). */
81
+ stepMs: number;
82
+ camPos: Vec3;
83
+ forward: Vec3;
84
+ /** Camera vertical FOV in radians (used for the screen-fraction proxy). */
85
+ fov: number;
86
+ meshes: VisibilityMeshObservation[];
87
+ }
88
+ /** Finalize the current mesh-visibility window: emit one summary per object. */
89
+ export interface VisibilityFlushSnapshot {
90
+ channel: "visibilityFlush";
91
+ }
92
+ /** A camera-gesture bracket (start→end) to classify (ADR 0025). */
93
+ export interface GestureSnapshot {
94
+ channel: "gesture";
95
+ start: CameraGestureSample;
96
+ end: CameraGestureSample;
97
+ /** Length of the input bracket (`down → up`) in ms, measured on the main thread. */
98
+ durationMs: number;
99
+ options?: GestureClassifyOptions;
100
+ /** Discrete input source that bracketed the gesture (ADR 0023), when known. */
101
+ source?: string;
102
+ }
103
+ /** A completed hover episode past its dwell threshold (#48). */
104
+ export interface HoverSnapshot {
105
+ channel: "hover";
106
+ mesh: string;
107
+ dwellMs: number;
108
+ source?: string;
109
+ }
110
+ /** The union the aggregator ingests. */
111
+ export type Snapshot = CameraSnapshot | PerfSnapshot | NodeSnapshot | VisibilityTickSnapshot | VisibilityFlushSnapshot | GestureSnapshot | HoverSnapshot;
112
+ /** Channel discriminator for a {@link Snapshot}. */
113
+ export type SnapshotChannel = Snapshot["channel"];
114
+ /** Re-export so callers can type the camera idle-diff pre-gate against it. */
115
+ export type { CameraPose };
116
+ /**
117
+ * Collect the transferable buffers a snapshot carries so they move to the worker
118
+ * zero-copy (ADR 0031 §6, #98). Transferring neuters the buffer on the main
119
+ * thread, so a snapshot that opts in must own a fresh buffer; the aggregator's
120
+ * default (main) path never transfers, so the buffer stays usable there.
121
+ */
122
+ export declare function collectSnapshotTransferables(snapshot: Snapshot): Transferable[];
123
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/aggregation/snapshot.ts"],"names":[],"mappings":"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"}